Skip to main content

Procedural spider animation

· 5 min read
Kirill Vasin

I have been always amazed by a fascinating procedural animation using in some games like Rain World. The key feature there is that you define sort of a target points for a model and a clever algorithm figures out the way how each bone or "leg" will move to achieve the goal. This is a common problem of kinematics. Let's start with the simplest approach

Cycloid

If we roll a ball over a plane surface with attached marker at the side it will produce a well-known curve

ParametricPlot[{x - Sin[x], 1 - Cos[x]}, {x,0,6Pi}]

Imagine it it were legs, which would follow multiple cycloids with a little offset. But firstly, we should get rid of a plane ground and turn it into something more interesting

To project cycloid onto land curve, we could not find anything better, that to offset y axis

try to zoom in with a mouse

FABRIK Inverse Kinematics

Legs of a spider are not straight lines, and consists of small segments needed to be animated separately. For this case there is a nice heuristic algorithm FABRIK.

I do not claim that my implementation is most optimized, but it does solve a problem

ClearAll[cached];
cached[expr_] := cached[expr] = expr;
SetAttributes[cached, HoldAll]

SetAttributes[fabrik, HoldFirst]

fabrik[chain_, target_, origin_] := Module[{
buffer, prev,
lengths = cached[Norm /@ (chain // Reverse // Differences) // Reverse]
},
buffer = Table[With[{p = chain[[-i]]},
If[i === 1,
prev = target;
target
,

prev = prev - Normalize[(prev - p)] lengths[[1-i]];
prev
]
], {i, chain // Length}] // Reverse;

chain = Table[With[{p = buffer[[i]]},
If[i === 1,
prev = origin;
origin
,

prev = prev - Normalize[(prev - p)] lengths[[i-1]];
prev
]
], {i, chain // Length}];
]

Let us see how it works in the following example

chain = {{0,0}, {0.5,1}, {1,1}, {1,0.5}};

Graphics[{
Line[chain // Offload],
EventHandler[Graphics`Canvas[], {"mousemove" -> Function[xy,
fabrik[chain, xy, {0,0}]
]}]
}]

The next idea will be to assign the target position of each leg to a cycloid.

Modelling legs

We can isolate our a leg into a independent component, hence it would be easier to combine them together

here the first argument specifies an EventObject identifier, that will be called later on to update all legs segments in the animation loop.

Now we can combine multiple legs, which target's variables will follows cycloids with small offsets as follows

Adding controls

Slides are boring. Using Graphics`Canvas[] with EventHandler we can capture arrow keys and animate accordingly. However, to animate continuously we can set a timer and remove it once the target position of a spider has been reached

Here we also animate the view of the canvas and pan it to keep our spider in the center of the screen. To achieve that we mark the graphics with MetaMarker and then execute in its context ZoomAt function, which affects the state of an existing Graphics container.

The result

focus on a canvas with your mouse and control the spider using arrow keys

Notebook is available by the link below

Spider.wln