[SOLVED] Roll Animation Not Playing Correctly

Im trying to get sonic to roll when you press down while walking or running. While the code for rolling works, the animation doesn’t play out. My theory on why this happens is because the animation keeps being recalled for some reason.

Here is my code:

var PlayerController = pc.createScript('playerController');

//Variables
var xsp = 0;
var ysp = 0;
var gsp = 0;
var acc = 0.126875;
var dec = 0.5;
var frc = acc;
var limit = 14;
var goingRight;
var angle = 0;
var grv = 0.713875;
var grounded = false;
var air = 0.29375;
var jmp = 15.5;
var gmove = new pc.Vec3();
var isJumping = false;
var slope;
var slp = 0.371;
var isRolling = false;
var isCrouching = false;
var canMove = true;
var rollfrc = frc/2;
var rolldec = 0.125;

//Animations
PlayerController.attributes.add("animations", { type: 'entity', title: 'Animations' });
PlayerController.attributes.add("idle", { type: 'entity', title: 'Idle' });
PlayerController.attributes.add("walk", { type: 'entity', title: 'Walking' });
PlayerController.attributes.add("run", { type: 'entity', title: 'Running' });
PlayerController.attributes.add("jump", { type: 'entity', title: 'Jumping' });
PlayerController.attributes.add("crouch", { type: 'entity', title: 'Crouching' });
PlayerController.attributes.add("roll", { type: 'entity', title: 'Rolling' });

// initialize code called once per entity
PlayerController.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('contact', this.onContact, this);  
    
    //Animations
    this.idle.enabled = true;
    this.walk.enabled = false;
    this.run.enabled = false;
    this.jump.enabled = false;
    this.crouch.enabled = false;
    this.roll.enabled = false;
};

// update code called every frame
PlayerController.prototype.update = function(dt) {
    //Functions
    this.MainFunction(dt);
    this.animation();
};

