Community Made Tools

Have you made any useful utilities with Odin?

Login and submit your creations here

Easy point based collider creator using Odin

Authored by Andrew
Shared 07-04-2022

This is a simple GameObject based collider creator.

Add the script to an empty GameObject then using its children to place points the script will then generate a collider based on the provided child objects.

Gist version is easier and faster to modify, so use it as it may have newer version than here

ColliderCreatorOdin.cs

using UnityEditor;
using UnityEngine;
using Sirenix.OdinInspector;

namespace TodelmerResources.Scripts.Utilities
{
    /// <summary>
    /// Creates a group of points that lets you easily create colliders for invisable walls, triggers or general blocking of player movements.
    /// </summary>
    [ExecuteInEditMode]
    [CanEditMultipleObjects]
    public class ColliderCreatorOdin : MonoBehaviour
    {
#if UNITY_EDITOR
        [HideIf("@this.transform.childCount < 1"), Header("Gizmos"), SerializeField]
        private bool visualize = true;

        [HideIf("@this.transform.childCount < 1"), SerializeField]
        private Color gizmosColor = Color.white;

        [HideIf("@this.transform.childCount < 1"), Header("Generation"), SerializeField]
        private bool generateCapsuleColliders = true;

        [HideIf("@this.transform.childCount < 1"), SerializeField]
        private bool isTrigger = false;

        [HideIf("@this.transform.childCount < 1"), SerializeField]
        private bool generateBoxColliders = true;

        [HideIf("@this.transform.childCount > 1"), Title("Child objects are not setup."), Button]
        private void Setup()
        {
            if (transform.childCount < 1)
            {
                var boxContainer = new GameObject("_COLLIDERS");
                boxContainer.transform.localPosition = Vector3.zero;
                boxContainer.transform.localScale = Vector3.one;
                boxContainer.transform.SetParent(this.transform);

                var point1 = new GameObject("Point (1)");
                point1.transform.SetParent(this.transform);
                point1.transform.localPosition = Vector3.zero;
                point1.transform.localScale = Vector3.one + Vector3.up * 3;

                var point2 = new GameObject("Point (2)");
                point2.transform.SetParent(this.transform);
                point2.transform.localPosition = Vector3.forward * 5;
                point2.transform.localScale = Vector3.one + Vector3.up * 3;
            }
        }

        [HideIf("@this.transform.childCount < 1")]
        [ButtonGroup]
        private void GenerateColliders()
        {
            var collidersTransform = this.transform.GetChild(0);

            ClearAllColliders();

            // create capsule AND box colliders.
            for (int i = 1; i < this.transform.childCount; i++)
            {
                var child = this.transform.GetChild(i);

                // create capsule collider.
                if (generateCapsuleColliders)
                {
                    var capsuleObject = Instantiate(child, collidersTransform);
                    var capsuleCollider = capsuleObject.gameObject.AddComponent<CapsuleCollider>();
                    capsuleCollider.radius = 1;
                    capsuleCollider.height = 1;
                    if (isTrigger == true)
                    {
                        capsuleCollider.isTrigger = true;
                    }
                }

                // create box colliders for inbetween children.
                if (generateBoxColliders && i < this.transform.childCount - 1)
                {
                    var nextChild = this.transform.GetChild(i + 1);

                    var position = (child.position + nextChild.position) / 2f;
                    var size = new Vector3((child.localScale.x + nextChild.localScale.x) / 2f, (child.localScale.y + nextChild.localScale.y) / 2f, Vector3.Distance(child.position, nextChild.position));
                    var rotation = Quaternion.LookRotation(nextChild.position - child.position);

                    var boxChild = new GameObject("Box " + i, typeof(BoxCollider));
                    boxChild.transform.SetParent(collidersTransform);
                    boxChild.transform.position = position;
                    boxChild.transform.localScale = size;
                    boxChild.transform.rotation = rotation;
                    if (isTrigger == true)
                    {
                        var box = boxChild.GetComponent<BoxCollider>();
                        box.isTrigger = true;
                    }

                }
            }
        }

