phatcoreportfolioprojects
Zoom inFig. 1: In-game screenshot of Cargo on a rock.
Fig. 1: In-game screenshot of Cargo on a rock.

Real-time Orientation for Crawling Characters

3 March 2012 (based on code published in February 2010)

The game Cargo began with a simple mechanic: the main character is a snail who can crawl on anything – the ground, leaves, walls and ceilings. Not only that, but the snail's long body can wrap around objects, making it feel like it is really part of the world. This article describes the technique for orienting the snail to stick to a surface.

Zoom inFig. 2: Finding the surface normal with linear rays. Left: initial state. Right: after alignment. The normal is marked
Fig. 2: Finding the surface normal with linear rays. Left: initial state. Right: after alignment. The normal is marked 'n'; the object's z-axis is marked 'z'. The blue circle represents the body of the snail; its head, tail and shell are not shown.
Zoom inFig. 3: Sharp edges cause the object to oscillate between two orientations.
Fig. 3: Sharp edges cause the object to oscillate between two orientations.

Raycasting

A naiive attempt might cast rays toward the ground to find the surface normal, and align the snail to it. The simplest would be a single ray, cast from the centre of the snail downwards – the surface could be queried at the intersection point to discover the normal. However, the ground is made up of discrete polygons (not a smooth surface), so this results in unpleasant motion as the snail moves from one polygon to the next.

A better approach would be to use multiple rays to “feel” the shape of the surface. The rays would be cast downwards from points attached to the snail. The points at which the rays strike the surface define a polygon (e.g. with three rays you would have a triangle); it is therefore possible to calculate the average normal of the surface underneath the snail. This works well for small angles, as shown in Fig. 2.

This method results in smooth motion and is very efficient: only three rays are needed to find the surface normal in 3D. Unfortunately, it fails when the surface has a high curvature, as shown in Fig. 3.

When approaching a sharp edge, the leading ray will fail to hit anything. This is not a big problem by itself: the length of the ray can be limited so that the surface appears to be pitched only slightly forward. However, after aligning the snail to the normal, the rays would strike different parts of the surface – which means the normal will be different on the next frame. The result is that the snail's orientation oscillates between the two states.

Zoom inFig. 4: Finding the surface normal with curved rays. Here two rays are cast, starting from the dot at the top.
Fig. 4: Finding the surface normal with curved rays. Here two rays are cast, starting from the dot at the top.
Zoom inFig. 5: Aligning to the normal of a concave surface.
Fig. 5: Aligning to the normal of a concave surface.

Searching Around the Pivot

The correct solution is to search for the surface in an arc around the centre of the snail (its pivot point), as shown in Fig. 4 and Fig. 5. When the snail is aligned with the normal, the circle described by the curved rays does not change. On the following frame they will strike the same positions, and the same normal will be calculated. This therefore results in a stable configuration. This solution works with both convex and concave surfaces.

The Blender Game Engine has no way to cast a curved ray – indeed, it may not be a feature of any current game engine. However it can be emulated using linear rays, by breaking the arcs into segments. The code should search along the length of the arc one segment after another, starting from the top, until the surface is found. The solution presented above is quite robust even with discretised curves, provided the line segments represent no more than 45 degrees of the arc.

Zoom inFig. 6: Cargo crawling over a convex surface. The curved rays are shown in yellow and orange.
Fig. 6: Cargo crawling over a convex surface. The curved rays are shown in yellow and orange.

Sticking to the Surface

Once the snail has been aligned, sticking to the surface is simply a matter of applying a force along the normal. In Cargo, this is done using two actuators: one applies a force upwards (positive Z) in world space to counter gravity; the other applies a force downwards (negative Z) in local space. Since the snail has been aligned, this is applied along the surface normal.

Wrapping

In Cargo, the algorithm is extended to wrap the snail around the surface. This is acheived by sampling the surface normal at more points along the length of the body, as shown in Fig. 6. In total, 12 curved rays are used: four for the body, and two for each section of the head and tail.

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 2.5 Australia License.