mirror of
https://github.com/minetest/minetest.git
synced 2024-12-24 07:02:23 +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)
|
- 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
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user