236 lines
7.2 KiB
C#
236 lines
7.2 KiB
C#
|
using UnityEngine;
|
|||
|
|
|||
|
[AddComponentMenu("Dynamic Bone/Dynamic Bone Collider")]
|
|||
|
public class DynamicBoneCollider : DynamicBoneColliderBase
|
|||
|
{
|
|||
|
#if UNITY_5_3_OR_NEWER
|
|||
|
[Tooltip("The radius of the sphere or capsule.")]
|
|||
|
#endif
|
|||
|
public float m_Radius = 0.5f;
|
|||
|
|
|||
|
#if UNITY_5_3_OR_NEWER
|
|||
|
[Tooltip("The height of the capsule.")]
|
|||
|
#endif
|
|||
|
public float m_Height = 0;
|
|||
|
|
|||
|
void OnValidate()
|
|||
|
{
|
|||
|
m_Radius = Mathf.Max(m_Radius, 0);
|
|||
|
m_Height = Mathf.Max(m_Height, 0);
|
|||
|
}
|
|||
|
|
|||
|
public override bool Collide(ref Vector3 particlePosition, float particleRadius)
|
|||
|
{
|
|||
|
float radius = m_Radius * Mathf.Abs(transform.lossyScale.x);
|
|||
|
float h = m_Height * 0.5f - m_Radius;
|
|||
|
if (h <= 0)
|
|||
|
{
|
|||
|
if (m_Bound == Bound.Outside)
|
|||
|
return OutsideSphere(ref particlePosition, particleRadius, transform.TransformPoint(m_Center), radius);
|
|||
|
else
|
|||
|
return InsideSphere(ref particlePosition, particleRadius, transform.TransformPoint(m_Center), radius);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Vector3 c0 = m_Center;
|
|||
|
Vector3 c1 = m_Center;
|
|||
|
|
|||
|
switch (m_Direction)
|
|||
|
{
|
|||
|
case Direction.X:
|
|||
|
c0.x -= h;
|
|||
|
c1.x += h;
|
|||
|
break;
|
|||
|
case Direction.Y:
|
|||
|
c0.y -= h;
|
|||
|
c1.y += h;
|
|||
|
break;
|
|||
|
case Direction.Z:
|
|||
|
c0.z -= h;
|
|||
|
c1.z += h;
|
|||
|
break;
|
|||
|
}
|
|||
|
if (m_Bound == Bound.Outside)
|
|||
|
return OutsideCapsule(ref particlePosition, particleRadius, transform.TransformPoint(c0), transform.TransformPoint(c1), radius);
|
|||
|
else
|
|||
|
return InsideCapsule(ref particlePosition, particleRadius, transform.TransformPoint(c0), transform.TransformPoint(c1), radius);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static bool OutsideSphere(ref Vector3 particlePosition, float particleRadius, Vector3 sphereCenter, float sphereRadius)
|
|||
|
{
|
|||
|
float r = sphereRadius + particleRadius;
|
|||
|
float r2 = r * r;
|
|||
|
Vector3 d = particlePosition - sphereCenter;
|
|||
|
float len2 = d.sqrMagnitude;
|
|||
|
|
|||
|
// if is inside sphere, project onto sphere surface
|
|||
|
if (len2 > 0 && len2 < r2)
|
|||
|
{
|
|||
|
float len = Mathf.Sqrt(len2);
|
|||
|
particlePosition = sphereCenter + d * (r / len);
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
static bool InsideSphere(ref Vector3 particlePosition, float particleRadius, Vector3 sphereCenter, float sphereRadius)
|
|||
|
{
|
|||
|
float r = sphereRadius - particleRadius;
|
|||
|
float r2 = r * r;
|
|||
|
Vector3 d = particlePosition - sphereCenter;
|
|||
|
float len2 = d.sqrMagnitude;
|
|||
|
|
|||
|
// if is outside sphere, project onto sphere surface
|
|||
|
if (len2 > r2)
|
|||
|
{
|
|||
|
float len = Mathf.Sqrt(len2);
|
|||
|
particlePosition = sphereCenter + d * (r / len);
|
|||
|
return true;
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
static bool OutsideCapsule(ref Vector3 particlePosition, float particleRadius, Vector3 capsuleP0, Vector3 capsuleP1, float capsuleRadius)
|
|||
|
{
|
|||
|
float r = capsuleRadius + particleRadius;
|
|||
|
float r2 = r * r;
|
|||
|
Vector3 dir = capsuleP1 - capsuleP0;
|
|||
|
Vector3 d = particlePosition - capsuleP0;
|
|||
|
float t = Vector3.Dot(d, dir);
|
|||
|
|
|||
|
if (t <= 0)
|
|||
|
{
|
|||
|
// check sphere1
|
|||
|
float len2 = d.sqrMagnitude;
|
|||
|
if (len2 > 0 && len2 < r2)
|
|||
|
{
|
|||
|
float len = Mathf.Sqrt(len2);
|
|||
|
particlePosition = capsuleP0 + d * (r / len);
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
float dl = dir.sqrMagnitude;
|
|||
|
if (t >= dl)
|
|||
|
{
|
|||
|
// check sphere2
|
|||
|
d = particlePosition - capsuleP1;
|
|||
|
float len2 = d.sqrMagnitude;
|
|||
|
if (len2 > 0 && len2 < r2)
|
|||
|
{
|
|||
|
float len = Mathf.Sqrt(len2);
|
|||
|
particlePosition = capsuleP1 + d * (r / len);
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (dl > 0)
|
|||
|
{
|
|||
|
// check cylinder
|
|||
|
t /= dl;
|
|||
|
d -= dir * t;
|
|||
|
float len2 = d.sqrMagnitude;
|
|||
|
if (len2 > 0 && len2 < r2)
|
|||
|
{
|
|||
|
float len = Mathf.Sqrt(len2);
|
|||
|
particlePosition += d * ((r - len) / len);
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
static bool InsideCapsule(ref Vector3 particlePosition, float particleRadius, Vector3 capsuleP0, Vector3 capsuleP1, float capsuleRadius)
|
|||
|
{
|
|||
|
float r = capsuleRadius - particleRadius;
|
|||
|
float r2 = r * r;
|
|||
|
Vector3 dir = capsuleP1 - capsuleP0;
|
|||
|
Vector3 d = particlePosition - capsuleP0;
|
|||
|
float t = Vector3.Dot(d, dir);
|
|||
|
|
|||
|
if (t <= 0)
|
|||
|
{
|
|||
|
// check sphere1
|
|||
|
float len2 = d.sqrMagnitude;
|
|||
|
if (len2 > r2)
|
|||
|
{
|
|||
|
float len = Mathf.Sqrt(len2);
|
|||
|
particlePosition = capsuleP0 + d * (r / len);
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
float dl = dir.sqrMagnitude;
|
|||
|
if (t >= dl)
|
|||
|
{
|
|||
|
// check sphere2
|
|||
|
d = particlePosition - capsuleP1;
|
|||
|
float len2 = d.sqrMagnitude;
|
|||
|
if (len2 > r2)
|
|||
|
{
|
|||
|
float len = Mathf.Sqrt(len2);
|
|||
|
particlePosition = capsuleP1 + d * (r / len);
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (dl > 0)
|
|||
|
{
|
|||
|
// check cylinder
|
|||
|
t /= dl;
|
|||
|
d -= dir * t;
|
|||
|
float len2 = d.sqrMagnitude;
|
|||
|
if (len2 > r2)
|
|||
|
{
|
|||
|
float len = Mathf.Sqrt(len2);
|
|||
|
particlePosition += d * ((r - len) / len);
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
void OnDrawGizmosSelected()
|
|||
|
{
|
|||
|
if (!enabled)
|
|||
|
return;
|
|||
|
|
|||
|
if (m_Bound == Bound.Outside)
|
|||
|
Gizmos.color = Color.yellow;
|
|||
|
else
|
|||
|
Gizmos.color = Color.magenta;
|
|||
|
float radius = m_Radius * Mathf.Abs(transform.lossyScale.x);
|
|||
|
float h = m_Height * 0.5f - m_Radius;
|
|||
|
if (h <= 0)
|
|||
|
{
|
|||
|
Gizmos.DrawWireSphere(transform.TransformPoint(m_Center), radius);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Vector3 c0 = m_Center;
|
|||
|
Vector3 c1 = m_Center;
|
|||
|
|
|||
|
switch (m_Direction)
|
|||
|
{
|
|||
|
case Direction.X:
|
|||
|
c0.x -= h;
|
|||
|
c1.x += h;
|
|||
|
break;
|
|||
|
case Direction.Y:
|
|||
|
c0.y -= h;
|
|||
|
c1.y += h;
|
|||
|
break;
|
|||
|
case Direction.Z:
|
|||
|
c0.z -= h;
|
|||
|
c1.z += h;
|
|||
|
break;
|
|||
|
}
|
|||
|
Gizmos.DrawWireSphere(transform.TransformPoint(c0), radius);
|
|||
|
Gizmos.DrawWireSphere(transform.TransformPoint(c1), radius);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|