mirror of
https://github.com/minetest/minetest.git
synced 2024-12-23 14:42:24 +01:00
Add bouncy node group
This commit is contained in:
parent
b17d3e7ad7
commit
3b43c69df4
@ -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
|
||||
----------------------------------------------
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user