Search code examples
algorithmlanguage-agnosticphysicsspring-annotations

Movement algorithm with friction


For example, I have an object that follows mouse horizontally, its minimum position is 100 and the maximum is 200.

Within this range, it follows mouse linearly, meaning 1 unit of mouse position equals to 1 unit of object position.

Now, if the mouse is outside of the range (below 100, or above 200), I want it to start applying friction, so the object gracefully stops the further it is from range, for example:

Mouse position  | Object position
200               200
220               205
240               209
260               212
280               215
300               217
320               218
340               219
360               220
380               220
400               220
...

I managed to implement it like this within mouse-move handler:

if (mousePosition > 200 || mousePosition < 100) {
  delta = mousePosition - objectPosition;
  objectPosition += delta * 0.25; // 0.25 if friction factor
}

But is there a better way? How to implement function outside of mouse-move handler:

getObjectPosition(mousePosition) {
  return // ???
}

The question is language agnostic.


Solution

  • You can calculate your the object position as a piecewise function of the mouse position:

    getObjectPosition(mousePosition) {
        if(mousePosition < 100)
            return 100 - friction(100 - mousePosition);
        if(mousePosition > 200)
            return 200 + friction(mousePosition - 200);
        return mousePosition;
    }
    

    Where friction is a function to calculate the "soft" function you want. A simple one would be:

    friction(x) {
        return 0.25*x;
    }
    

    which would reduce the object speed by 0.25 when its beyond the [100, 200] bounds. Your function seems to approach some kind of asymptote though. You can achieve it with, for example, a quadratic:

    friction(x) {
        M = 160;
        x = min(x, M);
        return x*(1 - x/(2*M));
    }
    

    Here the object will gradually slow down, and stop completely when the mouse is outside the [-60, 360] interval.