diff options
Diffstat (limited to 'marching/Assets/Scripts/Physics')
5 files changed, 185 insertions, 16 deletions
diff --git a/marching/Assets/Scripts/Physics/PhysicsManager.cs b/marching/Assets/Scripts/Physics/PhysicsManager.cs index 164d62b..1663410 100644 --- a/marching/Assets/Scripts/Physics/PhysicsManager.cs +++ b/marching/Assets/Scripts/Physics/PhysicsManager.cs @@ -6,14 +6,14 @@ using UnityEngine; public enum ColliderType { - Collider, + Collider, Hurtbox, Hitbox, } public partial class PhysicsManager : Singleton<PhysicsManager> { - + // 四叉树筛选结果 public List<IQuadTreeObject> sharedRetriveResults => m_SharedRetriveResults; private List<IQuadTreeObject> m_SharedRetriveResults = new List<IQuadTreeObject>(); diff --git a/marching/Assets/Scripts/Physics/PhysicsManager_Collide.cs b/marching/Assets/Scripts/Physics/PhysicsManager_Collide.cs index 7b4aa1c..4710b2e 100644 --- a/marching/Assets/Scripts/Physics/PhysicsManager_Collide.cs +++ b/marching/Assets/Scripts/Physics/PhysicsManager_Collide.cs @@ -3,34 +3,50 @@ using System.Collections; using System.Collections.Generic; using Unity.VisualScripting.Antlr3.Runtime.Tree; using UnityEngine; +using UnityEngine.UIElements; +/// <summary> +/// 物理查询 +/// </summary> public partial class PhysicsManager : Singleton<PhysicsManager> { + // 碰撞检测结果 private List<IQuadTreeObject> m_SharedCollideResults = new List<IQuadTreeObject>(); - public Vector4 GetCircleBound(Vector3 circle) + public static Vector4 GetCircleBound(Vector3 circle) { float size = circle.z * 2; return new Vector4(circle.x, circle.y, size, size); } - public Vector4 GetBoxBound(Vector4 box) + public static Vector4 GetBoxBound(Vector4 box) { return box; } - public Vector4 GetRayBound(Vector4 line, float maxLen=20f) + public static Vector4 GetRayBound(Vector4 ray) { - Vector2 tr = line.xy() + maxLen * line.zw().normalized; + Vector2 tr = ray.xy() + ray.zw(); Vector4 bound = new Vector4(); - bound.x = (tr.x + line.x) / 2; - bound.y = (tr.y + line.y) / 2; - bound.z = Mathf.Abs(tr.x - line.x); - bound.w = Mathf.Abs(tr.y - line.y); + bound.x = (tr.x + ray.x) / 2; + bound.y = (tr.y + ray.y) / 2; + bound.z = Mathf.Max(Mathf.Abs(tr.x - ray.x), 1); + bound.w = Mathf.Max(Mathf.Abs(tr.y - ray.y), 1); return bound; } - public Vector4 GetPointBound(Vector2 point) + public static Vector4 GetRaySegment(Vector4 ray) + { + Vector2 tr = ray.xy() + ray.zw(); + Vector4 seg = new Vector4(); + seg.x = ray.x; + seg.y = ray.y; + seg.z = tr.x; + seg.w = tr.y; + return seg; + } + + public static Vector4 GetPointBound(Vector2 point) { Vector4 bound = new Vector4(); bound.x = point.x; @@ -40,6 +56,20 @@ public partial class PhysicsManager : Singleton<PhysicsManager> return bound; } + /// <summary> + /// 把x,y,w,h的box转换为lowerx,higherx,lowery,highery + /// </summary> + /// <returns></returns> + public static Vector4 GetBoxRange(Vector4 box) + { + Vector4 Range = new(); + Range.x = box.x - box.z / 2; + Range.y = box.x + box.z / 2; + Range.z = box.y - box.w / 2; + Range.w = box.y + box.w / 2; + return Range; + } + public ref readonly List<IQuadTreeObject> CircleCast(ColliderType target, Vector3 circle) { m_SharedCollideResults.Clear(); @@ -109,13 +139,42 @@ public partial class PhysicsManager : Singleton<PhysicsManager> } /// <summary> - /// x,y dir.x dir.y + /// x,y dir.x dir.y(dir带长度) /// </summary> /// <param name="target"></param> /// <param name="line"></param> /// <returns></returns> - public ref readonly List<IQuadTreeObject> RayCast(ColliderType target, Vector4 ray, float maxLength = 20f) + public ref readonly List<IQuadTreeObject> RayCast(ColliderType target, Vector4 ray) { + m_SharedCollideResults.Clear(); + var retriver = GetRetriverByType(target); + if(retriver != null) + { + if(retriver(GetRayBound(ray))) + { + for (int i = 0; i < m_SharedRetriveResults.Count; ++i) + { + var collider = m_SharedRetriveResults[i]; + if (collider != null) + { + if (collider is FastCircleCollider) + { + if (RayVsCircle(ray, (collider as FastCircleCollider).circle)) + { + m_SharedCollideResults.Add(collider); + } + } + else if (collider is FastBoxCollider) + { + if (RayVsBox(ray, (collider as FastBoxCollider).box)) + { + m_SharedCollideResults.Add(collider); + } + } + } + } + } + } return ref m_SharedCollideResults; } diff --git a/marching/Assets/Scripts/Physics/PhysicsManager_CollisionDetection.cs b/marching/Assets/Scripts/Physics/PhysicsManager_CollisionDetection.cs index a0dcc97..5210767 100644 --- a/marching/Assets/Scripts/Physics/PhysicsManager_CollisionDetection.cs +++ b/marching/Assets/Scripts/Physics/PhysicsManager_CollisionDetection.cs @@ -1,7 +1,11 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; +using static UnityEditor.Rendering.CameraUI; +/// <summary> +/// 碰撞检测 +/// </summary> public partial class PhysicsManager : Singleton<PhysicsManager> { @@ -70,6 +74,88 @@ public partial class PhysicsManager : Singleton<PhysicsManager> return Vector2.Dot(u, u) < radius * radius; } + public static bool RayVsCircle(Vector4 ray, Vector3 circle) + { + Vector4 seg = GetRaySegment(ray); + Vector2 dir = ray.zw().normalized; + Vector2 center = circle.xy(); + float u = Vector2.Dot(center - seg.xy(), dir); + Vector2 near = new Vector2(); + if(u <= 0) + { + near = seg.xy(); + } + else if(u >= ray.zw().magnitude) + { + near = seg.zw(); + } + else + { + near = seg.xy() + dir * u; + } + return (near - center).sqrMagnitude <= circle.z * circle.z; + } + + + // From Real-time Collision Detection, p179 + // box2d + public static bool RayVsBox(Vector4 ray, Vector4 box) + { + float tmin = float.MinValue; + float tmax = float.MaxValue; + Vector2 dir = ray.zw().normalized; + Vector4 range = GetBoxRange(box); //lowerx,higherx,lowery,highery + Vector2 lowerBound = new Vector2(range.x, range.z); + Vector2 upperBound = new Vector2(range.y, range.w); + //Vector2 normal = new Vector2(); + Vector2 p = ray.xy(); + + for (int i = 0; i < 2; ++i) + { + + if (dir[i] < float.Epsilon) // 和x-slab平行 + { + if (p[i] < lowerBound[i] || p[i] > upperBound[i]) + { + return false; + } + } + else + { + float inv_d = 1f / dir[i]; + float t1 = (lowerBound[i] - p[i]) * inv_d; + float t2 = (upperBound[i] - p[i]) * inv_d; + float s = -1f; + if (t1 > t2) + { + MathUtils.Swap(ref t1, ref t2); + s = 1f; + } + if (t1 > tmin) + { + //normal = Vector2.zero; + //normal[i] = s; + tmin = t1; + } + + tmax = Mathf.Min(tmax, t2); + + if (tmin > tmax) + { + return false; + } + } + } + + if (tmin < 0 || ray.zw().magnitude < tmin) + return false; + //// Intersection. + //output->fraction = tmin; + //output->normal = normal; + + return true; + } + /// <summary> /// box x,y,w,h circle x,y,raduis /// </summary> diff --git a/marching/Assets/Scripts/Physics/PhysicsQuadtree.cs b/marching/Assets/Scripts/Physics/PhysicsQuadtree.cs index f4bad27..5cd374e 100644 --- a/marching/Assets/Scripts/Physics/PhysicsQuadtree.cs +++ b/marching/Assets/Scripts/Physics/PhysicsQuadtree.cs @@ -8,9 +8,20 @@ using UnityEngine; /// </summary> class PhysicsQuadtree { + /// <summary> + /// 杈圭晫 + /// </summary> public Vector4 quadtreeRange { set { m_QuadtreeRange = value; } } private Vector4 m_QuadtreeRange; + + /// <summary> + /// 鏍硅妭鐐 + /// </summary> private Quadtree m_Quadtree; + + /// <summary> + /// 鎵樼鐨勫叏閮ㄥ璞★紝浣嗕笉涓瀹氫細鍔犲叆鍒版爲閲岄潰锛堜腑蹇冪偣鍦ㄨ竟鐣屽鐨勪笉鍔犲叆鏍戯級 + /// </summary> private List<IQuadTreeObject> m_Objects = new List<IQuadTreeObject>(); public PhysicsQuadtree(Vector4 range) @@ -33,12 +44,17 @@ class PhysicsQuadtree { m_Quadtree.Clear(false); m_Quadtree.Rebound(m_QuadtreeRange); + InsertAllObjects(); + } + + private void InsertAllObjects() + { Vector4 bound = m_Quadtree.bound; for (int i = 0; i < m_Objects.Count; i++) { IQuadTreeObject obj = m_Objects[i]; // 绠鍗曠殑蹇界暐涓績鍦ㄨ竟鐣屽鐨刼bject - if(PhysicsManager.IsPointInsideBox(bound, obj.bound.xy())) + if (PhysicsManager.IsPointInsideBox(bound, obj.bound.xy())) { m_Quadtree.Insert(obj); } diff --git a/marching/Assets/Scripts/Physics/Quadtree.cs b/marching/Assets/Scripts/Physics/Quadtree.cs index 9f8ecba..a012d26 100644 --- a/marching/Assets/Scripts/Physics/Quadtree.cs +++ b/marching/Assets/Scripts/Physics/Quadtree.cs @@ -29,7 +29,7 @@ namespace mh private int m_Level; private Vector4 m_Bounds; // x,y,z,w => posx,posy,width,height private Quadtree[] m_SubTrees; // 从右上角开始逆时针索引 - private List<IQuadTreeObject> m_Objects; // 当前层能容纳,但任何一个子树都无法容纳的对象 + private List<IQuadTreeObject> m_Objects; // 非叶节点的为0 private bool m_IsRoot; public Vector4 bound { get { return m_Bounds; } } @@ -47,7 +47,6 @@ namespace mh public bool isRoot { get { return m_IsRoot; } } private static Queue<List<IQuadTreeObject>> m_QuadtreeObjPool = new Queue<List<IQuadTreeObject>>(); - private static Queue<Quadtree> m_QuadtreePool = new Queue<Quadtree>(); private Quadtree QueryQuadtree(int level, Vector4 bounds) @@ -97,8 +96,17 @@ namespace mh m_IsRoot = isRoot; } + /// <summary> + /// 更改边界,只适用于最外层的tree + /// </summary> + /// <param name="bounds"></param> public void Rebound(Vector4 bounds) { + if(!m_IsRoot) + { + Debug.LogError("Quadtree.Rebound()只能运用于最外层"); + return; + } m_Bounds = bounds; } |