I’m trying to code a basic collision system that detects when an actor hits a platform and stops the actor on the platform—basic 2D platformer stuff. I’m using Orthello2D. The way it should work is as follows:
2 RayCasts are fired out from the left and right sides of the actor’s collider, both from the bottom of the actor’s collider (this is very important). The length of the RayCast is equal to the absolute value of the actor’s current y velocity (since they’re moving down, it would be negative). If a collision is detected, the actor is moved to the point of impact plus half of the collider’s size (taking into account that the collider’s size is relative to the actor) and sets various variables (like airborne and velocity) to cease falling.
The problem I’ve been seeing during debugging is that the RayCasts are not firing from the bottom of the collider, but rather from slightly above said bottom, and I think that’s messing up all the hit detection/translation that needs to happen. This code works perfectly if I use hard numbers instead of calculating based on size (but I’m using size so I can use the same code for all actors regardless of sprite size—less error prone), so I think I’m missing something about how size and position of colliders is determined. Could someone take a look at my code and tell me what I’m not getting?
int platformMask = 1 << 8;
RaycastHit hit;
// colliderCenter should be the collider's position in the scene
// myCollider is the collider attached to the actor using GetComponent<BoxCollider>();
Vector3 colliderCenter = thisTransform.position + myCollider.center;
// colliderSize should be the collider's size, factoring in scale of the actor
Vector3 colliderSize = Vector3.Scale(thisTransform.localScale, myCollider.size);
// colliderBottom here is the problem; it's too high!
// How do I get the actual bottom of the collider (y value)?
float colliderBottom = colliderCenter.y - (colliderSize.y / 2);
float colliderLeft = colliderCenter.x - (colliderSize.x / 2);
float colliderRight = colliderCenter.x + (colliderSize.x / 2);
float rayLength = Mathf.Abs(velocity.y * Time.deltaTime) > 0 ? Mathf.Abs(velocity.y * Time.deltaTime) : 0.01f;
if (Physics.Raycast(new Vector3(colliderLeft, colliderBottom, colliderCenter.z), Vector3.down, out hit, rayLength, platformMask)
|| Physics.Raycast(new Vector3(colliderRight, colliderBottom, colliderCenter.z), Vector3.down, out hit, rayLength, platformMask))
{
// Momentum is 1 if velocity is positive, -1 if negative, and 0 if 0
// In this case, we're checking the the actor is falling
if (Momentum.y < 0) {
// Move the actor to its box collider height above the hit point
thisTransform.position = new Vector3(thisTransform.position.x, hit.point.y + (colliderSize.y / 2) - myCollider.center.y, 0f);
// Ground the actor (for acceleration and animation)
airborne = isJumping = false;
}
} else {
// Set the actor as airborne (for acceleration and animation)
airborne = true;
}