Manipulating Linear Damping only on the Y axis for jumping/falling

Hello All

Im currently trying to manipulate the Linear Damping only on the Y axis when the player is jumping/falling. Currently as you may know it is applied on all axis of a rigidbody and because of this when you set it at 0.99 (which is optimal to not slide on the surface when moving) it makes jumping/falling very slow. I tried an attempt after searching the forum but seems like I hit a brick wall.

Please could anyone help or put me in the right direction.

Below is the update function. The project can be found here: https://playcanvas.com/editor/scene/1191042

FirstPersonMovement.prototype.update = function(dt) {

    var force = this.force;
    var app = this.app;

    // Get camera directions to determine movement directions
    var forward = this.camera.forward;
    var right = this.camera.right;
    
    var linearDampingX = 0.99;
    var linearDampingY = 0;
    var linearDampingZ = 0.99;
    this.linearDamping = new pc.Vec3(linearDampingX, linearDampingY, linearDampingZ);
    
    var linearVelocity = this.entity.rigidbody.linearVelocity;
    linearVelocity.set(this.linearDamping);

    // movement
    var x = 0;
    var z = 0;

    // Use W-A-S-D keys to move player
    // Check for key presses
    if (app.keyboard.isPressed(pc.KEY_A)) {
        x -= right.x;
        z -= right.z;
    }

    if (app.keyboard.isPressed(pc.KEY_D)) {
        x += right.x;
        z += right.z;
    }

    if (app.keyboard.isPressed(pc.KEY_W)) {
        x += forward.x;
        z += forward.z;
    }

    if (app.keyboard.isPressed(pc.KEY_S)) {
        x -= forward.x;
        z -= forward.z;
    }
    
    if (app.keyboard.wasPressed(pc.KEY_SPACE)) {
        this.jumping = true;
        this.entity.rigidbody.linearVelocity = linearVelocity;
    }
    else {
        this.jumping = false;
    }
    
    if (this.jumping) {
        this.entity.rigidbody.applyImpulse(0, this.jumpPower, 0);
    }

    // use direction from keypresses to apply a force to the character
    if (x !== 0 && z !== 0) {
        force.set(x, 0, z).normalize().scale(this.movementSpeed);
        this.entity.rigidbody.applyForce(force);
    }

    // update camera angle from mouse events
    this.camera.setLocalEulerAngles(this.eulers.y, this.eulers.x, 0);
};

Thanks!

So, I think the issue in your case is you are trying to both apply an impulse momentarily and control the linear velocity of the body immediately after. Something there breaks your jumping.

I replaced your jumping code with only this:

    if (app.keyboard.wasPressed(pc.KEY_SPACE)) {
        this.entity.rigidbody.applyImpulse(0, this.jumpPower, 0);
    }

At the same time I parsed your script for the jumpPower attribute to appear, set it to 1000 and also set gravity in the project settings to 0, -20, 0 (that’s a common trick in FPS shooters to increase the falling spped).

Here is your project updated:

https://playcanvas.com/editor/scene/1199141

2 Likes

Hello

Thanks for the solution but this doesn’t work especially if the player is falling - the falling speed is still really slow even at -30 and I don’t want to manipulate the global gravity setting in the project because its not natural even though its a workaround.

Now that you said it, I think from what I understood I need to set and apply the linear damping globally in the script rather than controlling it inside the jump statement after jumping. But I still do not know how to manipulate this using code without breaking stuff. I wish there was option in engine rigidbody to change the values individually in each axis. I’m trying to get the x and z axis to be 0.99 but y axis to be 0 or 0.1.

If somebody has done something similar or has an idea of how to I would really appreciate it.

Thanks

You can check this thread on how to do it manually per axis Linear Damping issue. It should be a vector? XYZ? - #11 by steve_wk

And/Or you can apply a force downwards every frame/when it’s falling on just the player.

2 Likes

I’m checking this out now but its very difficult for me to convert this to javascript but I will try my best. Thanks for the suggestion.

In the meantime I did a workaround below which works well with -20 gravity. The movement speed while in the air is still a bit off and there is a constant raycast checking the floor at all time so its not optimal but works fine I guess.

