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.
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.
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.
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…
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!
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: