450 lines
19 KiB
C#
450 lines
19 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEngine;
|
|||
|
using UnityEngine.Serialization;
|
|||
|
|
|||
|
namespace RayFire
|
|||
|
{
|
|||
|
[Serializable]
|
|||
|
public class RFLimitations
|
|||
|
{
|
|||
|
[FormerlySerializedAs ("byCollision")] public bool col;
|
|||
|
[FormerlySerializedAs ("solidity")] public float sol;
|
|||
|
public string tag;
|
|||
|
public int depth;
|
|||
|
public float time;
|
|||
|
public float size;
|
|||
|
[FormerlySerializedAs ("visible")] public bool vis;
|
|||
|
[FormerlySerializedAs ("sliceByBlade")] public bool bld;
|
|||
|
public Bounds bound;
|
|||
|
|
|||
|
// Non serialized
|
|||
|
[NonSerialized] public List<Vector3> slicePlanes;
|
|||
|
[NonSerialized] public ContactPoint contactPoint;
|
|||
|
[NonSerialized] public Vector3 contactVector3;
|
|||
|
[NonSerialized] public Vector3 contactNormal;
|
|||
|
[NonSerialized] public bool demolitionShould;
|
|||
|
[NonSerialized] public bool demolished;
|
|||
|
[NonSerialized] public float birthTime;
|
|||
|
[NonSerialized] public float bboxSize;
|
|||
|
[NonSerialized] public int currentDepth;
|
|||
|
|
|||
|
// Blade props
|
|||
|
[NonSerialized] public float sliceForce;
|
|||
|
[NonSerialized] public bool affectInactive;
|
|||
|
|
|||
|
// Family data. Do not nullify in Reset
|
|||
|
[NonSerialized] public RayfireRigid anc; // ancestor
|
|||
|
[NonSerialized] public List<RayfireRigid> desc; // descendants
|
|||
|
|
|||
|
// Static
|
|||
|
static float kinematicCollisionMult = 7f;
|
|||
|
static string rootStr = "_root";
|
|||
|
public static string rigidStr = "RayFire Rigid: ";
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Constructor
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Constructor
|
|||
|
public RFLimitations()
|
|||
|
{
|
|||
|
InitValues();
|
|||
|
LocalReset();
|
|||
|
}
|
|||
|
|
|||
|
// Copy from
|
|||
|
public void CopyFrom (RFLimitations source)
|
|||
|
{
|
|||
|
col = source.col;
|
|||
|
sol = source.sol;
|
|||
|
depth = source.depth;
|
|||
|
time = source.time;
|
|||
|
size = source.size;
|
|||
|
tag = source.tag;
|
|||
|
vis = source.vis;
|
|||
|
bld = source.bld;
|
|||
|
|
|||
|
// Do not copy currentDepth. Set in other place
|
|||
|
|
|||
|
LocalReset();
|
|||
|
}
|
|||
|
|
|||
|
// Starting values
|
|||
|
void InitValues()
|
|||
|
{
|
|||
|
col = true;
|
|||
|
sol = 0.1f;
|
|||
|
depth = 1;
|
|||
|
time = 0.2f;
|
|||
|
size = 0.1f;
|
|||
|
tag = "Untagged";
|
|||
|
vis = false;
|
|||
|
bld = false;
|
|||
|
anc = null;
|
|||
|
desc = null;
|
|||
|
}
|
|||
|
|
|||
|
// Reset
|
|||
|
public void LocalReset()
|
|||
|
{
|
|||
|
slicePlanes = null;
|
|||
|
contactVector3 = Vector3.zero;
|
|||
|
contactNormal = Vector3.down;
|
|||
|
demolitionShould = false;
|
|||
|
demolished = false;
|
|||
|
affectInactive = false;
|
|||
|
currentDepth = 0;
|
|||
|
birthTime = 0f;
|
|||
|
sliceForce = 0;
|
|||
|
}
|
|||
|
|
|||
|
// Pool Reset
|
|||
|
public void GlobalReset()
|
|||
|
{
|
|||
|
InitValues();
|
|||
|
LocalReset();
|
|||
|
|
|||
|
// TODO
|
|||
|
// bound = new Bounds ();
|
|||
|
// contactPoint = null;
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Static
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// MeshRoot Integrity check
|
|||
|
public static void MeshRootCheck (RayfireRigid scr)
|
|||
|
{
|
|||
|
// Null fragments
|
|||
|
if (scr.HasFragments == true)
|
|||
|
{
|
|||
|
for (int f = 0; f < scr.fragments.Count; f++)
|
|||
|
{
|
|||
|
if (scr.fragments[f] == null)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " object has missing fragments. Reset Setup and used Editor Setup again", scr.gameObject);
|
|||
|
scr.fragments = new List<RayfireRigid>();
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Check for user mistakes
|
|||
|
public static void Checks (RayfireRigid scr)
|
|||
|
{
|
|||
|
// ////////////////
|
|||
|
// Sim Type
|
|||
|
// ////////////////
|
|||
|
|
|||
|
// Static and demolishable
|
|||
|
if (scr.simTp == SimType.Static)
|
|||
|
{
|
|||
|
if (scr.dmlTp != DemolitionType.None)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Simulation Type set to " + scr.simTp.ToString() + " but Demolition Type is not None. Static object can not be demolished. Demolition Type set to None.", scr.gameObject);
|
|||
|
scr.dmlTp = DemolitionType.None;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Non static simulation but static property
|
|||
|
if (scr.simTp != SimType.Static)
|
|||
|
{
|
|||
|
if (scr.gameObject.isStatic == true)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Simulation Type set to " + scr.simTp.ToString() + " but object is Static. Turn off Static checkbox in Inspector.", scr.gameObject);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// ////////////////
|
|||
|
// Object Type
|
|||
|
// ////////////////
|
|||
|
|
|||
|
// Object can not be simulated as mesh
|
|||
|
if (scr.objTp == ObjectType.Mesh)
|
|||
|
{
|
|||
|
// Has no mesh
|
|||
|
if (scr.mFlt == null || scr.mFlt.sharedMesh == null)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Object Type set to " + scr.objTp.ToString() + " but object has no mesh. Object Excluded from simulation.", scr.gameObject);
|
|||
|
scr.physics.exclude = true;
|
|||
|
}
|
|||
|
|
|||
|
// Awake or Runtime Convertation to Connectivity but fragments are not Inactive/Kinematik
|
|||
|
if (scr.mshDemol.cnv == RFDemolitionMesh.ConvertType.Connectivity)
|
|||
|
{
|
|||
|
if (scr.mshDemol.sim != FragSimType.Inactive && scr.mshDemol.sim != FragSimType.Kinematic)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Convert property set to " + scr.mshDemol.cnv.ToString() + " but Fragments Sim Type is not Inactive or Kinematik. Convertation disabled.", scr.gameObject);
|
|||
|
scr.mshDemol.cnv = RFDemolitionMesh.ConvertType.Disabled;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Not readable mesh
|
|||
|
if (scr.dmlTp != DemolitionType.None && scr.dmlTp != DemolitionType.ReferenceDemolition)
|
|||
|
{
|
|||
|
if (scr.mFlt != null && scr.mFlt.sharedMesh != null && scr.mFlt.sharedMesh.isReadable == false)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Mesh is not readable. Demolition type set to None. Open Import Settings and turn On Read/Write Enabled property", scr.mFlt.gameObject);
|
|||
|
scr.dmlTp = DemolitionType.None;
|
|||
|
scr.mshDemol.badMesh = 10;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Object can not be simulated as cluster
|
|||
|
else if (scr.objTp == ObjectType.NestedCluster || scr.objTp == ObjectType.ConnectedCluster)
|
|||
|
{
|
|||
|
if (scr.tsf.childCount == 0)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Object Type set to " + scr.objTp.ToString() + " but object has no children. Object Excluded from simulation.", scr.gameObject);
|
|||
|
scr.physics.exclude = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Object can not be simulated as mesh
|
|||
|
else if (scr.objTp == ObjectType.SkinnedMesh)
|
|||
|
{
|
|||
|
if (scr.skr == null)
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Object Type set to " + scr.objTp.ToString() + " but object has no SkinnedMeshRenderer. Object Excluded from simulation.", scr.gameObject);
|
|||
|
|
|||
|
// Excluded from sim by default
|
|||
|
scr.physics.exclude = true;
|
|||
|
}
|
|||
|
|
|||
|
// ////////////////
|
|||
|
// Demolition Type
|
|||
|
// ////////////////
|
|||
|
|
|||
|
// Demolition checks
|
|||
|
if (scr.dmlTp != DemolitionType.None)
|
|||
|
{
|
|||
|
// // Static
|
|||
|
// if (scr.simulationType == SimType.Static)
|
|||
|
// {
|
|||
|
// Debug.Log (rigidStr + scr.name + " Simulation Type set to " + scr.simulationType.ToString() + " but Demolition Type is " + scr.demolitionType.ToString() + ". Demolition Type set to None.", scr.gameObject);
|
|||
|
// scr.demolitionType = DemolitionType.None;
|
|||
|
// }
|
|||
|
|
|||
|
// Set runtime demolition for clusters and skinned mesh
|
|||
|
if (scr.objTp == ObjectType.SkinnedMesh ||
|
|||
|
scr.objTp == ObjectType.NestedCluster ||
|
|||
|
scr.objTp == ObjectType.ConnectedCluster)
|
|||
|
{
|
|||
|
if (scr.dmlTp != DemolitionType.Runtime && scr.dmlTp != DemolitionType.ReferenceDemolition)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Object Type set to " + scr.objTp.ToString() + " but Demolition Type is " + scr.dmlTp.ToString() + ". Demolition Type set to Runtime.", scr.gameObject);
|
|||
|
scr.dmlTp = DemolitionType.Runtime;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// No Shatter component for runtime demolition with Use Shatter on
|
|||
|
if (scr.dmlTp == DemolitionType.Runtime ||
|
|||
|
scr.dmlTp == DemolitionType.AwakePrecache ||
|
|||
|
scr.dmlTp == DemolitionType.AwakePrefragment)
|
|||
|
{
|
|||
|
if (scr.mshDemol.use == true && scr.mshDemol.sht == null)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + "Demolition Type is " + scr.dmlTp.ToString() + ". Has no Shatter component, but Use Shatter property is On. Use Shatter property was turned Off.", scr.gameObject);
|
|||
|
scr.mshDemol.use = false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// None check
|
|||
|
if (scr.dmlTp == DemolitionType.None)
|
|||
|
{
|
|||
|
if (scr.HasMeshes == true)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Demolition Type set to None. Had precached meshes which were destroyed.", scr.gameObject);
|
|||
|
scr.DeleteCache();
|
|||
|
}
|
|||
|
|
|||
|
if (scr.objTp == ObjectType.Mesh && scr.HasFragments == true)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Demolition Type set to None. Had prefragmented objects which were destroyed.", scr.gameObject);
|
|||
|
scr.DeleteFragments();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Runtime check
|
|||
|
else if (scr.dmlTp == DemolitionType.Runtime)
|
|||
|
{
|
|||
|
if (scr.HasMeshes == true)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Demolition Type set to Runtime. Had precached meshes which were destroyed.", scr.gameObject);
|
|||
|
scr.DeleteCache();
|
|||
|
}
|
|||
|
|
|||
|
if (scr.objTp == ObjectType.Mesh && scr.HasFragments == true)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Demolition Type set to Runtime. Had prefragmented objects which were destroyed.", scr.gameObject);
|
|||
|
scr.DeleteFragments();
|
|||
|
}
|
|||
|
|
|||
|
// No runtime caching for rigid with shatter with tets/slices/glue
|
|||
|
if (scr.mshDemol.use == true && scr.mshDemol.ch.tp != CachingType.Disabled)
|
|||
|
{
|
|||
|
if (scr.mshDemol.sht.type == FragType.Decompose ||
|
|||
|
scr.mshDemol.sht.type == FragType.Tets ||
|
|||
|
scr.mshDemol.sht.type == FragType.Slices ||
|
|||
|
scr.mshDemol.sht.clusters.enable == true)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Demolition Type is Runtime, Use Shatter is On. Unsupported fragments type. Runtime Caching supports only Voronoi, Splinters, Slabs and Radial fragmentation types. Runtime Caching was Disabled.", scr.gameObject);
|
|||
|
scr.mshDemol.ch.tp = CachingType.Disabled;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Awake precache check
|
|||
|
else if (scr.dmlTp == DemolitionType.AwakePrecache)
|
|||
|
{
|
|||
|
if (scr.HasMeshes == true)
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Demolition Type set to Awake Precache. Had manually precached Unity meshes which were overwritten.", scr.gameObject);
|
|||
|
|
|||
|
if (scr.HasFragments == true)
|
|||
|
{
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Demolition Type set to Awake Precache. Had manually prefragmented objects which were destroyed.", scr.gameObject);
|
|||
|
scr.DeleteFragments();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Awake prefragmented check
|
|||
|
else if (scr.dmlTp == DemolitionType.AwakePrefragment)
|
|||
|
{
|
|||
|
if (RayfireMan.debugStateStatic == true)
|
|||
|
{
|
|||
|
if (scr.HasFragments == true)
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Demolition Type set to Awake Prefragment. Has manually prefragmented objects", scr.gameObject);
|
|||
|
if (scr.HasMeshes == true)
|
|||
|
RayfireMan.Log (rigidStr + scr.name + " Demolition Type set to Awake Prefragment. Has manually precached Unity meshes.", scr.gameObject);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Reference demolition
|
|||
|
else if (scr.dmlTp == DemolitionType.ReferenceDemolition)
|
|||
|
{
|
|||
|
if (scr.refDemol.rfs == null && scr.refDemol.HasRandomRefs == false)
|
|||
|
{
|
|||
|
//Debug.Log (rigidStr + scr.name + " Demolition Type set to Reference Demolition but Reference is not defined.", scr.gameObject);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Set bound and size
|
|||
|
public static void SetBound (RayfireRigid scr)
|
|||
|
{
|
|||
|
if (scr.objTp == ObjectType.Mesh)
|
|||
|
scr.limitations.bound = scr.mRnd.bounds;
|
|||
|
else if (scr.objTp == ObjectType.SkinnedMesh)
|
|||
|
scr.limitations.bound = scr.skr.bounds;
|
|||
|
else if (scr.objTp == ObjectType.NestedCluster || scr.objTp == ObjectType.ConnectedCluster)
|
|||
|
scr.limitations.bound = RFCluster.GetChildrenBound (scr.tsf);
|
|||
|
scr.limitations.bboxSize = scr.limitations.bound.size.magnitude;
|
|||
|
}
|
|||
|
|
|||
|
// Set ancestor
|
|||
|
public static void SetAncestor (RayfireRigid scr)
|
|||
|
{
|
|||
|
// Set ancestor to this if it is ancestor
|
|||
|
if (scr.limitations.anc == null)
|
|||
|
for (int i = 0; i < scr.fragments.Count; i++)
|
|||
|
scr.fragments[i].limitations.anc = scr;
|
|||
|
else
|
|||
|
for (int i = 0; i < scr.fragments.Count; i++)
|
|||
|
scr.fragments[i].limitations.anc = scr.limitations.anc;
|
|||
|
}
|
|||
|
|
|||
|
// Set descendants
|
|||
|
public static void SetDescendants (RayfireRigid scr)
|
|||
|
{
|
|||
|
if (scr.reset.action == RFReset.PostDemolitionType.DestroyWithDelay)
|
|||
|
return;
|
|||
|
|
|||
|
if (scr.limitations.anc == null)
|
|||
|
scr.limitations.desc.AddRange (scr.fragments);
|
|||
|
else
|
|||
|
scr.limitations.anc.limitations.desc.AddRange (scr.fragments);
|
|||
|
}
|
|||
|
|
|||
|
// Create root
|
|||
|
public static void CreateRoot (RayfireRigid rfScr)
|
|||
|
{
|
|||
|
GameObject root = new GameObject(rfScr.gameObject.name + rootStr);
|
|||
|
rfScr.rtC = root.transform;
|
|||
|
rfScr.rtC.position = rfScr.tsf.position;
|
|||
|
rfScr.rtC.rotation = rfScr.tsf.rotation;
|
|||
|
rfScr.rtC.SetParent (rfScr.transform.parent);
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Demolition
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Check if collision data needed
|
|||
|
public bool CollisionCheck(RayfireRigid rigid)
|
|||
|
{
|
|||
|
if (rigid.limitations.col == true)
|
|||
|
return true;
|
|||
|
if (rigid.damage.en == true && rigid.damage.col == true)
|
|||
|
return true;
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Set Contact info
|
|||
|
public void SetContactInfo(ContactPoint contact)
|
|||
|
{
|
|||
|
contactPoint = contact;
|
|||
|
contactVector3 = contactPoint.point;
|
|||
|
contactNormal = contactPoint.normal;
|
|||
|
}
|
|||
|
|
|||
|
// Collision with kinematic object. Uses collision.impulse
|
|||
|
public bool KinematicCollisionCheck(Collision collision, float finalSolidity)
|
|||
|
{
|
|||
|
if (collision.rigidbody != null && collision.rigidbody.isKinematic == true)
|
|||
|
if (collision.impulse.magnitude > finalSolidity * kinematicCollisionMult)
|
|||
|
{
|
|||
|
SetContactInfo (collision.GetContact(0));
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Collision force checks. Uses relativeVelocity
|
|||
|
public bool ContactPointsCheck(Collision collision, float finalSolidity)
|
|||
|
{
|
|||
|
float collisionMagnitude = collision.relativeVelocity.magnitude;
|
|||
|
for (int i = 0; i < collision.contactCount; i++)
|
|||
|
{
|
|||
|
// Set contact point
|
|||
|
SetContactInfo (collision.GetContact(i));
|
|||
|
|
|||
|
// Demolish if collision high enough
|
|||
|
if (collisionMagnitude > finalSolidity)
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Collision force checks. Uses relativeVelocity
|
|||
|
public bool DamagePointsCheck(Collision collision, RayfireRigid rigid)
|
|||
|
{
|
|||
|
float collisionMagnitude = collision.relativeVelocity.magnitude;
|
|||
|
for (int i = 0; i < collision.contactCount; i++)
|
|||
|
{
|
|||
|
// Set contact point
|
|||
|
SetContactInfo (collision.GetContact(i));
|
|||
|
|
|||
|
// Collect damage by collision
|
|||
|
if (rigid.ApplyDamage (collisionMagnitude * rigid.damage.mlt, contactVector3, 0f, collision.contacts[i].thisCollider) == true)
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|