- Home /
Sliding along walls in top-down 2D with no diagonal movement
Hey everyone,
I'm working on my first Unity project, and it's a top-down game in the vein of Gauntlet and other similar classics. A key aspect of the gameplay is that I'm enforcing orthogonal-only movement (no diagonals), for which I'm using a pretty simple movement script that takes the input from the axes of a joystick, figures out the angle, and zeroes out either the horizontal or vertical input before moving the rigidbody2D.velocity. I've chosen not to use AddForce, instead simply directly changing the velocity, because that way I don't get the slow speed ramp-up, sliding, or diagonal movement when force is applied from two different axes.
This part works fine, and I get orthogonal-only movement.
However, the problem I'm running into is that, since I'm directly changing velocity and not using AddForce, it causes the character to stop dead in its tracks when the rigidbody is in contact with a kinematic surface, i.e. a wall. I've attached a 0-friction physics materials to the box colliders of the walls, but whenever the character collider runs into the wall, it gets kind of stuck there due to the fact that I'm zeroing out any movement along the axis that would allow it to slide. It's not until I move the joystick to a sufficient angle where it zeroes out the movement in the direction of the wall that the character begins to move again.
So, this makes perfect sense given the way I've coded it. However, this is producing some very bad controls, as every time you hit a wall or terrain object you stop dead in your tracks until you rotate the stick past the 45-degree mark, at which point your movement starts along the other axis.
I've been banging my head against the wall all week about this, and so now I'm hoping you folks can help me find a solution. How can I retain enforced orthogonal movement in top-down 2D while at the same time accounting for the fact that, when the character hits a wall, it has to favor the axis that will allow it to move along that wall instead of the axis it would normally favor based on the input?
Answer by PokeyDTD · Oct 20, 2014 at 04:21 AM
So, I ended up solving this earlier today. Here's the code for my hero unit mover script, and you can see that my switch statement in the Move function combines with OnCollisionStay2D to help solve my sliding along walls problem.
public class MoveHero : MonoBehaviour {
public GameObject player;
private PlayerController pc;
public float speed;
public float currentSpeed;
public bool isTouchingWallRight;
public bool isTouchingWallLeft;
public bool isTouchingWallUp;
public bool isTouchingWallDown;
// Use this for initialization
void Start () {
pc = player.GetComponent<PlayerController> (); //Gets PlayerController, where the controls are defined
currentSpeed = speed; //Uses a secondary public variable which can be modified by a dashing script
isTouchingWallRight = false;
isTouchingWallLeft = false;
isTouchingWallUp = false;
isTouchingWallDown = false;
}
void FixedUpdate () {
float moveHorizontal = Input.GetAxis (pc.horizontalAxis);
float moveVertical = Input.GetAxis (pc.verticalAxis);
Move (moveHorizontal, moveVertical, currentSpeed);
}
public void Move (float movehorizontal, float movevertical, float movespeed){
HeroController herocontroller = gameObject.GetComponent<HeroController>();
//Check to see what direction you are facing in, then, if you're touching a wall, prioritize the opposite axis's movement
switch (herocontroller.facingDirection) {
case Constants.RIGHT:
if (isTouchingWallRight){
movevertical = movevertical * 10;
movespeed = movespeed / 2; //This is so you don't move along walls at full speed
}
break;
case Constants.LEFT:
if (isTouchingWallLeft){
movevertical = movevertical * 10;
movespeed = movespeed / 2;
}
break;
case Constants.UP:
if (isTouchingWallUp){
movehorizontal = movehorizontal * 10;
movespeed = movespeed / 2;
}
break;
case Constants.DOWN:
if (isTouchingWallDown){
movehorizontal = movehorizontal * 10;
movespeed = movespeed / 2;
}
break;
default:
break;
}
//First, figure out the angle of the joystick in degrees
float angle = Mathf.Atan2 (movevertical, movehorizontal) * Mathf.Rad2Deg;
//Then, figure out whether or not the joystick is being sufficiently pushed to prevent joystick inaccuracy from creating false movement
float deadcheck = Mathf.Abs (movehorizontal) + Mathf.Abs (movevertical);
if (deadcheck > 0.6){
//Right
if ((angle > -45) && (angle <= 45)) {
herocontroller.facingDirection = Constants.RIGHT;
movehorizontal = 1;
movevertical = 0;
}
//Up
else if ((angle > 45) && (angle <= 135)){
herocontroller.facingDirection = Constants.UP;
movehorizontal = 0;
movevertical = 1;
}
//Down
else if ((angle > -135) && (angle <= -45)){
herocontroller.facingDirection = Constants.DOWN;
movehorizontal = 0;
movevertical = -1;
}
else {
herocontroller.facingDirection = Constants.LEFT;
movehorizontal = -1;
movevertical = 0;
}
}
else{
movevertical = 0;
movehorizontal = 0;
}
//Set the direction for the hero character to move
Vector2 movement1 = new Vector2 (movehorizontal, movevertical);
//Set the hero in motion by directly modifying its velocity
rigidbody2D.velocity = movement1 * movespeed;
}
//OnCollisionStay2D determines if you are touching a wall, and in which direction the wall is from you, setting the correct isTouchingWall to true
void OnCollisionStay2D(Collision2D coll){
if (coll.gameObject.tag == "Terrain"){
Vector3 contactPoint = coll.contacts[0].point;
Vector3 center = coll.collider.bounds.center;
isTouchingWallLeft = contactPoint.x > center.x;
isTouchingWallRight = contactPoint.x < center.x;
isTouchingWallUp = contactPoint.y < center.y;
isTouchingWallDown = contactPoint.y > center.y;
}
}
//OnCollisionExit2D is used to reset the isTouchingWall variables once you leave contact with a wall
void OnCollisionExit2D(Collision2D coll){
if (coll.gameObject.tag == "Terrain") {
isTouchingWallLeft = false;
isTouchingWallRight = false;
isTouchingWallUp = false;
isTouchingWallDown = false;
}
}
}
Your answer
Follow this Question
Related Questions
How to fix player bumping into the wall? 0 Answers
EnemyAi animations, are bugged while moving 0 Answers
Unexpected behaviour with Fixed Joint 2D 0 Answers
2D smooth top-down movement 1 Answer
Why isn't my 2d object facing the way it is moving? 0 Answers