Search code examples
c#unity-game-enginegame-developmentbounding-box

How would i find the center of an object with a Y axis offset to find the center on the top face?


I'm trying to make a climbing system (Player climbs on top of a cube). I'm using collider.bounds.center to get the center of the object but what would I have to do to get the center on the top face of the object?

enter image description here

Thank you for any help!


Solution

  • Define top face ;)

    For default cube it would be e.g.

    theCube.transform.position + theCube.transform.up * theCube.transform.lossyScale.y / 2f
    

    which would always take the "top" face in case the cube is rotated:

    public class Example : MonoBehaviour
    {
        public Transform target;
    
        private void Update()
        {
            transform.position = target.position + target.up * target.lossyScale.y / 2f;
        }
    }
    

    As you can see the sphere is always placed at the center of the top face of the cube (sphere has this script attached, cube is referenced in target)

    enter image description here


    Edit

    Sicne you rather wanted to find the center of the edge of the top face according to the side of the hit.

    This is slightly more comlpicated. The idea here is:

    • Get the four corner positions of the top face
    • get the two corners with the smallest distance to your raycast hit point
    • Get the center of this "edge"

    so something like

    public class Example : MonoBehaviour
    {
        [SerializeField] private Transform target;
        [SerializeField] private Renderer _renderer;
        [SerializeField] private Camera _camera;
    
        private void Start()
        {
            if (!_camera)
            {
                _camera = Camera.main;
            }
    
            if (!_renderer)
            {
                _renderer = GetComponent<Renderer>();
            }
        }
    
        private void Update()
        {
            if (!target)
            {
                return;
            }
    
            if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out var hit))
            {
                if (hit.collider is BoxCollider boxCollider)
                {
                    var verts = GetCubeVertices(boxCollider);
    
                    // Find the two verts with smalles distance from the hit point
                    var sortedVerts = verts.OrderBy(v => Vector3.Distance(v, hit.point)).Take(2).ToArray();
                    // Find the center between these two verts
                    var targetPosition = (sortedVerts[0] + sortedVerts[1]) / 2f;
    
                    transform.position = targetPosition;
                    _renderer.enabled = true;
                }
                else
                {
                    _renderer.enabled = false;
                }
            }
            else
            {
                _renderer.enabled = false;
            }
        }
    
        // Get the 4 vertices of the top cube face
        private Vector3[] GetCubeVertices(BoxCollider col)
        {
            var trans = col.transform;
            var min = col.center - col.size * 0.5f;
            var max = col.center + col.size * 0.5f;
    
            return new[]
            {
                trans.TransformPoint(new Vector3(min.x, max.y, min.z)),
                trans.TransformPoint(new Vector3(min.x, max.y, max.z)),
                trans.TransformPoint(new Vector3(max.x, max.y, min.z)),
                trans.TransformPoint(new Vector3(max.x, max.y, max.z))
            };
        }
    }
    

    enter image description here