[SOLVED] Wall Jumping Bug

Hi! I am trying to make it so that in my game the player is able to wall jump. I have managed to get it so it applies the force when it detects the sides are against a wall, but there is one small problem. The way my game is currently put together makes it so the player character never rotates, but the camera does. This is problematic because since the detects follow the camera and the player doesn’t, it tries to apply a left wall jump force when it is jumping off of the right wall. I need help fixing this.

Game: PlayCanvas 3D HTML5 Game Engine


I illustrated the problem for better understanding. The camera stays in the same spot relative to the player’s rigidbody, however the rigidbody receives force depending on which point is detected, so when you look behind you, the points swap, resulting in the force which should push you AWAY from the wall pushing you TOWARDS the wall. How can I fix it?

A couple of ways come to mind but they ultimately come down to using a local space vector to decide the direction.

Eg when player collides with the wall, get the position of the wall entity and use that to work out which side of the player they are on.

Or you can do a raycast and get the raycast normal to work out which way to jump off to

Well I currently have it raycast to those points shown in the diagram. It basically says “Ok, the raycast to the right of the camera wasn’t null, so boost them to the left” and vice versa. But the only problem is that when the player body doesn’t face the same way as the camera (because the camera rotates without the player rotating), it results in buggy movement. Do you know of any way that I can incorporate the players entity actually rotating instead of the camera? It would only rotate on the y axis (that way it turns from left to right but not up and down) and the camera rotates only up and down. I’ve just published a build that you could look at for this. (It is still the same link that is on the first post)

But you are doing it relative to the camera, not the player. I would make the logic work off the player’s position, not the camera.

Correct, because the points are under the camera instead of the player. How can I make it so the player rotates left and right instead of the camera so that these work properly? Doing that would fix my problems.

If I have it set the local Y euler angle of the player to the one that the camera would have set, it works as intended… that is until I start moving. Once I start moving, the camera snaps to (i think) 0, and only lets me move from side to side.

Do you need the player to rotate? Can you do a raycast from the player into the direction that they are/were jumping in to work out which side the wall is relative to the player?

I’ve started to figure out a solution, the reason the camera snaps is because it is trying to rotate to 0, which is odd. I will keep updated.

I failed horribly, but yes, I need the player to rotate on the y axis and for the camera to be linked to the player so it rotates when they rotate. Could you look at the build and see what could be done?

Whatever I try, it seems to work at first and stops working shortly after. I currently have it rotate the players Y axis but not the cameras Y axis, but while moving it doesn’t show the correct rotation for the camera at all times, and only shows it after the rigidbody is teleported.


I recorded what happens. As you can see, the rigidbody does rotate, as it moves in the direction it should move, but the camera does not rotate with it while moving and resets.

EDIT: I should also note it doesn’t let me move until I move my camera.

I’m just extremely confused why this all isn’t working, there is no reason that camera should be resetting orientation at all.

I’m afraid I don’t have the bandwidth to dig into a project to work out issues unfortunately

That’s fine, I found an issue that could be the solution to this if I can solve it. The camera never updates position until the rigidbody is teleported. How can I fix that? Shouldn’t it rotate with it all the time?

Hard to say without looking at the code tbh

Oh, well then here’s the code. After testing it, I deduced that NOTHING rotates with the rigidbody until it gets teleported.

FirstPersonMovement.prototype.update = function(dt) {
    this.camera.setLocalEulerAngles(this.eulers.y,this.entity.getLocalEulerAngles().y,0);
    this.entity.setLocalEulerAngles(0,this.eulers.x,0);
    //this.entity.rigidbody.teleport(this.entity.getPosition());
    
    
    

    this.normalJump = true;
    // If a camera isn't assigned from the Editor, create one
    if (!this.camera) {
        this._createCamera();
    }
    var force = this.force;
    var app = this.app;

    // Get camera directions to determine movement directions
    var forward = this.entity.forward;
    var right = this.entity.right;
       

    // 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) || app.keyboard.isPressed(pc.KEY_Q)) {
        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)) {
        var resultRight = this.app.systems.rigidbody.raycastFirst(this.entity.getPosition(), this.distanceEntRight.getPosition());
        var resultLeft = this.app.systems.rigidbody.raycastFirst(this.entity.getPosition(), this.distanceEntLeft.getPosition());
        var resultDown = this.app.systems.rigidbody.raycastFirst(this.entity.getPosition(), new pc.Vec3(this.entity.getPosition().x, this.entity.getPosition().y - 1.25, this.entity.getPosition().z));
        if (resultDown != null) {

        }
        if (resultDown == null && resultRight == null && resultLeft != null) {
            this.normalJump = false;
            this.entity.rigidbody.applyImpulse(1000,2000,0);
            
        }

        if (resultDown == null && resultRight != null && resultLeft == null) {
            this.normalJump = false;
            this.entity.rigidbody.applyImpulse(-1000,2000,0);
        }
        
        if (Math.floor(this.entity.rigidbody.linearVelocity.y) < 1 && Math.floor(this.entity.rigidbody.linearVelocity.y) > -2 && resultDown != null && this.normalJump == true) {
            this.entity.rigidbody.applyImpulse(0,1000,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.power);
        
        this.entity.rigidbody.applyForce(force);
    }

    // update camera angle from mouse events

    //this.camera.setLocalEulerAngles(this.eulers.y, this.eulers.x, 0);
};

Ok so I did another test, basically I put a render where the camera points. When the player is not moving, the camera is pointing where the rigidbody is looking, but as soon as the player starts moving, all things attached to the player go back to the orientation they had at the start.

This line looks the most suspect. You cannot set the rotation of a dynamic rigidbody via this method. This is because the dynamic rigidbody in the physics simulation will override the entity position and orientation in the update (ie when it moves).

Ah, how would I set its rotation properly? I don’t know of any way I would do this without using teleport, which removes my momentum/jitters my movement.