Alternative code for slipping (#6256)
authorBen Deutsch <ben@bendeutsch.de>
Sat, 26 Aug 2017 07:01:09 +0000 (09:01 +0200)
committerLoïc Blot <nerzhul@users.noreply.github.com>
Sat, 26 Aug 2017 07:01:09 +0000 (09:01 +0200)
* 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

src/localplayer.cpp
src/localplayer.h

index 2a098ba0a85d042dcf1c6e6a8bd998c85b162a3f..81e4009df6ba94d38ddbb18b2815932b79601885 100644 (file)
@@ -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;
+}
index c64e0042aac35b13dddbcaf7d1554d6678315b15..3521512af71c14ace31400270ee7b9a5da4d35e8 100644 (file)
@@ -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;