ThrowBall/Assets/Plugins/RayFire/Scripts/Components/RayfireRigid.cs

1164 lines
42 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
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
}
// UI
public InitType initialization = InitType.ByMethod;
[FormerlySerializedAs ("simulationType")] public SimType simTp = SimType.Dynamic;
[FormerlySerializedAs ("objectType")] public ObjectType objTp = ObjectType.Mesh;
[FormerlySerializedAs ("demolitionType")] public DemolitionType dmlTp = DemolitionType.None;
public RFPhysic physics = new RFPhysic();
public RFActivation activation = new RFActivation();
public RFLimitations limitations = new RFLimitations();
[FormerlySerializedAs ("meshDemolition")] public RFDemolitionMesh mshDemol = new RFDemolitionMesh();
[FormerlySerializedAs ("clusterDemolition")] public RFDemolitionCluster clsDemol = new RFDemolitionCluster();
[FormerlySerializedAs ("referenceDemolition")] public RFReferenceDemolition refDemol = 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 List<RayfireRigid> fragments;
[FormerlySerializedAs ("cacheRotation")] public Quaternion chRot; // NOTE. Should be public, otherwise rotation error on demolition.
[FormerlySerializedAs ("transForm")] public Transform tsf;
[FormerlySerializedAs ("rootChild")] public Transform rtC;
[FormerlySerializedAs ("rootParent")] public Transform rtP;
[FormerlySerializedAs ("meshFilter")] public MeshFilter mFlt;
[FormerlySerializedAs ("meshRenderer")] public MeshRenderer mRnd;
public SkinnedMeshRenderer skr;
public RayfireRestriction rest;
public RayfireSound sound;
// Non Serialized
[NonSerialized] public bool corState;
[NonSerialized] public List<Transform> particleList;
[NonSerialized] public List<RayfireDebris> debrisList;
[NonSerialized] public List<RayfireDust> dustList;
[NonSerialized] public RFDictionary[] subIds;
[NonSerialized] public Vector3[] pivots;
[NonSerialized] public Mesh[] meshes;
[NonSerialized] public RayfireRigid meshRoot;
[NonSerialized] public RayfireRigidRoot rigidRoot;
[NonSerialized] public int debrisState = 1; // 1 - debrisList have to be collected at Initialize
[NonSerialized] public int dustState = 1; // 0 - dustList already set by other object, skip collecting
// 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()
{
// Deactivated
if (gameObject.activeSelf == false)
return;
// Not initialized
if (initialized == false)
{
// Init Awake methods
AwakeMethods();
// Init sound
RFSound.InitializationSound(sound, limitations.bboxSize);
}
// TODO add reinit for already initialized objects in case of property change
}
// Awake ops
void AwakeMethods()
{
// Create RayFire manager if not created
RayfireMan.RayFireManInit();
// Set components for mesh / skinned mesh / clusters
SetComponentsBasic();
// Set particles
RFPoolingParticles.InitializeParticles(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 (mshDemol.inp == RFDemolitionMesh.MeshInputType.AtInitialization)
MeshInput();
// Precache meshes at awake
RFDemolitionMesh.Awake(this);
// Skinned mesh
SetSkinnedMesh();
// 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;
}
}
// Set skinned mesh
void SetSkinnedMesh()
{
// Skinned mesh FIXME
if (objTp == ObjectType.SkinnedMesh)
{
// Reset rigid data
Default();
// Set physics properties
physics.destructible = physics.Destructible;
if (Application.isPlaying == true)
initialized = true;
}
}
/// /////////////////////////////////////////////////////////
/// Enable/Disable
/// /////////////////////////////////////////////////////////
// Disable
void OnDisable()
{
// Set coroutines states
corState = false;
activation.velocityCorState = false;
activation.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()
{
// Deactivated
if (gameObject.activeSelf == false)
return;
// Setup mesh root
if (objTp == ObjectType.MeshRoot)
EditorSetupMeshRoot();
// Setup clusters
if (objTp == ObjectType.ConnectedCluster || objTp == ObjectType.NestedCluster)
RFDemolitionCluster.ClusterizeEditor (this);
}
// Editor Reset
public void ResetSetup()
{
// Deactivated
if (gameObject.activeSelf == false)
return;
// Reset setup for mesh root
if (objTp == ObjectType.MeshRoot)
ResetMeshRootSetup();
// Reset Setup for clusters
if (objTp == ObjectType.ConnectedCluster || objTp == ObjectType.NestedCluster)
RFDemolitionCluster.ResetClusterize (this);
}
/// /////////////////////////////////////////////////////////
/// Awake ops
/// /////////////////////////////////////////////////////////
// Define basic components
public void SetComponentsBasic()
{
// Set shatter component
mshDemol.sht = mshDemol.use == true
? GetComponent<RayfireShatter>()
: null;
// Tm
tsf = GetComponent<Transform>();
// Mesh/Renderer components
if (objTp == ObjectType.Mesh)
{
mFlt = GetComponent<MeshFilter>();
mRnd = GetComponent<MeshRenderer>();
}
else if (objTp == ObjectType.SkinnedMesh)
skr = GetComponent<SkinnedMeshRenderer>();
rest = GetComponent<RayfireRestriction>();
// Add missing mesh renderer
if (mFlt != null && mRnd == null)
mRnd = gameObject.AddComponent<MeshRenderer>();
// Init reset lists
if (reset.action == RFReset.PostDemolitionType.DeactivateToReset)
limitations.desc = new List<RayfireRigid>();
}
// Define components
public void SetComponentsPhysics()
{
// Excluded from simulation
if (physics.exclude == true)
return;
// Physics components
physics.rb = GetComponent<Rigidbody>();
physics.mc = GetComponent<Collider>();
// Mesh Set collider
if (objTp == ObjectType.Mesh)
RFPhysic.SetRigidCollider (this);
// Cluster check
if (objTp == ObjectType.NestedCluster || objTp == ObjectType.ConnectedCluster)
RFDemolitionCluster.Clusterize (this);
// Rigid body
if (Application.isPlaying == true)
if (simTp != SimType.Static)
if (physics.rb == null)
physics.rb = 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 && RayfireMan.inst != null)
DestroyImmediate (RayfireMan.inst.transform.gameObject);
}
// Init mesh root. Copy Rigid component for children with mesh
bool SetupMeshRoot()
{
if (objTp == 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)
RFLimitations.MeshRootCheck(this);
// Add Rigid to mesh Root children
if (HasFragments == false)
AddMeshRootRigid(transform);
// Init in runtime. DO not if editor setup
if (Application.isPlaying == true)
{
for (int i = 0; i < fragments.Count; i++)
{
fragments[i].Initialize();
fragments[i].meshRoot = this;
}
}
// 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);
RFPoolingParticles.CopyParticlesMeshroot (this, fragments);
// Copy sound
sound = GetComponent<RayfireSound>();
RFSound.CopySound (sound, fragments);
}
// Set unyielding
RayfireUnyielding.MeshRootSetup (this);
// Initialize connectivity
InitConnectivity();
// Turn off demolition and physics
if (Application.isPlaying == true)
{
dmlTp = DemolitionType.None;
physics.exclude = true;
initialized = true;
}
return true;
}
return false;
}
// Add Rigid to mesh Root children
void AddMeshRootRigid(Transform tm)
{
// Get children
List<Transform> children = new List<Transform>(tm.childCount);
for (int i = 0; i < tm.childCount; i++)
children.Add (tm.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.rtP = tm;
// Add new and copy props from parent
if (childRigid == null)
{
childRigid = children[i].gameObject.AddComponent<RayfireRigid>();
CopyPropertiesTo (childRigid);
// Copy Runtime caching properties. They are disabled for base copy
childRigid.mshDemol.ch.CopyFrom (mshDemol.ch);
}
// Set meshfilter
childRigid.mFlt = 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.cnt = GetComponent<RayfireConnectivity>();
if (activation.cnt != null && activation.cnt.rigidRootHost == null)
{
activation.cnt.meshRootHost = this;
activation.cnt.Initialize();
}
// Warnings
if (RayfireMan.debugStateStatic == true)
if (activation.con == true && activation.cnt == null)
RayfireMan.Log ("RayFireRigid: " + name + " object has enabled Connectivity activation but has no Connectivity component.", gameObject);
}
// Reset MeshRoot Setup
void ResetMeshRootSetup()
{
// Reset Connectivity
if (activation.cnt != null)
activation.cnt.ResetSetup();
activation.cnt = null;
// ReSet unyielding
RayfireUnyielding.ResetMeshRootSetup (this);
// Destroy new Rigid and clear custom Rigid components
if (HasFragments == true)
{
if (physics.cc != null)
{
// Clean fragments
for (int i = fragments.Count - 1; i >= 0; i--)
if (fragments[i] == null)
fragments.RemoveAt (i);
// Destroy colliders added by setup
HashSet<Collider> collidersHash = new HashSet<Collider> (physics.cc);
for (int i = 0; i < fragments.Count; i++)
if (fragments[i].physics.mc != null)
if (collidersHash.Contains (fragments[i].physics.mc) == false)
DestroyImmediate (fragments[i].physics.mc);
physics.cc = null;
// Destroy Rigids added by setup
for (int i = 0; i < fragments.Count; i++)
if (fragments[i].rtP == null)
DestroyImmediate (fragments[i]);
else
{
fragments[i].rtP = null;
fragments[i].mFlt = null;
fragments[i].mRnd = null;
fragments[i].physics.mc = null;
fragments[i].meshRoot = null;
}
}
}
// Reset common
tsf = null;
physics.ign = null;
fragments = null;
}
/// /////////////////////////////////////////////////////////
/// Start ops
/// /////////////////////////////////////////////////////////
// Set Start variables
public void SetObjectType ()
{
if (objTp == ObjectType.Mesh ||
objTp == ObjectType.NestedCluster ||
objTp == ObjectType.ConnectedCluster)
// Reset rigid data
Default();
// Set physics properties
SetPhysics();
}
// Reset rigid data
public void Default()
{
// Reset
limitations.LocalReset();
mshDemol.LocalReset();
clsDemol.LocalReset();
limitations.birthTime = Time.time + Random.Range (0f, 0.05f);
// Birth position for activation check
physics.SaveInitTransform (tsf);
// 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
// if (HasDebris == true) RFPhysic.SetParticleColliderMaterial (debrisList);
// Ops with rigidbody applied
if (physics.rb != null)
{
// Set physical simulation type. Important. Should after collider material define
if (Application.isPlaying == true)
RFPhysic.SetSimulationType (physics.rb, simTp, objTp, physics.gr, physics.si, physics.st);
// Do not set convex, mass, drag for static
if (simTp == SimType.Static)
return;
// Set drag properties
RFPhysic.SetDrag (this);
// Convex collider meshCollider. After SetSimulation Type to turn off convex for kinematic
RFPhysic.SetColliderConvex (this);
// Set density. After collider defined
RFPhysic.SetDensity (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 (simTp == SimType.Static)
return;
// Inactive
if (gameObject.activeSelf == false)
return;
// Prevent physics cors
if (physics.exclude == true)
return;
// Offset fade
if (fading.byOffset > 0)
RayfireMan.inst.AddToOffsetFadeCor (this);
// Start inactive coroutines
InactiveCors();
// Cache velocity data for fragments
RayfireMan.inst.AddToPhysicCor (this);
// All coroutines are running
corState = true;
}
// Start inactive coroutines
public void InactiveCors()
{
// Activation by velocity\offset coroutines
if (simTp == SimType.Inactive || simTp == SimType.Kinematic)
{
if (activation.vel > 0)
RayfireMan.inst.AddToVelocityActivationCor(this);
if (activation.off > 0)
RayfireMan.inst.AddToOffsetActivationCor (this);
}
}
/// /////////////////////////////////////////////////////////
/// Demolition types
/// /////////////////////////////////////////////////////////
// Awake Mesh input // TODO add checks in case has input mesh but mesh input is off
public void MeshInput()
{
if (objTp == ObjectType.Mesh &&
dmlTp == DemolitionType.Runtime &&
mshDemol.inp == RFDemolitionMesh.MeshInputType.AtStart)
{
// Set components for mesh / skinned mesh / clusters
SetComponentsBasic();
// Input
RFFragment.InputMesh (this);
}
}
/// /////////////////////////////////////////////////////////
/// Collision
/// /////////////////////////////////////////////////////////
// Collision check
protected virtual void OnCollisionEnter (Collision collision)
{
// No demolition allowed
if (dmlTp == DemolitionType.None)
return;
// Check if collision data needed
if (limitations.CollisionCheck(this) == false)
return;
// Demolish object check
if (DemolitionState() == 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;
// Check if collision demolition passed
if (CollisionDemolition (collision) == true)
{
limitations.demolitionShould = true;
RayfireMan.inst.AddToDemolitionCor (this);
}
}
// Check if collision demolition passed
protected virtual bool CollisionDemolition (Collision collision)
{
// Final object solidity
float finalSolidity = physics.solidity * limitations.sol * RayfireMan.inst.globalSolidity;
// Demolition by collision
if (limitations.col == true)
{
// Collision with kinematic object. Uses collision.impulse
if (limitations.KinematicCollisionCheck(collision, finalSolidity) == true)
return true;
// Collision force checks. Uses relativeVelocity
if (limitations.ContactPointsCheck(collision, finalSolidity) == true)
return true;
}
// Demolition by accumulated damage collision
if (damage.en == true && damage.col == true)
if (limitations.DamagePointsCheck(collision, this) == 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 (mshDemol.ch.inProgress == true)
return false;
// Bad mesh check
if (mshDemol.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 type objects can not be demolished
if (simTp == SimType.Static)
return false;
// Static objects can not be demolished
if (gameObject.isStatic == true)
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 (dmlTp == DemolitionType.None)
return false;
// Non destructible material
if (physics.destructible == false)
return false;
// Visibility check
if (Visible == false)
return false;
// Demolition available check
if (State() == false)
return false;
return true;
}
// Demolish object even if its demolition type is none
public void DemolishForced()
{
// Cache velocity
if (physics.rb != null)
physics.velocity = physics.rb.velocity;
// TODO obj without rb: save tm, set dmlShould, compare tm at next frame at dml
// Demolish
Demolish();
}
// Demolish object
public void Demolish()
{
// Initialize if not
if (initialized == false)
{
Initialize();
}
// 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, false);
// Set children with mesh as additional fragments
RFDemolitionMesh.ChildrenToFragments(this);
// Clusterize runtime fragments. RUNTIME dml type ONLY
RFDemolitionMesh.SetupRuntimeConnectedCluster (this, false);
// Setup awake connectivity
RFDemolitionMesh.SetupRuntimeConnectivity(this, false);
}
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;
dmlTp = DemolitionType.None;
return;
}
// Connectivity check
activation.CheckConnectivity();
// Fragments initialisation
InitMeshFragments();
// Init particles
RFPoolingEmitter.SetHostDemolition(this);
// Init sound
RFSound.DemolitionSound(sound, limitations.bboxSize);
// Event
RFDemolitionEvent.RigidDemolitionEvent (this);
// Destroy demolished object
RayfireMan.DestroyFragment (this, rtP, reset.destroyDelay);
}
/// /////////////////////////////////////////////////////////
/// Fragments
/// /////////////////////////////////////////////////////////
// Copy rigid properties from parent to fragments
public void CopyPropertiesTo (RayfireRigid toScr)
{
// Set local meshRoot
if (objTp == ObjectType.MeshRoot)
toScr.meshRoot = this;
else if (meshRoot != null)
toScr.meshRoot = meshRoot;
// Object type
toScr.objTp = objTp;
if (objTp == ObjectType.MeshRoot || objTp == ObjectType.SkinnedMesh)
toScr.objTp = ObjectType.Mesh;
// Sim type
toScr.simTp = simTp;
// Demolition type
toScr.dmlTp = dmlTp;
if (objTp != ObjectType.MeshRoot)
if (dmlTp != DemolitionType.None)
toScr.dmlTp = DemolitionType.Runtime;
// Copy physics
toScr.physics.CopyFrom (physics);
toScr.activation.CopyFrom (activation);
toScr.limitations.CopyFrom (limitations);
toScr.mshDemol.CopyFrom (mshDemol);
toScr.clsDemol.CopyFrom (clsDemol);
// Copy reference demolition props
if (objTp == ObjectType.MeshRoot)
toScr.refDemol.CopyFrom (refDemol);
toScr.materials.CopyFrom (materials);
toScr.damage.CopyFrom (damage);
toScr.fading.CopyFrom (fading);
toScr.reset.CopyFrom (reset, objTp);
}
// 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
/// /////////////////////////////////////////////////////////
// Clear cache info
public void DeleteCache()
{
meshes = null;
pivots = null;
subIds = null;
}
// Delete fragments
public void DeleteFragments()
{
// Destroy root
if (rtC != null)
{
if (Application.isPlaying == true)
Destroy (rtC.gameObject);
else
DestroyImmediate (rtC.gameObject);
// Clear ref
rtC = 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
if (limitations.slicePlanes == null)
limitations.slicePlanes = new List<Vector3>();
limitations.slicePlanes.AddRange (slicePlane);
// Add to demolition cor for slice
RayfireMan.inst.AddToDemolitionCor(this);
}
// Slice object
public void Slice()
{
// Check for slices
if (HasSlices == false)
{
RayfireMan.Log (RFLimitations.rigidStr + name + " has no defined slicing planes.", gameObject);
return;
}
// Slice
if (IsMesh == true)
{
// Slice. Stop if failed
if (RFDemolitionMesh.SliceMesh (this) == false)
return;
// Set children with mesh as additional fragments
RFDemolitionMesh.ChildrenToFragments(this);
}
else if (objTp == ObjectType.ConnectedCluster)
RFDemolitionCluster.SliceConnectedCluster (this);
// Particles
RFPoolingEmitter.SetHostDemolition(this);
// Sound
RFSound.DemolitionSound(sound, limitations.bboxSize);
// Event
RFDemolitionEvent.RigidDemolitionEvent (this);
// Destroy original
if (IsMesh == true)
RayfireMan.DestroyFragment (this, rtP, reset.destroyDelay);
}
/// /////////////////////////////////////////////////////////
/// Caching
/// /////////////////////////////////////////////////////////
// Caching into meshes over several frames
public void CacheFrames()
{
StartCoroutine (mshDemol.ch.RuntimeCachingCor(this));
}
/// /////////////////////////////////////////////////////////
/// Public methods
/// /////////////////////////////////////////////////////////
// Save init transform. Birth tm for activation check and reset
[ContextMenu("SaveInitTransform")]
public void SaveInitTransform ()
{
// Rigid save tm
if (objTp == ObjectType.Mesh)
physics.SaveInitTransform (tsf);
// Mesh Root save tm
else if (objTp == 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].tsf);
// Save is connectivity backup cluster
if (activation.cnt != null && reset.connectivity == true )
if (activation.cnt.backup != null)
RFBackupCluster.SaveTmRecursive (activation.cnt.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 (objTp != 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 (objTp != 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 DestroyObject(GameObject go) { Destroy (go); }
public void DestroyRigid(RayfireRigid rigid) { Destroy (rigid); }
/// /////////////////////////////////////////////////////////
/// 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 HasDebris { get { return debrisList != null && debrisList.Count > 0; } }
public bool HasDust { get { return dustList != null && dustList.Count > 0; } }
bool HasSlices { get { return limitations.slicePlanes != null && limitations.slicePlanes.Count > 0; } }
public bool IsCluster { get { return objTp == ObjectType.ConnectedCluster || objTp == ObjectType.NestedCluster; } }
bool IsMesh { get { return objTp == ObjectType.Mesh || objTp == ObjectType.SkinnedMesh; } }
// Check if object visible // TODO add cluster visibility support
bool Visible
{ get {
if (objTp == ObjectType.Mesh && mRnd != null) return mRnd.isVisible;
if (objTp == ObjectType.SkinnedMesh && skr != null) return skr.isVisible;
return true; }}
// CLuster Integrity
public float AmountIntegrity
{ get {
if (objTp == ObjectType.ConnectedCluster)
return clsDemol.cluster.shards.Count * 100f / clsDemol.am;
return 0f; }}
/// /////////////////////////////////////////////////////////
/// Compatibility
/// /////////////////////////////////////////////////////////
public SimType simulationType {
get { return simTp; }
set { simTp = value; } }
public ObjectType objectType {
get { return objTp; }
set { objTp = value; } }
public DemolitionType demolitionType {
get { return dmlTp; }
set { dmlTp = value; } }
public RFDemolitionMesh meshDemolition {
get { return mshDemol; }
set { mshDemol = value; } }
public RFDemolitionCluster clusterDemolition {
get { return clsDemol; }
set { clsDemol = value; } }
public RFReferenceDemolition referenceDemolition {
get { return refDemol; }
set { refDemol = value; } }
public Quaternion cacheRotation {
get { return chRot; }
set { chRot = value; } }
public MeshFilter meshFilter {
get { return mFlt; }
set { mFlt = value; } }
public MeshRenderer meshRenderer {
get { return mRnd; }
set { mRnd = value; } }
public Transform transForm {
get { return tsf; }
set { tsf = value; } }
public Transform rootChild {
get { return rtC; }
set { rtC = value; } }
public Transform rootParent {
get { return rtP; }
set { rtP = value; } }
}
}