Flickering Movement

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);

    }
}

What may be causing this issue ?
thank you

Fine movement


Also the same script which results in smooth movement .
How can I debug this issue

@Albertos @will any updates on above query

Try mulScalar on dt (deltaTime)

this.directionToMouse.normalize().scale(this.movementSpeed).mulScalar(dt);

Also, don’t forget to increase the speed, as this multiplier reduces the vector, but the speed will no longer depend on the frame rate

Hi @robert.ua
Still the jitter kind of issue is present. Is this issue is related to teleporting the body ?

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?

How can I fix this? is it by setting linearVelocity value

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.

And if you notice …along with player entity camera also moves which use lerp factor of 0.5 .Can it cause any issue ?.Not sure just asking …

You can check this if you remove the lerp and just move the camera behind the player, so you will be sure of one of two things.

cameraPosition = this.entity.getPosition().clone()

1 Like

No It didn’t work. Difficult part is we will not get this issue always…

Even when you changed the logic of movement from teleportation to velocity?
Can i have link to the editor for fork?

Do not modify the entity position directly like that:

this.entity.getPosition().add(this.directionToMouse);

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.

@LeXXik I used dynamic body inorder to have coliision with moon. I got your point that dynamic body gets reset at some point.
I have forked my project have a look @LeXXik , @robert.ua
https://playcanvas.com/editor/scene/1946615
Note : issue doesnt appears always…

It seems impossible to fork the project by link to the scene, need link to the project?

Project Link : PlayCanvas 3D HTML5 Game Engine

Two things:

  1. 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)

  2. 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);
}
2 Likes

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?

1 Like