Hello, I have been trying for a little while now to achieve precise collision for a 2D platforming game with an orthographic camera, but I just can’t seem to get it to behave how I want. The only way I have been able to get perfect collision is by using a CharacterController, which I can’t use because of the limitations of the capsule shape. Also, I don’t like the reactions by adding forces, so I am trying to manually set the velocity, or manually translate the object.
The Problem:
When landing from a jump, the character sometimes dips below into the ground, before snapping back up to ground level. This happens randomly, maybe 60% of the time. This is visually not good.
What I’ve Tried:
I have tried setting the velocity manually and then using Raycasts to detect the ground, and if the ground is present, just set the Y velocity to zero. I have also tried just translating the object and using Raycasts to detect the ground. Here is a real quick example you can test to demonstrate I am talking about:
-
Add another cube , make it smaller to use as the player. Add a rigidbody, disable gravity, constrain Z position and X,Y,Z rotation
-
Add a cube to use as the ground and stretch it out. Change the material to anything so you can differentiate from the player
-
Make your camera orthographic
-
Add this script to the player cube:
using UnityEngine;
using System.Collections;public class TestBox : MonoBehaviour {
// Use this for initialization private Rigidbody thisRigidbody; private Transform thisTransform; public float gravity = 500.0f; public float upSpd = 300.0f; private Vector3 movement = Vector3.zero; private float rayLength; void Start () { thisRigidbody = GetComponent<Rigidbody>(); rayLength = collider.bounds.extents.y + 0.1f; thisTransform = GetComponent<Transform>(); } // Update is called once per frame void Update () { if( Input.GetMouseButtonDown(0) ) { movement.y = upSpd; } if( IsGrounded() && movement.y < 0 ) movement.y = 0; else movement.y -= gravity * Time.deltaTime; } bool IsGrounded() { RaycastHit hit; if (Physics.Raycast(thisTransform.position, -Vector3.up, out hit, rayLength)) { return true; } return false; } void FixedUpdate() { thisRigidbody.velocity = movement; }
}
You can adjust the gravity and upSpd depending on the scale of your objects. If you run it and click the mouse you’ll see if the gravity is high enough, the dipping will occur.
I have no idea why the results are so inconsistent. The problem appears to be in the Raycast itself, where it returns true at slightly different times in code execution. The “dipping” doesn’t happen when the Y speed is slow enough, but under any normal speed, the temporary dip happens.
Does anyone have ANY idea as to why this is happening? Am I going about this the wrong way? Is there a way for me to ensure that the Raycast always returns true at the right time? I don’t know how the CharacterController works, but whatever it does, it seems to not suffer from this problem.
Thanks in advance!