- Home /
Character keeps jumping up walls
I'm making a 2D platformer and after making a level, my character kept getting stuck when hitting a wall. I fixed this by adding a 2D Physics Material to the walls with friction set to 0. However, there is still an issue where when touching the walls, the character can jump up them repeatedly. I am using Box Collider 2D on the walls.
My code:
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class Player : MonoBehaviour { private Rigidbody2D myRigidbody;
[SerializeField]
private float movementSpeed;
[SerializeField]
private Transform[] groundPoints;
[SerializeField]
private float groundRadius;
[SerializeField]
private LayerMask whatIsGround;
private bool isGrounded;
private bool jump;
[SerializeField]
private bool airControl;
[SerializeField]
private float jumpForce;
void Start()
{
myRigidbody = GetComponent<Rigidbody2D>();
}
void Update()
{
HandleInput();
}
void FixedUpdate()
{
float horizontal = Input.GetAxis("Horizontal");
isGrounded = IsGrounded();
HandleMovement(horizontal);
ResetValues();
}
private void HandleInput()
{
if (Input.GetKeyDown(KeyCode.Space))
{
jump = true;
isGrounded = false;
}
}
private void HandleMovement(float horizontal)
{
myRigidbody.velocity = new Vector2(horizontal * movementSpeed, myRigidbody.velocity.y);
if (isGrounded && jump)
{
isGrounded = false;
myRigidbody.AddForce(new Vector2(0, jumpForce));
}
}
private bool IsGrounded()
{
if (myRigidbody.velocity.y <= 0)
{
foreach (Transform point in groundPoints)
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(point.position, groundRadius, whatIsGround);
for (int i = 0; i < colliders.Length; i++)
{
if (colliders[i].gameObject != gameObject)
{
return true;
}
}
}
}
return false;
}
private void ResetValues()
{
jump = false;
}
}
Answer by Eno-Khaon · Apr 08, 2018 at 11:19 PM
To determine whether your character is grounded, you're doing the following:
•Check if the player's Y-axis velocity is < 0
•Check if there's a nearby object you're colliding with
And that's it. You're not verifying that what you're colliding with is supposed to be treated as "ground" in this situation. Therefore, as long as you're moving downward and touching *anything* you count as grounded and are able to jump.
The next step you need to implement, in whichever way you choose to implement it, is to verify that the surface you've contacted is one you can actually stand on, such as by checking the surface normal of the point of contact.
With that in mind, such tests are often performed in OnCollisionEnter2D() or OnCollisionStay2D() to determine whether the character is on the ground, rather than allocating an array of colliders every frame. Furthermore, the Collision2D generated into those functions allows you to retrieve the points of contact, which in turn allows you to get the surface normal of the contact(s) used to verify whether that surface can/should be treated as "ground".
Ok, I see what you mean with the problems of my current code. I'm trying to use the OnCollisionEnter2D, but how exactly do I actually implement this? I'm a bit new to Unity sorry
The most direct way to do it would likely be to get the normal direction the object collided with and check that against the up direction. Basically, you can use OnCollisionEnter or OnCollisionStay to track the contact points of your player collider and whatever it's touching. Then you can get the normal direction of the contact point(s) and if that direction is less than, say, 30 degrees off the up vector, allow the player to stand on it and set grounded to true. Of course your threshold for what the angle should be depends on the game and how steep of an incline you'd like to allow the player to traverse. I'm not familiar with working in a 2d environment, but you might also be able to simply check the platforms up vector (transform.up) vs the world up (vector3.up) and compare the angle there. That will only work if the gameobject is straight though, as transform.up will not change to match the curves of the object, it will just align with the axis of the object's pivot point.
Answer by Chimer0s · Apr 08, 2018 at 11:07 PM
It looks to me as though "if (colliders[i].gameObject != gameObject)" is the problem. This is saying if the game object detected is NOT the game object that this script is attached to (i.e. the player). Changing != to == might be all you need.
But, if I'm understanding the code correctly, it seems as though you're having the ground detect the player. This seems woefully inefficient to me. Would it not be easier to have the player check for any ground colliders that its touching? I've never made a 2d game with Unity, so it's very possible that I'm just ignorant in the matter.
Your answer
Follow this Question
Related Questions
Unity 2D - Rigidbody2D Velocity sudden freeze 0 Answers
While Moving Left or Right my character falls more slowly. 2 Answers
What's a good way at keeping a ball bounce around inside the scene? 1 Answer
2d: Problem with player running/walking between 2 box colliders/platforms 2 Answers
2D Physics Problem? 1 Answer