Alternative code for slipping (#6256)

* Alternative code for slipping

- does not depend on frame rate
- controllable via environment variables for now

* Adjust slipping speed for item entities too.

* Final version of framerate-independent slippery code

* Remove dead code and fix formatting

* getStandingNodePos should only look 0.05 nodes downwards

This ensures that, even if the player is standing on a partially
filled node, this node is used as the standing node and not the
node below it.

Specific use: enables slippery slabs

* Exchange global getStandingPosNode change for local inline change

Reverts previous commit

* Revert the item movement changes

* Slippery nodes now slip over cliffs and edges

Players no longer suddenly stop before falling off.
Also refactored slippery code into getSlipFactor method.

* Slipping over an edge gated by player's is_slipping state

A new flag for just this case, to reduce costly node lookups in
the normal case of leaning over a non-slippery edge.
Public access for consistency and potential future uses.

* Minor code tweaks / cosmetics

* Add temp variable to improve readability and fix indentation issues
This commit is contained in:
Ben Deutsch 2017-08-26 09:01:09 +02:00 committed by Loïc Blot
parent 0e0643df35
commit fc13c00ef3
2 changed files with 55 additions and 16 deletions

@ -656,13 +656,10 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
else else
incH = incV = movement_acceleration_default * BS * dtime; incH = incV = movement_acceleration_default * BS * dtime;
const INodeDefManager *nodemgr = env->getGameDef()->ndef(); float slip_factor = getSlipFactor(env, speedH);
Map *map = &env->getMap();
const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
bool slippery = (itemgroup_get(f.groups, "slippery") != 0);
// Accelerate to target speed with maximum increment // Accelerate to target speed with maximum increment
accelerateHorizontal(speedH * physics_override_speed, accelerateHorizontal(speedH * physics_override_speed,
incH * physics_override_speed, slippery); incH * physics_override_speed * slip_factor);
accelerateVertical(speedV * physics_override_speed, accelerateVertical(speedV * physics_override_speed,
incV * physics_override_speed); incV * physics_override_speed);
} }
@ -702,19 +699,12 @@ v3f LocalPlayer::getEyeOffset() const
// Horizontal acceleration (X and Z), Y direction is ignored // Horizontal acceleration (X and Z), Y direction is ignored
void LocalPlayer::accelerateHorizontal(const v3f &target_speed, void LocalPlayer::accelerateHorizontal(const v3f &target_speed,
const f32 max_increase, bool slippery) const f32 max_increase)
{ {
if (max_increase == 0) if (max_increase == 0)
return; return;
v3f d_wanted = target_speed - m_speed; v3f d_wanted = target_speed - m_speed;
if (slippery) {
if (target_speed == v3f())
d_wanted = -m_speed * 0.05f;
else
d_wanted *= 0.1f;
}
d_wanted.Y = 0.0f; d_wanted.Y = 0.0f;
f32 dl = d_wanted.getLength(); f32 dl = d_wanted.getLength();
if (dl > max_increase) if (dl > max_increase)
@ -1038,3 +1028,52 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
m_can_jump = false; m_can_jump = false;
} }
} }
float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH)
{
if (!touching_ground)
return 1.0f;
float slip_factor = 1.0f;
// Slip on slippery nodes
const INodeDefManager *nodemgr = env->getGameDef()->ndef();
Map *map = &env->getMap();
const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(
floatToInt(getPosition() - v3f(0, 0.05f * BS, 0), BS)));
int slippery = 0;
if (f.walkable) {
slippery = itemgroup_get(f.groups, "slippery");
} else if (is_slipping) {
// slipping over an edge? Check surroundings for slippery nodes
slippery = 2 << 16; // guard value, bigger than all realistic ones
for (int z = 0; z <= 1; z++) {
for (int x = 0; x <= 1; x++) {
// this should cover all nodes surrounding player position
v3f offset((x - 0.5f) * BS, 0.05f * BS, (z - 0.5f) * BS);
const ContentFeatures &f2 = nodemgr->get(map->getNodeNoEx(
floatToInt(getPosition() - offset, BS)));
if (f2.walkable) {
// find least slippery node we might be standing on
int s = itemgroup_get(f2.groups, "slippery");
if (s < slippery)
slippery = s;
}
}
}
// without any hits, ignore slippery
if (slippery >= (2 << 16))
slippery = 0;
}
if (slippery >= 1) {
if (speedH == v3f(0.0f)) {
slippery = slippery * 2;
}
slip_factor = core::clamp(1.0f / (slippery + 1), 0.001f, 1.0f);
is_slipping = true;
} else {
// remember this to avoid checking the edge case above too often
is_slipping = false;
}
return slip_factor;
}

@ -60,6 +60,7 @@ public:
u8 liquid_viscosity = 0; u8 liquid_viscosity = 0;
bool is_climbing = false; bool is_climbing = false;
bool swimming_vertical = false; bool swimming_vertical = false;
bool is_slipping = false;
float physics_override_speed = 1.0f; float physics_override_speed = 1.0f;
float physics_override_jump = 1.0f; float physics_override_jump = 1.0f;
@ -143,11 +144,10 @@ public:
void setCollisionbox(const aabb3f &box) { m_collisionbox = box; } void setCollisionbox(const aabb3f &box) { m_collisionbox = box; }
private: private:
// clang-format off void accelerateHorizontal(const v3f &target_speed, const f32 max_increase);
void accelerateHorizontal(const v3f &target_speed, f32 max_increase, bool slippery);
// clang-format on
void accelerateVertical(const v3f &target_speed, const f32 max_increase); void accelerateVertical(const v3f &target_speed, const f32 max_increase);
bool updateSneakNode(Map *map, const v3f &position, const v3f &sneak_max); bool updateSneakNode(Map *map, const v3f &position, const v3f &sneak_max);
float getSlipFactor(Environment *env, const v3f &speedH);
v3f m_position; v3f m_position;