Net.Like.Xue.Tokyo/Assets/Plugins/Dreamteck/Splines/Components/CapsuleColliderGenerator.cs

213 lines
6.4 KiB
C#

namespace Dreamteck.Splines
{
using UnityEngine;
public class CapsuleColliderGenerator : SplineUser, ISerializationCallbackReceiver
{
[SerializeField, HideInInspector, Min(0f)] private float _radius = 1f;
[SerializeField, HideInInspector, Min(0f)] private float _height = 1f;
[SerializeField, HideInInspector] private bool _overlapCaps = true;
[SerializeField, HideInInspector] private CapsuleColliderZDirection _direction = CapsuleColliderZDirection.Z;
[SerializeField, HideInInspector] private ColliderObject[] _colliders = new ColliderObject[0];
public float radius
{
get { return _radius; }
set
{
if (value != _radius)
{
_radius = value;
Rebuild();
}
}
}
public float height
{
get { return _height; }
set
{
if (value != _height)
{
_height = value;
Rebuild();
}
}
}
public bool overlapCaps
{
get { return _overlapCaps; }
set
{
if (value != _overlapCaps)
{
_overlapCaps = value;
Rebuild();
}
}
}
public CapsuleColliderZDirection direction
{
get { return _direction; }
set
{
if (value != _direction)
{
_direction = value;
Rebuild();
}
}
}
private void DestroyCollider(ColliderObject collider)
{
#if UNITY_EDITOR
if (Application.isPlaying)
{
Destroy(collider.transform.gameObject);
}
else
{
DestroyImmediate(collider.transform.gameObject);
}
#else
Destroy(collider.transform.gameObject);
#endif
}
protected override void Build()
{
base.Build();
if (sampleCount == 0)
{
for (int i = 0; i < _colliders.Length; i++)
{
DestroyCollider(_colliders[i]);
}
_colliders = new ColliderObject[0];
return;
}
int objectCount = sampleCount - 1;
if (objectCount != _colliders.Length)
{
GenerateColliders(objectCount);
}
SplineSample current = new SplineSample();
SplineSample next = new SplineSample();
Evaluate(0.0, ref current);
bool controlHeight = _direction == CapsuleColliderZDirection.Z;
for (int i = 0; i < objectCount; i++)
{
double nextPercent = (double)(i + 1) / (sampleCount - 1);
Evaluate(nextPercent, ref next);
_colliders[i].transform.position = Vector3.Lerp(current.position, next.position, 0.5f);
_colliders[i].transform.rotation = Quaternion.LookRotation(next.position - current.position, Vector3.Slerp(current.up, next.up, 0.5f));
_colliders[i].collider.radius = _radius;
_colliders[i].collider.direction = (int)_direction;
var distance = Vector3.Distance(current.position, next.position);
if (controlHeight)
{
if (_overlapCaps)
{
_colliders[i].collider.height = distance + _radius * 2f;
} else
{
_colliders[i].collider.height = distance;
}
_colliders[i].collider.radius = _radius;
}
else
{
_colliders[i].collider.height = _height;
_colliders[i].collider.radius = distance * 0.5f;
}
current = next;
}
}
private void GenerateColliders(int count)
{
ColliderObject[] newColliders = new ColliderObject[count];
for (int i = 0; i < newColliders.Length; i++)
{
if (i < _colliders.Length)
{
newColliders[i] = _colliders[i];
}
else
{
GameObject newObject = new GameObject("Collider " + i);
newObject.layer = gameObject.layer;
newObject.transform.parent = trs;
newColliders[i] = new ColliderObject(newObject.transform, newObject.AddComponent<CapsuleCollider>(), _direction, _height);
}
}
if (newColliders.Length < _colliders.Length)
{
for (int i = newColliders.Length; i < _colliders.Length; i++)
{
DestroyCollider(_colliders[i]);
}
}
_colliders = newColliders;
}
public override void OnBeforeSerialize()
{
base.OnBeforeSerialize();
Build();
}
protected override void OnDestroy()
{
base.OnDestroy();
for (int i = 0; i < _colliders.Length; i++)
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
DestroyImmediate(_colliders[i].transform.gameObject);
}
else
{
Destroy(_colliders[i].transform.gameObject);
}
#else
Destroy(_colliders[i].transform.gameObject);
#endif
}
}
[System.Serializable]
public class ColliderObject
{
public Transform transform;
public CapsuleCollider collider;
public ColliderObject(Transform transform, CapsuleCollider collider, CapsuleColliderZDirection direction, float height)
{
this.transform = transform;
this.collider = collider;
this.collider.direction = (int)direction;
this.collider.height = height;
}
}
public enum CapsuleColliderZDirection
{
X = 0, Y = 1, Z = 2,
}
}
}