Stuck in making 2D game movement engine
I am making a movement engine for my top-down 2D game, but I got stuck trying to solve the following problem:
- The player can move using the arrow keys, which accelerate you in the respective directions. There is friction so you stop moving after releasing the keys, though not instantly.
- When you hold two perpendicular keys, you accelerate in this 45° direction the same speed as you would on one axis
- There is a maximum speed which above you cannot accelerate by walking, this also limits your maximum walking speed, obviously. You can get knocked away, and thus exceed this speed however.
- If you move faster than max. walkspeed, you can slow down faster if you hold keys in the opposite direction(s)
Pseudocode for the first point, without friction:
gameTick(){
tempX += LeftKeyHeld ? -1 : 0;
tempX += RightKeyHeld ? 1 : 0;
tempY += UpKeyHeld ? -1 : 0;
tempY += DownKeyHeld ? 1 : 0;
ratio = 0.71;
if( |tempX| == |tempY| ) {
tempX =tempX* ratio;
tempY =tempY* ratio;
}
player.x += tempX;
player.y += tempY;
}
I can solve the friction (getting the length of the movement vector, reducing it by the friction, projecting it back with the same x:y ratio), however, I can't wrap my head around getting the maxSpeed done.
I tried a solution of not allowing the player to walk at all when above maxSpeed, but this violates point 4. Also, it had the nasty side-effect, that when you moved at MaxSpeed to the left, and started pressing down, the movement direction didn't, or barely changed.
Then I started thinking about numerous products, differences and other stuff with the vectors, but I mostly couldn't follow it anymore or ran into early problems.
So in conclusion, could someone explain a system which fulfills all the points above, or point to an article which explains how a system like this could be implemented? Don't worry about suggesting 开发者_如何学编程something complex, I can grasp even difficult concepts given some time.
Thanks for your help!
Sorry for not letting you think about this for more than a day, but I managed to solve it, and it ain't two lines of code. (Though still thanks for everyone for the ideas)
Because I'm lazy and tired, I won't change it to pseudocode, except the following two methods:
updateGame(){
player.walk();
player.move();
}
player.move(){
player.x += player.speedX
player.y += player.speedY
}
And the code (java):
public void walk() {
float tempX = 0;
float tempY = 0;
float accelX;
float accelY;
float nextSpeedX;
float nextSpeedY;
float nextSpeed;
float speed;
tempX += walkLeft ? -1 : 0;
tempX += walkRight ? 1 : 0;
tempY += walkUp ? -1 : 0;
tempY += walkDown ? 1 : 0;
if (Math.abs(tempX) == Math.abs(tempY)) {
tempX = (float) tempX * rat;
tempY = (float) tempY * rat;
}
accelX = tempX * (float) runSpeed;
accelY = tempY * (float) runSpeed;
speed = (float) Math.sqrt(speedX * speedX + speedY * speedY);
nextSpeedX = speedX + accelX;
nextSpeedY = speedY + accelY;
nextSpeed = (float) Math.sqrt(nextSpeedX * nextSpeedX + nextSpeedY * nextSpeedY);
if (nextSpeed > maxSpeed) { //can't accelerate by running
if (nextSpeed > speed) { //wants to accelerate
if (speed > maxSpeed) { //the current speed is larger than maximum.
float diff = (float)(speed / nextSpeed);
float greenX = nextSpeedX*diff;
float greenY = nextSpeedY*diff;
accelX = greenX-speedX;
accelY = greenY-speedY;
} else { //speed <= maxspeed
float diff = (float)(maxSpeed / nextSpeed);
float greenX = nextSpeedX*diff;
float greenY = nextSpeedY*diff;
accelX = greenX-speedX;
accelY = greenY-speedY;
}
} else { //wants to slow! allow it!
//acceleration doesn't need to be changed
}
} else { //no problem, allow it!
//acceleration doesn't need to be changed
}
speedX += accelX;
speedY += accelY;
}
Could be shorter, could be a bit more optimised, but it works. I hope this'll help anyone who stumbles upon this problem in the future.
Add to the bottom:
If (|tempX|>maxSpeed)
tempX=maxSpeed*sign(tempX);
If (|tempY|>maxSpeed)
tempY=maxSpeed*sign(tempX);
Where int sign(x) { if x<0 return -1; }
I'd suggest associating a specific velocity with the player in addition to position, and only checking that velocity against maxSpeed when arrow keys are pressed.
If the velocity DOES exceed maxSpeed, but the arrow keys from the opposite side are being pressed, then you'd keep the current velocity above maxSpeed and simply apply the negative acceleration.
精彩评论