Add bouncy node group

This commit is contained in:
Perttu Ahola 2012-09-01 12:58:37 +03:00
parent b17d3e7ad7
commit 3b43c69df4
5 changed files with 104 additions and 39 deletions

View File

@ -455,6 +455,7 @@ Special groups
- 3: node is removed without tool wear immediately (torch) - 3: node is removed without tool wear immediately (torch)
- disable_jump: Player (and possibly other things) cannot jump from node - disable_jump: Player (and possibly other things) cannot jump from node
- fall_damage_add_percent: damage speed = speed * (1 + value/100) - fall_damage_add_percent: damage speed = speed * (1 + value/100)
- bouncy: value is bounce speed in percent
Known damage and digging time defining groups Known damage and digging time defining groups
---------------------------------------------- ----------------------------------------------

View File

@ -211,6 +211,8 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
std::vector<aabb3f> cboxes; std::vector<aabb3f> cboxes;
std::vector<bool> is_unloaded; std::vector<bool> is_unloaded;
std::vector<bool> is_step_up; std::vector<bool> is_step_up;
std::vector<int> bouncy_values;
std::vector<v3s16> node_positions;
{ {
//TimeTaker tt2("collisionMoveSimple collect boxes"); //TimeTaker tt2("collisionMoveSimple collect boxes");
ScopeProfiler sp(g_profiler, "collisionMoveSimple collect boxes avg", SPT_AVG); 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 y = min_y; y <= max_y; y++)
for(s16 z = min_z; z <= max_z; z++) for(s16 z = min_z; z <= max_z; z++)
{ {
v3s16 p(x,y,z);
try{ try{
// Object collides into walkable nodes // Object collides into walkable nodes
MapNode n = map->getNode(v3s16(x,y,z)); MapNode n = map->getNode(p);
if(gamedef->getNodeDefManager()->get(n).walkable == false) const ContentFeatures &f = gamedef->getNodeDefManager()->get(n);
if(f.walkable == false)
continue; continue;
int n_bouncy_value = itemgroup_get(f.groups, "bouncy");
std::vector<aabb3f> nodeboxes = n.getNodeBoxes(gamedef->ndef()); std::vector<aabb3f> nodeboxes = n.getNodeBoxes(gamedef->ndef());
for(std::vector<aabb3f>::iterator for(std::vector<aabb3f>::iterator
@ -245,21 +250,27 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
cboxes.push_back(box); cboxes.push_back(box);
is_unloaded.push_back(false); is_unloaded.push_back(false);
is_step_up.push_back(false); is_step_up.push_back(false);
bouncy_values.push_back(n_bouncy_value);
node_positions.push_back(p);
} }
} }
catch(InvalidPositionException &e) catch(InvalidPositionException &e)
{ {
// Collide with unloaded nodes // Collide with unloaded nodes
aabb3f box = getNodeBox(v3s16(x,y,z), BS); aabb3f box = getNodeBox(p, BS);
cboxes.push_back(box); cboxes.push_back(box);
is_unloaded.push_back(true); is_unloaded.push_back(true);
is_step_up.push_back(false); is_step_up.push_back(false);
bouncy_values.push_back(0);
node_positions.push_back(p);
} }
} }
} // tt2 } // tt2
assert(cboxes.size() == is_unloaded.size()); assert(cboxes.size() == is_unloaded.size());
assert(cboxes.size() == is_step_up.size()); assert(cboxes.size() == is_step_up.size());
assert(cboxes.size() == bouncy_values.size());
assert(cboxes.size() == node_positions.size());
/* /*
Collision detection Collision detection
@ -342,6 +353,10 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
cbox.MaxEdge.Y - movingbox.MinEdge.Y, cbox.MaxEdge.Y - movingbox.MinEdge.Y,
d)); 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 // Move to the point of collision and reduce dtime by nearest_dtime
if(nearest_dtime < 0) if(nearest_dtime < 0)
{ {
@ -362,29 +377,57 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
dtime -= 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 // Set the speed component that caused the collision to zero
if(step_up) if(step_up)
{ {
// Special case: Handle stairs // Special case: Handle stairs
is_step_up[nearest_boxindex] = true; is_step_up[nearest_boxindex] = true;
is_collision = false;
} }
else if(nearest_collided == 0) // X else if(nearest_collided == 0) // X
{ {
if(fabs(speed_f.X) > BS*3)
speed_f.X *= bounce;
else
speed_f.X = 0; speed_f.X = 0;
result.collides = true; result.collides = true;
result.collides_xz = true; result.collides_xz = true;
} }
else if(nearest_collided == 1) // Y else if(nearest_collided == 1) // Y
{ {
if(fabs(speed_f.Y) > BS*3)
speed_f.Y *= bounce;
else
speed_f.Y = 0; speed_f.Y = 0;
result.collides = true; result.collides = true;
} }
else if(nearest_collided == 2) // Z else if(nearest_collided == 2) // Z
{ {
if(fabs(speed_f.Z) > BS*3)
speed_f.Z *= bounce;
else
speed_f.Z = 0; speed_f.Z = 0;
result.collides = true; result.collides = true;
result.collides_xz = 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);
}
} }
} }

View File

@ -26,12 +26,35 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Map; class Map;
class IGameDef; 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 struct collisionMoveResult
{ {
bool touching_ground; bool touching_ground;
bool collides; bool collides;
bool collides_xz; bool collides_xz;
bool standing_on_unloaded; bool standing_on_unloaded;
std::vector<CollisionInfo> collisions;
collisionMoveResult(): collisionMoveResult():
touching_ground(false), touching_ground(false),
@ -72,16 +95,5 @@ bool wouldCollideWithCeiling(
f32 y_increase, f32 d); f32 y_increase, f32 d);
enum CollisionType
{
COLLISION_FALL
};
struct CollisionInfo
{
CollisionType t;
f32 speed;
};
#endif #endif

View File

@ -2033,27 +2033,28 @@ void ClientEnvironment::step(float dtime)
i = player_collisions.begin(); i = player_collisions.begin();
i != player_collisions.end(); i++) i != player_collisions.end(); i++)
{ {
CollisionInfo &info = *i; f32 pre_factor = 1; // 1 hp per node/s
if(info.t == COLLISION_FALL)
{
//f32 tolerance = BS*10; // 2 without damage
//f32 tolerance = BS*12; // 3 without damage
f32 tolerance = BS*14; // 5 without damage f32 tolerance = BS*14; // 5 without damage
f32 factor = 1; f32 post_factor = 1; // 1 hp per node/s
CollisionInfo &info = *i;
if(info.type == COLLISION_NODE)
{
const ContentFeatures &f = m_gamedef->ndef()-> const ContentFeatures &f = m_gamedef->ndef()->
get(m_map->getNodeNoEx(lplayer->getStandingNodePos())); get(m_map->getNodeNoEx(info.node_p));
// Determine fall damage multiplier // Determine fall damage multiplier
int addp = itemgroup_get(f.groups, "fall_damage_add_percent"); int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
info.speed *= (1.0 + (float)addp/100.0); pre_factor = 1.0 + (float)addp/100.0;
if(info.speed > tolerance) }
float speed = (info.new_speed - info.old_speed).getLength();
speed *= pre_factor;
if(speed > tolerance)
{ {
f32 damage_f = (info.speed - tolerance)/BS*factor; f32 damage_f = (speed - tolerance)/BS * post_factor;
u16 damage = (u16)(damage_f+0.5); u16 damage = (u16)(damage_f+0.5);
if(damage != 0) if(damage != 0)
damageLocalPlayer(damage, true); damageLocalPlayer(damage, true);
} }
} }
}
/* /*
A quick draft of lava damage A quick draft of lava damage

View File

@ -189,7 +189,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
bool touching_ground_was = touching_ground; bool touching_ground_was = touching_ground;
touching_ground = result.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 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 Report collisions
*/ */
bool bouncy_jump = false;
if(collision_info) if(collision_info)
{ {
// Report fall collision for(size_t i=0; i<result.collisions.size(); i++){
if(old_speed.Y < m_speed.Y - 0.1 && !standing_on_unloaded) const CollisionInfo &info = result.collisions[i];
{
CollisionInfo info;
info.t = COLLISION_FALL;
info.speed = m_speed.Y - old_speed.Y;
collision_info->push_back(info); 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){ if(!touching_ground_was && touching_ground){
MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround"); MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
m_gamedef->event()->put(e); m_gamedef->event()->put(e);
@ -479,8 +486,9 @@ void LocalPlayer::applyControl(float dtime)
v3f speed = getSpeed(); v3f speed = getSpeed();
if(speed.Y >= -0.5*BS) if(speed.Y >= -0.5*BS)
{ {
speed.Y = 6.5*BS; speed.Y += 6.5*BS;
setSpeed(speed); setSpeed(speed);
m_can_jump = false;
MtEvent *e = new SimpleTriggerEvent("PlayerJump"); MtEvent *e = new SimpleTriggerEvent("PlayerJump");
m_gamedef->event()->put(e); m_gamedef->event()->put(e);