- Home /
Rigidbody2D climbing 45 degrees slopes
I have problem with my 2d platformer.
I have created several slopes around the map, which are usually 45 degrees. The problem here is that rigidbody cannot just climb the slopes up with the "small' force (which is enough for player to move, but not to climb). Any solutions?
Answer by Xarbrough · Aug 18, 2017 at 07:28 PM
Here are some ideas:
are you maybe applying the force vector left to right in world space? Then you should rotate the force upwards along the slope. So instead of moving (1, 0, 0), you want to move (0.7, 0.7, 0), or even scale it up to (1, 1, 0), so that you have extra force when going up a slope.
secondly, you can make the slopes have a PhysicsMaterial that has less or even no friction, so the player slides up more easily.
I hope this helps, if you need any more specific examples, please post some code and maybe show the inspector for your rigidbodies and colliders ;)
I'm adding a small example project of what I mean:
It's not a complete 2D controller and doesn't feel juicy yet, but it shows the principle. You can also look at the many official Unity tutorials and live trainings about 2D character controllers. Most of the time, you actually don't want to use AddForce, but write all logic yourself and set the position or velocity directly.
Here is just the script if the link goes down:
using UnityEngine;
public class Movement : MonoBehaviour
{
public LayerMask groundLayerMask;
public Rigidbody2D rb;
public float speed = 10f;
void FixedUpdate()
{
float input = Input.GetAxis("Horizontal");
// By default we don't want to move.
Vector2 forceDirection = new Vector2(0, 0);
// Check for ground underneath.
RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.down, 1f, groundLayerMask);
// We can only move when on ground.
if(hit.collider != null)
{
// hit.normal points to the surface upwards direction.
Debug.DrawRay(transform.position, hit.normal, Color.white);
// If this doesn't point straight up, we are at a slope
// and should adjust our forceDirection...
// Get a perpendicular vector to the normal.
// This will point upwards along the slope.
if(input >= 0) // Right
forceDirection = new Vector2(hit.normal.y, -hit.normal.x);
else // Left
forceDirection = new Vector2(-hit.normal.y, hit.normal.x);
}
// Now the green line points in the direction we want to adjust force.
Debug.DrawRay(transform.position, forceDirection * Mathf.Abs(input), Color.green);
// We want to scale by the input amount, but not by it's direction
// because we already picked the direction in our ground check.
rb.AddForce(forceDirection * Mathf.Abs(input) * speed);
}
}
None of the method stated above actually helped me. I tried to move (1, 1), though the result wasn't very good. ...and I was using little friction physics material to the character...
Post your script and settings ;) maybe there's another problem.
I just started a new project for testing.
Here is the code:
void FixedUpdate()
{
Rb2D.AddForce(new Vector2(1, 1) * speed);
CheckForRamp();
}
Images:
Rigidbody2D settings:
Physics $$anonymous$$aterial:
Answer by Bip901 · Aug 19, 2017 at 11:56 AM
I have an idea [untested] [C#]:
Make the player use a stronger movement force when you touch a slope.
void OnCollisionStay2D(Collision2D coll) {
if (coll.gameObject.tag == "slope") { //use extra force as long as you're touching a slope
extraForce = true;
}
}
When you are no longer touching a slope, remove the extra force
void OnCollisionExit2D(Collision2D coll) {
if (coll.gameObject.tag == "slope")
extraForce = false;
}
Now, in the place in your script where you make the player move, add something like this: (I assumed you normally use a force of (1 , 0) when moving the player)
if (extraForce) {
Rb2D.AddForce(new Vector2(2, 0.5f) * speed); //Double power + some Y-axis movement
}
else {
Rb2D.AddForce(new Vector2(1, 0) * speed);
}
I have tried that method with the Raycast (ins$$anonymous$$d of collision, since I thought it was more efficient), and it did work, but I'm trying to look for another solution...
If it's possible, use a character controller ins$$anonymous$$d of physics. Or always use extra force. Or add some extra friction to the slopes so the player won't slide down.