Hi ,
I am facing issue with player ship movement sometimes. I have attached two videos of the same for reference also the code which I used for movement. Flickering movement
Code
var PlayerController = pc.createScript('playerController');
PlayerController.attributes.add('cameraEntity', { type: 'entity' });
PlayerController.attributes.add('movementSpeed', { type: 'number', default: 0.02 });//0.03
PlayerController.attributes.add('thrustFireEffect', { type: 'entity' });
PlayerController.attributes.add('boundary', { type: 'entity' });
PlayerController.attributes.add('offsetFromBoundary', { type: 'number', default: 1 });
PlayerController.prototype.initialize = function () {
this.baseMovementSpeed = this.movementSpeed;
this.addOnSpeed = 0;
this.screenWidth = this.app.graphicsDevice.width;
this.screenHeight = this.app.graphicsDevice.height;
this.camera = this.cameraEntity.camera;
this.pointerPos = new pc.Vec3();
this.screenPos = new pc.Vec3();
this.directionToMouse = new pc.Vec3();
this.targetRotation = new pc.Quat();
this.newRotation = new pc.Quat();
this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.onMouseDown, this);
this.app.mouse.on(pc.EVENT_MOUSEMOVE, this.onMouseMove, this);
this.app.mouse.on(pc.EVENT_MOUSEUP, this.onMouseUp, this);
};
PlayerController.prototype.onMouseDown = function (event) {
if (event.button === 0) {
// console.log(event.x, event.y)
this.pointerLocked = true;
this.thrustFireEffect.particlesystem.reset();
this.thrustFireEffect.particlesystem.play();
}
}
PlayerController.prototype.onMouseUp = function (event) {
if (event.button === 0) {
this.pointerLocked = false;
this.thrustFireEffect.particlesystem.stop();
}
};
PlayerController.prototype.onMouseMove = function (e) {
this.pointerPos.set(e.x, e.y, 0);
};
PlayerController.prototype.update = function (dt) {
if (this.pointerLocked) {
this.camera.worldToScreen(this.entity.position, this.screenPos);
this.screenPos.z = 0;
this.directionToMouse.sub2(this.pointerPos, this.screenPos);
this.directionToMouse.y *= -1;
var angle = Math.atan2(this.directionToMouse.x, this.directionToMouse.y) * pc.math.RAD_TO_DEG;
var targetRotation = this.targetRotation.clone().setFromEulerAngles(90, 0, 90 - angle);
var newRotation = this.newRotation.slerp(this.entity.getRotation(), targetRotation, 0.2);// slerp for smooth rotation
this.directionToMouse.normalize().scale(this.movementSpeed);
this.entity.setRotation(newRotation);
this.entity.rigidbody.teleport(this.entity.getPosition().add(this.directionToMouse));
let cameraPosition = new pc.Vec3();
cameraPosition.lerp(this.cameraEntity.getPosition().clone(), this.entity.getPosition().clone(), 0.5);
this.cameraEntity.setPosition(cameraPosition.x, cameraPosition.y, this.cameraEntity.getPosition().clone().z);
}
}
I usually prioritize physicsless movement, but if you already use physics with rigidboy, it makes sense not to teleport your target, but to change its volocity.
Maybe the problem is that the rigidbody gets its velocity from somewhere and therefore moves after it at the same time as teleportation, which does not remove its velocity?
I think so. Accordingly, if velocity is set manually, then the vector does not need to be multiplied by dt, because it is precisely the velocity/inertia of the rigidbody.
Copy the position to temp vector and modify that temp vector instead. Then teleport to that temp vector. Also, since you are setting the position every frame, you can just use a kinematic body and set the position on entity.
Teleporting a dynamic body is not suitable for every frame update. Its more of a “respawn or reset” type of move, when you need to immediately move a dynamic to some new spot.
Camera tracking should be in postUpdate (of course it is better to organize it in a different way, but the point is that the camera needs already receive the changed position of the target)
Even with that, leaving the lerp also doesn’t work without jittering, so I made a linear follow
PlayerController.prototype.update = function (dt) {
if (this.pointerLocked) {
this.camera.worldToScreen(this.entity.position, this.screenPos);
this.screenPos.z = 0;
this.directionToMouse.sub2(this.pointerPos, this.screenPos);
this.directionToMouse.y *= -1;
var angle = Math.atan2(this.directionToMouse.x, this.directionToMouse.y) * pc.math.RAD_TO_DEG;
var targetRotation = this.targetRotation.clone().setFromEulerAngles(90, 0, 90 - angle);
var newRotation = this.newRotation.slerp(this.entity.getRotation(), targetRotation, 0.2);// slerp for smooth rotation
this.directionToMouse.normalize().mulScalar(this.movementSpeed);
let condition = this.isPlayerInsideTheBoundary(this.entity.getPosition(), this.directionToMouse);
// condition === true ? console.log("inside") : console.log("outside");
if (condition) {
this.entity.rigidbody.teleport(this.entity.getPosition().add(this.directionToMouse), newRotation);
console.log('velocity = ', this.entity.rigidbody.linearVelocity);
}
}
}
PlayerController.prototype.postUpdate = function (dt){
let cameraPosition = this.entity.getPosition().clone();
//cameraPosition.lerp(this.cameraEntity.getPosition().clone(), this.entity.getPosition().clone(), 0.1);
this.cameraEntity.setPosition(cameraPosition.x, cameraPosition.y, this.cameraEntity.getPosition().clone().z);
}
Yes now it works fine. Thanks @robert.ua .May I know the reason for using postUpdate instead of update.
I know it runs after update but what difference it makes here ?
It is best practice for camera tracking. It is for the camera calculating own position relative to position of target if this target moving in update, so camera always get changed position of the target in current frame (not previous one).
Perhaps the teleport function does not change the position of the body immediately, therefore getPosition() return old values?