From 290e9219208fd904807bded7ccdb7109a4f92bc6 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Mon, 21 Nov 2011 14:36:21 +0200 Subject: [PATCH] Relatively snappy object-ground collision detection --- data/mods/default/init.lua | 15 ++++++-------- src/collision.cpp | 3 +++ src/collision.h | 4 +++- src/content_cao.cpp | 41 ++++++++++++++++++++++++++++++-------- src/content_cao.h | 2 +- src/content_sao.cpp | 33 +++++++++++++++++++++++++----- src/content_sao.h | 1 + src/environment.h | 11 +++++----- src/luaentity_common.cpp | 2 +- 9 files changed, 81 insertions(+), 31 deletions(-) diff --git a/data/mods/default/init.lua b/data/mods/default/init.lua index a8a1d08f4..4f825626d 100644 --- a/data/mods/default/init.lua +++ b/data/mods/default/init.lua @@ -651,8 +651,7 @@ end local TNT = { -- Static definition - -- Maybe handle gravity and collision this way? dunno - -- physical = true, + physical = true, -- Collides with things -- weight = 5, collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5}, visual = "cube", @@ -662,17 +661,14 @@ local TNT = { -- Initial value for our timer timer = 0, -- Number of punches required to defuse - health = 3, - -- List names of state variables, for serializing object state - -- (NOTE: not implemented and implementation will not be like this) - -- state_variables = {"timer"}, + health = 1, } -- Called when a TNT object is created function TNT:on_activate(staticdata) print("TNT:on_activate()") - self.object:setvelocity({x=0, y=1, z=0}) - self.object:setacceleration({x=0, y=-5, z=0}) + self.object:setvelocity({x=0, y=2, z=0}) + self.object:setacceleration({x=0, y=-10, z=0}) end -- Called periodically @@ -709,6 +705,7 @@ minetest.register_entity("TNT", TNT) function register_falling_node(nodename, texture) minetest.register_entity("falling_"..nodename, { -- Static definition + physical = true, collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5}, visual = "cube", textures = {texture,texture,texture,texture,texture,texture}, @@ -719,7 +716,7 @@ function register_falling_node(nodename, texture) self.object:setacceleration({x=0, y=-10, z=0}) -- Turn to actual sand when collides to ground or just move pos = self.object:getpos() - bcp = {x=pos.x, y=pos.y-0.5, z=pos.z} -- Position of bottom center point + bcp = {x=pos.x, y=pos.y-0.6, z=pos.z} -- Position of bottom center point bcn = minetest.env:get_node(bcp) if bcn.name ~= "air" then -- Turn to a sand node diff --git a/src/collision.cpp b/src/collision.cpp index 674cf4ed4..24f1e9d18 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -177,6 +177,7 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef, 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]; + result.collides = true; } } @@ -232,6 +233,8 @@ collisionMoveResult collisionMovePrecise(Map *map, IGameDef *gamedef, if(result.touching_ground) final_result.touching_ground = true; + if(result.collides) + final_result.collides = true; } while(dtime_downcount > 0.001); diff --git a/src/collision.h b/src/collision.h index 3354ea09a..e823a08fe 100644 --- a/src/collision.h +++ b/src/collision.h @@ -28,9 +28,11 @@ class IGameDef; struct collisionMoveResult { bool touching_ground; + bool collides; collisionMoveResult(): - touching_ground(false) + touching_ground(false), + collides(false) {} }; diff --git a/src/content_cao.cpp b/src/content_cao.cpp index f5ef3fb07..213de554b 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -1457,11 +1457,34 @@ void LuaEntityCAO::updateNodePos() void LuaEntityCAO::step(float dtime, ClientEnvironment *env) { - m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration; - m_velocity += dtime * m_acceleration; - pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time); - pos_translator.translate(dtime); - updateNodePos(); + if(m_prop->physical){ + core::aabbox3d box = m_prop->collisionbox; + box.MinEdge *= BS; + box.MaxEdge *= BS; + collisionMoveResult moveresult; + f32 pos_max_d = BS*0.25; // Distance per iteration + v3f p_pos = m_position; + v3f p_velocity = m_velocity; + IGameDef *gamedef = env->getGameDef(); + moveresult = collisionMovePrecise(&env->getMap(), gamedef, + pos_max_d, box, dtime, p_pos, p_velocity); + // Apply results + m_position = p_pos; + m_velocity = p_velocity; + + bool is_end_position = moveresult.collides; + pos_translator.update(m_position, is_end_position, dtime); + pos_translator.translate(dtime); + updateNodePos(); + + m_velocity += dtime * m_acceleration; + } else { + m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration; + m_velocity += dtime * m_acceleration; + pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time); + pos_translator.translate(dtime); + updateNodePos(); + } } void LuaEntityCAO::processMessage(const std::string &data) @@ -1487,10 +1510,12 @@ void LuaEntityCAO::processMessage(const std::string &data) // update_interval float update_interval = readF1000(is); - if(do_interpolate) - pos_translator.update(m_position, is_end_position, update_interval); - else + if(do_interpolate){ + if(!m_prop->physical) + pos_translator.update(m_position, is_end_position, update_interval); + } else { pos_translator.init(m_position); + } updateNodePos(); } } diff --git a/src/content_cao.h b/src/content_cao.h index 3f6b9d877..fa7a0cb4c 100644 --- a/src/content_cao.h +++ b/src/content_cao.h @@ -92,7 +92,7 @@ struct SmoothTranslator if(anim_time > 0.001) moveratio = anim_time_counter / anim_time; // Move a bit less than should, to avoid oscillation - moveratio = moveratio * 0.5; + moveratio = moveratio * 0.8; float move_end = 1.5; if(aim_is_end) move_end = 1.0; diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 986e3f15f..5d63b295e 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -1555,6 +1555,7 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos, m_yaw(0), m_last_sent_yaw(0), m_last_sent_position(0,0,0), + m_last_sent_velocity(0,0,0), m_last_sent_position_timer(0), m_last_sent_move_precision(0) { @@ -1612,8 +1613,27 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) { m_last_sent_position_timer += dtime; - m_base_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration; - m_velocity += dtime * m_acceleration; + if(m_prop->physical){ + core::aabbox3d box = m_prop->collisionbox; + box.MinEdge *= BS; + box.MaxEdge *= BS; + collisionMoveResult moveresult; + f32 pos_max_d = BS*0.25; // Distance per iteration + v3f p_pos = getBasePosition(); + v3f p_velocity = m_velocity; + IGameDef *gamedef = m_env->getGameDef(); + moveresult = collisionMovePrecise(&m_env->getMap(), gamedef, + pos_max_d, box, dtime, p_pos, p_velocity); + // Apply results + setBasePosition(p_pos); + m_velocity = p_velocity; + + m_velocity += dtime * m_acceleration; + } else { + m_base_position += dtime * m_velocity + 0.5 * dtime + * dtime * m_acceleration; + m_velocity += dtime * m_acceleration; + } if(m_registered){ lua_State *L = m_env->getLua(); @@ -1623,7 +1643,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) if(send_recommended == false) return; - // TODO: force send when velocity/acceleration changes enough + // TODO: force send when acceleration changes enough? float minchange = 0.2*BS; if(m_last_sent_position_timer > 1.0){ minchange = 0.01*BS; @@ -1632,7 +1652,9 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) } float move_d = m_base_position.getDistanceFrom(m_last_sent_position); move_d += m_last_sent_move_precision; - if(move_d > minchange || fabs(m_yaw - m_last_sent_yaw) > 1.0){ + float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity); + if(move_d > minchange || vel_d > minchange || + fabs(m_yaw - m_last_sent_yaw) > 1.0){ sendPosition(true, false); } } @@ -1675,6 +1697,7 @@ std::string LuaEntitySAO::getStaticData() InventoryItem* LuaEntitySAO::createPickedUpItem() { + // TODO: Ask item from scriptapi std::istringstream is("CraftItem testobject1 1", std::ios_base::binary); IGameDef *gamedef = m_env->getGameDef(); InventoryItem *item = InventoryItem::deSerialize(is, gamedef); @@ -1732,7 +1755,7 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) m_last_sent_position_timer = 0; m_last_sent_yaw = m_yaw; m_last_sent_position = m_base_position; - //m_last_sent_velocity = m_velocity; + m_last_sent_velocity = m_velocity; //m_last_sent_acceleration = m_acceleration; float update_interval = m_env->getSendRecommendedInterval(); diff --git a/src/content_sao.h b/src/content_sao.h index 04d33647e..17d87e342 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -231,6 +231,7 @@ private: float m_yaw; float m_last_sent_yaw; v3f m_last_sent_position; + v3f m_last_sent_velocity; float m_last_sent_position_timer; float m_last_sent_move_precision; }; diff --git a/src/environment.h b/src/environment.h index a8213ea6d..1abf73867 100644 --- a/src/environment.h +++ b/src/environment.h @@ -362,14 +362,13 @@ public: ~ClientEnvironment(); Map & getMap() - { - return *m_map; - } + { return *m_map; } ClientMap & getClientMap() - { - return *m_map; - } + { return *m_map; } + + IGameDef *getGameDef() + { return m_gamedef; } void step(f32 dtime); diff --git a/src/luaentity_common.cpp b/src/luaentity_common.cpp index 138e72dcb..503083d0b 100644 --- a/src/luaentity_common.cpp +++ b/src/luaentity_common.cpp @@ -24,7 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" LuaEntityProperties::LuaEntityProperties(): - physical(true), + physical(false), weight(5), collisionbox(-0.5,-0.5,-0.5, 0.5,0.5,0.5), visual("single_sprite")