I’m working on a very simple automated character controller.
It is moving from left to right over a set of tiles (crates). They each have their separate BoxCollider2D and are placed at exactly 1 unit next to each other (vertex snapped).
To check whether I’m at an edge, I cast a ray down.
The problem is: sometimes, the ray moves exactly inbetween the BoxColliders of the crates.
Even though they are perfectly aligned next to each other, sometimes it stops movement and thinks there is a gap.
I suspect this has something to do with rounding issues in the physics engine, but I can’t seem to find a good solution.
I have attached an image that displays the point where the character usually ‘breaks’.
The green lines are box-colliders, the small yellow line is my raycast.
It also doesn’t seem to flip (like expected) when inbetween colliders, it’s just idle there…
When I log to debug, it says that it’s not grounded when it gets stuck inbetween colliders. (meaning the ray.collider is null! - At the point of the screenshot, my ray.collider is null…)
My alternative would be to cast 2 rays, but I’d rather not resort to something ‘dirty’
//this is the movement code
void FixedUpdate()
{
if (!ControllerStats.Falling)
{
var currentPosition = _rigidBody.position;
var newPosition = currentPosition + (_lastAiDecision * MovementSpeed * Time.fixedDeltaTime);
_rigidBody.MovePosition(newPosition);
}
}
void LateUpdate()
{
//Ask AI what to do next and pass along current data (such as direction)
_lastAiDecision = _ai.CalculateAi(this);
}
//this is the platform ai
public override Vector2 CalculateAi(EnemyControllerBase controller)
{
var stats = controller.ControllerStats;
if (stats.Falling)
return Vector2.zero;
var facingDirection = stats.FacingDirection;
if (!base.CheckIfGrounded(facingDirection))
{
controller.Flip();
facingDirection *= -1;
}
return (int)facingDirection.x == 1 ? Vector2.right : Vector2.left;
}
protected virtual bool CheckIfGrounded(Vector2 facingDirection)
{
var bounds = _collider.bounds.extents;
var lowerbound = -bounds.y;
var sidebound = bounds.x * facingDirection.x;
var rayStart = (Vector2) transform.position + new Vector2(sidebound, lowerbound);
var ray = Physics2D.Raycast(rayStart, Vector2.down, GroundCheckTreshold, CollisionMask);
if(Manager.Instance.IsDebug)
Debug.DrawRay(rayStart, Vector2.down * GroundCheckTreshold, Color.yellow);
return ray.collider != null;
}