using System; using System.Collections.Generic; using UnityEngine; namespace RayFire { [DisallowMultipleComponent] [AddComponentMenu ("RayFire/Rayfire Man")] [HelpURL ("https://rayfirestudios.com/unity-online-help/components/unity-man-component/")] public class RayfireMan : MonoBehaviour { // UI public bool setGravity; public float multiplier = 1f; public RigidbodyInterpolation interpolation = RigidbodyInterpolation.None; public CollisionDetectionMode meshCollision = CollisionDetectionMode.ContinuousDynamic; public CollisionDetectionMode clusterCollision = CollisionDetectionMode.Discrete; public float minimumMass = 0.1f; public float maximumMass = 400f; public RFMaterialPresets materialPresets = new RFMaterialPresets(); public GameObject parent; public float globalSolidity = 1f; public float timeQuota = 0.033f; public RFManDemolition advancedDemolitionProperties = new RFManDemolition(); public RFPoolingFragment fragments = new RFPoolingFragment(); public RFPoolingParticles particles = new RFPoolingParticles(); public RFStorage storage; public float colliderSize = 0.05f; public int coplanarVerts = 30; public MeshColliderCookingOptions cookingOptions = (MeshColliderCookingOptions)30; public bool debug = true; // Non Serialized [NonSerialized] public Transform transForm; [NonSerialized] public float maxTimeThisFrame; // Static public static RayfireMan inst; public static int buildMajor = 1; public static int buildMinor = 60; public static float colliderSizeStatic = 0.05f; public static int coplanarVertLimit = 30; public static MeshColliderCookingOptions cookingOptionsStatic = (MeshColliderCookingOptions)30; public static bool debugStatic = true; /// ///////////////////////////////////////////////////////// /// Common /// ///////////////////////////////////////////////////////// // Awake void Awake() { // Set static instance SetInstance(); //System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(method.MethodHandle); } // Late Update void LateUpdate() { maxTimeThisFrame = 0f; } /// ///////////////////////////////////////////////////////// /// Instance /// ///////////////////////////////////////////////////////// // Set instance void SetInstance() { // Inst not define, set to this if (inst == null) { inst = this; } // Inst defined if (inst != null) { // Instance is this mono - > Init if (inst == this) { // Set vars SetVariables(); // Runtime ops if (Application.isPlaying == true) { // Start pooling objects for fragments SetPooling(); // Create storage and stat root check coroutine SetStorage(); } } // Inst is not this mono. Destroy. if (inst != this) { if (Application.isPlaying == true) Destroy (gameObject); else if (Application.isEditor == true) DestroyImmediate (gameObject); } } } /// ///////////////////////////////////////////////////////// /// Enable/Disable /// ///////////////////////////////////////////////////////// // Disable void OnDisable() { fragments.inProgress = false; particles.inProgress = false; if (storage != null) storage.inProgress = false; } // Activation void OnEnable() { if (Application.isPlaying == true && gameObject.activeSelf == true) { // Continue pooling SetPooling(); // Continue storage check SetStorage(); } } /// ///////////////////////////////////////////////////////// /// Methods /// ///////////////////////////////////////////////////////// // Set vars void SetVariables() { // Get components transForm = GetComponent(); // Reset amount advancedDemolitionProperties.ResetCurrentAmount(); // Set gravity SetGravity(); // Set Physic Materials if needed materialPresets.SetMaterials(); colliderSizeStatic = colliderSize; cookingOptionsStatic = cookingOptions; debugStatic = debug; coplanarVertLimit = coplanarVerts; } // Set gravity void SetGravity() { if (setGravity == true) Physics.gravity = -9.81f * multiplier * Vector3.up; } /// ///////////////////////////////////////////////////////// /// Other /// ///////////////////////////////////////////////////////// // Create RayFire manager if not created public static void RayFireManInit() { if (inst == null) { GameObject rfMan = new GameObject ("RayFireMan"); inst = rfMan.AddComponent(); } if (Application.isPlaying == false) { inst.SetInstance(); } } // Max fragments amount check public static bool MaxAmountCheck { get { if (inst.advancedDemolitionProperties.currentAmount < inst.advancedDemolitionProperties.maximumAmount) return true; inst.advancedDemolitionProperties.AmountWarning(); return false; } } /// ///////////////////////////////////////////////////////// /// Pooling /// ///////////////////////////////////////////////////////// // Enable objects pooling for fragments void SetPooling() { // Create pool root fragments.CreatePoolRoot (transform); // Create pool instance fragments.CreateInstance (transform); // Pooling. Mot in editor if (Application.isPlaying == true && fragments.enable == true && fragments.inProgress == false) StartCoroutine (fragments.StartPoolingCor (transForm)); // Create pool root particles.CreatePoolRoot (transform); // Create pool instance particles.CreateInstance (); // Pooling. Mot in editor if (Application.isPlaying == true && particles.enable == true && particles.inProgress == false) StartCoroutine (particles.StartPoolingCor ()); } /// ///////////////////////////////////////////////////////// /// Storage /// ///////////////////////////////////////////////////////// // Create storage root void SetStorage() { // Create if (storage == null) storage = new RFStorage(); // Create storage if has no storage.CreateStorageRoot (transform); // Start empty root removing coroutine if not running if (Application.isPlaying == true && storage.inProgress == false) StartCoroutine (storage.StorageCor ()); } // Destroy all storage objects public void DestroyStorage() { storage.DestroyAll(); } /// ///////////////////////////////////////////////////////// /// Parent /// ///////////////////////////////////////////////////////// // Set root to manager or to the same parent public static void SetParentByManager (Transform tm, Transform original, bool noRegister = false) { // Storage if (inst != null && inst.advancedDemolitionProperties.parent == RFManDemolition.FragmentParentType.Manager) tm.parent = inst.storage.storageRoot; // Global parent else if (inst != null && inst.advancedDemolitionProperties.parent == RFManDemolition.FragmentParentType.GlobalParent && inst.advancedDemolitionProperties.globalParent != null) tm.parent = inst.advancedDemolitionProperties.globalParent; // Storage if no local parent else if (original == null || original.parent == null) tm.parent = inst.storage.storageRoot; // Local parent else tm.parent = original.parent; // Register in storage if (noRegister == false) inst.storage.Register (tm); } // Set root to manager or to the same parent public static void SetParentByManager (Transform tm) { if (inst != null && inst.advancedDemolitionProperties.parent == RFManDemolition.FragmentParentType.Manager) tm.parent = inst.storage.storageRoot; // Global parent else if (inst != null && inst.advancedDemolitionProperties.parent == RFManDemolition.FragmentParentType.GlobalParent && inst.advancedDemolitionProperties.globalParent != null) tm.parent = inst.advancedDemolitionProperties.globalParent; // Register in storage inst.storage.Register (tm); } // Get parent for connected cluster detached shards public static Transform GetParentByManager(RayfireRigid scr) { // Manager parent if (inst != null && inst.advancedDemolitionProperties.parent == RFManDemolition.FragmentParentType.Manager) return inst.storage.storageRoot; // Parent of main cluster if (scr.clusterDemolition.cluster.mainCluster != null && scr.clusterDemolition.cluster.mainCluster.tm != null) return scr.clusterDemolition.cluster.mainCluster.tm.parent; // Parent of Rigid return scr.transform.parent; } /// ///////////////////////////////////////////////////////// /// Destroy/Deactivate Fragment/Shard /// ///////////////////////////////////////////////////////// // Check if fragment is the last child in root and delete root as well public static void DestroyFragment (RayfireRigid scr, Transform tm, float time = 0f) { // Decrement total amount. if (Application.isPlaying == true) inst.advancedDemolitionProperties.currentAmount--; // Deactivate scr.gameObject.SetActive (false); // Destroy if (scr.reset.action == RFReset.PostDemolitionType.DestroyWithDelay) DestroyOp (scr, tm, time); } // Destroy rigidroot shard public static void DestroyShard (RayfireRigidRoot scr, RFShard shard) { // Deactivate shard.tm.gameObject.SetActive (false); // Destroy if (scr.reset.action == RFReset.PostDemolitionType.DestroyWithDelay) DestroyGo (shard.tm.gameObject); } /// ///////////////////////////////////////////////////////// /// Destroy /// ///////////////////////////////////////////////////////// // Check if fragment is the last child in root and delete root as well public static void DestroyGo (GameObject go) { Destroy (go); } // Check if fragment is the last child in root and delete root as well static void DestroyOp (RayfireRigid scr, Transform tm, float time = 0f) { // Set delay if (time == 0) time = scr.reset.destroyDelay; // Object is going to be destroyed. Timer is on scr.reset.toBeDestroyed = true; // Destroy object inst.fragments.DestroyOrReset (scr, time); // Destroy root if (tm != null && tm.childCount == 0) { // TODO collect root in special roots list, check every 10 seconds and destroy if they are empty Destroy (tm.gameObject, time); } } } }