        [HideIf("@this.transform.childCount < 1")]
        [ButtonGroup]
        private void ClearAllColliders()
        {
            var boxContainerTransform = transform.GetChild(0);

            // delete all existing box colliders.
            for (int i = boxContainerTransform.childCount - 1; i >= 0; i--)
            {
                DestroyImmediate(boxContainerTransform.GetChild(i).gameObject);
            }

            // delete all capsule colliders of children.
            for (int i = 1; i < this.transform.childCount; i++)
            {
                var child = this.transform.GetChild(i);
                var capsuleCollider = child.GetComponent<CapsuleCollider>();
                if (capsuleCollider != null)
                {
                    DestroyImmediate(capsuleCollider);
                }
            }
        }

        private void OnDrawGizmos()
        {
            if (!visualize)
                return;

            // start at 1 (2nd child), first child is container for box colliders.
            for (int i = 1; i < transform.childCount; i++)
            {
                var target = transform.GetChild(i);

                // render capsule for this child.
                if (generateCapsuleColliders)
                {
                    DrawWireCapsule(target.position, target.rotation, target.localScale.x, target.localScale.y);
                }

                // render box for child inbetween this and next child.
                if (generateBoxColliders && i < transform.childCount - 1)
                {
                    var other = transform.GetChild(i + 1);

                    var position = (target.position + other.position) / 2f;
                    var size = new Vector3((target.localScale.x + other.localScale.x) / 2f, (target.localScale.y + other.localScale.y) / 2f, Vector3.Distance(target.position, other.position));

                    Matrix4x4 rotationMatrix = Matrix4x4.TRS(position, Quaternion.LookRotation(other.position - target.position), size);
                    Gizmos.matrix = rotationMatrix;

                    Gizmos.color = gizmosColor * 0.3f;
                    Gizmos.DrawCube(Vector3.zero, Vector3.one);

                    Gizmos.color = gizmosColor;
                    Gizmos.DrawWireCube(Vector3.zero, Vector3.one);

                    Gizmos.matrix = Matrix4x4.identity;
                }
            }
        }

        private void DrawWireCapsule(Vector3 position, Quaternion rotation, float radius, float height)
        {
            Handles.color = gizmosColor;
            Matrix4x4 angleMatrix = Matrix4x4.TRS(position, rotation, Handles.matrix.lossyScale);
            using (new Handles.DrawingScope(angleMatrix))
            {
                var pointOffset = (height - (radius * 2)) / 2;

                // draw sideways.
                Handles.DrawWireArc(Vector3.up * pointOffset, Vector3.left, Vector3.back, -180, radius);
                Handles.DrawLine(new Vector3(0, pointOffset, -radius), new Vector3(0, -pointOffset, -radius));
                Handles.DrawLine(new Vector3(0, pointOffset, radius), new Vector3(0, -pointOffset, radius));
                Handles.DrawWireArc(Vector3.down * pointOffset, Vector3.left, Vector3.back, 180, radius);
                // draw frontways.
                Handles.DrawWireArc(Vector3.up * pointOffset, Vector3.back, Vector3.left, 180, radius);
                Handles.DrawLine(new Vector3(-radius, pointOffset, 0), new Vector3(-radius, -pointOffset, 0));
                Handles.DrawLine(new Vector3(radius, pointOffset, 0), new Vector3(radius, -pointOffset, 0));
                Handles.DrawWireArc(Vector3.down * pointOffset, Vector3.back, Vector3.left, -180, radius);
                // draw center.
                Handles.DrawWireDisc(Vector3.up * pointOffset, Vector3.up, radius);
                Handles.DrawWireDisc(Vector3.down * pointOffset, Vector3.up, radius);

            }
        }
#endif
    }
}