PlayerController.prototype.MainFunction = function(dt) {
    //Main Movement
    this.entity.rigidbody.linearVelocity = gmove.set(xsp, ysp, 0);
    if (grounded === true) {
        //Basic Movement
        xsp = gsp * Math.cos(angle * pc.math.DEG_TO_RAD);
        ysp = gsp * Math.sin(angle * pc.math.DEG_TO_RAD);
        if (canMove === true) {
            if (this.app.keyboard.isPressed(pc.KEY_RIGHT)) {
            gsp += acc;
            goingRight = true;
        }
            if (this.app.keyboard.isPressed(pc.KEY_LEFT)) {
            gsp -= acc;
            goingRight = false;
        }
            if (!this.app.keyboard.isPressed(pc.KEY_RIGHT) && !this.app.keyboard.isPressed(pc.KEY_LEFT)) {
            goingRight = null;
        }
            if (this.app.keyboard.isPressed(pc.KEY_RIGHT) && this.app.keyboard.isPressed(pc.KEY_LEFT)) {
            goingRight = null;
        }
        }
        
        //Slope Factor
        if (isRolling === false) {
            slope = slp;
        }
        gsp -= slope * Math.sin(angle * pc.math.DEG_TO_RAD);
        if ((angle > 43 && angle < 319) && (gsp < 0.9 && gsp > -0.9)) {
            grounded = false;
            angle = 0;
            this.entity.rigidbody.teleport(this.entity.getPosition().x, this.entity.getPosition().y, this.entity.getPosition().z, 0, 0, 0);
        }
    }   
    
    //Friction / Deceleration
    if (goingRight === true && gsp < 0) {
        gsp += dec;
    }
    if (goingRight === false && gsp > 0) {
        gsp -= dec;
    }
    if (goingRight === null && (gsp > 0 || gsp < 0)) {
        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;
        }
    }
    
    //Air
    if (grounded === false) {
        ysp = ysp;
        gsp = xsp;
        
        //Gravity
        ysp -= grv;
        if (ysp < -16) { ysp = -16; }
        
        //Air Drag
        if (ysp > 0 && ysp < 10.33) {
            if (Math.abs(xsp) >= 0.125) {
                xsp = xsp * 0.96875;   
            }
        }
        
        //Air Movement
        if (this.app.keyboard.isPressed(pc.KEY_RIGHT)) {
            xsp += air;
            goingRight = true;
        }
        if (this.app.keyboard.isPressed(pc.KEY_LEFT)) {
            xsp -= air;
            goingRight = false;
        }
    }
    
    //Flip
    if (goingRight === true && gsp > 0) {
        this.animations.setLocalScale(1, 1, 1);
    }
    if (goingRight === false && gsp < 0) {
        this.animations.setLocalScale(-1, 1, 1);
    }
    
    //Jump
    if (this.app.keyboard.wasPressed(pc.KEY_A) && grounded === true) {
        ysp += jmp * Math.cos(angle * pc.math.DEG_TO_RAD);
        xsp -= jmp * Math.sin(angle * pc.math.DEG_TO_RAD);
        grounded = false;
        isJumping = true;   
        this.entity.rigidbody.teleport(this.entity.getPosition().x, this.entity.getPosition().y, this.entity.getPosition().z, 0, 0, 0);
    }
    
    //Crouch Check
    if (this.app.keyboard.isPressed(pc.KEY_DOWN)) {
        isCrouching = true;
    }
    if (this.app.keyboard.wasReleased(pc.KEY_DOWN)) {
        isCrouching = false;
    }
    
    //Check Can Move
    if (isCrouching === false || isRolling === false) {
        canMove = true;
    }
    if (isCrouching === true || isRolling === true) {
        canMove = false;
    }
    
    //Rolling
    if (this.app.keyboard.wasPressed(pc.KEY_DOWN) && (gsp > 0.5 || gsp < -0.5) && grounded === true) {
        isRolling = true;
    }
    if ((gsp < 0.3 && gsp > -0.3) && isRolling === true) {
        isRolling = false;
    }
    if (isRolling === true) {
        if (gsp > 0) {
            gsp -= rollfrc;
        } 
        if (gsp < 0) {
            gsp += rollfrc;
        }
        if (gsp < rollfrc && gsp > -rollfrc) {
            gsp = 0;
        }
        if (this.app.keyboard.isPressed(pc.KEY_RIGHT) && gsp < 0) {
            gsp += rolldec;    
        }
        if (this.app.keyboard.isPressed(pc.KEY_LEFT) && gsp > 0) {
            gsp -= rolldec;
        }
        if (this.app.keyboard.isPressed(pc.KEY_RIGHT) && gsp >= -0.12) {
            gsp = 0.5;       
        }
        if (this.app.keyboard.isPressed(pc.KEY_LEFT) && gsp <= 0.12) {
            gsp = -0.5;
        }
    }
};

