Y gravity breaking X

Godot Version

4.3

For player movement, I’m struggling with an interaction that doesn’t make much sense to me. For some reason, when I apply gravity to velocity.Y, it causes the player to stop being able to move to the left. The X velocity will go to -200, then drop (or rise, whatever) to -50 and stop moving. I thought it was some interaction between different bits for a while, but when I comment out everything except what I post below, it still does it. For some reason, the velocity.Y += gravity line is causing the X velocity to break. I’m completely lost on this.

public const float speed = 200f;
public const float jumpVelocity = -300f;
public const float gravity = 15f;
public const float friction = 25f;
public float acc = 50f;

 public Vector2 InputDirection() {
    Vector2 inputDir = Vector2.Zero;
    inputDir.X = Input.GetAxis("left", "right");
    return inputDir;
}

public override void _PhysicsProcess(double delta) {
    Vector2 velocity = Velocity;
    Vector2 inputDir = InputDirection();

 if (inputDir != Vector2.Zero) {
        velocity.X = velocity.MoveToward(speed * inputDir, acc).X;
    } else {
        velocity.X = velocity.MoveToward(Vector2.Zero, friction).X;
    }

 if (!IsOnFloor()) {
        velocity.Y += gravity;
    }

Edit: Alright, idk when I screwed this up, but I’m wrong about what’s wrong. if (!IsOnFloor() is not causing any problems, it’s just with the MoveToward stuff. I swear it was working properly when I eliminated that bit of code when I made this post, but now it doesn’t matter if I have it or not. So, the problem is entirely with the method of movement I’m using. I’m still not sure why that’s happening, if anyone has a suggestion.

If you call velocity.MoveToward and velocity has a y-component, it will output the velocity moved in a 2-dimensional straight line to the target velocity.


This does not correspond with the desired acceleration, which should be just on the x-axis with the length acc. A correct way to calculate would be for example: velocity.X += inputDir.X * acc * delta; (Using delta makes the speed the same on all framerates; this does dramatically slow everything down though so you’ll have to increase acc, friction, and gravity) Then, to clamp the horizontal speed to the maximum speed I think it would be velocity.X = Mathf.Clamp(velocity.X, -speed, speed);. To stop the deceleration from “overshooting” and flipping the velocity to the other direction, you should also clamp the deceleration to the absolute value of velocity.X. So, putting that together, the final process would be (I made inputDir a double because you don’t seem to be using the y-component anyway; I think InputDirection should really be private unless it’s used in another script for some reason)

private double InputDirection() {
	double inputDir = Input.GetAxis("left", "right");
	return inputDir;
}

public override void _PhysicsProcess(double delta) {
	Vector2 velocity = Velocity;
	double inputDir = InputDirection();

	if (inputDir != 0) {
		velocity.X += inputDir * acc * delta = velocity.MoveToward(speed * inputDir, acc).X;
		velocity.X = Mathf.Clamp(velocity.X, -speed, speed);
	}
	else {
		velocity.X -= Mathf.Clamp(Math.Sign(velocity.X) * friction * delta, -abs(velocity.X), abs(velocity.X))
	}

	if (!IsOnFloor()) {
		velocity.Y += gravity * delta;
	}

	// whatever you left out in the snippet
}

Unfortunately I have no way to test this because I don’t use C# for Godot, so sorry if there are any mistakes, at least the maths should be fine though