From 65ed53a40f990e895305ff17a5e48e3cd6b8785b Mon Sep 17 00:00:00 2001 From: chai Date: Sat, 24 Oct 2020 17:30:07 +0800 Subject: =?UTF-8?q?*=E7=89=A9=E7=90=86=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Scripts/Physics/PhysicsBody.cs | 4 + Assets/Scripts/Physics/PhysicsBox.cs | 76 +++++++++++----- Assets/Scripts/Physics/PhysicsHelper.cs | 47 ++++++---- Assets/Scripts/Physics/PhysicsPrimitive.cs | 28 ++++-- Assets/Scripts/Physics/PhysicsWorld.cs | 134 ++++++++++++++++++++++++++--- 5 files changed, 229 insertions(+), 60 deletions(-) (limited to 'Assets/Scripts/Physics') diff --git a/Assets/Scripts/Physics/PhysicsBody.cs b/Assets/Scripts/Physics/PhysicsBody.cs index ff5972b4..84a5fcb0 100644 --- a/Assets/Scripts/Physics/PhysicsBody.cs +++ b/Assets/Scripts/Physics/PhysicsBody.cs @@ -29,6 +29,10 @@ public sealed class PhysicsBody : MonoBehaviour { return m_Velocity; } + set + { + m_Velocity = value; + } } [SerializeField] diff --git a/Assets/Scripts/Physics/PhysicsBox.cs b/Assets/Scripts/Physics/PhysicsBox.cs index 8c93a1e1..f8b4fee4 100644 --- a/Assets/Scripts/Physics/PhysicsBox.cs +++ b/Assets/Scripts/Physics/PhysicsBox.cs @@ -7,30 +7,62 @@ using UnityEngine; /// public class PhysicsBox : PhysicsPrimitive { - public override PrimitiveType Type - { - get - { - return PrimitiveType.Box; - } - } + public override PrimitiveType Type + { + get + { + return PrimitiveType.Box; + } + } - [SerializeField] - private Vector3 m_Size; - public Vector3 Size - { - get - { - return m_Size; - } - } + [SerializeField] + private Vector3 m_Size; + public Vector3 Size + { + get + { + return m_Size; + } + } - public float Long { get { return m_Size.x; } } - public float Wide { get { return m_Size.y; } } - public float Height { get { return m_Size.z; } } + public float Long { get { return m_Size.x; } } + public float Wide { get { return m_Size.z; } } + public float Height { get { return m_Size.y; } } public bool m_DrawGizmo = true; + public float Top + { + get + { + return Position.y + Height / 2f; + } + } + + public float Left + { + get + { + return Position.x - Long / 2f; + } + } + + public float Right + { + get + { + return Position.x + Long / 2f; + } + } + + public float Bottom + { + get + { + return Position.y - Height / 2f; + } + } + public void OnDrawGizmos() { if (!m_IsActive || !m_DrawGizmo) @@ -38,9 +70,11 @@ public class PhysicsBox : PhysicsPrimitive Vector3 pos = Position; Gizmos.color = m_HintColor; Gizmos.DrawCube(pos, m_Size); - } + //Gizmos.color = Color.blue; + //Gizmos.DrawSphere(pos, 0.1f); + } - private void Start() + private void Start() { base.OnInit(); } diff --git a/Assets/Scripts/Physics/PhysicsHelper.cs b/Assets/Scripts/Physics/PhysicsHelper.cs index 0bd11ba7..821241e3 100644 --- a/Assets/Scripts/Physics/PhysicsHelper.cs +++ b/Assets/Scripts/Physics/PhysicsHelper.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using UnityEngine; -enum CollisionType +public enum CollisionType { BallvsBall = 1, BallvsBox, @@ -13,12 +13,12 @@ enum CollisionType /// /// 碰撞的信息 /// -public class PhysicsCollisionInfo +public struct PhysicsCollisionInfo { - CollisionType type; - PhysicsPrimitive prim1; - PhysicsPrimitive prim2; - Vector3 contacts; + public CollisionType type; + public PhysicsPrimitive prim1; + public PhysicsPrimitive prim2; + public Vector3 contact; } public sealed class PhysicsHelper @@ -44,22 +44,33 @@ public sealed class PhysicsHelper return false; } - public static bool BallvsBall2D(PhysicsBall ball1, PhysicsBall ball2, out PhysicsCollisionInfo info) + public static bool BallvsBall2D(PhysicsBall ball1, PhysicsBall ball2, ref PhysicsCollisionInfo info) { - info = null; return true; } - public static bool BoxvsBox2D(PhysicsBox box1, PhysicsBox box2, out PhysicsCollisionInfo info) + public static bool BoxvsBox2D(PhysicsBox box1, PhysicsBox box2, ref PhysicsCollisionInfo info) { - info = null; - return true; + if(box1.Left < box2.Right && box1.Right > box2.Left && box1.Bottom < box2.Top && box1.Top > box2.Bottom) + { + info.type = CollisionType.BoxvsBox; + info.prim1 = box1; + info.prim2 = box2; + + float left = Mathf.Max(box1.Left, box2.Left); + float right = Mathf.Min(box1.Right, box2.Right); + float top = Mathf.Min(box1.Top, box2.Top); + float bottom = Mathf.Max(box1.Bottom, box2.Bottom); + info.contact = new Vector3((left + right )/2f, (top + bottom)/2f, 0 ); + + return true; + } + return false; } - public static bool BallvsBox2D(PhysicsBall ball, PhysicsBox box, out PhysicsCollisionInfo info) + public static bool BallvsBox2D(PhysicsBall ball, PhysicsBox box, ref PhysicsCollisionInfo info) { - info = null; return true; } @@ -78,21 +89,21 @@ public sealed class PhysicsHelper return false; } - public static bool PrimvsPrim(PhysicsPrimitive prim1, PhysicsPrimitive prim2, out PhysicsCollisionInfo info) + public static bool PrimvsPrim(PhysicsPrimitive prim1, PhysicsPrimitive prim2, ref PhysicsCollisionInfo info) { if(prim1.Type == PrimitiveType.Ball) { if (prim2.Type == PrimitiveType.Ball) - return BallvsBall2D(prim1 as PhysicsBall, prim2 as PhysicsBall, out info); + return BallvsBall2D(prim1 as PhysicsBall, prim2 as PhysicsBall, ref info); else - return BallvsBox2D(prim1 as PhysicsBall, prim2 as PhysicsBox, out info); + return BallvsBox2D(prim1 as PhysicsBall, prim2 as PhysicsBox, ref info); } else { if (prim2.Type == PrimitiveType.Ball) - return BallvsBox2D(prim2 as PhysicsBall, prim1 as PhysicsBox, out info); + return BallvsBox2D(prim2 as PhysicsBall, prim1 as PhysicsBox, ref info); else - return BoxvsBox2D(prim1 as PhysicsBox, prim2 as PhysicsBox, out info); + return BoxvsBox2D(prim1 as PhysicsBox, prim2 as PhysicsBox, ref info); } } diff --git a/Assets/Scripts/Physics/PhysicsPrimitive.cs b/Assets/Scripts/Physics/PhysicsPrimitive.cs index 59c56aaf..f52fb9e9 100644 --- a/Assets/Scripts/Physics/PhysicsPrimitive.cs +++ b/Assets/Scripts/Physics/PhysicsPrimitive.cs @@ -30,15 +30,15 @@ public abstract class PhysicsPrimitive : MonoBehaviour { get { - return transform.TransformPoint(m_Center); + Vector3 euler = Quaternion.ToEulerAngles(transform.rotation); + euler.y = Mathf.Rad2Deg * euler.y; + Vector3 res = m_Center; + res.x = (euler.y > 90 && euler.y <= 180) ? -res.x : res.x; + res = transform.position + res; + return res; } } - /// - /// 中心点在本地空间的位置 - /// - public Vector3 m_Center; - [SerializeField] /// /// 这个primitive是否参与物理计算,用来快速给物体取消和恢复重力影响 @@ -124,6 +124,7 @@ public abstract class PhysicsPrimitive : MonoBehaviour protected void OnInit() { m_ID = UIDManager.Acquire(); + PhysicsWorld.Instance.AddPrimitive(this); } protected Color Color_Green = new Color(0,1, 0, 0.5f); @@ -133,6 +134,19 @@ public abstract class PhysicsPrimitive : MonoBehaviour [Tooltip("Physics body, leave blank and primitive will be static.")] [SerializeField] - protected PhysicsBody m_Body; + protected PhysicsBody m_Body; + + public PhysicsBody Body + { + get + { + return m_Body; + } + } + + /// + /// 中心点在本地空间的位置 + /// + public Vector3 m_Center; } \ No newline at end of file diff --git a/Assets/Scripts/Physics/PhysicsWorld.cs b/Assets/Scripts/Physics/PhysicsWorld.cs index c2397909..7994e14b 100644 --- a/Assets/Scripts/Physics/PhysicsWorld.cs +++ b/Assets/Scripts/Physics/PhysicsWorld.cs @@ -12,6 +12,9 @@ public enum PhysicsGroup Ground, // 地面 Wall, // 墙面 + HitBox, // hitbox + HurtBox, // hurtbox + GroupCount, } @@ -20,6 +23,7 @@ public enum PhysicsGroup /// public enum PhysicsTag { + Null = 0, Player = 1, // 从属于玩家 Oponent = 1 << 1, // 从属于对手 } @@ -28,21 +32,28 @@ public class PhysicsWorld : Singleton { private int m_UpdateRate = 60; // 重力加速度 - private readonly Vector3 m_Gravity = new Vector3(0, -9.8f, 0); + private readonly Vector3 m_Gravity = new Vector3(0, -12f, 0); // 当前管理的碰撞体 private List m_Primitives = new List(); private float m_TimeCount; + private const int _ = 0; private readonly int[] m_CollisionTable = { - // wall ground prop character -/*character*/ 1, 1, 1, 1, -/*prop */ 1, 1, 0, 0, -/*ground */ 0, 0, 0, 0, -/*wall */ 0, 0, 0, 0, + // hurtbox hitBox wall ground prop character +/*character*/ 0, 0, 1, 1, 1, 1, +/*prop */ 0, 0, 1, 1, 0, _, +/*ground */ 0, 0, 0, 0, _, _, +/*wall */ 0, 0, 0, _, _, _, +/*hitbox */ 1, 0, _, _, _, _, +/*hurtbox */ 0, _, _, _, _, _, }; private List m_Animators = new List(); + private List m_Contacts = new List(); + + private List m_CollisionInfo = new List(); + public void Init() { m_TimeCount = Time.time; @@ -85,6 +96,7 @@ public class PhysicsWorld : Singleton /// public void Update() { + BeforeUpdate(); float preTime = m_TimeCount; m_TimeCount = Time.time; float dt = m_TimeCount - preTime; @@ -94,9 +106,35 @@ public class PhysicsWorld : Singleton dt -= 1f / m_UpdateRate; } m_TimeCount -= dt; + AfterUpdate(); } - void Tick() + // 更新之前 + private void BeforeUpdate() + { + m_CollisionInfo.Clear(); + } + + // 更新之后 + private void AfterUpdate() + { + + } + + public void DrawGizmos() + { + if (m_Contacts.Count == 0) + return; + + for(int i = 0; i < m_Contacts.Count; ++i) + { + Vector3 center = m_Contacts[i]; + Gizmos.DrawSphere(center, 0.05f); + } + } + + + void Tick() { float deltaTime = 1f / m_UpdateRate; // animator -> OnAnimatorMove() -> physics @@ -119,32 +157,100 @@ public class PhysicsWorld : Singleton // 更新物理系统 void UpdatePrimitives(float deltaTime) { + m_Contacts.Clear(); + + PhysicsCollisionInfo info = new PhysicsCollisionInfo(); + + // 处理动力学 + for(int i = 0; i < m_Primitives.Count; ++i) + { + PhysicsPrimitive prim = m_Primitives[i]; + HandleDynamics(prim, deltaTime); + } + + // 处理碰撞 int groupCount = (int)PhysicsGroup.GroupCount; for (int i = 0; i < m_Primitives.Count; ++i) { PhysicsPrimitive prim1 = m_Primitives[i]; + if (!prim1.IsActive) + continue; for (int j = i + 1; j < m_Primitives.Count; ++j) { PhysicsPrimitive prim2 = m_Primitives[j]; // check collision by group - int minType = Mathf.Min((int)prim1.Type, (int)prim2.Type); - int maxType = Mathf.Max((int)prim1.Type, (int)prim2.Type); - if (m_CollisionTable[minType * groupCount + groupCount - maxType - 1] == 0) + int minGroup = Mathf.Min((int)prim1.Group, (int)prim2.Group); + int maxGroup = Mathf.Max((int)prim1.Group, (int)prim2.Group); + if (m_CollisionTable[minGroup * groupCount + groupCount - maxGroup - 1] == 0) continue; // check collision by label if (prim1.Label == prim2.Label) continue; - PhysicsCollisionInfo info; - if (PhysicsHelper.PrimvsPrim(prim1, prim2, out info)) + if (PhysicsHelper.PrimvsPrim(prim1, prim2, ref info)) { - //没有physics body的primitive将不会被移动,只有那些绑定了physics body的会被施加物理效果,比如角色身体、物品 - + SolveCollision(prim1, info, deltaTime); + SolveCollision(prim2, info, deltaTime); + m_CollisionInfo.Add(info); + m_Contacts.Add(info.contact); } } } } + //没有physics body的primitive将不会被移动,只有那些绑定了physics body的会被施加物理效果,比如角色身体、物品 + void HandleDynamics(PhysicsPrimitive prim, float dt) + { + PhysicsBody body = prim.Body; + if (body == null) + return; + if (!body.UseGravity) + return; + + Vector3 position = body.transform.position; + + Vector3 velocity = body.Velocity; + velocity += m_Gravity * dt; + body.Velocity = velocity; + + position += velocity * dt; + + body.transform.position = position; + } + + void SolveCollision(PhysicsPrimitive prim, PhysicsCollisionInfo collision, float dt) + { + PhysicsBody body = prim.Body; + if (body == null) + return; + if (!body.UseGravity) + return; + Vector3 contact = collision.contact; + Vector3 dir = (prim.Position - contact).normalized; + dir.z = 0; + + float mag = Mathf.Max(0.3f, body.Velocity.magnitude); + + Vector3 position = body.transform.position; + position += mag * dir * dt; + body.Velocity = Vector3.zero; + body.transform.position = position; + } + + // prim在当前帧是否有碰撞 + public bool HasCollision(PhysicsPrimitive prim) + { + for(int i = 0; i < m_CollisionInfo.Count; ++i) + { + PhysicsCollisionInfo info = m_CollisionInfo[i]; + if(info.prim1 == prim || info.prim2 == prim) + { + return true; + } + } + return false; + } + } \ No newline at end of file -- cgit v1.1-26-g67d0