ElasticSea / unity-fracture

Fracture any mesh at runtime
MIT License
1.11k stars 128 forks source link

Any way to remove chunks rather than send chunks flying? #5

Closed hmatt843 closed 1 year ago

hmatt843 commented 4 years ago

Thank you for publishing this awesome project.

I'm trying to use this to remove chunks instead of blast them away. So, I modified the ChunkNode.cs script to try to Destroy the pieces when they're clicked (added void OnMouseDown, for example) but this caused problems with the script still trying to access Rigidbodies. I also tried to add logic like "if (rb)" instead of running Rigidbody-accessing codeblocks by default.

I'm not that comfortable with C#, honestly, so I was wondering if anyone could take a look and let me know the correct way to modify this script's behavior to simply remove Mouse-clicked chunks, rather than blast them flying away?

My poorly changed code:

using System.Collections.Generic;
using System.Linq;
using Project.Scripts.Utils;
using UnityEngine;

namespace Project.Scripts.Fractures
{
    public class ChunkNode : MonoBehaviour
    {
        public HashSet<ChunkNode> Neighbours = new HashSet<ChunkNode>();
        public ChunkNode[] NeighboursArray = new ChunkNode[0];
        private Dictionary<Joint, ChunkNode> JointToChunk = new Dictionary<Joint, ChunkNode>();
        private Dictionary<ChunkNode, Joint> ChunkToJoint = new Dictionary<ChunkNode, Joint>();
        private Rigidbody rb;
        private Vector3 frozenPos;
        private Quaternion forzenRot;
        private bool frozen;        
        public bool IsStatic => rb.isKinematic;

        public Color Color { get; set; } = Color.black;
        public bool HasBrokenLinks { get; private set; }

        void OnMouseDown()
        {

            Destroy(this.gameObject);
            return;

        }

        private bool Contains(ChunkNode chunkNode)
        {
            return Neighbours.Contains(chunkNode);
        }

        private void FixedUpdate()
        {

            // Kinda hacky, but otherwise the chunks slowly drift apart.
            if (frozen)
            {
                transform.position = frozenPos;
                transform.rotation = forzenRot;
            }

        }

        public void Setup()
        {
            rb = GetComponent<Rigidbody>();
            Freeze();

            JointToChunk.Clear();
            ChunkToJoint.Clear();
            foreach (var joint in GetComponents<Joint>())
            {
                var chunk = joint.connectedBody.GetOrAddComponent<ChunkNode>();
                JointToChunk[joint] = chunk;
                ChunkToJoint[chunk] = joint;
            }

            foreach (var chunkNode in ChunkToJoint.Keys)
            {
                Neighbours.Add(chunkNode);

                if (chunkNode.Contains(this) == false)
                {
                    chunkNode.Neighbours.Add(this);
                }
            }

            NeighboursArray = Neighbours.ToArray();
        }

        private void OnJointBreak(float breakForce)
        {
            HasBrokenLinks = true;
        }

        public void CleanBrokenLinks()
        {
            var brokenLinks = JointToChunk.Keys.Where(j => j == false).ToList();
            foreach (var link in brokenLinks)
            {
                var body = JointToChunk[link];

                JointToChunk.Remove(link);
                ChunkToJoint.Remove(body);

                body.Remove(this);
                Neighbours.Remove(body);
            }

            NeighboursArray = Neighbours.ToArray();
            HasBrokenLinks = false;
        }

        private void Remove(ChunkNode chunkNode)
        {
            ChunkToJoint.Remove(chunkNode);
            Neighbours.Remove(chunkNode);
            NeighboursArray = Neighbours.ToArray();
        }

        public void Unfreeze()
        {
            frozen = false;
            rb.constraints = RigidbodyConstraints.None;
            rb.useGravity = true;
            rb.gameObject.layer = LayerMask.NameToLayer("Default");
        }

        private void Freeze()
        {
            frozen = true;
            rb.constraints = RigidbodyConstraints.FreezeAll;
            rb.useGravity = false;
            rb.gameObject.layer = LayerMask.NameToLayer("FrozenChunks");
            frozenPos = rb.transform.position;
            forzenRot = rb.transform.rotation;
        }

        private void OnDrawGizmos()
        {
            Gizmos.color = Color;
            Gizmos.DrawSphere(transform.TransformPoint(transform.GetComponent<Rigidbody>().centerOfMass), 0.1f);

            foreach (var joint in JointToChunk.Keys)
            {
                if (joint)
                {
                    if (rb)
                    {
                        var from = transform.TransformPoint(rb.centerOfMass);

                        if (joint.connectedBody)
                        {
                            var to = joint.connectedBody.transform.TransformPoint(joint.connectedBody.centerOfMass);
                            Gizmos.DrawLine(from, to);
                        }
                    }

                }
            }
        }

        private void OnDrawGizmosSelected()
        {
            foreach (var node in Neighbours)
            {
                var mesh = node.GetComponent<MeshFilter>().mesh;
                Gizmos.color = Color.yellow.SetAlpha(.2f);
                Gizmos.DrawMesh(mesh, node.transform.position, node.transform.rotation);
            }
        }
    }
}