3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "collision.h"
24 collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
25 const core::aabbox3d<f32> &box_0,
26 f32 dtime, v3f &pos_f, v3f &speed_f)
28 collisionMoveResult result;
31 v3s16 oldpos_i = floatToInt(oldpos_f, BS);
34 Calculate new position
36 pos_f += speed_f * dtime;
43 v3s16 pos_i = floatToInt(pos_f, BS);
46 Collision uncertainty radius
47 Make it a bit larger than the maximum distance of movement
49 f32 d = pos_max_d * 1.1;
50 // A fairly large value in here makes moving smoother
53 // This should always apply, otherwise there are glitches
54 assert(d > pos_max_d);
57 Calculate collision box
59 core::aabbox3d<f32> box = box_0;
62 core::aabbox3d<f32> oldbox = box_0;
63 oldbox.MaxEdge += oldpos_f;
64 oldbox.MinEdge += oldpos_f;
67 If the object lies on a walkable node, this is set to true.
69 result.touching_ground = false;
72 Go through every node around the object
73 TODO: Calculate the range of nodes that need to be checked
75 for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++)
76 for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)
77 for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++)
80 // Object collides into walkable nodes
81 if(content_walkable(map->getNode(v3s16(x,y,z)).d) == false)
84 catch(InvalidPositionException &e)
86 // Doing nothing here will block the object from
87 // walking over map borders
90 core::aabbox3d<f32> nodebox = getNodeBox(v3s16(x,y,z), BS);
93 See if the object is touching ground.
95 Object touches ground if object's minimum Y is near node's
96 maximum Y and object's X-Z-area overlaps with the node's
99 Use 0.15*BS so that it is easier to get on a node.
102 //fabs(nodebox.MaxEdge.Y-box.MinEdge.Y) < d
103 fabs(nodebox.MaxEdge.Y-box.MinEdge.Y) < 0.15*BS
104 && nodebox.MaxEdge.X-d > box.MinEdge.X
105 && nodebox.MinEdge.X+d < box.MaxEdge.X
106 && nodebox.MaxEdge.Z-d > box.MinEdge.Z
107 && nodebox.MinEdge.Z+d < box.MaxEdge.Z
109 result.touching_ground = true;
112 // If object doesn't intersect with node, ignore node.
113 if(box.intersectsWithBox(nodebox) == false)
117 Go through every axis
120 v3f(0,0,1), // back-front
121 v3f(0,1,0), // top-bottom
122 v3f(1,0,0), // right-left
124 for(u16 i=0; i<3; i++)
127 Calculate values along the axis
129 f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[i]);
130 f32 nodemin = nodebox.MinEdge.dotProduct(dirs[i]);
131 f32 objectmax = box.MaxEdge.dotProduct(dirs[i]);
132 f32 objectmin = box.MinEdge.dotProduct(dirs[i]);
133 f32 objectmax_old = oldbox.MaxEdge.dotProduct(dirs[i]);
134 f32 objectmin_old = oldbox.MinEdge.dotProduct(dirs[i]);
137 Check collision for the axis.
138 Collision happens when object is going through a surface.
140 bool negative_axis_collides =
141 (nodemax > objectmin && nodemax <= objectmin_old + d
142 && speed_f.dotProduct(dirs[i]) < 0);
143 bool positive_axis_collides =
144 (nodemin < objectmax && nodemin >= objectmax_old - d
145 && speed_f.dotProduct(dirs[i]) > 0);
146 bool main_axis_collides =
147 negative_axis_collides || positive_axis_collides;
150 Check overlap of object and node in other axes
152 bool other_axes_overlap = true;
153 for(u16 j=0; j<3; j++)
157 f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[j]);
158 f32 nodemin = nodebox.MinEdge.dotProduct(dirs[j]);
159 f32 objectmax = box.MaxEdge.dotProduct(dirs[j]);
160 f32 objectmin = box.MinEdge.dotProduct(dirs[j]);
161 if(!(nodemax - d > objectmin && nodemin + d < objectmax))
163 other_axes_overlap = false;
169 If this is a collision, revert the pos_f in the main
172 if(other_axes_overlap && main_axis_collides)
174 speed_f -= speed_f.dotProduct(dirs[i]) * dirs[i];
175 pos_f -= pos_f.dotProduct(dirs[i]) * dirs[i];
176 pos_f += oldpos_f.dotProduct(dirs[i]) * dirs[i];