var playerFalling = this.playerFalling;
var linearDamping = this.entity.rigidbody.linearDamping;
    
    if (!this.raycastFloor()) {
        this.playerFalling = true;
        movementSpeed = movementSpeed / 2;
    }
    else {
        this.playerFalling = false;
        
    }
    console.log(playerFalling);
    
    if (this.playerFalling) {
        this.entity.rigidbody.linearDamping = 0;
    }
    else {
        this.entity.rigidbody.linearDamping = 0.99;
    }
    console.log(linearDamping);

And/Or you can apply a force downwards every frame/when it’s falling on just the player.

@yaustar Do you think its better for me to try and manipulate each Axis of Linear Damping or do you think the applying force downwards would be better option. Does 1 have more benefit than other?

Also if anybody has experience of manipulating the linear damping per axis or could assist me with converting the C++ bullet code to javascript please reach out. I will attempt it myself but I am not confident because it seems very complicated and I would like to learn.

Honestly, it’s up to you.

I personally would manipulate each axis independently and add an extra falling force to make the jump feel right.

The C++ code for the damping is only one line:

m_linearVelocity *= btPow(btScalar(1) - m_linearDamping, timeStep);

m_linearVelocity being a 3 dimensional vector.

1 Like

I tried my best to do it for just the Y axis but I am not sure if it is close to being correct or completely wrong. Is the logic close? or did I understand it wrong? Please could you help me or explain in pseudo code for a noob like me because this is really interesting to learn but also really difficult. I want to be able to figure it out :relaxed:

//setDampingY function called every frame
FirstPersonMovement.prototype.setDampingY = function(dt) {
    var linearVelocity = new pc.Vec3(0, 0, 0);
    var linearDamping = new pc.Vec3(0, 0, 0);
    var linearDampingY = linearVelocity.y *= Math.pow(linearVelocity.y.mulScalar(1) - linearDamping.y * dt);
    
    linearVelocity.y *= linearDampingY;
    this.entity.rigidbody.linearVelocity.set(linearVelocity);
};

Ah. I think there’s a misunderstanding.

I was implying that you do the damping on the X and Z axis and leave the Y as is so that you can use ‘normal’ gravity values like -9.8

The logic is in the right direction but the calculation is wrong. I think it would even throw an error when you run it.

When you say the calculation is wrong is it to do with mulScalar function? I didn’t quite understand what btScalar means in the Bullet code so I got no clue how to calculation from there. Here is what I did for all axis individually using mulScalar, what do you think? Is it the right approach?

//setLinearDamping function called every frame
FirstPersonMovement.prototype.setLinearDamping = function(dt) {
    var linearVelocity = new pc.Vec3(0, 0, 0);
    var linearDamping = new pc.Vec3(0.99, 0, 0.99);
    var linearVelocityByAxis = new pc.Vec3(
        (linearVelocityX = linearVelocity.x *= Math.pow(linearVelocity.mulScalar(1)) - linearDamping.x, dt),
        (linearVelocityY = linearVelocity.y *= Math.pow(linearVelocity.mulScalar(1)) - linearDamping.y, dt),
        (linearVelocityZ = linearVelocity.z *= Math.pow(linearVelocity.mulScalar(1)) - linearDamping.z, dt)
    );
    linearVelocity *= linearVelocityByAxis;
    
    this.entity.rigidbody.linearVelocity.set(linearVelocity);
};

A look at the source shows that it’s a way of changing between double and float easily so we can leave it as a JS number type.

Here is an example project of the damping applied per axis and press space to jump: https://playcanvas.com/editor/scene/1200911

Damping code:

    // apply the damping
    var dampingAmount = Math.pow(1 - this.moveDamping, dt);
    var linearVelocity = this.entity.rigidbody.linearVelocity;
    linearVelocity.x *= dampingAmount;
    linearVelocity.z *= dampingAmount;

You were pretty much there, just seems like there was confusion on the btScaler function/macro from Bullet.

2 Likes

I am so dumb for overcomplicating it. I should have known that the logic would be to first: calculate the damping and then multiply the damping with the rigidbody’s linear velocity axes. The logic is more straightforward than I thought but the btScalar confused things for me. Thank you for this! You helped me a lot and inspire me to learn and create new things that I never done before. The Playcanvas community is amazing.

I will now apply a force downward when in the air to complete the jump/falling effect.

ALSO - can I ask why this code is inside a postUpdate function? and not the update function?

So that it happens after the physics simulation update.

1 Like