JumpaholicFrog
JumpaholicFrog

Reputation: 120

How to check if an object is colliding at the top or bottom part of a sphere

I have a colliding object which can come from any direction, and I would like to check the position relative to the center of a sphere.

enter image description here

My idea was to create a vector with the same direction as the arrow that went through the center of the sphere and then check if the arrow position is over or under the new vector, but I don't know how to achieve this.

Upvotes: 1

Views: 659

Answers (2)

CorrieJanse
CorrieJanse

Reputation: 2598

You can get the point of impact. You can then measure the distance from the top and bottom of the sphere to the point of impact. The smaller distance is always the one it is closer to.

void OnCollisionEnter(Collision col)
{
    var top = transform.position + transform.localscale.y/2 * transform.up;
    var bottom = transform.position + transform.localscale.y/2 * -transform.up;
    
    var isTop = Vector3.Distance(top, collision.point) < Vector3.Distance(bottom, collision.point);
    
    if (isTop) {
        // It hit the top
        
    } else {
        // It hit the bottom
        
    }   
}

Upvotes: 0

derHugo
derHugo

Reputation: 90683

In general a Vector has no position. It is only a direction and magnitude in space. A position basically is a vector itself that points from the world origin (0,0,0) to the according position. So if you only have a directional vector it contains no information whatsoever about the position.

You would need to define top and bottom better but if you just want to check in global space you can simply check whether the collision contact point is above or below the sphere center by comparing their Y axis value.

Something like e.g.

// Assuming this script is on the Sphere
private void OnCollisionEnter(Collision collision)
{
    // You could of course take all contact points into account and take an average etc
    // but to keep things simple just use only one for now
    var contact = collision.GetContact(0);
    var contactPoint = contact.point;
    var ownCenter = contact.thisCollider.bounds.center;

    if(contactPoint.y > ownCenter.y)
    {
        Debug.Log("Hit on top half");
    }
    else
    {
        Debug.Log("Hit on bottom half");
    }
}

If you rather want to check the local space (e.g. because your sphere is rotated like in your graphic) you can use almost the same but simply convert the positions into local space first

var contactPoint = transform.InverseTransformPoint(contact.point);

// In the case for a sphere this should most probably be equal to simply using 0,0,0
// In case of a "SphereCollider" you could also use that specific type and then use "sphereCollider.center" which already is in local space
// But to have it working generally keep using the center for now
var ownCenter = transform.InverseTransformPoint(contact.thisCollider.bounds.center);

Upvotes: 2

Related Questions