- Home /
Player stalls on consecutive steps
I have a player controller that handles physics, and there is a raycast that goes in front of the player. 0.125 is half the size of a block, so I offset it on x 0.125 in front and behind the player. if I started from the head of the player, it could potentially hit the edge of the block above the player's head, which isn't a block I need to worry about. The player's height is 1, so I went a half a block down, and that is what the 0.875 is.
Then, I cast down 0.75 because that should bring be to the middle of the block next to the player that I am trying to step up on.
Then I check if the raycast distance is greater than 0.62, because 0.625 is where it should hit the right height, and I wanted to make sure it doesn't go wrong and undershoot.
Now, after I coded all this, I realized after a while that sometimes when climbing consecutive stairs, it pauses on the 2nd or 3rd step a little longer.
EDIT
I actually made a mistake on when it is stalling... It actually stalls when there are a lot of steps, because there is more chance of the player catching on a block. But why?
Player code:
using UnityEngine;
using System.Collections;
[RequireComponent (typeof (PlayerController))]
public class Player : MonoBehaviour {
private PlayerController controller;
private Vector2 velocity;
public float gravity;
public float speed;
public float jumpForce;
public BoxCollider2D colliderRef;
void Start () {
controller = GetComponent <PlayerController> ();
colliderRef = GetComponent <BoxCollider2D> ();
}
void Update () {
velocity.y -= gravity * Time.deltaTime;
if (Input.GetKey (KeyCode.A) && !Input.GetKey (KeyCode.D))
{
velocity.x = -speed;
colliderRef.offset = new Vector3 (-0.09375f, 0);
}
if (Input.GetKey (KeyCode.D) && !Input.GetKey (KeyCode.A))
{
velocity.x = speed;
colliderRef.offset = new Vector3 (0.09375f, 0);
}
if (Input.GetKey (KeyCode.A) && Input.GetKey (KeyCode.D) || !Input.GetKey (KeyCode.A) && !Input.GetKey (KeyCode.D))
{
velocity.x = 0;
}
controller.CheckForGround ();
if (Input.GetKey (KeyCode.Space) && controller.isJumping == false)
{
velocity.y = jumpForce;
}
controller.Move (velocity * Time.deltaTime);
}
}
Controller code:
using UnityEngine;
using System.Collections;
[RequireComponent (typeof (BoxCollider2D))]
public class PlayerController : MonoBehaviour {
private BoxCollider2D colliderRef;
private RaycastOrigins raycastOrigins;
public float skinWidth;
public int rayCountX = 4, rayCountY = 4;
private float spacingX, spacingY;
public LayerMask layerMask;
public bool isJumping;
public bool isSteppingUp;
struct RaycastOrigins {
public Vector2 bottomLeft, bottomRight;
public Vector2 topLeft, topRight;
}
void Start () {
colliderRef = GetComponent <BoxCollider2D> ();
CalculateRaySpacing ();
}
void UpdateRaycastBounds () {
Bounds bounds = colliderRef.bounds;
raycastOrigins.bottomLeft = new Vector2 (bounds.min.x + skinWidth / 2, bounds.min.y + skinWidth / 2);
raycastOrigins.bottomRight = new Vector2 (bounds.max.x - skinWidth / 2, bounds.min.y + skinWidth / 2);
raycastOrigins.topLeft = new Vector2 (bounds.min.x + skinWidth / 2, bounds.max.y - skinWidth / 2);
raycastOrigins.topRight = new Vector2 (bounds.max.x - skinWidth / 2, bounds.max.y - skinWidth / 2);
}
void CalculateRaySpacing () {
Bounds bounds = colliderRef.bounds;
rayCountX = Mathf.Clamp (rayCountX, 2, 8);
rayCountY = Mathf.Clamp (rayCountY, 2, 16);
spacingX = (bounds.size.x - skinWidth) / (rayCountY - 1);
spacingY = (bounds.size.y - skinWidth) / (rayCountX - 1);
}
public void Move (Vector3 velocity) {
UpdateRaycastBounds ();
CollideVertically (ref velocity);
CollideHorizontally (ref velocity);
transform.Translate (velocity);
}
void CollideVertically (ref Vector3 velocity) {
float directionY = Mathf.Sign (velocity.y);
float rayLength = Mathf.Abs (velocity.y) + skinWidth / 2;
for (int r = 0; r < rayCountY; r ++)
{
Vector2 rayOrigin = Vector2.zero;
if (directionY == -1)
{
rayOrigin = raycastOrigins.bottomLeft;
}
else if (directionY == 1)
{
rayOrigin = raycastOrigins.topLeft;
}
rayOrigin += Vector2.right * spacingX * r;
Debug.DrawRay (rayOrigin, Vector3.down * 2, Color.red);
RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.up * directionY, rayLength, layerMask);
if (hit == true)
{
velocity.y = (hit.distance - skinWidth / 2) * directionY;
rayLength = hit.distance;
}
}
for (int r = 0; r < rayCountY; r ++)
{
Vector2 rayOrigin = raycastOrigins.bottomLeft;
rayOrigin += Vector2.right * spacingX * r;
RaycastHit2D groundCheck = Physics2D.Raycast (rayOrigin, Vector2.down, skinWidth / 2, layerMask);
if (groundCheck == true)
{
Bounds bounds = colliderRef.bounds;
RaycastHit2D hitLeft = Physics2D.Raycast (new Vector2 (bounds.min.x - 0.125f, bounds.min.y + 0.875F), Vector2.down, 0.75f, layerMask);
if (hitLeft == true)
{
if (hitLeft.distance >= 0.62f)
{
if (Input.GetKey (KeyCode.A) && isSteppingUp == false)
{
StartCoroutine (WalkUpBlocks (Vector3.up / 4 + Vector3.left / 4));
isSteppingUp = true;
}
}
}
RaycastHit2D hitRight = Physics2D.Raycast (new Vector2 (bounds.max.x + 0.125f, bounds.min.y + 0.875f), Vector2.down, 0.75f, layerMask);
if (hitRight == true)
{
if (hitRight.distance >= 0.62f)
{
if (Input.GetKey (KeyCode.D) && isSteppingUp == false)
{
StartCoroutine (WalkUpBlocks (Vector3.up / 4 + Vector3.right / 4));
isSteppingUp = true;
}
}
}
}
}
}
void CollideHorizontally (ref Vector3 velocity) {
float directionX = Mathf.Sign (velocity.x);
float rayLength = Mathf.Abs (velocity.x) + skinWidth / 2;
for (int r = 0; r < rayCountX; r ++)
{
Vector2 rayOrigin = Vector2.zero;
if (directionX == -1)
{
rayOrigin = raycastOrigins.bottomLeft;
}
else if (directionX == 1)
{
rayOrigin = raycastOrigins.bottomRight;
}
rayOrigin += Vector2.up * spacingY * r;
RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.right * directionX, rayLength, layerMask);
if (hit == true)
{
Debug.Log (velocity.x);
velocity.x = (hit.distance - skinWidth / 2) * directionX;
rayLength = hit.distance;
}
}
}
IEnumerator WalkUpBlocks (Vector3 direction) {
yield return new WaitForSeconds (0.1f);
transform.Translate (direction);
isSteppingUp = false;
}
public void CheckForGround () {
for (int r = 0; r < rayCountY; r ++)
{
Vector2 rayOrigin = raycastOrigins.bottomLeft;
rayOrigin += Vector2.right * (spacingX * r);
RaycastHit2D groundCheck = Physics2D.Raycast (rayOrigin, Vector2.down, skinWidth / 2, layerMask);
isJumping = !groundCheck;
}
}
}
I'm still trying to figure this out. I might have to take a break and leave it up to Unity Answers for a bit. I've been trying to fix it for 3 hours.