Upgrading movement to use acceleration / deceleration, rather than static values

Hi all!

I’m pretty comfortable with camera movement so far:


private void moveForward()
{
    float dist = (maxMoveSpeedInUnitsPerSecond / 1000) * Engine.DELTA;
    float addX = dist * Math.sin(Math.toRadians(camera.yaw));
    float addZ = dist * Math.cos(Math.toRadians(camera.yaw));

    camera.position.x += addX;
    camera.position.z += addZ;
}

However, this is a pretty linear way of moving around (a key press makes you instant move at your ‘maximum speed’).

I’d like to modify this set up to use some degree of acceleration (and deceleration). I’m not sure how to approach this concept, as I’m somewhat confused as to how acceleration / deceleration on both movement axes are combined (forward / reverse combined with strafing).

Any insights here would be most appreciated, thanks!

I would personally just do it the lazy way, and make a vector that holds both the x and y velocity, and then assign floats for acceleration (final float ACCEL = whatever you want, experiment), then assign another for friction (final float FRICTION = whatever you want). Each tick when not moving, use friction to decelerate, and any tick when a movement key is pressed, use accel to accelerate in that direction (so you just do something like player.velocity.x += ACCEL if say the D key was pressed,), then each tick you add the velocity to the camera vector, so Camera.x += velocity.x and camera.y += velocity.y.

An example of this lazy set up from my code:

public void doPlayerMovement(){
		if(Gdx.input.isKeyPressed(Keys.A)){
			if(player.xvel > -MAX_X_VEL){
				player.xvel -= accel;
			}
		}else if(Gdx.input.isKeyPressed(Keys.D)){
			if(player.xvel < MAX_X_VEL){
				player.xvel += accel;
			}
		}else{
			if(player.xvel < 0 && player.xvel < -friction){
				player.xvel += friction;
			}else if(player.xvel > 0 && player.xvel > friction){
				player.xvel -= friction;
			}else if(player.xvel < friction && player.xvel > 0){
				player.xvel = 0;
			}else if(player.xvel > -friction && player.xvel < 0){
				player.xvel = 0;
			}
		}
		if(Gdx.input.isKeyPressed(Keys.W) && grounded){
			player.yvel += 4;
			grounded = false;
		}else if(Gdx.input.isKeyPressed(Keys.W) && (touchingRight||touchingLeft) && jumpable && !grounded && player.yvel <= 2){
			player.yvel += 2;
			jumpable = false;
		}
		if(Gdx.input.isKeyPressed(Keys.S) && grounded){
			player.rect.height = 30;
		}else{
			player.rect.height = 60;
		}
		collisionChecks();
		handleJump();
	}

Mine doesn’t use a vector, it uses individual floats, but a vector is better (probably). I use S to crouch and W to jump, I just add velocity for my jump, it isn’t programmed any differently from my actual movement. Also, I am not moving the camera, so you would need to adjust for that, but it’s very similar in set up.

Here’s a handy method I’ve come across.


public static float tweenApproach(float maxSpeed, float currentSpeed, float accelerationSpeed) {
	float difference = maxSpeed - currentSpeed;
		
	if (difference > accelerationSpeed)
		return currentSpeed + accelerationSpeed;
	if (difference < -accelerationSpeed)
		return currentSpeed - accelerationSpeed;
	else
		return maxSpeed;
}

The credit goes to Jorge Rodriguez. He has some other great videos worth watching too, youtube/user/BSVino.

Thanks to you both for your helpful replies, I’ll get onto trying these out!

Many thanks again :slight_smile:

Havn’t done much outside of 2D but what works for very nice smooth movement is something like.


public float friction;
public float speed;
public Vector2f vel;

public void update()
{
if(moveRight)
vel.x += speed;
if(moveLeft)
vel.x -= speed;

vel *= friction; 
}

friction of like .98-.95 or so gives a nice deceleration for smooth movement.