dimforge / rapier.js

Official JavaScript bindings for the Rapier physics engine.
https://rapier.rs
Apache License 2.0
392 stars 55 forks source link

KinematicCharacterController.setMaxSlopeClimbAngle is not working #274

Open khudiiash opened 1 month ago

khudiiash commented 1 month ago

I have a character controller and a trimesh as terrain. The terrain is mostly flat but has some heals and walls The character controller climbs on top of even the steepest hills, and the setMaxSlopeClimbAngle value does not change a thing.

rapier3D, v0.13.1, javascript

sebcrozet commented 1 month ago

Hi! Can you provide more informations on your setup? In particular, the piece of code where you initialize and call the character controller’s methods, and how you apply it to the corresponding rigid-body. What is the geometric shape of your character?

khudiiash commented 1 month ago

here's the code where I create and move the character controller setting any value to setMaxSlopeClimbAngle has no effect: the character climbs any slops that less than 90 degrees Geometric shape is a capsule.

create() {
        const RAPIER = pc.app.rapier;
        const offset = 0.01;

        this.controller = this.world.createCharacterController(offset);
        this.controller.setMaxSlopeClimbAngle(0);

        const rigidBodyDesc = new RAPIER.RigidBodyDesc(
            RAPIER.RigidBodyType.KinematicPositionBased,
        );

        this.body = this.world.createRigidBody(rigidBodyDesc);
        const position = this.entity.getPosition();
        this.body.setTranslation(position);

        const colliderDesc = RAPIER.ColliderDesc.capsule(0.8, 0.8);

        colliderDesc.setCollisionGroups(GROUPS.PLAYER);
        this.collider = this.world.createCollider(colliderDesc, this.body);

        this.collider.userData = { userID: this.app.userInfo.userID, isPlayer: true, isSelf: true }
        this.entity.rigidBody = this.body;
        this.world.character = this;
    },
        move(input, dt = 0.01666) {
        if (!this.body) return;
        const direction = input.inputMove;
        const current = this.body.translation();

        this.vector.x = direction.x * input.speed * dt;
        this.vector.y = 0;
        this.vector.z = direction.z * input.speed * dt;

        this.controller.computeColliderMovement(this.collider, this.vector, null, GROUPS.BULLET | GROUPS.PLAYER);

        const correctedMovement = this.controller.computedMovement();

        this.vector.x = current.x + correctedMovement.x;
        this.vector.y = current.y + correctedMovement.y;
        this.vector.z = current.z + correctedMovement.z;

        this.body.setNextKinematicTranslation(this.vector);
        const newPosition = this.body.translation();
        this.entity.setPosition(newPosition.x, newPosition.y, newPosition.z);
    },
sebcrozet commented 1 month ago

Small update. I was able to reproduce the issue. This is mainly caused by the fact that there is no gravity being applied this.vector.y = 0. But I do consider this a bug that should be fixed.

khudiiash commented 1 month ago

I have rapier simulations on both the server and the client. I try to run them in sync with each other. Determinism helps, but when I apply gravity, I start having issues - the collision resolution with the ground seems very erratic and unpredictable, and the more gravity you apply, the more the two simulations diverge from each other. So it required me to apply too much server reconciliation, which was not ideal. I found the only solution was to stop applying gravity, but then this bug happened. I kinda solved it by raycasting the ground and applying gravity only if the character was getting higher, but yeah, that sucks. Would be great if it is fixed and I could use setMaxSlopeClimbAngle to handle this.