aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Rottmann <30634967+JRottm@users.noreply.github.com>2017-08-04 21:48:32 +0200
committerSmallJoker <mk939@ymail.com>2018-06-03 17:31:59 +0200
commit90a9e4e69fac32f368b275428fa42407ea9b7883 (patch)
treeb3e42ff9719b3f53f231dd6e7ea970d93b04dcc8
parente5311a4d565dece751745f859ac1b8d92da67564 (diff)
downloadminetest-90a9e4e69fac32f368b275428fa42407ea9b7883.tar.gz
minetest-90a9e4e69fac32f368b275428fa42407ea9b7883.tar.bz2
minetest-90a9e4e69fac32f368b275428fa42407ea9b7883.zip
Fix player coordinate rounding in collisionMoveSimple() (#6197)
To determine the area (nodes) where a player movement took place collisionMoveSimple() first took the old/new player coordinates and rounded them to integers, then added the player character's collision box and implicitely rounded the result. This has 2 problems: Rounding the position and the box seperately, then adding the resulting integers means you get twice the rounding error. And implicit rounding always rounds towards 0.0, unlike floatToInt(), which rounds towards the closest integer. Previous (simplified) behavior: round(pos)+(int)box, for example player at Y=0.9, body is 1.75m high: round(0.9)+(int)1.75 = 1+1 = 2. ==> A character's height of 1.75m always got rounded down to 1m, its width of +/-0.3 even became 0. Fixed by adding the floats first, then rounding properly: round(pos+box) = round(0.9+1.75) = round(2.65) = 3.
-rw-r--r--src/collision.cpp27
1 files changed, 16 insertions, 11 deletions
diff --git a/src/collision.cpp b/src/collision.cpp
index c0891c152..c9a945916 100644
--- a/src/collision.cpp
+++ b/src/collision.cpp
@@ -258,20 +258,25 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
//TimeTaker tt2("collisionMoveSimple collect boxes");
ScopeProfiler sp(g_profiler, "collisionMoveSimple collect boxes avg", SPT_AVG);
- v3s16 oldpos_i = floatToInt(*pos_f, BS);
- v3s16 newpos_i = floatToInt(*pos_f + *speed_f * dtime, BS);
- s16 min_x = MYMIN(oldpos_i.X, newpos_i.X) + (box_0.MinEdge.X / BS) - 1;
- s16 min_y = MYMIN(oldpos_i.Y, newpos_i.Y) + (box_0.MinEdge.Y / BS) - 1;
- s16 min_z = MYMIN(oldpos_i.Z, newpos_i.Z) + (box_0.MinEdge.Z / BS) - 1;
- s16 max_x = MYMAX(oldpos_i.X, newpos_i.X) + (box_0.MaxEdge.X / BS) + 1;
- s16 max_y = MYMAX(oldpos_i.Y, newpos_i.Y) + (box_0.MaxEdge.Y / BS) + 1;
- s16 max_z = MYMAX(oldpos_i.Z, newpos_i.Z) + (box_0.MaxEdge.Z / BS) + 1;
+ v3f newpos_f = *pos_f + *speed_f * dtime;
+ v3f minpos_f(
+ MYMIN(pos_f->X, newpos_f.X),
+ MYMIN(pos_f->Y, newpos_f.Y),
+ MYMIN(pos_f->Z, newpos_f.Z)
+ );
+ v3f maxpos_f(
+ MYMAX(pos_f->X, newpos_f.X),
+ MYMAX(pos_f->Y, newpos_f.Y),
+ MYMAX(pos_f->Z, newpos_f.Z)
+ );
+ v3s16 min = floatToInt(minpos_f + box_0.MinEdge, BS) - v3s16(1, 1, 1);
+ v3s16 max = floatToInt(maxpos_f + box_0.MaxEdge, BS) + v3s16(1, 1, 1);
bool any_position_valid = false;
- for(s16 x = min_x; x <= max_x; x++)
- for(s16 y = min_y; y <= max_y; y++)
- for(s16 z = min_z; z <= max_z; z++)
+ for(s16 x = min.X; x <= max.X; x++)
+ for(s16 y = min.Y; y <= max.Y; y++)
+ for(s16 z = min.Z; z <= max.Z; z++)
{
v3s16 p(x,y,z);