2d物理引擎学习 - 圆与圆碰撞信息计算
碰撞情况分析
球1向上运动,球2向下运动
1) 如果它们速度不快,碰撞的瞬间,碰撞点可能就在球的边缘上(红色点为碰撞点,绿色箭头为碰撞法向量)
2) 如果它们速度很快,碰撞的瞬间,两球可能就发生重叠(穿插),碰撞点就到球的里面去了
在物理引擎中,需要用到的碰撞信息包括:
1) 碰撞点。主要用于旋转运动相关的计算。
2) 分离向量(即:碰撞法向量+穿透深度),沿着分离向量可以将两物体分开
计算
1) 碰撞法向量为两圆圆心连线方向
2) 穿透深度为两圆的半径和减去两圆圆心距离
3) 碰撞点在穿透深度的中点处
using UnityEditor; using UnityEngine; public class MyCricleContact : MonoBehaviour { public MyCircle m_C1; public MyCircle m_C2; public Vector2 m_C1MoveDir = Vector2.up; //展示圆1移动方向 public Vector2 m_C2MoveDir = Vector2.down; //展示圆2移动方向 public Vector2 m_Normal; //碰撞法向量 public float m_Penetration; //穿透深度 public Vector2 m_Point; //碰撞点 #if UNITY_EDITOR private void OnDrawGizmos() { if (m_C1 && m_C2) { var c1Trans = m_C1.transform; var c2Trans = m_C2.transform; Gizmos.color = Color.gray; Gizmos.DrawLine(c1Trans.position, c2Trans.position); Gizmos.color = Color.blue; DrawArrowLine(c1Trans.position, m_C1MoveDir, m_C1.m_Radius * 0.6f, 0.03f); //c1运动方向 DrawArrowLine(c2Trans.position, m_C2MoveDir, m_C2.m_Radius * 0.6f, 0.03f); //c2运动方向 float totalR = (m_C1.m_Radius + m_C2.m_Radius); var circleDistVec = c2Trans.position - c1Trans.position; //圆心距离向量 m_Penetration = totalR - circleDistVec.magnitude; //穿透深度 if (m_Penetration > 0) //发生碰撞了 { m_Normal = circleDistVec.normalized; //碰撞法线为圆心连线方向 m_Point = (Vector2)c1Trans.position + m_Normal * (m_C1.m_Radius - m_Penetration * 0.5f); //碰撞点在穿透向量中点处 Gizmos.color = Color.green; DrawArrowLine(m_Point, m_Normal, 0.15f, 0.03f); //碰撞法线方向 Handles.color = Color.red; Handles.DrawSolidDisc(m_Point, Vector3.back, 0.018f); //碰撞点 } else { m_Penetration = 0; m_Normal = Vector2.zero; m_Point = Vector2.zero; } Handles.color = Color.white; Gizmos.color = Color.white; } } public static void DrawArrowLine(Vector2 start, Vector2 dir, float len, float size = 0.2f) { var end = start + dir * len; Gizmos.DrawLine(start, end); Vector2 arrowLineDirCCW = Quaternion.Euler(0, 0, 150) * dir * size; Gizmos.DrawLine(end, end + arrowLineDirCCW); Vector2 arrowLineDirCW = Quaternion.Euler(0, 0, -150) * dir * size; Gizmos.DrawLine(end, end + arrowLineDirCW); } #endif }
using UnityEngine; public class MyCircle : MonoBehaviour { protected MyRigidbody m_Rigidbody; //关联的刚体 public float m_Radius; public MyCircle() {} public MyCircle(float r) { m_Radius = r; } #if UNITY_EDITOR public bool m_ShowRadius; private void OnDrawGizmos() { var trans = this.transform; DrawCircle(trans.position, m_Radius); if (m_ShowRadius) Gizmos.DrawLine(trans.position, trans.TransformPoint(Vector3.right * m_Radius)); } public static void DrawCircle(Vector2 c, float r) { int segmentCount = 30; float radDelta = Mathf.PI * 2 / segmentCount; float rad = 0; var lastPoint = new Vector2(r * Mathf.Cos(rad), r * Mathf.Sin(rad)); for (int i = 1; i <= segmentCount; ++i) { rad += radDelta; var curPoint = new Vector2(r * Mathf.Cos(rad), r * Mathf.Sin(rad)); Gizmos.DrawLine(c + lastPoint, c + curPoint); lastPoint = curPoint; } } #endif }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端