diff options
-rw-r--r-- | src/localplayer.cpp | 65 | ||||
-rw-r--r-- | src/localplayer.h | 6 |
2 files changed, 55 insertions, 16 deletions
diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 2a098ba0a..81e4009df 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -656,13 +656,10 @@ void LocalPlayer::applyControl(float dtime, Environment *env) else incH = incV = movement_acceleration_default * BS * dtime; - const INodeDefManager *nodemgr = env->getGameDef()->ndef(); - Map *map = &env->getMap(); - const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos())); - bool slippery = (itemgroup_get(f.groups, "slippery") != 0); + float slip_factor = getSlipFactor(env, speedH); // Accelerate to target speed with maximum increment accelerateHorizontal(speedH * physics_override_speed, - incH * physics_override_speed, slippery); + incH * physics_override_speed * slip_factor); accelerateVertical(speedV * physics_override_speed, incV * physics_override_speed); } @@ -702,19 +699,12 @@ v3f LocalPlayer::getEyeOffset() const // Horizontal acceleration (X and Z), Y direction is ignored void LocalPlayer::accelerateHorizontal(const v3f &target_speed, - const f32 max_increase, bool slippery) + const f32 max_increase) { if (max_increase == 0) return; 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; f32 dl = d_wanted.getLength(); if (dl > max_increase) @@ -1038,3 +1028,52 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d, 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; +} diff --git a/src/localplayer.h b/src/localplayer.h index c64e0042a..3521512af 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -60,6 +60,7 @@ public: u8 liquid_viscosity = 0; bool is_climbing = false; bool swimming_vertical = false; + bool is_slipping = false; float physics_override_speed = 1.0f; float physics_override_jump = 1.0f; @@ -143,11 +144,10 @@ public: void setCollisionbox(const aabb3f &box) { m_collisionbox = box; } private: - // clang-format off - void accelerateHorizontal(const v3f &target_speed, f32 max_increase, bool slippery); - // clang-format on + void accelerateHorizontal(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); + float getSlipFactor(Environment *env, const v3f &speedH); v3f m_position; |