using System;
using System.Diagnostics;
using UnityEngine;
public interface ICube : IMyCollider
{
Vector3 angle { get; }
Vector3 size { get; }
}
public interface IAnnular : ICircle
{
Vector3 dir { get; }
float radian { get; }
[Obsolete]
float minRadius { get; }
}
public interface ICapsule : ICircle
{
Vector3 point1 { get; }
Vector3 point2 { get; }
}
public interface ICircle : IMyCollider
{
float radius { get; }
}
public interface IMyCollider
{
Bounds bounds { get; }
Transform transform { get; }
Vector3 center { get; }
}
[DebuggerStepThrough, Serializable]
public struct Cube : ICube
{
public Transform transform { get; set; }
public Bounds bounds { get; set; }
public Vector3 angle { get; set; }
public Vector3 center { get; set; }
public Vector3 size { get; set; }
public static implicit operator Cube(BoxCollider box)
{
return new Cube
{
transform = box.transform,
center = box.center + box.transform.position,
size = box.size.Multiply(box.transform.localScale),
bounds = box.bounds,
angle = box.transform.eulerAngles
};
}
public static explicit operator Cube(Bounds bound)
{
return new Cube
{
center = bound.center,
size = bound.size,
bounds = bound
};
}
}
[DebuggerStepThrough, Serializable]
public struct Annular : IAnnular
{
public Vector3 dir { get; set; }
public float radian { get; set; }
[Obsolete]
public float minRadius { get; set; }
public Vector3 center { get; set; }
public float radius { get; set; }
public Bounds bounds { get; set; }
public Transform transform { get; set; }
}
[DebuggerStepThrough, Serializable]
public struct Capsule : ICapsule
{
public Vector3 center { get; set; }
public float radius { get; set; }
public Transform transform { get; set; }
public Bounds bounds { get; set; }
public Vector3 point1 { get; set; }
public Vector3 point2 { get; set; }
public static explicit operator Capsule(CapsuleCollider capsule)
{
float height = (capsule.height - 2 * capsule.radius) * capsule.transform.lossyScale.y;
Vector3 vec = capsule.transform.rotation * (Vector3.up * (height / 2));
Capsule ret = new Capsule
{
center = capsule.bounds.center,
radius = capsule.radius * capsule.transform.lossyScale.y,
transform = capsule.transform,
bounds = capsule.bounds,
point1 = capsule.bounds.center + vec,
point2 = capsule.bounds.center - vec,
};
return ret;
}
}
[DebuggerStepThrough, Serializable]
public struct Circle : ICircle
{
public Vector3 center { get; set; }
public float radius { get; set; }
public Transform transform { get; set; }
public Bounds bounds { get; set; }
public static implicit operator Circle(SphereCollider sphere)
{
return new Circle
{
center = sphere.center,
radius = sphere.radius,
transform = sphere.transform,
bounds = sphere.bounds,
};
}
}
using System;
using UnityEngine;
public static class PhysicsExtension
{
public static bool XZIntersects(this IMyCollider self, IMyCollider target)
{
if (self is ICapsule cap)
return cap.XZIntersects(target);
else if (self is IAnnular ann)
return ann.XZIntersects(target);
else if (self is ICircle cir)
return cir.XZIntersects(target);
else if (self is ICube cub)
return cub.XZIntersects(target);
return target.bounds.XZIntersects(self.bounds);
}
public static bool XZIntersects(this IMyCollider self, Bounds bound)
{
if (self is ICapsule cap)
return cap.XZIntersects(bound);
if (self is IAnnular ann)
return ann.XZIntersects(bound);
else if (self is ICircle cir)
return cir.XZIntersects(bound);
else if (self is ICube cub)
return cub.XZIntersects(bound);
else
return self.bounds.XZIntersects(bound);
}
public static float XZDistance(this IMyCollider self, Vector3 target)
{
if (self is ICapsule cap)
return cap.XZDistance(target);
if (self is IAnnular ann)
return ann.XZDistance(target);
else if (self is ICircle cir)
return cir.XZDistance(target);
else if (self is ICube cub)
return cub.XZDistance(target);
else
return self.bounds.XZDistance(target);
}
public static bool Intersects(this IMyCollider self, IMyCollider target)
{
if (self is ICapsule cap)
{
if (target is ICapsule tcap)
return cap.Intersects(tcap);
if (target is ICircle tcir)
return cap.Intersects(tcir);
if (target is ICube tcub)
return cap.Intersects(tcub);
return cap.Intersects(target.bounds);
}
else if (self is ICircle cir)
{
if (target is ICapsule tcap)
return tcap.Intersects(cir);
if (target is ICircle tcir)
return cir.Intersects(tcir);
if (target is ICube tcub)
return cir.Intersects(tcub);
return cir.Intersects(target.bounds);
}
else if (self is ICube cub)
{
if (target is ICapsule tcap)
return tcap.Intersects(cub);
if (target is ICircle tcir)
return tcir.Intersects(cub);
if (target is ICube tcub)
return cub.Intersects(tcub);
return cub.Intersects(target.bounds);
}
return target.bounds.Intersects(self.bounds);
}
public static float Distance(this IMyCollider self, Vector3 target)
{
if (self is ICapsule cap)
return cap.Distance(target);
else if (self is ICircle cir)
return cir.Distance(target);
else if (self is ICube cub)
return cub.Distance(target);
else
return self.bounds.Distance(target);
}
#region XZ坐标系内
#region 胶囊体
public static bool XZIntersects(this ICapsule capsule, IMyCollider target)
{
if (target is ICapsule tcap)
return capsule.XZIntersects(tcap);
if (target is IAnnular tann)
return capsule.XZIntersects(tann);
if (target is ICircle tcir)
return capsule.XZIntersects(tcir);
if (target is ICube tcub)
return capsule.XZIntersects(tcub);
return capsule.XZIntersects(target.bounds);
}
public static bool XZIntersects(this ICapsule capsule1, ICapsule capsule2)
{
return XZIntersectsCircle(capsule1.center, capsule1.radius, capsule2.center, capsule2.radius);
}
public static bool XZIntersects(this ICapsule capsule, IAnnular annular)
{
return annular.XZIntersects((ICircle)capsule);
}
public static bool XZIntersects(this ICapsule capsule, ICircle circle)
{
return XZIntersectsCircle(capsule.center, capsule.radius, circle.center, circle.radius);
}
public static bool XZIntersects(this ICapsule capsule, ICube cube)
{
return ((ICircle)capsule).XZIntersects(cube);
}
public static bool XZIntersects(this ICapsule capsule, Bounds bound)
{
return (capsule as ICircle).XZIntersects(bound);
}
public static float XZDistance(this ICapsule capsule, Vector3 vec)
{
return (capsule as ICircle).XZDistance(vec);
}
#endregion
#region 环形
public static bool XZIntersects(this IAnnular annular, IMyCollider target)
{
if (target is ICapsule tcap)
return tcap.XZIntersects(annular);
if (target is IAnnular tann)
return annular.XZIntersects(tann);
if (target is ICircle tcir)
return annular.XZIntersects(tcir);
if (target is ICube tcub)
return annular.XZIntersects(tcub);
return annular.XZIntersects(target.bounds);
}
public static bool XZIntersects(this IAnnular annular1, IAnnular annular2)
{
return XZIntersectsCircle(annular1.center, annular1.radius, annular2.center, annular2.radius);
}
public static bool XZIntersects(this IAnnular annular, ICircle circle)
{
if (!XZIntersectsCircle(annular.center, annular.radius, circle.center, circle.radius)) return false;
Vector3 dir = annular.dir;
Vector3 vec = circle.center - annular.center;
dir.y = 0;
vec.y = 0;
if (Vector3.Angle(dir, vec) <= annular.radian / 2) return true;
dir = dir.normalized * annular.radius;
dir = dir.Rotate(Vector3.up * annular.radian / 2);
if (circle.XZIntersects(annular.center, annular.center + dir)) return true;
dir = dir.Rotate(-Vector3.up * annular.radian);
return circle.XZIntersects(annular.center, annular.center + dir);
}
public static bool XZIntersects(this IAnnular annular, ICube cube)
{
return ((ICircle)annular).XZIntersects(cube);
}
public static bool XZIntersects(this IAnnular annular, Bounds bound)
{
return (annular as ICircle).XZIntersects(bound);
}
#endregion
#region 圆
public static bool XZIntersects(this ICircle circle, IMyCollider target)
{
if (target is ICapsule tcap)
return tcap.XZIntersects(circle);
if (target is IAnnular tann)
return tann.XZIntersects(circle);
if (target is ICircle tcir)
return circle.XZIntersects(tcir);
if (target is ICube tcub)
return circle.XZIntersects(tcub);
return circle.XZIntersects(target.bounds);
}
public static bool XZIntersects(this ICircle circle1, ICircle circle2)
{
return XZIntersectsCircle(circle1.center, circle1.radius, circle2.center, circle2.radius);
}
public static bool XZIntersects(this ICircle circle, ICube cube)
{
Vector3 newC = circle.center.RotatePointAroundPivot(cube.center, -cube.angle);
Vector3 v = (newC - cube.center).Abs();
Vector3 u = (v - cube.size / 2).ClampMin(0);
u.y = 0;
return Vector3.Dot(u, u) <= circle.radius * circle.radius;
}
public static bool XZIntersects(this ICircle circle, Bounds bound)
{
Vector3 v = (circle.center - bound.center).Abs();
Vector3 u = (v - bound.extents).ClampMin(0);
u.y = 0;
return Vector3.Dot(u, u) <= circle.radius * circle.radius;
}
public static float XZDistance(this ICircle circle, Vector3 vec)
{
Vector3 v = circle.center - vec;
v.y = 0;
return v.magnitude - circle.radius;
}
public static bool XZIntersects(this ICircle circle, Vector3 lStart, Vector3 lEnd)
{
Vector3 cirCenter = circle.center;
cirCenter.y = 0;
lStart.y = 0;
lEnd.y = 0;
Vector3 p1 = cirCenter.GetProjectionOnLine(lStart, lEnd);
return Vector3.Dot(p1 - cirCenter, p1 - cirCenter) <= circle.radius * circle.radius;
}
public static bool XZIntersectsCircle(Vector3 center1, float radius1, Vector3 center2, float radius2)
{
Vector3 vec = center1 - center2;
vec.y = 0;
return Vector3.Dot(vec, vec) <= Mathf.Pow(radius1 + radius2, 2);
}
#endregion
#region 方形
public static bool XZIntersects(this ICube cube, IMyCollider target)
{
if (target is ICapsule tcap)
return tcap.XZIntersects(cube);
if (target is IAnnular tann)
return tann.XZIntersects(cube);
if (target is ICircle tcir)
return tcir.XZIntersects(cube);
if (target is ICube tcub)
return cube.XZIntersects(tcub);
return cube.XZIntersects(target.bounds);
}
public static bool XZIntersects(this ICube cube1, ICube cube2)
{
float r1 = cube1.angle.y * Mathf.PI / 180;
Vector3 v1 = new Vector3(Mathf.Cos(r1), 0, -Mathf.Sin(r1));
Vector3 v2 = new Vector3(-v1.z, 0, v1.x);
float r2 = cube2.angle.y * Mathf.PI / 180;
Vector3 v3 = new Vector3(Mathf.Cos(r2), 0, -Mathf.Sin(r2));
Vector3 v4 = new Vector3(-v3.z, 0, v3.x);
Func<Vector3, Vector3, float> absDot = (v1, v2) => Mathf.Abs(Vector3.Dot(v1, v2));
Func<Vector3, Vector3, Vector3, Vector3, float> func = (extent, axis, mAxissx, mAxissz) =>
{
return (extent.x * absDot(axis, mAxissx) + extent.z * absDot(axis, mAxissz)) / 2;
};
Vector3 dis = cube1.center - cube2.center;
dis.y = 0;
return (func(cube1.size, v1, v1, v2) + func(cube2.size, v1, v3, v4) > absDot(dis, v1))
&& (func(cube1.size, v2, v1, v2) + func(cube2.size, v2, v3, v4) > absDot(dis, v2))
&& (func(cube1.size, v3, v1, v2) + func(cube2.size, v3, v3, v4) > absDot(dis, v3))
&& (func(cube1.size, v4, v1, v2) + func(cube2.size, v4, v3, v4) > absDot(dis, v4));
}
public static bool XZIntersects(this ICube cube, Bounds bound)
{
return cube.XZIntersects((Cube)bound);
}
public static float XZDistance(this ICube cube, Vector3 vec)
{
Vector3 v = vec.RotatePointAroundPivot(cube.center, -cube.angle);
v = (cube.center - v).Abs();
Vector3 u = v - cube.size / 2;
if (u.x > 0 && u.z > 0)
return Mathf.Sqrt(u.x * u.x + u.z * u.z);
return Mathf.Max(u.x, u.z);
}
#endregion
#region Bounds
public static bool XZContains(this Bounds container, Bounds bound)
{
return container.XZContains(bound.max) && container.XZContains(bound.min)
&& container.XZContains(new Vector3(bound.center.x - bound.extents.x, 0, bound.center.z + bound.extents.z))
&& container.XZContains(new Vector3(bound.center.x + bound.extents.x, 0, bound.center.z - bound.extents.z));
}
public static bool XZContains(this Bounds container, Vector3 point)
{
return container.max.x >= point.x && container.min.x <= point.x && container.max.z >= point.z && container.min.z <= point.z;
}
public static bool XZIntersects(this Bounds bound1, Bounds bound2)
{
return bound1.min.x <= bound2.max.x && bound1.max.x >= bound2.min.x && bound1.min.z <= bound2.max.z && bound1.max.z >= bound2.min.z;
}
public static float XZDistance(this Bounds bound, Vector3 vec)
{
Vector3 v = (bound.center - vec).Abs();
Vector3 u = v - bound.extents;
if (u.x > 0 && u.z > 0)
return Mathf.Sqrt(u.x * u.x + u.z * u.z);
return Mathf.Max(u.x, u.z);
}
public static bool XZIntersects(this Bounds bound, Vector3 center, float radius)
{
Vector3 extents = new Vector3(radius, 0, radius);
Vector3 max = center + extents;
Vector3 min = center - extents;
return bound.min.x <= max.x && bound.max.x >= min.x && bound.min.z <= max.z && bound.max.z >= min.z;
}
#endregion
#endregion
#region 3D坐标系内
#region 胶囊体
public static bool Intersects(this ICapsule capsule1, ICapsule capsule2)
{
Vector3Extension.GetCommonPerpendicular(capsule1.point1, capsule1.point2, capsule2.point1, capsule2.point2, out Vector3 point1, out Vector3 point2);
return IntersectsCircle(point1, capsule1.radius, point2, capsule2.radius);
}
public static bool Intersects(this ICapsule capsule, ICircle circle)
{
Vector3 newCenter = circle.center.GetProjectionOnLine(capsule.point1, capsule.point2);
return IntersectsCircle(circle.center, circle.radius, newCenter, capsule.radius);
}
public static bool Intersects(this ICapsule capsule, ICube cube)
{
return capsule.Intersects(cube.bounds);
}
public static bool Intersects(this ICapsule capsule, IMyCollider collider)
{
return capsule.Intersects(collider.bounds);
}
public static bool Intersects(this ICapsule capsule, Bounds bound)
{
Vector3 newCenter = bound.center.GetProjectionOnLine(capsule.point1, capsule.point2);
return new Circle { center = newCenter, radius = capsule.radius }.Intersects(bound);
}
public static float Distance(this ICapsule capsule, Vector3 vec)
{
Vector3 newCenter = vec.GetProjectionOnLine(capsule.point1, capsule.point2);
return new Circle { center = newCenter, radius = capsule.radius }.Distance(vec);
}
#endregion
#region 球体
public static bool Intersects(this ICircle circle1, ICircle circle2)
{
return IntersectsCircle(circle1.center, circle1.radius, circle2.center, circle2.radius);
}
public static bool Intersects(this ICircle circle, ICube cube)
{
return circle.Intersects(cube.bounds);
}
public static bool Intersects(this ICircle circle, IMyCollider collider)
{
return circle.Intersects(collider.bounds);
}
public static bool Intersects(this ICircle circle, Bounds bound)
{
Vector3 v = (circle.center - bound.center).Abs();
Vector3 u = (v - bound.extents).ClampMin(0);
return Vector3.Dot(u, u) <= circle.radius * circle.radius;
}
public static float Distance(this ICircle circle, Vector3 vec)
{
Vector3 v = circle.center - vec;
return v.magnitude - circle.radius;
}
public static bool IntersectsCircle(Vector3 center1, float radius1, Vector3 center2, float radius2)
{
Vector3 vec = center1 - center2;
return Vector3.Dot(vec, vec) <= (radius1 + radius2) * (radius1 + radius2);
}
#endregion
#region 方形
public static bool Intersects(this ICube cube, ICube cube2)
{
return cube.Intersects(cube2.bounds);
}
public static bool Intersects(this ICube cube, IMyCollider collider)
{
return cube.Intersects(collider.bounds);
}
public static bool Intersects(this ICube cube, Bounds bound)
{
return cube.bounds.Intersects(bound);
}
public static float Distance(this ICube cube, Vector3 vec)
{
return cube.bounds.Distance(vec);
}
#endregion
public static float Distance(this Bounds bound, Vector3 vec)
{
Vector3 v = vec - bound.center;
v.x = (Mathf.Abs(v.x));
v.y = (Mathf.Abs(v.y));
v.z = (Mathf.Abs(v.z));
Vector3 u = v - bound.extents;
int i = 0;
i += v.x >= 0 ? 1 : 0;
i += v.y >= 0 ? 1 : 0;
i += v.z >= 0 ? 1 : 0;
if (i < 2)
return Mathf.Max(v.x, v.y, v.z);
float dis = 0;
dis += Mathf.Pow(Mathf.Max(v.x, 0), 2);
dis += Mathf.Pow(Mathf.Max(v.y, 0), 2);
dis += Mathf.Pow(Mathf.Max(v.z, 0), 2);
return Mathf.Sqrt(dis);
}
#endregion
}