PlayerController.prototype.animation = function() {
    //Basic Movement
    if (grounded === true) {
        if ((gsp < 0.01 && gsp > -0.01) && isCrouching === false) {
            this.idle.enabled = true;
            this.walk.enabled = false;
            this.run.enabled = false;
            this.jump.enabled = false;
            this.crouch.enabled = false;
            this.roll.enabled = false;
        }
        if ((gsp > 0.01 && gsp < limit) || (gsp < -0.01 && gsp > -limit)) {
            this.idle.enabled = false;
            this.walk.enabled = true;
            this.run.enabled = false;
            this.jump.enabled = false;
            this.crouch.enabled = false;
            this.roll.enabled = false;
        }
        if (gsp >= limit || gsp <= -limit) {
            this.idle.enabled = false;
            this.walk.enabled = false;
            this.run.enabled = true;
            this.jump.enabled = false;
            this.crouch.enabled = false;
            this.roll.enabled = false;
        }
    }
    if (grounded === false && isJumping === false) {
        if (gsp < limit && gsp > -limit) {
            this.idle.enabled = false;
            this.walk.enabled = true;
            this.run.enabled = false;
            this.crouch.enabled = false;
            this.roll.enabled = false;
        }
        if (gsp >= limit || gsp <= -limit) {
            this.idle.enabled = false;
            this.walk.enabled = false;
            this.run.enabled = true;
            this.crouch.enabled = false;
            this.roll.enabled = false;
        }
    }
    
    //Jump
    if (isJumping === true) {
        this.idle.enabled = false;
        this.walk.enabled = false;
        this.run.enabled = false;
        this.jump.enabled = true;
        this.crouch.enabled = false;
        this.roll.enabled = false;
    }
    
    //Crouching
    if ((gsp < 0.01 && gsp > -0.01) && isJumping === false && isCrouching === true) {
        this.idle.enabled = false;
        this.walk.enabled = false;
        this.run.enabled = false;
        this.jump.enabled = false;
        this.crouch.enabled = true;
        this.roll.enabled = false;
    }
    
    //Rolling
    if (isRolling === true) {
        this.idle.enabled = false;
        this.walk.enabled = false;
        this.run.enabled = false;
        this.jump.enabled = false;
        this.crouch.enabled = false;
        this.roll.enabled = true;
    }
};

PlayerController.prototype.onCollisionStart = function(result) {
    //Ground Check
    if (result.other.tags.has('ground')) {
        grounded = true;
        isJumping = false;
        angle = result.other.getEulerAngles().z;
    }    
    
    //Change Visual Angle Check
    if (result.other.tags.has('ground') && result.other.tags.has('vAngle')) {
        this.entity.rigidbody.teleport(this.entity.getPosition().x, this.entity.getPosition().y, this.entity.getPosition().z, 0, 0, result.other.getEulerAngles().z);
    }
};

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

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

Link to editor: https://playcanvas.com/editor/scene/926034

Can someone tell me how I should go about fixing this issue?

Does anyone know how to make it so that the roll animation actually plays out?

@Leonidas @Albertos do you have any idea of what I should do?

Hi @DevPlex01,

That’s a complex state manager, not easy to debug. As a first step try checking your conditions here, either with the browser debugger or console.log():

if (isRolling === true && isJumping === false) {

You need to check if and when this conditions are set to true in your logic above, to start the roll animation.

Is rolling, is crouching and is jumping sound like exclusive states that sonic can be in.

Rather having that as several Boolean variables, I have it as single variable (like an int with named constants).

I would also create a function that changes the value of that state variable so you have one easy place to do basic logging and breakpointing

Hello @DevPlex01! I have look at your project, but currently I see nothing in your game to play with, so I can’t see whats going wrong. If you add me to the project I can help you to debug.

The answer of @Leonidas is the first thing you have to do. The suggestion of @yaustar can be a good improvement. I did something in my own game too. First I was using booleans like playerIsUsingStone, playerIsUsingRifle, playerIsUsingKnife, but I replaced that booleans for something like playerEquipment = “CurrentEquipment”. So that’s easier to use.

1 Like

Thank you all. And I think using a number would perhaps improve the animation states. I’ll implement it and see if anything has changed.

Also, the test scene is now back on, so you can see how the game works now. Currently it’s ARROW KEYS to move and A to jump.

Well I tried implementing states as you said, although after I implement everything, not only did the roll just stop working in general, but the crouch also stopped working. So for now, I’ll continue using separate variables, as it’s worked fine for me as of now. I think you should play the game and see what the problem might be other than the is variables.

I think there a two things that you have to check with console.log(CurrentAnimation); in your script:

  • Is the animation started once or repeatedly?

  • Is the animation conflicting with another animation?

The variable is played repeatedly while it’s true. But the jump variable also plays repeatedly while true, so this shouldn’t be an issue while rolling. This makes me think it could be conflicting.

Ok, so I solved the issue. Turns out, it was conflicting with other animations, which is why it wasn’t playing correctly. I made sure that those animations don’t play while isRolling is true.

1 Like