2D Platformer: Player can't ascend slopes

Alright, let me get some basics out of the way. I’m making a 2D platformer game (or sidescroller, as some call them) The player’s hitbox is made out of a circle collider around his feet, and a box collider around the rest. Here, let me link a screenshot. (All the extra collision boxes are just triggers, so ignore them.)

Another thing, I’m using Ferr2D. That shouldn’t matter much, since it just generates polygon colliders. My player’s horizontal movement is based on editing it’s rigidbody’s velocity. I’m guessing that’s where the problem lies… Only problem is that using a Rigidbody2D.AddForce method doesn’t work well either, since the player just goes a little bit up the slope and then slips down. Also, AddForce gives the player unwanted acceleration. So what can I do to fix this? Before I go, here’s the player’s movement script. If you decide to reply to this post, then thanks in advanced!

Player Movement Script (JavaScript)

Make sure to mostly pay attention to everything in the FixedUpdate function, since that’s where most of the player’s movement code lies. Really, you’d just want to look at everything under the “//Walking” comment.

var moveSpeed : float;
var jumpPower : float;
var doubleJumpPower : float;
var isGrounded : boolean;
var isTouching : boolean;
var respawning : boolean;
var isPunching : boolean;
var isAttacking : boolean;

var visible : boolean;
var isPaused : boolean;

private var jumpHeight : float;
private var jumping : boolean;
private var facingRight : boolean;
private var body : Rigidbody2D;
private var oScale;
private var spaceHeld : boolean;
private var anim : Animator;
private var isTouchingRight : int;
private var jumpCount : int = 2;
private var wentThrough : boolean;
private var punchHeld : boolean;

private var horiIn : float;
private var verIn : float;
private var button1In : float;
private var button2In : float;
private var button3In : float;

function Start(){
    body = GetComponent(Rigidbody2D);
    oScale = transform.localScale.x;

    anim = GetComponent("Animator");

}


//Movement
function FixedUpdate(){
if((anim.GetBool("isDead") == false)&&(isPaused == false)){

    //New Jumping
    if((button1In == 1)&&(isGrounded)&&(!spaceHeld)&&(respawning == false)&&(!isPunching)){
        body.AddForce(new Vector2(0,jumpPower),ForceMode2D.Impulse);
    }
    //DoubleJump
    if((button1In == 1)&&(jumpCount > 0)&&(!isGrounded)&&(!spaceHeld)&&(respawning == false)&&(!isPunching)){
        body.velocity.y=0;
        body.AddForce(new Vector2(0,doubleJumpPower),ForceMode2D.Impulse);
        jumpCount -= 1;
    }

    if(isGrounded){
        jumpCount = 2;
        GameObject.Find("wallCheck").GetComponent(WallDetection).inAir = true;
    }

    if((spaceHeld == false)&&(jumpCount > 0)&&(button1In == 1)&&(!isPunching)){
        jumpCount -= 1;
    }

    if(button1In == 1){
        spaceHeld = true;
    }else{
        spaceHeld = false;
    }

    //Checking if touching a wall
    if(isTouching){

        if(facingRight){
            isTouchingRight = 1;
        }else{
            isTouchingRight = -1;
        }

    }else{isTouchingRight = 0;}

    //Walking
    if((horiIn == 1)&&(isTouchingRight != 1)&&(respawning == false)&&(!isPunching)){
        facingRight = true;
        Flip();
        maxSpeed = moveSpeed;
    }
    if((horiIn == -1)&&(isTouchingRight != -1)&&(respawning == false)&&(!isPunching)){
        facingRight = false;
        Flip();
        wasD = false;
        maxSpeed = -moveSpeed;
    }

    body.velocity.x = maxSpeed;

    //body.AddForce(new Vector2(maxSpeed,0));

 

}
}

