summaryrefslogtreecommitdiff
path: root/src/collision.cpp
diff options
context:
space:
mode:
authorPerttu Ahola <celeron55@gmail.com>2011-04-10 15:16:27 +0300
committerPerttu Ahola <celeron55@gmail.com>2011-04-10 15:16:27 +0300
commit5a4d8ffad3b172eae67844deda6b65273b7c9757 (patch)
tree70b32f31eaf824fec947d890377bf1e40555225c /src/collision.cpp
parent08bbf9687742c0b159cc1d963ab470796f74c6c8 (diff)
downloadminetest-5a4d8ffad3b172eae67844deda6b65273b7c9757.tar.gz
minetest-5a4d8ffad3b172eae67844deda6b65273b7c9757.tar.bz2
minetest-5a4d8ffad3b172eae67844deda6b65273b7c9757.zip
implemented rats in new system to verify that it works
Diffstat (limited to 'src/collision.cpp')
-rw-r--r--src/collision.cpp184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/collision.cpp b/src/collision.cpp
new file mode 100644
index 000000000..83cefe4d1
--- /dev/null
+++ b/src/collision.cpp
@@ -0,0 +1,184 @@
+/*
+Minetest-c55
+Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "collision.h"
+#include "mapblock.h"
+#include "map.h"
+
+collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
+ const core::aabbox3d<f32> &box_0,
+ f32 dtime, v3f &pos_f, v3f &speed_f)
+{
+ collisionMoveResult result;
+
+ v3f oldpos_f = pos_f;
+ v3s16 oldpos_i = floatToInt(oldpos_f, BS);
+
+ /*
+ Calculate new position
+ */
+ pos_f += speed_f * dtime;
+
+ /*
+ Collision detection
+ */
+
+ // position in nodes
+ v3s16 pos_i = floatToInt(pos_f, BS);
+
+ /*
+ Collision uncertainty radius
+ Make it a bit larger than the maximum distance of movement
+ */
+ f32 d = pos_max_d * 1.1;
+ // A fairly large value in here makes moving smoother
+ //f32 d = 0.15*BS;
+
+ // This should always apply, otherwise there are glitches
+ assert(d > pos_max_d);
+
+ /*
+ Calculate collision box
+ */
+ core::aabbox3d<f32> box = box_0;
+ box.MaxEdge += pos_f;
+ box.MinEdge += pos_f;
+ core::aabbox3d<f32> oldbox = box_0;
+ oldbox.MaxEdge += oldpos_f;
+ oldbox.MinEdge += oldpos_f;
+
+ /*
+ If the object lies on a walkable node, this is set to true.
+ */
+ result.touching_ground = false;
+
+ /*
+ Go through every node around the object
+ */
+ for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++)
+ for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)
+ for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++)
+ {
+ try{
+ // Object collides into walkable nodes
+ if(content_walkable(map->getNode(v3s16(x,y,z)).d) == false)
+ continue;
+ }
+ catch(InvalidPositionException &e)
+ {
+ // Doing nothing here will block the object from
+ // walking over map borders
+ }
+
+ core::aabbox3d<f32> nodebox = getNodeBox(v3s16(x,y,z), BS);
+
+ /*
+ See if the object is touching ground.
+
+ Object touches ground if object's minimum Y is near node's
+ maximum Y and object's X-Z-area overlaps with the node's
+ X-Z-area.
+
+ Use 0.15*BS so that it is easier to get on a node.
+ */
+ if(
+ //fabs(nodebox.MaxEdge.Y-box.MinEdge.Y) < d
+ fabs(nodebox.MaxEdge.Y-box.MinEdge.Y) < 0.15*BS
+ && nodebox.MaxEdge.X-d > box.MinEdge.X
+ && nodebox.MinEdge.X+d < box.MaxEdge.X
+ && nodebox.MaxEdge.Z-d > box.MinEdge.Z
+ && nodebox.MinEdge.Z+d < box.MaxEdge.Z
+ ){
+ result.touching_ground = true;
+ }
+
+ // If object doesn't intersect with node, ignore node.
+ if(box.intersectsWithBox(nodebox) == false)
+ continue;
+
+ /*
+ Go through every axis
+ */
+ v3f dirs[3] = {
+ v3f(0,0,1), // back-front
+ v3f(0,1,0), // top-bottom
+ v3f(1,0,0), // right-left
+ };
+ for(u16 i=0; i<3; i++)
+ {
+ /*
+ Calculate values along the axis
+ */
+ f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[i]);
+ f32 nodemin = nodebox.MinEdge.dotProduct(dirs[i]);
+ f32 objectmax = box.MaxEdge.dotProduct(dirs[i]);
+ f32 objectmin = box.MinEdge.dotProduct(dirs[i]);
+ f32 objectmax_old = oldbox.MaxEdge.dotProduct(dirs[i]);
+ f32 objectmin_old = oldbox.MinEdge.dotProduct(dirs[i]);
+
+ /*
+ Check collision for the axis.
+ Collision happens when object is going through a surface.
+ */
+ bool negative_axis_collides =
+ (nodemax > objectmin && nodemax <= objectmin_old + d
+ && speed_f.dotProduct(dirs[i]) < 0);
+ bool positive_axis_collides =
+ (nodemin < objectmax && nodemin >= objectmax_old - d
+ && speed_f.dotProduct(dirs[i]) > 0);
+ bool main_axis_collides =
+ negative_axis_collides || positive_axis_collides;
+
+ /*
+ Check overlap of object and node in other axes
+ */
+ bool other_axes_overlap = true;
+ for(u16 j=0; j<3; j++)
+ {
+ if(j == i)
+ continue;
+ f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[j]);
+ f32 nodemin = nodebox.MinEdge.dotProduct(dirs[j]);
+ f32 objectmax = box.MaxEdge.dotProduct(dirs[j]);
+ f32 objectmin = box.MinEdge.dotProduct(dirs[j]);
+ if(!(nodemax - d > objectmin && nodemin + d < objectmax))
+ {
+ other_axes_overlap = false;
+ break;
+ }
+ }
+
+ /*
+ If this is a collision, revert the pos_f in the main
+ direction.
+ */
+ if(other_axes_overlap && main_axis_collides)
+ {
+ speed_f -= speed_f.dotProduct(dirs[i]) * dirs[i];
+ pos_f -= pos_f.dotProduct(dirs[i]) * dirs[i];
+ pos_f += oldpos_f.dotProduct(dirs[i]) * dirs[i];
+ }
+
+ }
+ } // xyz
+
+ return result;
+}
+
+