using System; using System.IO; using kt.Utility; using UnityEngine; namespace kt.Physics { public class NativeCapsuleCollider : ANativeColliderBase { public virtual NativeCapsuleColliderStatus capsuleStatus { get { return this.CapsuleStatus; } } public override NativeColliderStatus status { get { return this.CapsuleStatus; } protected set { this.CapsuleStatus = (value as NativeCapsuleColliderStatus); } } public Vector3 localDirection { get { Vector3 vector = MathUtility.GetPrimitiveVector(this.capsuleStatus.direction); if (this.capsuleStatus.isDirectionInverse) { vector = -vector; } return vector; } } public Vector3 worldDirection { get { return base.transform.TransformDirection(this.localDirection); } } public Vector3 startPos { get { return this.worldCenter - this.worldDirection * this.capsuleStatus.height / 2f; } } public Vector3 endPos { get { return this.worldCenter + this.worldDirection * this.capsuleStatus.height / 2f; } } public virtual float startRadius { get { return this.capsuleStatus.startRadius * base.GetLossyScale(); } } public virtual float endRadius { get { return this.capsuleStatus.endRadius * base.GetLossyScale(); } } public override bool Collide(ref Vector3 position, float radius) { Vector3 lhs = position - this.startPos; float num = Vector3.Dot(lhs, this.worldDirection); Vector3 a = Vector3.zero; Vector3 vector = Vector3.zero; float num2; if (num < 0f || num * num > (this.endPos - this.startPos).sqrMagnitude) { vector = ((num >= 0f) ? this.endPos : this.startPos); a = position - vector; num2 = ((num >= 0f) ? this.endRadius : this.startRadius); } else { vector = this.startPos + this.worldDirection * num; a = position - vector; if (this.capsuleStatus.height > 0f) { num2 = Mathf.Lerp(this.startRadius, this.endRadius, Mathf.Clamp01(num / this.capsuleStatus.height)); } else { num2 = Mathf.Max(this.startRadius, this.endRadius); } } if (this.status.bound == NativeColliderStatus.Bound.Outside) { float num3 = num2 + radius; if (a.sqrMagnitude > num3 * num3) { return false; } float magnitude = a.magnitude; if (magnitude > 0f) { position = vector + a / magnitude * num3; } } else { float num4 = Mathf.Max(num2 - radius, 0f); if (a.sqrMagnitude < num4 * num4) { return false; } float magnitude2 = a.magnitude; if (magnitude2 > 0f) { position = vector + a / magnitude2 * num4; } } return true; } protected override bool CollideCapsule(NativeCapsuleCollider capsule, ref Vector3 normal) { Vector3 zero = Vector3.zero; float radius = 0f; bool flag; if (!this.IsIntersectProjection(capsule, ref zero, ref radius)) { Vector3 b = zero; flag = this.Collide(ref zero, radius); if (flag) { normal = zero - b; } if (MathUtility.IsVector3NaN(normal)) { flag = false; normal = Vector3.zero; } return flag; } if (!capsule.IsIntersectProjection(this, ref zero, ref radius)) { Vector3 b2 = zero; flag = capsule.Collide(ref zero, radius); if (flag) { normal = -(zero - b2); } if (MathUtility.IsVector3NaN(normal)) { flag = false; normal = Vector3.zero; } return flag; } Vector3 vector = Vector3.Cross(this.worldDirection, capsule.worldDirection).normalized; float num = Vector3.Dot(capsule.startPos - this.startPos, vector); if (num < 0f) { vector = -vector; num = Mathf.Abs(num); } float num2 = Mathf.Max(this.startRadius, this.endRadius); num2 += Mathf.Max(capsule.startRadius, capsule.endRadius); if (num > num2) { return false; } flag = true; Vector3 vector2 = capsule.startPos - vector * num; Vector3 vector3 = capsule.endPos - vector * num; float d = Vector3.Dot(this.startPos - vector2, capsule.worldDirection); float num3 = Vector3.Distance(this.startPos, vector2 + capsule.worldDirection * d); float d2 = Vector3.Dot(this.endPos - vector2, capsule.worldDirection); float num4 = Vector3.Distance(this.endPos, vector2 + capsule.worldDirection * d2); float num5 = num3 / (num3 + num4); Vector3 a = this.startPos + this.worldDirection * this.capsuleStatus.height * num5; float num6 = (capsule.capsuleStatus.height <= 0f) ? 0f : (Vector3.Dot(a - capsule.startPos, capsule.worldDirection) / capsule.capsuleStatus.height); Vector3 vector4 = capsule.startPos + capsule.worldDirection * capsule.capsuleStatus.height * num6; float num7 = Mathf.Lerp(this.startRadius, this.endRadius, num5); num7 += Mathf.Lerp(capsule.startRadius, capsule.endRadius, num6); if (num > num7) { return false; } normal = vector * (num7 - num); if (MathUtility.IsVector3NaN(normal)) { flag = false; normal = Vector3.zero; } return flag; } private bool IsIntersectProjection(NativeCapsuleCollider capsule, ref Vector3 near_point, ref float near_radius) { Vector3 worldDirection = this.worldDirection; Vector3 lhs = Vector3.Cross(worldDirection, capsule.startPos - this.startPos); Vector3 rhs = Vector3.Cross(worldDirection, capsule.endPos - this.startPos); near_radius = ((lhs.sqrMagnitude > rhs.sqrMagnitude) ? capsule.endRadius : capsule.startRadius); near_point = ((lhs.sqrMagnitude > rhs.sqrMagnitude) ? capsule.endPos : capsule.startPos); return Vector3.Dot(lhs, rhs) < 0f; } public override void Save(StreamWriter writer) { base.Save(writer); } public override void Load(StreamReader reader, Transform parent_search_root) { base.Load(reader, parent_search_root); } [SerializeField] private NativeCapsuleColliderStatus CapsuleStatus = new NativeCapsuleColliderStatus(); } }