Skip to content

Commit 6ef7ad0

Browse files
authoredMay 14, 2020
Collision detection - #9343 follow-up (#9764)
* truncate speed to prevent inf result * code styling * change truncate() input parameters
1 parent 836dd4a commit 6ef7ad0

File tree

1 file changed

+69
-52
lines changed

1 file changed

+69
-52
lines changed
 

‎src/collision.cpp

+69-52
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,22 @@ struct NearbyCollisionInfo {
6666
aabb3f box;
6767
};
6868

69+
// Helper functions:
70+
// Truncate floating point numbers to specified number of decimal places
71+
// in order to move all the floating point error to one side of the correct value
72+
static inline f32 truncate(const f32 val, const f32 factor)
73+
{
74+
return truncf(val * factor) / factor;
75+
}
76+
77+
static inline v3f truncate(const v3f& vec, const f32 factor)
78+
{
79+
return v3f(
80+
truncate(vec.X, factor),
81+
truncate(vec.Y, factor),
82+
truncate(vec.Z, factor)
83+
);
84+
}
6985

7086
// Helper function:
7187
// Checks for collision of a moving aabbox with a static aabbox
@@ -78,95 +94,94 @@ CollisionAxis axisAlignedCollision(
7894
//TimeTaker tt("axisAlignedCollision");
7995

8096
aabb3f relbox(
81-
movingbox.MaxEdge.X - movingbox.MinEdge.X + staticbox.MaxEdge.X - staticbox.MinEdge.X, // sum of the widths
82-
movingbox.MaxEdge.Y - movingbox.MinEdge.Y + staticbox.MaxEdge.Y - staticbox.MinEdge.Y,
83-
movingbox.MaxEdge.Z - movingbox.MinEdge.Z + staticbox.MaxEdge.Z - staticbox.MinEdge.Z,
97+
(movingbox.MaxEdge.X - movingbox.MinEdge.X) + (staticbox.MaxEdge.X - staticbox.MinEdge.X), // sum of the widths
98+
(movingbox.MaxEdge.Y - movingbox.MinEdge.Y) + (staticbox.MaxEdge.Y - staticbox.MinEdge.Y),
99+
(movingbox.MaxEdge.Z - movingbox.MinEdge.Z) + (staticbox.MaxEdge.Z - staticbox.MinEdge.Z),
84100
std::max(movingbox.MaxEdge.X, staticbox.MaxEdge.X) - std::min(movingbox.MinEdge.X, staticbox.MinEdge.X), //outer bounding 'box' dimensions
85101
std::max(movingbox.MaxEdge.Y, staticbox.MaxEdge.Y) - std::min(movingbox.MinEdge.Y, staticbox.MinEdge.Y),
86102
std::max(movingbox.MaxEdge.Z, staticbox.MaxEdge.Z) - std::min(movingbox.MinEdge.Z, staticbox.MinEdge.Z)
87103
);
88104

89105
const f32 dtime_max = *dtime;
90-
const f32 inner_margin = -1.5f;
106+
f32 inner_margin; // the distance of clipping recovery
91107
f32 distance;
92108
f32 time;
93109

94-
if (speed.X) {
95-
distance = relbox.MaxEdge.X - relbox.MinEdge.X;
96110

97-
*dtime = distance >= 0 ? std::abs(distance / speed.X) : -std::abs(distance / speed.X);
111+
if (speed.Y) {
112+
distance = relbox.MaxEdge.Y - relbox.MinEdge.Y;
113+
*dtime = distance / std::abs(speed.Y);
98114
time = std::max(*dtime, 0.0f);
99115

100-
if (distance > inner_margin) {
101-
if (*dtime <= dtime_max) {
102-
if ((speed.X > 0 && staticbox.MaxEdge.X > movingbox.MaxEdge.X) ||
103-
(speed.X < 0 && staticbox.MinEdge.X < movingbox.MinEdge.X)) {
104-
if (
105-
(std::max(movingbox.MaxEdge.Y + speed.Y * time, staticbox.MaxEdge.Y)
106-
- std::min(movingbox.MinEdge.Y + speed.Y * time, staticbox.MinEdge.Y)
107-
- relbox.MinEdge.Y < 0) &&
116+
if (*dtime <= dtime_max) {
117+
inner_margin = std::max(-0.5f * (staticbox.MaxEdge.Y - staticbox.MinEdge.Y), -2.0f);
118+
119+
if ((speed.Y > 0 && staticbox.MinEdge.Y - movingbox.MaxEdge.Y > inner_margin) ||
120+
(speed.Y < 0 && movingbox.MinEdge.Y - staticbox.MaxEdge.Y > inner_margin)) {
121+
if (
122+
(std::max(movingbox.MaxEdge.X + speed.X * time, staticbox.MaxEdge.X)
123+
- std::min(movingbox.MinEdge.X + speed.X * time, staticbox.MinEdge.X)
124+
- relbox.MinEdge.X < 0) &&
108125
(std::max(movingbox.MaxEdge.Z + speed.Z * time, staticbox.MaxEdge.Z)
109126
- std::min(movingbox.MinEdge.Z + speed.Z * time, staticbox.MinEdge.Z)
110127
- relbox.MinEdge.Z < 0)
111-
)
112-
return COLLISION_AXIS_X;
113-
}
114-
} else {
115-
return COLLISION_AXIS_NONE;
128+
)
129+
return COLLISION_AXIS_Y;
116130
}
117131
}
132+
else {
133+
return COLLISION_AXIS_NONE;
134+
}
118135
}
119136

120137
// NO else if here
121138

122-
if (speed.Y) {
123-
distance = relbox.MaxEdge.Y - relbox.MinEdge.Y;
124-
125-
*dtime = distance >= 0 ? std::abs(distance / speed.Y) : -std::abs(distance / speed.Y);
139+
if (speed.X) {
140+
distance = relbox.MaxEdge.X - relbox.MinEdge.X;
141+
*dtime = distance / std::abs(speed.X);
126142
time = std::max(*dtime, 0.0f);
127143

128-
if (distance > inner_margin) {
129-
if (*dtime <= dtime_max) {
130-
if ((speed.Y > 0 && staticbox.MaxEdge.Y > movingbox.MaxEdge.Y) ||
131-
(speed.Y < 0 && staticbox.MinEdge.Y < movingbox.MinEdge.Y)) {
132-
if (
133-
(std::max(movingbox.MaxEdge.X + speed.X * time, staticbox.MaxEdge.X)
134-
- std::min(movingbox.MinEdge.X + speed.X * time, staticbox.MinEdge.X)
135-
- relbox.MinEdge.X < 0) &&
144+
if (*dtime <= dtime_max) {
145+
inner_margin = std::max(-0.5f * (staticbox.MaxEdge.X - staticbox.MinEdge.X), -2.0f);
146+
147+
if ((speed.X > 0 && staticbox.MinEdge.X - movingbox.MaxEdge.X > inner_margin) ||
148+
(speed.X < 0 && movingbox.MinEdge.X - staticbox.MaxEdge.X > inner_margin)) {
149+
if (
150+
(std::max(movingbox.MaxEdge.Y + speed.Y * time, staticbox.MaxEdge.Y)
151+
- std::min(movingbox.MinEdge.Y + speed.Y * time, staticbox.MinEdge.Y)
152+
- relbox.MinEdge.Y < 0) &&
136153
(std::max(movingbox.MaxEdge.Z + speed.Z * time, staticbox.MaxEdge.Z)
137154
- std::min(movingbox.MinEdge.Z + speed.Z * time, staticbox.MinEdge.Z)
138155
- relbox.MinEdge.Z < 0)
139-
)
140-
return COLLISION_AXIS_Y;
141-
}
142-
} else {
143-
return COLLISION_AXIS_NONE;
156+
)
157+
return COLLISION_AXIS_X;
144158
}
159+
} else {
160+
return COLLISION_AXIS_NONE;
145161
}
146162
}
147163

148164
// NO else if here
149165

150166
if (speed.Z) {
151167
distance = relbox.MaxEdge.Z - relbox.MinEdge.Z;
152-
153-
*dtime = distance >= 0 ? std::abs(distance / speed.Z) : -std::abs(distance / speed.Z);
168+
*dtime = distance / std::abs(speed.Z);
154169
time = std::max(*dtime, 0.0f);
155170

156-
if (distance > inner_margin) {
157-
if (*dtime <= dtime_max) {
158-
if ((speed.Z > 0 && staticbox.MaxEdge.Z > movingbox.MaxEdge.Z) ||
159-
(speed.Z < 0 && staticbox.MinEdge.Z < movingbox.MinEdge.Z)) {
160-
if (
161-
(std::max(movingbox.MaxEdge.X + speed.X * time, staticbox.MaxEdge.X)
162-
- std::min(movingbox.MinEdge.X + speed.X * time, staticbox.MinEdge.X)
163-
- relbox.MinEdge.X < 0) &&
171+
if (*dtime <= dtime_max) {
172+
inner_margin = std::max(-0.5f * (staticbox.MaxEdge.Z - staticbox.MinEdge.Z), -2.0f);
173+
174+
if ((speed.Z > 0 && staticbox.MinEdge.Z - movingbox.MaxEdge.Z > inner_margin) ||
175+
(speed.Z < 0 && movingbox.MinEdge.Z - staticbox.MaxEdge.Z > inner_margin)) {
176+
if (
177+
(std::max(movingbox.MaxEdge.X + speed.X * time, staticbox.MaxEdge.X)
178+
- std::min(movingbox.MinEdge.X + speed.X * time, staticbox.MinEdge.X)
179+
- relbox.MinEdge.X < 0) &&
164180
(std::max(movingbox.MaxEdge.Y + speed.Y * time, staticbox.MaxEdge.Y)
165181
- std::min(movingbox.MinEdge.Y + speed.Y * time, staticbox.MinEdge.Y)
166182
- relbox.MinEdge.Y < 0)
167-
)
168-
return COLLISION_AXIS_Z;
169-
}
183+
)
184+
return COLLISION_AXIS_Z;
170185
}
171186
}
172187
}
@@ -245,6 +260,8 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
245260
speed_f->X = rangelim(speed_f->X, -5000, 5000);
246261
speed_f->Z = rangelim(speed_f->Z, -5000, 5000);
247262

263+
*speed_f = truncate(*speed_f, 10000.0f);
264+
248265
/*
249266
Collect node boxes in movement range
250267
*/
@@ -464,7 +481,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
464481

465482
if (nearest_collided == COLLISION_AXIS_NONE) {
466483
// No collision with any collision box.
467-
*pos_f += *speed_f * dtime;
484+
*pos_f += truncate(*speed_f * dtime, 100.0f);
468485
dtime = 0; // Set to 0 to avoid "infinite" loop due to small FP numbers
469486
} else {
470487
// Otherwise, a collision occurred.
@@ -500,7 +517,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
500517
pos_f->Z += speed_f->Z * nearest_dtime;
501518
}
502519
} else {
503-
*pos_f += *speed_f * nearest_dtime;
520+
*pos_f += truncate(*speed_f * nearest_dtime, 100.0f);
504521
dtime -= nearest_dtime;
505522
}
506523

0 commit comments

Comments
 (0)
Please sign in to comment.