[SOLVED] Sonic Lags A Lot

I’ve been coding in some sonic physics for a game. When I try it out though, sonic lags a lot with the camera movement. This issue doesn’t happen in Unity, so I’m not sure why this is happening.

Player Code:

var PlayerPhysics = pc.createScript('playerPhysics');

//Variables
var xsp = 0;
var ysp = 0;
var gsp = 0;
var acc = 7;
var frc = 7;
var dec = 14;
var limit = 1000;
var angle = 0;
var grounded = false;
var facingRight;
var grv = 20;
var air = 22;
var jmp = 1300;
var sjmp = 667;
var goBackToZero = false;
var isJumping = false;
var lockRight = false;
var lockLeft = false;

//How did you manage to mess up the physics this bad?

//Parent
PlayerPhysics.attributes.add("player", { type: 'entity', title: 'Player' });

// initialize code called once per entity
PlayerPhysics.prototype.initialize = function() {
    this.app.keyboard.on(pc.EVENT_KEYDOWN, this.onKeyDown, this);
    this.app.keyboard.on(pc.EVENT_KEYUP, this.onKeyUp, this);
    this.entity.collision.on('collisionstart', this.onCollisionStart, this);
    this.entity.collision.on('collisionend', this.onCollisionEnd, this);
    this.entity.collision.on('contact', this.onContact, this);
};

// update code called every frame
PlayerPhysics.prototype.update = function(dt) {
    //Init Velocity
    this.entity.rigidbody.linearVelocity = new pc.Vec3(xsp * dt, ysp * dt, 0);
    console.log(ysp);
    
    //Init Mode
    if (grounded === true) {
        isJumping = false;
        //Set Speeds
        xsp = gsp * Math.cos(angle * pc.math.DEG_TO_RAD);
        ysp = gsp * Math.sin(angle * pc.math.DEG_TO_RAD);
        
        //Acceleration
        if (this.app.keyboard.isPressed(pc.KEY_RIGHT) && lockRight === false) {
            gsp += acc;
            facingRight = true;
        }  
        if (this.app.keyboard.isPressed(pc.KEY_LEFT) && lockLeft === false) {
            gsp -= acc;
            facingRight = false;
        }
        if ((!this.app.keyboard.isPressed(pc.KEY_RIGHT) && !this.app.keyboard.isPressed(pc.KEY_LEFT)) || (this.app.keyboard.isPressed(pc.KEY_RIGHT) && this.app.keyboard.isPressed(pc.KEY_LEFT))) {
            facingRight = null;
        }
        
        //Friction / Deceleration
        if (facingRight === true && gsp < 0) {
            gsp += dec;
        }
        if (facingRight === false && gsp > 0) {
            gsp -= dec;
        }
        if ((gsp < 0 || gsp > 0) && facingRight === null) {
            if (gsp > 0) {
                gsp -= frc;
            }
            if (gsp < 0) {
                gsp += frc;
            }
            if (gsp < frc && gsp > -frc) {
                gsp = 0;
            }
        }
        
        //Limit
        if (gsp > limit || gsp < -limit) {
            if (gsp > limit) {
                gsp = limit;
            }
            if (gsp < -limit) {
                gsp = -limit;
            }
        }
    }    
    if (grounded === false) {
        //Set Speeds
        gsp = xsp;
        ysp = ysp;
        
        //Gravity
        ysp -= grv;
        if (ysp < -1400) { ysp = -1400; }
        
        //Air Drag
        if (ysp > 0 && ysp < 733) {
            if (Math.abs(xsp) >= 10.5) { xsp = xsp * 0.96875; }    
        }
        
        //Air Acceleration
        if (this.app.keyboard.isPressed(pc.KEY_RIGHT) && lockRight === false) {
            xsp += air;
            facingRight = true;
        }
        if (this.app.keyboard.isPressed(pc.KEY_LEFT) && lockLeft === false) {
            xsp -= air;
            facingRight = false;
        }
        
        //Air Limit
        if (xsp > limit || xsp < -limit) {
            if (xsp > limit) {
                xsp = limit;
            }
            if (xsp < -limit) {
                xsp = -limit;
            }
        }
    }
    
    //Flip
    if (facingRight === true && xsp > 0) {
        this.entity.sprite.flipX = false;
    }
    if (facingRight === false && xsp < 0) {
        this.entity.sprite.flipX = true;
    }
    
    //Jump
    if (this.app.keyboard.wasPressed(pc.KEY_Z) && grounded === true) {
        ysp += jmp * Math.cos(angle * pc.math.DEG_TO_RAD);
        xsp -= jmp * Math.sin(angle * pc.math.DEG_TO_RAD);
        this.entity.sound.play('Jump');
        this.entity.rigidbody.teleport(this.entity.getPosition().x, this.entity.getPosition().y, this.entity.getPosition().z, 0, this.entity.getEulerAngles().y, 0); 
        isJumping = true;
        grounded = false;
    }
    if (isJumping === true) {
        if (!this.app.keyboard.isPressed(pc.KEY_Z) && ysp > sjmp) {
            ysp = sjmp;
        }    
    }
    
    //Angle Set In Air
    if (goBackToZero === true && (this.entity.getEulerAngles().z > 0 || this.entity.getEulerAngles < 0)) {
        var change = 2;
        this.entity.rigidbody.teleport(this.entity.getPosition().x, this.entity.getPosition().y, this.entity.getPosition().z, 0, this.entity.getEulerAngles().y, this.entity.getEulerAngles().z -= change); 
        if (this.entity.getEulerAngles().z === 0) {
            this.entity.rigidbody.teleport(this.entity.getPosition().x, this.entity.getPosition().y, this.entity.getPosition().z, 0, this.entity.getEulerAngles().y, 0);     
        }
    }
    
    //Animation
    this.animation();
};

