So, I’m trying to program a side-on view metroidvania type platformer, and I’m running into a problem.
So, the method that keeps my character in the centre of the screen simply checks where they have moved to, then sets that to 0,0 to drag the screen to their position. However, this has been accomplished by changing player position directly, since any use of velocity changing position causes the character to accelerate unintentionally.
Due to this, most collision methods I look for are unsuitable as they require the use of a velocity variable, which I do not have.
Should I replace my camera method, or does anyone know a collision method that doesn’t need to use velocity?
Any answers are greatly appreciated.
so instead of moving the player you just move the whole world to always have the player at position 0?
what you normally do is, you have some sort of camera, which is positioned to the players position and in rendering, you are rendering everything in relation to the camera. Not moving the whole “world” to the position of the camera. Basically, the view and the world do not interact with their respective positions, it’s jsut used as an offset for displaying the world.
This also gives the option to lerp the camera position for smoother movement on the screen
Well PlayerPosition as a variable does change, but after said change, the world then shifts to return the player to (0,0).
This was discovered when I tried to use PlayerVelocity. Updates to PlayerVelocity caused PlayerPosition to update, however, they kept PlayerPosition updated. So after the world shifted, even though PlayerVelocity was correctly 0 (as I was not pressing any keys), PlayerPosition was still a non-zero value, and so the character would continue moving.
To remedy this, I simply changed it to PlayerPosition being modified instead of PlayerVelocity, but now that means that the player has no velocity and thus it doesn’t work with other collision methods I have looked at.
can you cache the value before moving the player to 0,0? so you can use it to compare the previous position against the last one so you get speed
Perhaps. But, in the time it took to get home from college, I just thought, what if I cached the desired location and the proposed speed, then checked for collision before moving? So it would take the button input, check the tiles for collision, then stop the movement at the point of collision. Using the desired location to obtain speed, it can then use a regular method of collision to figure it out. How does that sound?
This could certainly work, but it’s a somewhat roundabout way of doing things. And you’ve already seen one of the big pitfalls of doing things in a roundabout manner: your code becomes incompatible with online resources that use a simpler, more straightforward approach.
The same can be said for moving the world instead of a camera object.
What I’d recommend is taking another look at your previously mentioned velocity implementation, because “caching the desired location and the proposed speed” is exactly what a velocity implementation is. You cache the proposed speed in a velocity variable, and use that to set the position prior to drawing.
PlayerVelocity = 0; //Ensure that velocity defaults to 0 each frame
if(Key.IsDown(Keys.Right))
PlayerVelocity = 1;
else if(Key.IsDown(Keys.Left))
PlayerVelocity = -1;
PlayerPosition += PlayerVelocity;
WorldPosition -= PlayerPosition; //Player is a part of world, so
//it gets pulled back to 0,0 here
As reiti.net has said you should not be moving the world around. You create a 2d camera. There is plenty of sample code on the internet. You then move the camera and not the world. It would be much easier and generally considered best practice.
Just imagine trying to do a screen shake effect. If you don’t have a camera you would have to move every object in your world. If you have a proper 2d camera, all you have to do is just move the camera around.
That’s precisely part of the problem: that right there is exactly the code that caused the first problem. Even though the velocity is 0, the position is still changed, so it just shunts the player, and thus the entire world, along, continuing movement. As for the roundabout way of doing things, you can blame my college for that. I took all my camera work off their recommended, own-brand wiki, and it made the mess that I need to sort out now.
Ah, I think I understand. Player isn’t a child object of World, so pulling World back to 0,0 doesn’t pull Player back with it?
Assuming you want to make minimal changes to the existing code, is there anything stopping you from deliberately bringing PlayerPosition back to 0,0 alongside the World?
PlayerPosition += PlayerVelocity;
WorldPosition -= PlayerPosition;
PlayerPosition -= PlayerPosition;
As others have said, a 2d camera is a better way to go, but from an abstract point of view that’s exactly what the WorldPosition variable is. It’s the inverse of the camera position.
Well, I don’t think I even have a world object. It’s all ported in from Tiled using a tileset.
Honestly, I could do what is being suggested, but that still leaves the roundabout method left which causes innumerable complications. It would be best to do as suggested before and make the camera method from scratch.
You could also just implement a quadtree to check for collisions in the world.