[SOLVED] First person with model (rotation issues)

shown in the video, we want the players body to match the cameras y rotation, issue is at a certain point (around 45, -45 y) the players model no longer follows the camera, which looks horrible in first person (main reason why I added a camera child to the fps camera, also you can see the animation/body move and rotation better) If anyone could help that would be nice.

Better video showing my issue:

Hi @Jacob_McBride2!

It seems that the rotation is flipped 180 degrees when the mouse position is behind the entity or camera or something like that.

I think it will be helpful if you share some code you use, so someone can look at it.

1 Like

Screenshot 2024-12-12 12.49.29 PM
Screenshot 2024-12-12 12.49.22 PM
Screenshot 2024-12-12 12.49.12 PM
You are absolutly right, the camera is flipped on the z and x rotation since it’s a child of head_1, I apply the rotations of the camera to the head_1 so the head moves the camera view, this way the character head isnt in one place while the camera moves.

see code here:

var FirstPersonMovement = pc.createScript('firstPersonMovement');

FirstPersonMovement.attributes.add('head', {
    type: 'entity',
    description: 'Assign the head_1 entity for rotation'
});

FirstPersonMovement.attributes.add('bodyParts', {
    type: 'entity',
    array: true,
    description: 'Assign the body parts that should follow the cameras Y rotation'
});

FirstPersonMovement.attributes.add('power', {
    type: 'number',
    default: 2500,
    description: 'Adjusts the speed of player movement'
});

FirstPersonMovement.attributes.add('lookSpeed', {
    type: 'number',
    default: 0.25,
    description: 'Adjusts the sensitivity of looking'
});

// initialize code called once per entity
FirstPersonMovement.prototype.initialize = function() {
    this.force = new pc.Vec3();
    this.eulers = new pc.Vec3();

    var app = this.app;

    // Listen for mouse move events
    app.mouse.on("mousemove", this._onMouseMove, this);

    // When the mouse is clicked, hide the cursor
    app.mouse.on("mousedown", function () {
        app.mouse.enablePointerLock();
    }, this);

    // Check for required components
    if (!this.entity.collision) {
        console.error("First Person Movement script needs to have a 'collision' component");
    }

    if (!this.entity.rigidbody || this.entity.rigidbody.type !== pc.BODYTYPE_DYNAMIC) {
        console.error("First Person Movement script needs to have a DYNAMIC 'rigidbody' component");
    }

    // Lock rotation to prevent the player from falling over
    this.entity.rigidbody.fixedRotation = true;

    // Get animation component
    this.animComponent = this.entity.anim;
    if (!this.animComponent) {
        console.error("First Person Movement script needs to have an 'anim' component");
    }

    // Track whether the player is moving
    this.isMoving = false;
};

// update code called every frame
FirstPersonMovement.prototype.update = function(dt) {
    var force = this.force;
    var app = this.app;

    // Movement variables
    var forward = this.head.forward;
    var right = this.head.right;
    var x = 0;
    var z = 0;

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

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

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

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

    // Apply force if moving
    if (x !== 0 || z !== 0) {
        force.set(x, 0, z).normalize().scale(this.power);
        this.entity.rigidbody.applyForce(force);
        this._setWalkState(true);
    } else {
        this._setWalkState(false);
    }

    // Update body parts to face the Y rotation of the head
    this.bodyParts.forEach(function(part) {
        var currentAngles = part.getLocalEulerAngles();
        part.setLocalEulerAngles(currentAngles.x, this.eulers.x, currentAngles.z);
    }, this);
};

FirstPersonMovement.prototype._onMouseMove = function (e) {
    // Rotate the head_1 entity instead of the camera
    if (pc.Mouse.isPointerLocked() || e.buttons[0]) {
        this.eulers.x -= this.lookSpeed * e.dx;
        this.eulers.y += this.lookSpeed * e.dy; // Fixed inverted movement
        this.eulers.y = pc.math.clamp(this.eulers.y, -90, 90); // Clamp vertical rotation
        this.head.setLocalEulerAngles(this.eulers.y, this.eulers.x, 0);
    }
};

FirstPersonMovement.prototype._setWalkState = function(isWalking) {
    if (this.animComponent) {
        if (isWalking && !this.isMoving) {
            this.animComponent.setBoolean('isWalk', true);
            this.isMoving = true;
        } else if (!isWalking && this.isMoving) {
            this.animComponent.setBoolean('isWalk', false);
            this.isMoving = false;
        }
    }
};

Unfortunately, I don’t know how to solve this myself, but in the topic below I have shared some related topics that might help you.

1 Like

there isn’t a conclusive answer… Do you think rotating the model 180, and re exporting it would fix it? I’ll try it and see.

Same result. The main issue is the y becomes 0 at 180 degrees and z and x become 180 or -180, maybe I could track and use the rotation of the z and x at 180 as well?

Maybe @yaustar can give some advice here.

1 Like

Try changing part.setLocalEulerAngles(currentAngles.x, this.eulers.x, currentAngles.z); to part.setLocalEulerAngles(0, this.eulers.x, 0);.

I think the issue is with using the last angles, if currentAngles.x were 180 or -180, you’d keep it while your this.eulers.x has not been changed due to PlayCanvas’s euler logic. This messes it up and stuff…

2 Likes

Yeah! the issue was the values were flipping from 180 to -180 x and z. This fix just automatically worked. Thanks alot for your help!

result for third person and first person here (screen recording view is smaller due to loading speed)

I apprecite your help! :grin:

Off topic a bit, but, I removed the shadows on the player model (since it looked weird and buggy) I also added running and jumping, as well as 3rd person front and back cameras, and buttons to toggle them on/off: