LibGDX Box2D Applying Horizontal Linear Impulse Causes Object To Glide

Hello, I’m trying to implement player movement into my game using Box2D. Through applying linear impulses, the player is able to move around and jump, but, whenever the player jumps and move around, they appear to glide around.


	@Override
	public void update(float deltaTime) {
		super.update(deltaTime);

		Body body = this.getComponent(PhysicsComponent.class).body;
		Vector2 pos = body.getPosition();

		if(moveLeft) {
			body.applyLinearImpulse(new Vector2(-walkSpeed, 0F), pos, true); //move left
			facing = Direction.LEFT;
		}

		if(moveRight) {
			body.applyLinearImpulse(new Vector2(walkSpeed, 0F), pos, true); //move right
			facing = Direction.RIGHT;
		}

		if(!moveLeft && !moveRight) {
			Vector2 vel = body.getLinearVelocity();
			
			body.applyForce(new Vector2(-vel.x * 10F, 0F), pos, true); //stop
			
			walkTime = 0F;
			idleTime += deltaTime;
		} else {
			idleTime = 0F;
			walkTime += deltaTime;
		}
	}

	public void jump() {
		Body body = this.getComponent(PhysicsComponent.class).body;
		Vector2 pos = body.getPosition();
		
		body.applyLinearImpulse(new Vector2(0F, 100F), pos, true); //jump
	}

If I don’t move horizontally while falling, everything seems to be okay.

Could you elaborate on the desired behavior a bit. ‘Glide’ indicates that the player moves horizontally and down, which is generally I’d expect after a jump.

If you don’t want the player to be able to change direction while airborne you’ll want to check if the player is grounded prior to applying impulses.

Sorry being a little vague. I guess I’m defining “glide” as moving horizontally but falling at a much slower speed.

Here’s a video demonstration:

Olr9CDiOgrw

From what little I remember from playing with Box2D, I think I know what’s going on. You’re applying too much force and have a too low maximum velocity for your player. What happens is that the horizontal motion completely overwhelms the vertical motion, so when the velocity is capped to the max velocity, the vertical motion pretty much disappears.

Example: Max velocity 10, velocity (100, 1). Velocity is calculated to ~100.005, which is capped to the max velocity. The end result is that velocity is set to around (10, 0.1). If you keep pumping horizontal impulse into the entity, he’ll never be able to pick up speed and fall due to the max velocity clamping continually reducing the vertical velocity.

I’ll second your opinion Theagentd.
I’m using basically the same code and I haven’t seen that behavior, but I only limit maximum horizontal speed, not total or vertical. I’m guessing what you said is the reason why.

As a side note I found this example to be helpful when I was starting out with Box2D
http://www.badlogicgames.com/wordpress/?p=2017

I implemented a system to cap the horizontal velocity, but I’m still experiencing some of the “gliding,” and another problem.


	public float walkSpeed = 5F, maxWalkSpeed = 5F, jumpSpeed = 98F;

	@Override
	public void update(float deltaTime) {
		super.update(deltaTime);

		Body body = this.getComponent(PhysicsComponent.class).body;
		Vector2 pos = body.getPosition();
		Vector2 vel = body.getLinearVelocity();

		if(moveLeft) {
			body.applyLinearImpulse(new Vector2(-walkSpeed, 0F), pos, true); //move left
			facing = Direction.LEFT;
		}

		if(moveRight) {
			body.applyLinearImpulse(new Vector2(walkSpeed, 0F), pos, true); //move left
			facing = Direction.RIGHT;
		}
		
		if(Math.abs(vel.x) > maxWalkSpeed) {
			vel.x = Math.signum(vel.x) * maxWalkSpeed;
		}

		if(!moveLeft && !moveRight) {
			body.applyLinearImpulse(new Vector2(-vel.x * 1.5F, 0F), pos, true); //stop
			
			walkTime = 0F;
			idleTime += deltaTime;
		} else {
			idleTime = 0F;
			walkTime += deltaTime;
		}
	}

	public void jump() {
		Body body = this.getComponent(PhysicsComponent.class).body;
		Vector2 pos = body.getPosition();
		
		body.applyLinearImpulse(new Vector2(0F, jumpSpeed), pos, true); //jump
	}