function Update(){
    //Setting my visible
    visible = GetComponent(Renderer).isVisible;

    //Main Animations
    if(((horiIn == -1)||(horiIn == 1))&&(isGrounded == true)&&(respawning == false)&&(!isPunching)&&(!isPaused)){
        anim.SetInteger("Action",1);
    }else if((body.velocity.y > 0)&&(isGrounded == false)&&(respawning == false)&&(!isPunching)&&(!isPaused)){
        anim.SetInteger("Action",2);
        GameObject.Find("wallCheck").GetComponent(WallDetection).inAir = true;
    }else if((body.velocity.y < 0)&&(isGrounded == false)&&(respawning == false)&&(!isPunching)&&(!isPaused)){
        anim.SetInteger("Action",4);
        GameObject.Find("wallCheck").GetComponent(WallDetection).inAir = true;
    }else if((horiIn == 0)&&(isGrounded == true)&&(respawning == false)&&(!isPunching)&&(!isPaused)){
        anim.SetInteger("Action",0);
    }else if((respawning == false)&&(!isPunching)){
        anim.SetInteger("Action",0);
    }
    //Other Animations
    if(respawning == true){
            anim.SetInteger("Action",3);
            if(isPunching){
                isPunching = false;
                anim.SetInteger("Action",3);
                wentThrough = false;
                isAttacking = false;
            }
        }

        //Punching
        if((respawning == false)&&(isPaused == false)){
            if((isGrounded)&&(isPunching == false)&&(button3In == 1)&&(punchHeld == false)){
                anim.SetInteger("Action",5);
                isPunching = true;
            }
            if((anim.GetCurrentAnimatorStateInfo(0).IsName("pPunching"))&&(isPunching)&&(wentThrough == false)){
                wentThrough = true;
            }
            if((anim.GetCurrentAnimatorStateInfo(0).IsName("pAttack"))&&(isPunching)){
                isAttacking = true;
            }
            if((anim.GetCurrentAnimatorStateInfo(0).IsName("pStanding"))&&(isPunching)&&(wentThrough == true)){
                isPunching = false;
                anim.SetInteger("Action",0);
                wentThrough = false;
                isAttacking = false;
            }
            //Making sure the player isn't respawning
            if((anim.GetCurrentAnimatorStateInfo(0).IsName("pRespawn"))&&(isPunching)){
                isPunching = false;
                anim.SetInteger("Action",3);
                wentThrough = false;
                isAttacking = false;
            }

            if(button3In == 1){
                punchHeld = true;
            }else{
                punchHeld = false;
            }
        }
    //Setting Inputs
    horiIn = Input.GetAxis("Horizontal");
    vertIn = Input.GetAxis("Vertical");
    button1In = Input.GetAxis("Fire1");
    button2In = Input.GetAxis("Fire2");
    button3In = Input.GetAxis("Fire3");


}



function Flip()
{

    if(facingRight)
        transform.localScale.x = oScale;
    if(!facingRight)
        transform.localScale.x = -oScale;
}

function OnTriggerEnter2D(other : Collider2D){

    //Getting Crushed
    if((other.tag == "Block")&&(transform.position.y < other.transform.position.y)){
        if((other.GetComponent(Crate).canRight == true)&&(transform.position.x > other.transform.position.x)){
            transform.position.x = other.transform.position.x + 1;
        }else if((other.GetComponent(Crate).canLeft == true)&&(transform.position.x < other.transform.position.x)){
            transform.position.x = other.transform.position.x - 1;
        }else if(other.GetComponent(Crate).canRight == true){
            transform.position.x = other.transform.position.x + 1;
        }else if(other.GetComponent(Crate).canLeft == true){
            transform.position.x = other.transform.position.x - 1;
        }
    }
}

Have you thought about using the character controller instead? That lets you enter the slope angle that it can ascend

1 Like

I like to keep all my code custom, and have no real idea how to use a character controller. (Or even what one is, for that matter…)

In physics you add the character controller instead of the rigidbody & you can still use your standard movement scripts that you write. It has premapped keys so you can just call input horizontal etc instead of specific keys, has jump built in, Gravity etc. maybe try adding one & just u tick the rigid body & see how it goes?

Alright, thanks for the tip! I’ll try that tomorrow,

I can’t seem to add a character controller due to all of the player’s 2D colliders

Is it difficult to turn the extra colliders off just to see if the controller works the way you want? It might be easier to then add them back via a childed empty game object.

What is the wasD bool doing? You set it in one of the walking bits but not the other.

I think that has stuff to do with animation, I actually just deleted it a second ago.
I think I fixed the problem, though. I added some objects that checked whether or not the player is on a slope, done with 2 colliders. If the player is on a slope, he will automatically rotate 25 degrees on the Z axis. This seems to have fixed the problem pretty well, although it looks weird at times. But thanks for your help, anyways ^)^

Screenshots


The Colliders that check for a slope, if the bottom one is inside of something while the top one isn’t, it believes there is a slope present.


On a slope

1 Like