PlayerPhysics.prototype.animation = function() {
    //Check Ground Variable
    if (grounded === true) {
        //Idle
        if (gsp === 0) {
            this.entity.sprite.play("IDLE");           
        }
        //Walk
        if ((gsp > 0.01 && gsp < 1000) || (gsp < -0.01 && gsp > -1000)) {
            this.entity.sprite.play("WALK");
        }
        //Run
        if (gsp >= 1000 || gsp <= -1000) {
            this.entity.sprite.play("RUN");
        }
    }  
    if (grounded === false) {
        //Check Whether Jump Is True
        if (isJumping === false) {
            //Walk
            if (gsp < 1000 && gsp > -1000) {
                this.entity.sprite.play("WALK");
            }    
            //Run
            if (gsp >= 1000 || gsp <= -1000) {
                this.entity.sprite.play("RUN");
            }
        }    
        else {
            this.entity.sprite.play("ROLL");
        }
    }
};

PlayerPhysics.prototype.onCollisionStart = function(result) {
    //Ground Check
    if (result.other.tags.has('ground')) {
        grounded = true;   
        angle = result.other.getEulerAngles().z;
        this.entity.rigidbody.teleport(this.entity.getPosition().x, this.entity.getPosition().y, this.entity.getPosition().z, 0, this.entity.getEulerAngles().y, result.other.getEulerAngles().z);
        goBackToZero = false;
    } 
    
    //Wall Stop
    if (result.other.tags.has('left_wall') || result.other.tags.has('right_wall')) {
        gsp = 0;
        xsp = 0;
    }
};

PlayerPhysics.prototype.onCollisionEnd = function(other) {
    //Ground Check
    if (other.tags.has('ground')) {
        
    }    
    
    //Wall Leave
    if (other.tags.has('left_wall') || other.tags.has('right_wall')) {
        lockLeft = false;
        lockRight = false;
    }
};

PlayerPhysics.prototype.onContact = function(result) {
    //Wall Checks
    if (result.other.tags.has('left_wall') || result.other.tags.has('right_wall')) {
        if (result.other.tags.has('left_wall')) {
            lockRight = true;    
        }
        if (result.other.tags.has('right_wall')) {
            lockLeft = true;
        }
    }  
};

// swap method called for script hot-reloading
// inherit your script state here
// PlayerPhysics.prototype.swap = function(old) { };

// to learn more about script anatomy, please read:
// http://developer.playcanvas.com/en/user-manual/scripting/

Camera Code:

var Camera = pc.createScript('camera');
 
//Attributes
Camera.attributes.add("player", { type: 'entity', title: 'Player' });

// initialize code called once per entity
Camera.prototype.initialize = function() {

    this.pivotPoint = new pc.Vec3();
    this.pivotPoint2 = new pc.Vec3();
    
    // --- the smoothness of the camera, larger values make the movement smoother
    this.inertia = 0.08;
    this.inertia2 = 0.15;

    // --- the initial offset of the camera position set in editor
    this.offset = this.entity.getLocalPosition().clone();
};

// update code called every frame
Camera.prototype.update = function(dt) {      
    var inertiaFactor = Math.min(dt / this.inertia, 1);
    var inertiaFactor2 = Math.min(dt / this.inertia2, 1);
    var pos = this.player.getPosition();

    // --- here is where we smooth out the current position based on the inertia factor
    this.pivotPoint.lerp(this.pivotPoint, pos, inertiaFactor);
    this.pivotPoint2.lerp(this.pivotPoint2, pos, inertiaFactor2);

    this.entity.setPosition(this.pivotPoint.x, this.pivotPoint2.y, 0);
    this.entity.translateLocal(this.offset);
    

};

Link to Editor: https://playcanvas.com/editor/scene/1006987

Video Footage:

Try updating the camera in postUpdate instead.

The lagging has decreased a bit. It still kinda lags though.

Looking at the project, it seems to be an issue with the inertia code as setting as using the player position directly and doing the camera logic in the postUpdate is fine.

It’s probably less noticeable in Unity as it’s at a higher framerate.

Edit: I would probably make the camera distance from Sonic based on the player’s speed. :thinking:

@yaustar, hmm, I disabled everything, and just left these 2 methods:

PlayerPhysics.prototype.update = function(dt) {
    this.entity.rigidbody.applyForce(new pc.Vec3(1, 0, 0));
};
Camera.prototype.postUpdate = function(dt) {      
    var pos = this.player.getPosition();
    this.entity.setPosition(pos.x, pos.y, this.offset.z);
};

And I got this result. Is it different for you? What am I missing?

Checking the player speed while running right and it looks like it is going backwards in same cases:

image

You can see here where I track the speed by taking the current position and taking away the last frame position while running right. There are minuses in the distance which indicates it’s going backwards so this means there’s something going wrong with the player physics.

With some quick debugging, the ground check teleport is what is causing issues.

Here’s my fork: https://playcanvas.com/editor/scene/1020717

And all I’ve done is commented out this line: https://playcanvas.com/editor/code/731648?tabs=37197681&line=205

Edit: You might be running into this issue: https://github.com/playcanvas/engine/issues/2337

2 Likes

I’ve looked into how sonic rotates, and it was the issue. I was able to fix it by adding an if statement that only rotated sonic when his current sprite rotation and his angle variable in the code don’t match up. All lag is now gone.