If I’m understanding this correctly, whenever a player jumps while walking at full speed his velocity will be (5F, 98F). Would this be clamped in any way? If it did, it shouldn’t hamper the vertical velocity at all? Yet, I think an example of this is seen when I jump standing still vs. when I jump running. While standing still, I am able to clear a little more than 1.3 tiles (in my game). While running, I can clear about 0.5 tiles. I’m reluctant to lower the max walk speed any further since it seems a little slow for my purposes, and the jump speed is perfect since the player is able to move past tiles.

Also the vector for my world is (0, -98F).

It seams Theagentd and my original suggestion to change how you were limiting player velocity was wrong since you weren’t limiting player velocity at all.

I think the issue is that Box2D is tuned to work best with values 0.1 < 10 and your jump impulse and world vector are 98.

according to iforce there’s a compiled limit of 2 m/time step. This is adjustable but since it involves recompiling the library in c++ it’s probably not worth the time/effort unless you’re working with c++ regularly.
http://www.iforce2d.net/b2dtut/gotchas#speedlimit

sort of… You’re applying an impulse not setting a velocity. Impulse is the integral of force through time which loosely translates to velocity = impulse / (mass * time). That said I rambled on my blog for a post or two about how I couldn’t get theoretical impulse/acceleration/velocity to match the numbers I was getting out of box2D.

Ok, so I changed all my numbers and have thrown out anything pretty much any Box2D code that I wrote. In its place I used numbers and snippets from the example you provided yesterday, and it works. The time to fall doesn’t change when moving or standing still. Yet, for some reason everything seems sluggish? In the video provided with the example the player seems to be moving with ease and jumping relatively high. In my instance, my player is sluggishly moving around a non-moving platform and jumping and falling as if time has been slowed. My world step is synced to be the delta time provided by LibGDX, which is what the example uses. Additionally, my player’s friction is set to 0.2F when moving and 100F when standing still, and the platform I’m using has a density of 3F, with no other variables being touched.

Player code:


	public float walkSpeed = 2F, maxWalkSpeed = 7F, jumpSpeed = 30F;

	@Override
	public void update(float deltaTime) {
		super.update(deltaTime);

		PhysicsComponent phys = this.getComponent(PhysicsComponent.class);
		Body body = phys.body;
		Fixture fix = phys.fixture;
		Vector2 pos = body.getPosition();
		Vector2 vel = body.getLinearVelocity();

		if(moveLeft) {
			facing = Direction.LEFT;
			
			if(vel.x > -maxWalkSpeed) {
				body.applyLinearImpulse(new Vector2(-walkSpeed, 0F), pos, true); //move left
			}
		}

		if(moveRight) {
			facing = Direction.RIGHT;
			
			if(vel.x < maxWalkSpeed) {
				body.applyLinearImpulse(new Vector2(walkSpeed, 0F), pos, true); //move left
			}
		}
		
		if(Math.abs(vel.x) > maxWalkSpeed) {
			body.setLinearVelocity(Math.signum(vel.x) * maxWalkSpeed, vel.y);
		}

		if(!moveLeft && !moveRight) {
			body.setLinearVelocity(vel.x * 0.9F, vel.y);

			fix.setFriction(100F);
			walkTime = 0F;
			idleTime += deltaTime;
		} else {
			fix.setFriction(0.2F);
			idleTime = 0F;
			walkTime += deltaTime;
		}
	}

	public void jump() {
		Body body = this.getComponent(PhysicsComponent.class).body;
		Vector2 pos = body.getPosition();
		Vector2 vel = body.getLinearVelocity();
		
		body.setLinearVelocity(vel.x, 0F);
		body.setTransform(pos.x, pos.y + 0.01F, 0);
		body.applyLinearImpulse(0, jumpSpeed, pos.x, pos.y, true);
	}

World initialization:


world = new World(new Vector2(0, -20F), true);

If the ‘gliding’ is gone you can try fiddling with your impulse values, world vector and player mass until the responsiveness is where you want.

Otherwise I’m out of ideas. If you haven’t already try over on the box2d or iforce2d forums or even stack exchange.