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)
- 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
----------------------------------------------

View File

@ -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)
{
@ -362,29 +377,57 @@ collisionMoveResult collisionMoveSimple(Map *map, IGameDef *gamedef,
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);
}
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);