Spyderpunk — Decentraland Game Jam entry (Part 1)

Bence Varga

This is the first of a blog post series on how the spider’s mechanics were created for my submission to the Decentraland game jam in September 2019 : https://gamejam.decentraland.org/

Here’s a sample video of the spider itself without any environment, capable of following the player around with procedural foot placement:

1. Getting a leg to work

My first goal was to get a single leg to work as intended:

If I have a point in space representing the ‘shoulder’ of the spider and a target point on the ground or elsewhere, then the leg should bend and rotate in a way that it reaches this target point.

This is a classic use case of inverse kinematics, where you only modify an endpoint of an arm or leg and the shoulders, elbows and knees rotate the required amount automatically.

In the above image I’m only moving the endpoint ‘C’ and I need to calculate the ROTATIONS of ‘A’ and ‘B’ which results in the leg touching ‘C’ .

As a first step I have created a simple setup in the Decentraland SDK, where I had three Entities: A, B and C with transformed position according to the figure above, along the z-axis. Entity A is the parent of Entity B, but C is not parented at all as it should be the target point moved around in the world separately from the leg. At first I’d actually just set point C to be the player’s head position (camera.position) so the test leg would always point at the players head and bend if you move closer to it.

Then came the calculation of inverse kinematics (IK)… I’m no wizard of this, I just knew that this is possible, so I looked for help in hexapod robot programming blogs and found the basic math needed on this site:

More precisely these two note pages helped me with the implementation the most:

Top view and side view of leg

This image above describes the leg from a top view and a side view. The target point which the leg wants to reach is called P(x,y,z) here (ours is C). The bone from Entity A to B is called Femur, and the bone from B to C is called the Tibia. Femur Length is equal to the distance you placed B from A initially, and Tibia Length is equal to the initial distance from B to C. By initial I mean when you laid out your leg along the Z-axis, for example EntityB.addComponent( Transform({ position: new Vector3(0, 0, 4) })) will result in a Femur Length of 4.

The Coxa Angle here represents the Y-axis (Up) rotation, which is done by a separate physical motor on a hexapod. Since the spider is virtual I can just rotate the shoulder (Entity A) on both Y and X axis, so I removed the ‘coxaLength’ offset completely from the calculations below.

It might look like too much at first, but this is all math you can directly implement inside the SDK (Math.pow, Math.sqrt, Math.atan2, Math.acos etc). I only had to modify the above a little bit because my test leg was extended along the Z-axis (not X), and the hexapods default rotations are different from the Decentra engine’s, but at the end the whole thing was translated to this:

IK code snippet

And you only need to input the point you want to ‘touch’, in my example this is Entity C’s position (x,y,z) along with your femur and tibia lengths. All the others are just temporary variables for the calculations (LegLength, HF, A1, A2, B1)

The beauty of it is that it results in three angles:

  1. femurAngle -> How much to rotate Entity A (femur) along the X-axis
  2. coxaAngle -> How much to rotate Entity A (femur) along the Y-axis
  3. tibiaAngle -> How much to rotate Entity B (tibia) along the X-axis

GREAT!

Now I had a leg in the origin of the scene (0,0,0) and it was bending and pointing at any input point in the world it could reach with a 4 unit long femur and 4 unit long tibia.

(Remember this is only a bone rig hierarchy with invisible entities! In order to see the leg in the preview I had to add visible entities with stretched cubeShapes and parent them under the rig entities A and B. Later on these cubeShapes were replaced by the spider leg .GLTF models.

You DO NOT want to scale the rig entities themselves because then every child of them will be scaled as well resulting in all kinds of errors in the calculations)

So as it turns out the algorithm above only calculates the angles correctly if the origin of the coordinate system is the shoulder (‘A’) itself. Or in other words the position of the target point ‘C’ has to be in the space of ‘A’. This meant that if I want to move the spider’s body around the scene I have to calculate the target point’s relative position to the shoulder with every update. This is crucial since you want the spiders ‘feet’ to stay in one place and stick to the floor while the body itself moves. This will create the dynamic movement of the creature.

The spider’s shoulder is parented under the spiderBody Entity. So in order to get the local position of target point ‘C’ we need to invert the spiderBody’s transforms:

C_Local.position = C_World.position.subtract( spiderBody.position ).rotate( Quaternion.Inverse( spiderBody.rotation ))

This will give you the C_Local.position(x,y,z) coordinates relative to the spiderBody, that you want to feed into the IK code snippet above. Calculate this every frame while moving the spiderBody and you have yourself a leg that sticks to any point ‘C’ in space that you want.

That’s it for he first part. In the next post I will cover how to add stepping logic (basically the logic that moves point ‘C’) and how I added multiple legs to the beast…

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade