2

I'm generating a bunch of basic sphere and capsule mesh objects at runtime in a 3D fractal-based piece I'm working on, and I'm stuck on how to apply the appropriate Collider type when each object gets created.

My script randomly selects from either spheres or capsules and arranges them based on a range of orientation possibilities. I need help on how to assign the appropriate Collider when each mesh gets created.

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class BuildFractal : MonoBehaviour 
{
    public Mesh[] meshes;
    public Material material;
    public Material[,] materials;
    private Rigidbody rb;

    public int maxDepth;             // max children depth
    private int depth;
    public float childScale;         // set scale of child objects
    public float spawnProbability;   // determine whether a branch is created or not
    public float maxRotationSpeed;   // set maximium rotation speed
    private float rotationSpeed;
    public float maxTwist;
    public Text positionText;
    public int objectMass;

    // Create arrays for direction and orientation data
    private static Vector3[] childDirections = {
        Vector3.up,
        Vector3.right,
        Vector3.left,
        Vector3.forward,
        Vector3.back,
        // Vector3.down
    };
    private static Quaternion[] childOrientations = {
        Quaternion.identity,
        Quaternion.Euler(0f, 0f, -90f),
        Quaternion.Euler(0f, 0f, 90f),
        Quaternion.Euler(90f, 0f, 0f),
        Quaternion.Euler(-90f, 0f, 0f),
        // Quaternion.Euler(180f, 0f, 0f)
    };

    private void Start () 
    {
        Rigidbody rb;

        rotationSpeed = Random.Range(-maxRotationSpeed, maxRotationSpeed);
        transform.Rotate(Random.Range(-maxTwist, maxTwist), 0f, 0f);

        if (materials == null)
        {
            InitializeMaterials();
        }

        // Select from random range of meshes
        gameObject.AddComponent<MeshFilter>().mesh = meshes[Random.Range(0, meshes.Length)];
        // Select from random range of colors
        gameObject.AddComponent<MeshRenderer>().material = materials[depth, Random.Range(0, 2)];
        // Add Rigigbody to each object
        rb = gameObject.AddComponent<Rigidbody>();
        rb.useGravity = false;
        rb.mass = objectMass;

        // Create Fractal Children
        if (depth < maxDepth)
        {
            StartCoroutine(CreateChildren());
        }
    }

    private void Update ()
    {
        transform.Rotate(0f, rotationSpeed * Time.deltaTime, 0f);
    }

    private void Initialize (BuildFractal parent, int childIndex)
    {
        maxRotationSpeed = parent.maxRotationSpeed;

        // copy mesh and material references from parent object
        meshes = parent.meshes;
        materials = parent.materials;
        maxTwist = parent.maxTwist;

        // set depth and scale based on variables defined in parent
        maxDepth = parent.maxDepth;
        depth = parent.depth + 1;
        childScale = parent.childScale;

        transform.parent = parent.transform;           // set child transform to parent

        // transform.localScale = Vector3.one * childScale;

        transform.localScale = Vector3.one * Random.Range(childScale / 10, childScale * 1);
        transform.localPosition = childDirections[childIndex] * (Random.Range((0.1f + 0.1f * childScale),(0.9f + 0.9f * childScale)));
        transform.localRotation = childOrientations[childIndex];

        spawnProbability = parent.spawnProbability;
    }

    private void InitializeMaterials ()
    {
        materials = new Material[maxDepth + 1, 2];

        for (int i = 0; i <= maxDepth; i++)
        {
            float t = i / (maxDepth - 1f);
            t *= t;

            // Create a 2D array to hold color progressions
            materials[i, 0] = new Material(material);
            materials[i, 0].color = Color.Lerp(Color.gray, Color.white, t);
            materials[i, 1] = new Material(material);
            materials[i, 1].color = Color.Lerp(Color.white, Color.cyan, t);
        }
        // materials[maxDepth, 0].color = Color.white;
        materials[maxDepth, 1].color = Color.white;
    }

    private IEnumerator CreateChildren ()
    {
        for (int i = 0; i < childDirections.Length; i++)
        {
            if (Random.value < spawnProbability)
            {
                yield return new WaitForSeconds(Random.Range(0.1f, 1.5f));
                new GameObject("Fractal Child").AddComponent<BuildFractal>().Initialize(this, i);
            }
        }
    }

    /*void OnCollisionEnter(Collision col)
    {
        if(col.gameObject.name == "Fractal Child")
        {
            Destroy(this.gameObject);
        }
    }*/
}
user3071284
  • 6,955
  • 6
  • 43
  • 57
greyBow
  • 1,298
  • 3
  • 28
  • 62
  • Could you apply the collider to the mesh's specificaly and make them prefabs and choose from the range of prefabs instead of mesh's? – Al Wyvern Nov 04 '15 at 14:42
  • that's a good idea, i was trying to do everything programmatically though, as part of the project requirements. – greyBow Nov 04 '15 at 15:22
  • any thoughts on how I might be able to do this without prefabs? – greyBow Nov 04 '15 at 15:54
  • 1
    What about using a polygon collider, they usually autodetect the shape and try best to fit it – Al Wyvern Nov 04 '15 at 15:57
  • since your using just a `Mesh` array, there unfortunately *isn't* any way to back track or easily determine the primitive shape of closest resemblance. I think the prefab option is the way to go, otherwise i see a lot of math and hundreds of lines of code slowing everything down just to do what can be prepared for beforehand anyway. – maraaaaaaaa Nov 04 '15 at 20:26
  • Contradicting my last comment, you potentially *could* do a very very vague guess placing your mesh into 3 potential categories: plane, cube, and other primitive. You can do this by using the `mesh.vertices` field. If `mesh.vertices < 7` there is a high chance that you are dealing with a plane. if `mesh.vertices == 24` you almost certainly have a cube, if it is a closed mesh. and if `mesh.vertices > 24` then you have other primitive. – maraaaaaaaa Nov 04 '15 at 20:31
  • Ugly work-around could be to rely on that the instantiated meshes are given a descriptive name in their `gameObject.name` field, like `if (mesh.name == "Cube Instance") { /* box collider */}`. (or with `string.Contains()`) – Maximilian Gerhardt Nov 04 '15 at 20:32

1 Answers1

1

Add a mesh collider after you instantiate and set the same mesh, job done!

http://docs.unity3d.com/ScriptReference/MeshCollider.html

that should sort it out programmatically

Al Wyvern
  • 199
  • 1
  • 15