Files
Zombie/Assets/Plugins/ThirdParty/RayFire/Scripts/Components/RayfireRigid.cs

1198 lines
43 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
namespace RayFire
{
[SelectionBase]
[DisallowMultipleComponent]
[AddComponentMenu ("RayFire/Rayfire Rigid")]
[HelpURL ("https://rayfirestudios.com/unity-online-help/components/unity-rigid-component/")]
public class RayfireRigid : MonoBehaviour
{
public enum InitType
{
ByMethod = 0,
AtStart = 1
}
public InitType initialization = InitType.ByMethod;
public SimType simulationType = SimType.Dynamic;
public ObjectType objectType = ObjectType.Mesh;
public DemolitionType demolitionType = DemolitionType.None;
public RFPhysic physics = new RFPhysic();
public RFActivation activation = new RFActivation();
public RFLimitations limitations = new RFLimitations();
public RFDemolitionMesh meshDemolition = new RFDemolitionMesh();
public RFDemolitionCluster clusterDemolition = new RFDemolitionCluster();
public RFReferenceDemolition referenceDemolition = new RFReferenceDemolition();
public RFSurface materials = new RFSurface();
public RFDamage damage = new RFDamage();
public RFFade fading = new RFFade();
public RFReset reset = new RFReset();
/// /////////////////////////////////////////////////////////
/// Hidden
/// /////////////////////////////////////////////////////////
public bool initialized;
public bool corState;
public Mesh[] meshes;
public Vector3[] pivots;
public RFMesh[] rfMeshes;
public List<RFDictionary> subIds;
public List<RayfireRigid> fragments;
public Quaternion cacheRotation; // NOTE. Should be public, otherwise rotation error on demolition.
public Transform transForm;
public Transform rootChild;
public Transform rootParent;
public MeshFilter meshFilter;
public MeshRenderer meshRenderer;
public SkinnedMeshRenderer skinnedMeshRend;
public List<RayfireDebris> debrisList;
public List<RayfireDust> dustList;
public RayfireRestriction restriction;
public RayfireSound sound;
[NonSerialized] public RayfireRigid meshRoot;
[NonSerialized] public RayfireRigidRoot rigidRoot;
[NonSerialized] public List<Transform> particleList;
/// /////////////////////////////////////////////////////////
/// Events
/// /////////////////////////////////////////////////////////
public RFDemolitionEvent demolitionEvent = new RFDemolitionEvent();
public RFActivationEvent activationEvent = new RFActivationEvent();
public RFRestrictionEvent restrictionEvent = new RFRestrictionEvent();
/// /////////////////////////////////////////////////////////
/// Common
/// /////////////////////////////////////////////////////////
// Awake
void Awake()
{
// Awake Mesh input
MeshInput();
// Initialize at start
if (initialization == InitType.AtStart)
{
Initialize();
}
}
// Initialize
public void Initialize()
{
if (initialized == false)
{
AwakeMethods();
// Init sound
RFSound.InitializationSound(sound, limitations.bboxSize);
}
// TODO add reinit for already initialized objects in case of property change
else
{
}
}
// Awake ops
void AwakeMethods()
{
// Create RayFire manager if not created
RayfireMan.RayFireManInit();
// Set components for mesh / skinned mesh / clusters
SetComponentsBasic();
// Set particles
RFParticles.SetParticleComponents(this);
// Init mesh root.
if (SetupMeshRoot() == true)
return;
// Check for user mistakes
RFLimitations.Checks(this);
// Set components for mesh / skinned mesh / clusters
SetComponentsPhysics();
// Initialization Mesh input
if (meshDemolition.meshInput == RFDemolitionMesh.MeshInputType.AtInitialization)
MeshInput();
// Precache meshes at awake
RFDemolitionMesh.AwakePrecache(this);
// Prefragment object at awake
RFDemolitionMesh.AwakePrefragment(this);
// Skinned mesh FIXME
if (objectType == ObjectType.SkinnedMesh)
{
// Reset rigid data
Default();
// Check for demolition state every frame
if (demolitionType != DemolitionType.None)
StartCoroutine (limitations.DemolishableCor(this));
// Reset rigid data
Default();
// Set physics properties
physics.destructible = physics.Destructible;
if (Application.isPlaying == true)
initialized = true;
}
// Excluded from simulation
if (physics.exclude == true)
return;
// Set Start variables
SetObjectType();
// Runtime ops
if (Application.isPlaying == true)
{
// Start all coroutines
StartAllCoroutines();
// Object initialized
initialized = true;
}
}
/// /////////////////////////////////////////////////////////
/// Enable/Disable
/// /////////////////////////////////////////////////////////
// Disable
void OnDisable()
{
// Set coroutines states
corState = false;
limitations.demolishableCorState = false;
physics.physicsDataCorState = false;
activation.inactiveCorState = false;
activation.velocityCorState = false;
activation.offsetCorState = false;
fading.offsetCorState = false;
}
// Activation
void OnEnable()
{
// Start cors // TODO add support for fragment caching and the rest cors:skinned
if (gameObject.activeSelf == true && initialized == true && corState == false)
{
StartAllCoroutines();
}
}
/// /////////////////////////////////////////////////////////
/// Setup
/// /////////////////////////////////////////////////////////
// Editor Setup
public void EditorSetup()
{
// Setup mesh root
if (objectType == ObjectType.MeshRoot)
EditorSetupMeshRoot();
// Setup clusters
if (objectType == ObjectType.ConnectedCluster || objectType == ObjectType.NestedCluster)
RFDemolitionCluster.ClusterizeEditor (this);
}
// Editor Reset
public void ResetSetup()
{
// Reset setup for mesh root
if (objectType == ObjectType.MeshRoot)
ResetMeshRootSetup();
// Reset Setup for clusters
if (objectType == ObjectType.ConnectedCluster || objectType == ObjectType.NestedCluster)
RFDemolitionCluster.ResetClusterize (this);
}
/// /////////////////////////////////////////////////////////
/// Awake ops
/// /////////////////////////////////////////////////////////
// Define basic components
public void SetComponentsBasic()
{
// Set shatter component
meshDemolition.scrShatter = meshDemolition.useShatter == true
? GetComponent<RayfireShatter>()
: null;
// Tm
transForm = GetComponent<Transform>();
// Mesh components
if (objectType == ObjectType.Mesh)
{
meshFilter = GetComponent<MeshFilter>();
meshRenderer = GetComponent<MeshRenderer>();
}
// Skinned mesh
if (objectType == ObjectType.SkinnedMesh)
skinnedMeshRend = GetComponent<SkinnedMeshRenderer>();
restriction = GetComponent<RayfireRestriction>();
// Add missing mesh renderer
if (meshFilter != null && meshRenderer == null)
meshRenderer = gameObject.AddComponent<MeshRenderer>();
// Init reset lists
if (reset.action == RFReset.PostDemolitionType.DeactivateToReset)
limitations.descendants = new List<RayfireRigid>();
}
// Define components
void SetComponentsPhysics()
{
// Excluded from simulation
if (physics.exclude == true)
return;
// Physics components
physics.rigidBody = GetComponent<Rigidbody>();
physics.meshCollider = GetComponent<Collider>();
// Mesh Set collider
if (objectType == ObjectType.Mesh)
RFPhysic.SetRigidCollider (this);
// Cluster check
if (objectType == ObjectType.NestedCluster || objectType == ObjectType.ConnectedCluster)
RFDemolitionCluster.Clusterize (this);
// Rigid body
if (Application.isPlaying == true)
if (simulationType != SimType.Static)
if (physics.rigidBody == null)
physics.rigidBody = gameObject.AddComponent<Rigidbody>();
}
/// /////////////////////////////////////////////////////////
/// MeshRoot
/// /////////////////////////////////////////////////////////
// Setup mesh root editor ops
void EditorSetupMeshRoot()
{
// Check if manager should be destroyed after setup
bool destroyMan = RayfireMan.inst == null;
// Create RayFire manager if not created
RayfireMan.RayFireManInit();
// Reset
ResetMeshRootSetup();
// Setup
SetupMeshRoot();
// Destroy manager
if (destroyMan == true)
DestroyImmediate (RayfireMan.inst.transform.gameObject);
}
// Init mesh root. Copy Rigid component for children with mesh
bool SetupMeshRoot()
{
if (objectType == ObjectType.MeshRoot)
{
// Get transform for Editor setup
if (transForm == null)
transForm = GetComponent<Transform>();
// Stop if already initiated
if (limitations.demolished == true || physics.exclude == true)
return true;
// Save tm
physics.SaveInitTransform (transForm);
// MeshRoot Integrity check
if (Application.isPlaying == true)
MeshRootCheck();
// Add Rigid to mesh Root children
if (HasFragments == false)
AddMeshRootRigid();
// Init in runtime. DO not if editor setup
if (Application.isPlaying == true)
for (int i = 0; i < fragments.Count; i++)
fragments[i].Initialize();
// Editor only ops
if (Application.isPlaying == false)
{
for (int i = 0; i < fragments.Count; i++)
{
// Set basic fragments components for collider apply
fragments[i].SetComponentsBasic();
// Set bound and size for connection size by bounding box
RFLimitations.SetBound (fragments[i]);
}
// Add colliders to speedup. Editor only. Frags get collider at runtime in Initialize()
RFPhysic.SetupMeshRootColliders (this);
}
// Ignore neib collisions
RFPhysic.SetIgnoreColliders (physics, fragments);
// Runtime only ops
if (Application.isPlaying == true)
{
// Copy components.
RayfireShatter.CopyRootMeshShatter (this, fragments);
RFParticles.CopyRootMeshParticles (this, fragments);
RFSound.CopySound (sound, fragments);
}
// Set unyielding
RayfireUnyielding.MeshRootSetup (this);
// Initialize connectivity
InitConnectivity();
// Turn off demolition and physics
if (Application.isPlaying == true)
{
demolitionType = DemolitionType.None;
physics.exclude = true;
initialized = true;
}
return true;
}
return false;
}
// MeshRoot Integrity check
void MeshRootCheck()
{
if (HasFragments == true)
for (int f = 0; f < fragments.Count; f++)
if (fragments[f] == null)
{
Debug.Log ("RayFire Rigid: " + name + " has missing fragments. Reset Setup and used Editor Setup again", gameObject);
fragments = new List<RayfireRigid>();
return;
}
}
// Add Rigid to mesh Root children
void AddMeshRootRigid()
{
// Get children
List<Transform> children = new List<Transform>();
for (int i = 0; i < transForm.childCount; i++)
children.Add (transForm.GetChild (i));
// Add Rigid to child with mesh
fragments = new List<RayfireRigid>();
for (int i = 0; i < children.Count; i++)
{
MeshFilter mf = children[i].GetComponent<MeshFilter>();
if (mf != null)
{
// Get rigid
RayfireRigid childRigid = children[i].gameObject.GetComponent<RayfireRigid>();
// Mark Rigid as custom Rigid component to keep it at Mesh Root Reset
if (childRigid != null)
childRigid.rootParent = transForm;
// Add new and copy props from parent
if (childRigid == null)
{
childRigid = children[i].gameObject.AddComponent<RayfireRigid>();
CopyPropertiesTo (childRigid);
}
// Set meshfilter
childRigid.meshFilter = mf;
// Collect
fragments.Add (childRigid);
// Set parent meshRoot. IMPORTANT needed in case of custom Rigid
childRigid.meshRoot = this;
}
}
}
// Init connectivity if has
void InitConnectivity()
{
activation.connect = GetComponent<RayfireConnectivity>();
if (activation.connect != null && activation.connect.rigidRootHost == null)
{
activation.connect.meshRootHost = this;
activation.connect.Initialize();;
}
}
// Reset MeshRoot Setup
void ResetMeshRootSetup()
{
// Reset Connectivity
if (activation.connect != null)
activation.connect.ResetSetup();
activation.connect = null;
// Destroy new Rigid and clear custom Rigid components
if (HasFragments == true)
{
// Destroy colliders added by setup
HashSet<Collider> collidersHash = new HashSet<Collider>(physics.clusterColliders);
for (int i = 0; i < fragments.Count; i++)
if (fragments[i].physics.meshCollider != null)
if (collidersHash.Contains (fragments[i].physics.meshCollider) == false)
DestroyImmediate (fragments[i].physics.meshCollider);
physics.clusterColliders = null;
// Destroy Rigids added by setup
for (int i = 0; i < fragments.Count; i++)
if (fragments[i].rootParent == null)
DestroyImmediate (fragments[i]);
else
{
fragments[i].rootParent = null;
fragments[i].meshFilter = null;
fragments[i].meshRenderer = null;
fragments[i].physics.meshCollider = null;
fragments[i].meshRoot = null;
}
}
// Reset common
physics.ignoreList = null;
fragments = null;
}
/// /////////////////////////////////////////////////////////
/// Start ops
/// /////////////////////////////////////////////////////////
// Set Start variables
void SetObjectType ()
{
if (objectType == ObjectType.Mesh ||
objectType == ObjectType.NestedCluster ||
objectType == ObjectType.ConnectedCluster)
// Reset rigid data
Default();
// Set physics properties
SetPhysics();
}
// Reset rigid data
public void Default()
{
// Reset
limitations.Reset();
meshDemolition.Reset();
if (clusterDemolition != null)
clusterDemolition.Reset();
limitations.birthTime = Time.time + Random.Range (0f, 0.05f);
// Birth position for activation check
physics.SaveInitTransform (transForm);
// Set bound and size
RFLimitations.SetBound(this);
// Backup original layer
RFActivation.BackupActivationLayer (this);
// meshDemolition.properties.layerBack = gameObject.layer;
// gameObject.tag;
}
// Set physics properties
void SetPhysics()
{
// Excluded from sim
if (physics.exclude == true)
return;
// MeshCollider physic material preset. Set new or take from parent
RFPhysic.SetColliderMaterial (this);
// Set debris collider material
RFPhysic.SetParticleColliderMaterial (debrisList);
// Ops with rigidbody applied
if (physics.rigidBody != null)
{
// Set physical simulation type. Important. Should after collider material define
if (Application.isPlaying == true)
RFPhysic.SetSimulationType (physics.rigidBody, simulationType, objectType, physics.useGravity, physics.solverIterations);
// Do not set convex, mass, drag for static
if (simulationType == SimType.Static)
return;
// Convex collider meshCollider. After SetSimulation Type to turn off convex for kinematic
RFPhysic.SetColliderConvex (this);
// Set density. After collider defined
RFPhysic.SetDensity (this);
// Set drag properties
RFPhysic.SetDrag (this);
}
// Set material solidity and destructible
physics.solidity = physics.Solidity;
physics.destructible = physics.Destructible;
}
/// /////////////////////////////////////////////////////////
/// Coroutines
/// /////////////////////////////////////////////////////////
// Start all coroutines
public void StartAllCoroutines()
{
// Stop if static
if (simulationType == SimType.Static)
return;
// Inactive
if (gameObject.activeSelf == false)
return;
// Prevent physics cors
if (physics.exclude == true)
return;
// Check for demolition state every frame
if (demolitionType != DemolitionType.None)
StartCoroutine (limitations.DemolishableCor(this));
// Offset fade
if (fading.byOffset > 0)
{
fading.offsetEnum = RFFade.FadeOffsetCor (this);
StartCoroutine (fading.offsetEnum);
}
// Start inactive coroutines
InactiveCors();
// Cache physics data for fragments
physics.physicsEnum = physics.PhysicsDataCor (this);
StartCoroutine (physics.physicsEnum);
// Init restriction check
RayfireRestriction.InitRestriction (this);
// All coroutines are running
corState = true;
}
// Start inactive coroutines
public void InactiveCors()
{
// Activation by velocity\offset coroutines
if (simulationType == SimType.Inactive || simulationType == SimType.Kinematic)
{
if (activation.byVelocity > 0)
{
activation.velocityEnum = activation.ActivationVelocityCor (this);
StartCoroutine (activation.velocityEnum);
}
if (activation.byOffset > 0)
{
activation.offsetEnum = activation.ActivationOffsetCor (this);
StartCoroutine (activation.offsetEnum);
}
}
// Init inactive every frame update coroutine
if (simulationType == SimType.Inactive)
//RayfireMan.inst.AddInactive (this);
StartCoroutine (activation.InactiveCor(this));
}
/// /////////////////////////////////////////////////////////
/// Demolition types
/// /////////////////////////////////////////////////////////
// Awake Mesh input // TODO add checks in case has input mesh but mesh input is off
public void MeshInput()
{
if (objectType == ObjectType.Mesh &&
demolitionType == DemolitionType.Runtime &&
meshDemolition.meshInput == RFDemolitionMesh.MeshInputType.AtStart)
{
// Set components for mesh / skinned mesh / clusters
SetComponentsBasic();
// Input
RFFragment.InputMesh (this);
}
}
/// /////////////////////////////////////////////////////////
/// Collision
/// /////////////////////////////////////////////////////////
// Collision check
protected virtual void OnCollisionEnter (Collision collision)
{
// Check if collision data needed
if (CollisionCheck() == false)
return;
// Tag check. IMPORTANT keep length check for compatibility with older builds
if (limitations.tag.Length > 0 && limitations.tag != "Untagged" && collision.collider.CompareTag (limitations.tag) == false)
return;
// Demolish object check
if (DemolitionState() == false)
return;
// Check if collision demolition passed
if (CollisionDemolition (collision) == true)
limitations.demolitionShould = true;
}
// Check if collision demolition passed
protected virtual bool CollisionDemolition (Collision collision)
{
// Final object solidity
float finalSolidity = physics.solidity * limitations.solidity * RayfireMan.inst.globalSolidity;
// Collision with kinematic object. Uses collision.impulse
if (collision.rigidbody != null && collision.rigidbody.isKinematic == true)
{
if (collision.impulse.magnitude > finalSolidity * 7f) // TODO fix
{
limitations.contactPoint = collision.GetContact(0);
limitations.contactVector3 = limitations.contactPoint.point;
limitations.contactNormal = limitations.contactPoint.normal;
return true;
}
}
// Collision force checks. Uses relativeVelocity
float collisionMagnitude = collision.relativeVelocity.magnitude;
for (int i = 0; i < collision.contactCount; i++)
{
// Set contact point
limitations.contactPoint = collision.GetContact(i);
limitations.contactVector3 = limitations.contactPoint.point;
limitations.contactNormal = limitations.contactPoint.normal;
// Demolish if collision high enough
if (collisionMagnitude > finalSolidity)
return true;
// Collect damage by collision
if (damage.enable == true && damage.collect == true)
if (ApplyDamage (collisionMagnitude * damage.multiplier, limitations.contactVector3, 0f, collision.contacts[i].thisCollider) == true)
return true;
}
return false;
}
// Check if collision data needed
bool CollisionCheck()
{
if (limitations.byCollision == true)
return true;
if (damage.enable == true && damage.collect == true)
return true;
return false;
}
/// /////////////////////////////////////////////////////////
/// Demolition
/// /////////////////////////////////////////////////////////
// Demolition available state
public bool State ()
{
// Object already demolished
if (limitations.demolished == true)
return false;
// Object already passed demolition state and demolishing is in progress
if (meshDemolition.runtimeCaching.inProgress == true)
return false;
// Bad mesh check
if (meshDemolition.badMesh > RayfireMan.inst.advancedDemolitionProperties.badMeshTry)
return false;
// Max amount check
if (RayfireMan.MaxAmountCheck == false)
return false;
// Depth level check
if (limitations.depth > 0 && limitations.currentDepth >= limitations.depth)
return false;
// Min Size check. Min Size should be considered and size is less than
if (limitations.bboxSize < limitations.size)
return false;
// Safe frame
if (Time.time - limitations.birthTime < limitations.time)
return false;
// Static objects can not be demolished
if (simulationType == SimType.Static)
return false;
// Fading
if (fading.state == 2)
return false;
return true;
}
// Check if object should be demolished
public virtual bool DemolitionState ()
{
// No demolition allowed
if (demolitionType == DemolitionType.None)
return false;
// Non destructible material
if (physics.destructible == false)
return false;
// Visibility check
if (limitations.visible == true)
{
if (meshRenderer != null && meshRenderer.isVisible == false)
return false;
if (skinnedMeshRend != null && skinnedMeshRend.isVisible == false)
return false;
}
// Demolition available check
if (State() == false)
return false;
// Per frame time check
if (RayfireMan.inst.timeQuota > 0 && RayfireMan.inst.maxTimeThisFrame > RayfireMan.inst.timeQuota)
return false;
return true;
}
// Demolish object
public void Demolish()
{
// Profiler.BeginSample ("Demolition");
// Debug.Log (limitations.demolitionShould);
// Initialize if not
if (initialized == false)
Initialize();
// Timestamp
float t1 = Time.realtimeSinceStartup;
// Demolish mesh or cluster to reference
if (RFReferenceDemolition.DemolishReference(this) == false)
return;
// Demolish mesh and create fragments. Stop if runtime caching or no meshes/fragments were created
if (RFDemolitionMesh.DemolishMesh (this) == true)
{
// Check for inactive/kinematic fragments with unyielding
RayfireUnyielding.SetUnyieldingFragments (this);
// Set children with mesh as additional fragments
RFDemolitionMesh.ChildrenToFragments(this);
// Clusterize runtime fragments
RFDemolitionMesh.ClusterizeFragments (this);
}
else
return;
// Demolish cluster to children nodes
if (RFDemolitionCluster.DemolishCluster (this) == true)
return;
// Check fragments and proceed TODO separate flow for connected cls demolition
if (limitations.demolished == false)
{
limitations.demolitionShould = false;
demolitionType = DemolitionType.None;
return;
}
// Connectivity check
activation.CheckConnectivity();
// Fragments initialisation
InitMeshFragments();
// Sum total demolition time
RayfireMan.inst.maxTimeThisFrame += Time.realtimeSinceStartup - t1;
// Init particles
RFParticles.InitDemolitionParticles(this);
// Init sound
RFSound.DemolitionSound(sound, limitations.bboxSize);
// Event
demolitionEvent.InvokeLocalEvent (this);
RFDemolitionEvent.InvokeGlobalEvent (this);
// Destroy demolished object
RayfireMan.DestroyFragment (this, rootParent);
// Debug.Log (fragments[0].fragments.Count);
// Debug.Log (fragments[0].fragments[0], fragments[0].fragments[0].gameObject);
// Timestamp
// float t2 = Time.realtimeSinceStartup;
// Debug.Log (t2 - t1);
// Profiler.EndSample();
}
/// /////////////////////////////////////////////////////////
/// Fragments
/// /////////////////////////////////////////////////////////
// Copy rigid properties from parent to fragments
public void CopyPropertiesTo (RayfireRigid toScr)
{
// Set local meshRoot
if (objectType == ObjectType.MeshRoot)
toScr.meshRoot = this;
else if (meshRoot != null)
toScr.meshRoot = meshRoot;
// Object type
toScr.objectType = objectType;
if (objectType == ObjectType.MeshRoot || objectType == ObjectType.SkinnedMesh)
toScr.objectType = ObjectType.Mesh;
// Sim type
toScr.simulationType = simulationType;
if (objectType != ObjectType.MeshRoot)
if (simulationType == SimType.Kinematic || simulationType == SimType.Static || simulationType == SimType.Sleeping)
toScr.simulationType = SimType.Dynamic;
// Demolition type
toScr.demolitionType = demolitionType;
if (objectType != ObjectType.MeshRoot)
if (demolitionType != DemolitionType.None)
toScr.demolitionType = DemolitionType.Runtime;
if (demolitionType == DemolitionType.ReferenceDemolition)
toScr.demolitionType = DemolitionType.None;
// Copy physics
toScr.physics.CopyFrom (physics);
toScr.activation.CopyFrom (activation);
toScr.limitations.CopyFrom (limitations);
toScr.meshDemolition.CopyFrom (meshDemolition);
toScr.clusterDemolition.CopyFrom (clusterDemolition);
// Copy reference demolition props
if (objectType == ObjectType.MeshRoot)
toScr.referenceDemolition.CopyFrom (referenceDemolition);
toScr.materials.CopyFrom (materials);
toScr.damage.CopyFrom (damage);
toScr.fading.CopyFrom (fading);
toScr.reset.CopyFrom (reset, objectType);
// Copy restriction
if (restriction != null)
{
toScr.restriction = toScr.gameObject.AddComponent<RayfireRestriction>();
toScr.restriction.CopyFrom (restriction);
}
}
// Fragments initialisation
public void InitMeshFragments()
{
// No fragments
if (HasFragments == false)
return;
// Set velocity
RFPhysic.SetFragmentsVelocity (this);
// Sum total new fragments amount
RayfireMan.inst.advancedDemolitionProperties.ChangeCurrentAmount (fragments.Count);
// Set ancestor and descendants
RFLimitations.SetAncestor (this);
RFLimitations.SetDescendants (this);
// Fading. move to fragment
if (fading.onDemolition == true)
fading.DemolitionFade (fragments);
}
/// /////////////////////////////////////////////////////////
/// Manual methods
/// /////////////////////////////////////////////////////////
// Predefine fragments
public void Prefragment()
{
// Delete existing
DeleteFragments();
// Create fragments from cache
fragments = RFDemolitionMesh.CreateFragments(this);
// Stop
if (HasFragments == false)
{
demolitionType = DemolitionType.None;
return;
}
// Set physics properties
for (int i = 0; i < fragments.Count; i++)
{
fragments[i].SetComponentsBasic();
//fragments[i].SetParticleComponents();
fragments[i].SetComponentsPhysics();
fragments[i].SetObjectType();
// Increment demolition depth. Disable if last
fragments[i].limitations.currentDepth = 1;
if (limitations.depth == 1)
fragments[i].demolitionType = DemolitionType.None;
}
// Deactivate fragments root
if (rootChild != null)
rootChild.gameObject.SetActive (false);
}
// Clear cache info
public void DeleteCache()
{
meshes = null;
pivots = null;
rfMeshes = null;
subIds = new List<RFDictionary>();
}
// Delete fragments
public void DeleteFragments()
{
// Destroy root
if (rootChild != null)
{
if (Application.isPlaying == true)
Destroy (rootChild.gameObject);
else
DestroyImmediate (rootChild.gameObject);
// Clear ref
rootChild = null;
}
// Clear array
fragments = null;
}
/// /////////////////////////////////////////////////////////
/// Blade
/// /////////////////////////////////////////////////////////
// Add new slice plane
public void AddSlicePlane (Vector3[] slicePlane)
{
// Not even amount of slice data
if (slicePlane.Length % 2 == 1)
return;
// Add slice plane data
limitations.slicePlanes.AddRange (slicePlane);
}
// Slice object
public void Slice()
{
// Check for slices
if (HasSlices == false)
{
Debug.Log ("RayFire Rigid: " + name + " has no defined slicing planes.", gameObject);
return;
}
// Slice
if (objectType == ObjectType.Mesh || objectType == ObjectType.SkinnedMesh)
{
RFDemolitionMesh.SliceMesh (this);
// Set children with mesh as additional fragments
RFDemolitionMesh.ChildrenToFragments(this);
}
else if (objectType == ObjectType.ConnectedCluster)
RFDemolitionCluster.SliceConnectedCluster (this);
// Particles
RFParticles.InitDemolitionParticles(this);
// Sound
RFSound.DemolitionSound(sound, limitations.bboxSize);
// Event
demolitionEvent.InvokeLocalEvent (this);
RFDemolitionEvent.InvokeGlobalEvent (this);
// Destroy original
if (objectType == ObjectType.Mesh || objectType == ObjectType.SkinnedMesh)
RayfireMan.DestroyFragment (this, rootParent);
}
/// /////////////////////////////////////////////////////////
/// Caching
/// /////////////////////////////////////////////////////////
// Caching into meshes over several frames
public void CacheFrames()
{
StartCoroutine (meshDemolition.RuntimeCachingCor(this));
}
/// /////////////////////////////////////////////////////////
/// Public methods
/// /////////////////////////////////////////////////////////
// Save init transform. Birth tm for activation check and reset
[ContextMenu("SaveInitTransform")]
public void SaveInitTransform ()
{
// Rigid save tm
if (objectType == ObjectType.Mesh)
physics.SaveInitTransform (transForm);
// Mesh Root save tm
else if (objectType == ObjectType.MeshRoot)
{
if (HasFragments == true)
{
// Save for Rigids
for (int i = 0; i < fragments.Count; i++)
if (fragments[i] != null)
fragments[i].physics.SaveInitTransform (fragments[i].transForm);
// Save is connectivity backup cluster
if (activation.connect != null && reset.connectivity == true )
if (activation.connect.backup != null)
RFBackupCluster.SaveTmRecursive (activation.connect.backup.cluster);
}
}
}
// Apply damage
public bool ApplyDamage (float damageValue, Vector3 damagePoint, float damageRadius = 0f, Collider coll = null)
{
return RFDamage.ApplyDamage (this, damageValue, damagePoint, damageRadius, coll);
}
// Activate inactive object
public void Activate(bool connCheck = true)
{
if (objectType != ObjectType.MeshRoot)
RFActivation.ActivateRigid (this, connCheck);
else
for (int i = 0; i < fragments.Count; i++)
RFActivation.ActivateRigid (fragments[i], connCheck);
}
// Fade this object
public void Fade()
{
if (objectType != ObjectType.MeshRoot)
RFFade.FadeRigid (this);
else
for (int i = 0; i < fragments.Count; i++)
RFFade.FadeRigid (fragments[i]);
}
// Reset object
public void ResetRigid()
{
RFReset.ResetRigid (this);
}
/// /////////////////////////////////////////////////////////
/// Other
/// /////////////////////////////////////////////////////////
// Destroy
public void DestroyCollider(Collider col) { Destroy (col); }
public void DestroyObject(GameObject go) { Destroy (go); }
public void DestroyRigid(RayfireRigid rigid) { Destroy (rigid); }
public void DestroyRb(Rigidbody rb) { Destroy (rb); }
/// /////////////////////////////////////////////////////////
/// Getters
/// /////////////////////////////////////////////////////////
// Fragments/Meshes check
public bool HasFragments { get { return fragments != null && fragments.Count > 0; } }
public bool HasMeshes { get { return meshes != null && meshes.Length > 0; } }
public bool HasRfMeshes { get { return rfMeshes != null && rfMeshes.Length > 0; } }
public bool HasDebris { get { return debrisList != null && debrisList.Count > 0; } }
public bool HasDust { get { return dustList != null && dustList.Count > 0; } }
public bool HasSlices { get { return limitations.slicePlanes != null && limitations.slicePlanes.Count > 0; } }
public bool IsCluster { get { return objectType == ObjectType.ConnectedCluster || objectType == ObjectType.NestedCluster; } }
// CLuster Integrity
public float AmountIntegrity
{
get
{
if (objectType == ObjectType.ConnectedCluster)
return (float)clusterDemolition.cluster.shards.Count / (float)clusterDemolition.am * 100f;
return 0f;
}
}
}
}