summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPerttu Ahola <celeron55@gmail.com>2012-09-01 12:58:37 +0300
committerPerttu Ahola <celeron55@gmail.com>2012-09-01 12:58:37 +0300
commit3b43c69df4ce7d68aebb4bd02aaa4aca18b9afad (patch)
tree60f6b5b30e8f18eacc71d812a30776641c32999c
parentb17d3e7ad7e59a10df50277c15174529f20d0bed (diff)
downloadminetest-3b43c69df4ce7d68aebb4bd02aaa4aca18b9afad.tar.gz
minetest-3b43c69df4ce7d68aebb4bd02aaa4aca18b9afad.tar.bz2
minetest-3b43c69df4ce7d68aebb4bd02aaa4aca18b9afad.zip
Add bouncy node group
-rw-r--r--doc/lua_api.txt1
-rw-r--r--src/collision.cpp55
-rw-r--r--src/collision.h34
-rw-r--r--src/environment.cpp29
-rw-r--r--src/localplayer.cpp24
5 files changed, 104 insertions, 39 deletions
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 008c9d40c..d3e254a2d 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -455,6 +455,7 @@ Special groups
- 3: node is removed without tool wear immediately (torch)
- disable_jump: Player (and possibly other things) cannot jump from node
- fall_damage_add_percent: damage speed = speed * (1 + value/100)
+- bouncy: value is bounce speed in percent
Known damage and digging time defining groups
----------------------------------------------
diff --git a/src/collision.cpp b/src/collision.cpp
index 09a7df7c2..143b559fa 100644
--- a/src/collision.cpp
+++ b/src/collision.cpp
@@ -211,6 +211,8 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
std::vector<aabb3f> cboxes;
std::vector<bool> is_unloaded;
std::vector<bool> is_step_up;
+ std::vector<int> bouncy_values;
+ std::vector<v3s16> node_positions;
{
//TimeTaker tt2("collisionMoveSimple collect boxes");
ScopeProfiler sp(g_profiler, "collisionMoveSimple collect boxes avg", SPT_AVG);
@@ -228,11 +230,14 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
for(s16 y = min_y; y <= max_y; y++)
for(s16 z = min_z; z <= max_z; z++)
{
+ v3s16 p(x,y,z);
try{
// Object collides into walkable nodes
- MapNode n = map->getNode(v3s16(x,y,z));
- if(gamedef->getNodeDefManager()->get(n).walkable == false)
+ MapNode n = map->getNode(p);
+ const ContentFeatures &f = gamedef->getNodeDefManager()->get(n);
+ if(f.walkable == false)
continue;
+ int n_bouncy_value = itemgroup_get(f.groups, "bouncy");
std::vector<aabb3f> nodeboxes = n.getNodeBoxes(gamedef->ndef());
for(std::vector<aabb3f>::iterator
@@ -245,21 +250,27 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
cboxes.push_back(box);
is_unloaded.push_back(false);
is_step_up.push_back(false);
+ bouncy_values.push_back(n_bouncy_value);
+ node_positions.push_back(p);
}
}
catch(InvalidPositionException &e)
{
// Collide with unloaded nodes
- aabb3f box = getNodeBox(v3s16(x,y,z), BS);
+ aabb3f box = getNodeBox(p, BS);
cboxes.push_back(box);
is_unloaded.push_back(true);
is_step_up.push_back(false);
+ bouncy_values.push_back(0);
+ node_positions.push_back(p);
}
}
} // tt2
assert(cboxes.size() == is_unloaded.size());
assert(cboxes.size() == is_step_up.size());
+ assert(cboxes.size() == bouncy_values.size());
+ assert(cboxes.size() == node_positions.size());
/*
Collision detection
@@ -342,6 +353,10 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
cbox.MaxEdge.Y - movingbox.MinEdge.Y,
d));
+ // Get bounce multiplier
+ bool bouncy = (bouncy_values[nearest_boxindex] >= 1);
+ float bounce = -(float)bouncy_values[nearest_boxindex] / 100.0;
+
// Move to the point of collision and reduce dtime by nearest_dtime
if(nearest_dtime < 0)
{
@@ -361,30 +376,58 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
pos_f += speed_f * nearest_dtime;
dtime -= nearest_dtime;
}
+
+ bool is_collision = true;
+ if(is_unloaded[nearest_boxindex])
+ is_collision = false;
+
+ CollisionInfo info;
+ info.type = COLLISION_NODE;
+ info.node_p = node_positions[nearest_boxindex];
+ info.bouncy = bouncy;
+ info.old_speed = speed_f;
// Set the speed component that caused the collision to zero
if(step_up)
{
// Special case: Handle stairs
is_step_up[nearest_boxindex] = true;
+ is_collision = false;
}
else if(nearest_collided == 0) // X
{
- speed_f.X = 0;
+ if(fabs(speed_f.X) > BS*3)
+ speed_f.X *= bounce;
+ else
+ speed_f.X = 0;
result.collides = true;
result.collides_xz = true;
}
else if(nearest_collided == 1) // Y
{
- speed_f.Y = 0;
+ if(fabs(speed_f.Y) > BS*3)
+ speed_f.Y *= bounce;
+ else
+ speed_f.Y = 0;
result.collides = true;
}
else if(nearest_collided == 2) // Z
{
- speed_f.Z = 0;
+ if(fabs(speed_f.Z) > BS*3)
+ speed_f.Z *= bounce;
+ else
+ speed_f.Z = 0;
result.collides = true;
result.collides_xz = true;
}
+
+ info.new_speed = speed_f;
+ if(info.new_speed.getDistanceFrom(info.old_speed) < 0.1*BS)
+ is_collision = false;
+
+ if(is_collision){
+ result.collisions.push_back(info);
+ }
}
}
diff --git a/src/collision.h b/src/collision.h
index 243c4b294..52a7bbb7d 100644
--- a/src/collision.h
+++ b/src/collision.h
@@ -26,12 +26,35 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Map;
class IGameDef;
+enum CollisionType
+{
+ COLLISION_NODE
+};
+
+struct CollisionInfo
+{
+ enum CollisionType type;
+ v3s16 node_p; // COLLISION_NODE
+ bool bouncy;
+ v3f old_speed;
+ v3f new_speed;
+
+ CollisionInfo():
+ type(COLLISION_NODE),
+ node_p(-32768,-32768,-32768),
+ bouncy(false),
+ old_speed(0,0,0),
+ new_speed(0,0,0)
+ {}
+};
+
struct collisionMoveResult
{
bool touching_ground;
bool collides;
bool collides_xz;
bool standing_on_unloaded;
+ std::vector<CollisionInfo> collisions;
collisionMoveResult():
touching_ground(false),
@@ -72,16 +95,5 @@ bool wouldCollideWithCeiling(
f32 y_increase, f32 d);
-enum CollisionType
-{
- COLLISION_FALL
-};
-
-struct CollisionInfo
-{
- CollisionType t;
- f32 speed;
-};
-
#endif
diff --git a/src/environment.cpp b/src/environment.cpp
index 292679542..24943ad5f 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -2033,25 +2033,26 @@ void ClientEnvironment::step(float dtime)
i = player_collisions.begin();
i != player_collisions.end(); i++)
{
+ f32 pre_factor = 1; // 1 hp per node/s
+ f32 tolerance = BS*14; // 5 without damage
+ f32 post_factor = 1; // 1 hp per node/s
CollisionInfo &info = *i;
- if(info.t == COLLISION_FALL)
+ if(info.type == COLLISION_NODE)
{
- //f32 tolerance = BS*10; // 2 without damage
- //f32 tolerance = BS*12; // 3 without damage
- f32 tolerance = BS*14; // 5 without damage
- f32 factor = 1;
const ContentFeatures &f = m_gamedef->ndef()->
- get(m_map->getNodeNoEx(lplayer->getStandingNodePos()));
+ get(m_map->getNodeNoEx(info.node_p));
// Determine fall damage multiplier
int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
- info.speed *= (1.0 + (float)addp/100.0);
- if(info.speed > tolerance)
- {
- f32 damage_f = (info.speed - tolerance)/BS*factor;
- u16 damage = (u16)(damage_f+0.5);
- if(damage != 0)
- damageLocalPlayer(damage, true);
- }
+ pre_factor = 1.0 + (float)addp/100.0;
+ }
+ float speed = (info.new_speed - info.old_speed).getLength();
+ speed *= pre_factor;
+ if(speed > tolerance)
+ {
+ f32 damage_f = (speed - tolerance)/BS * post_factor;
+ u16 damage = (u16)(damage_f+0.5);
+ if(damage != 0)
+ damageLocalPlayer(damage, true);
}
}
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 16111629e..15b6fd15d 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -189,7 +189,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
bool touching_ground_was = touching_ground;
touching_ground = result.touching_ground;
- bool standing_on_unloaded = result.standing_on_unloaded;
+ //bool standing_on_unloaded = result.standing_on_unloaded;
/*
Check the nodes under the player to see from which node the
@@ -282,18 +282,25 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
/*
Report collisions
*/
+ bool bouncy_jump = false;
if(collision_info)
{
- // Report fall collision
- if(old_speed.Y < m_speed.Y - 0.1 && !standing_on_unloaded)
- {
- CollisionInfo info;
- info.t = COLLISION_FALL;
- info.speed = m_speed.Y - old_speed.Y;
+ for(size_t i=0; i<result.collisions.size(); i++){
+ const CollisionInfo &info = result.collisions[i];
collision_info->push_back(info);
+ if(info.new_speed.Y - info.old_speed.Y > 0.1*BS &&
+ info.bouncy)
+ bouncy_jump = true;
}
}
+ if(bouncy_jump && control.jump){
+ m_speed.Y += 6.5*BS;
+ touching_ground = false;
+ MtEvent *e = new SimpleTriggerEvent("PlayerJump");
+ m_gamedef->event()->put(e);
+ }
+
if(!touching_ground_was && touching_ground){
MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
m_gamedef->event()->put(e);
@@ -479,8 +486,9 @@ void LocalPlayer::applyControl(float dtime)
v3f speed = getSpeed();
if(speed.Y >= -0.5*BS)
{
- speed.Y = 6.5*BS;
+ speed.Y += 6.5*BS;
setSpeed(speed);
+ m_can_jump = false;
MtEvent *e = new SimpleTriggerEvent("PlayerJump");
m_gamedef->event()->put(e);