1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
|
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// primitive分类
/// </summary>
public enum PhysicsGroup
{
Character, // 角色
Prop, // 物体
Ground, // 地面
Wall, // 墙面
HitBox, // hitbox
HurtBox, // hurtbox
GroupCount,
}
/// <summary>
/// primitive标记
/// </summary>
public enum PhysicsTag
{
Null = 0,
Player = 1, // 从属于玩家
Oponent = 1 << 1, // 从属于对手
}
public class PhysicsWorld : Singleton<PhysicsWorld>
{
private int m_UpdateRate = 60;
// 重力加速度
private readonly Vector3 m_Gravity = new Vector3(0, -12f, 0);
// 当前管理的碰撞体
private List<PhysicsPrimitive> m_Primitives = new List<PhysicsPrimitive>();
private float m_TimeCount;
private const int _ = 0;
private readonly int[] m_CollisionTable = {
// 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<Animator> m_Animators = new List<Animator>();
private List<Vector3> m_Contacts = new List<Vector3>();
private List<PhysicsCollisionInfo> m_CollisionInfo = new List<PhysicsCollisionInfo>();
public void Init()
{
m_TimeCount = Time.time;
}
public void AddPrimitive(PhysicsPrimitive prim)
{
if (prim == null)
return;
if(m_Primitives.Contains(prim))
{
Debug.LogError("PhysicsWorld已经存在此碰撞体,ID=" + prim.ID + ", 类型=" + prim.Tag);
return;
}
m_Primitives.Add(prim);
}
public void RemovePrimitive(PhysicsPrimitive prim)
{
if (prim == null)
return;
m_Primitives.Remove(prim);
}
public void AddAnimator(Animator animator)
{
if (m_Animators.Contains(animator))
return;
m_Animators.Add(animator);
}
public void RemoveAnimator(Animator animator)
{
if (m_Animators.Contains(animator))
m_Animators.Remove(animator);
}
/// <summary>
/// 物理系统已稳定的逻辑帧率执行
/// </summary>
public void Update()
{
BeforeUpdate();
float preTime = m_TimeCount;
m_TimeCount = Time.time;
float dt = m_TimeCount - preTime;
while (dt > 1f / m_UpdateRate)
{
Tick();
dt -= 1f / m_UpdateRate;
}
m_TimeCount -= dt;
AfterUpdate();
}
// 更新之前
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
//UpdateAnimator(deltaTime);
UpdatePrimitives(deltaTime);
}
// 更新动画,并处理OnAnimatorMove()
void UpdateAnimator(float deltaTime)
{
for (int i = 0; i < m_Animators.Count; ++i)
{
Animator animator = m_Animators[i];
animator.speed = 1;
animator.Update(deltaTime);
animator.speed = 0;
}
}
// 更新物理系统
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 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;
if (PhysicsHelper.PrimvsPrim(prim1, prim2, ref info))
{
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;
}
}
|