3D Worm Controller Tutorial for Unity

In this tutorial, I will be showing how to create a simple worm controller in Unity, inspired by the TornadoTwins beginner game development tutorial series.

The worm controller will slither around with a smooth tail-follow effect and have the ability to jump.

The scripts in this tutorial were originally written in JavaScript (a.k.a. UnityScript) which is no longer supported, so I will be providing a C# alternative.

Sharp Coder Video Player

To create a worm controller in Unity we will need:

  • Create the necessary scripts
  • Create a worm character
  • Assign the scripts to the character

Step 1: Create all the necessary scripts

Let's start by creating all the scripts that will be needed to set up a worm controller:

  • Create a new script, call it "SC_WormController" and paste the code below inside it:

SC_WormController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(CharacterController))]
public class SC_WormController : MonoBehaviour
{
    public float speed = 3.0f;
    public float rotateSpeed = 1.0f;
    public float jumpSpeed = 5.0f;
    public float gravity = 9.8f;

    CharacterController controller;
    Vector3 moveDirection;

    // Start is called before the first frame update
    void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    // Update is called once per frame
    void Update()
    {
        // Rotate around y - axis
        transform.Rotate(0, Input.GetAxis("Horizontal") * rotateSpeed, 0);

        // Move forward / backward
        Vector3 forward = transform.TransformDirection(Vector3.forward);
        float curSpeed = speed * Input.GetAxis("Vertical");
        float movementDirectionY = moveDirection.y;
        moveDirection = forward * curSpeed;

        // Jumping
        if (Input.GetButtonDown("Jump") && controller.isGrounded)
        {
            moveDirection.y = jumpSpeed;
        }
        else
        {
            moveDirection.y = movementDirectionY;
        }

        // Apply gravity. Gravity is multiplied by deltaTime twice (once here, and once below
        // when the moveDirection is multiplied by deltaTime). This is because gravity should be applied
        // as an acceleration (ms^-2)
        if (!controller.isGrounded)
        {
            moveDirection.y -= gravity * Time.deltaTime;
        }

        // Move the controller
        controller.Move(moveDirection * Time.deltaTime);
    }
}
  • Create a new script, call it "SC_CameraFollow" and paste the code below inside it:

SC_CameraFollow.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SC_CameraFollow : MonoBehaviour
{
    /*
    This camera smoothers out rotation around the y-axis and height.
    Horizontal Distance to the target is always fixed.

    There are many different ways to smooth the rotation but doing it this way gives you a lot of control over how the camera behaves.

    For every of those smoothed values we calculate the wanted value and the current value.
    Then we smooth it using the Lerp function.
    Then we apply the smoothed values to the transform's position.
    */

    // The target we are following
    public Transform target;
    // The distance in the x-z plane to the target
    public float distance = 10.0f;
    // the height we want the camera to be above the target
    public float height = 5.0f;
    // How much we 
    public float heightDamping = 2.0f;
    public float rotationDamping = 3.0f;

    void LateUpdate()
    {
        // Early out if we don't have a target
        if (!target)
            return;

        // Calculate the current rotation angles
        float wantedRotationAngle = target.eulerAngles.y;
        float wantedHeight = target.position.y + height;
        float currentRotationAngle = transform.eulerAngles.y;
        float currentHeight = transform.position.y;

        // Damp the rotation around the y-axis
        currentRotationAngle = Mathf.LerpAngle(currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);

        // Damp the height
        currentHeight = Mathf.Lerp(currentHeight, wantedHeight, heightDamping * Time.deltaTime);

        // Convert the angle into a rotation
        Quaternion currentRotation = Quaternion.Euler(0, currentRotationAngle, 0);

        // Set the position of the camera on the x-z plane to:
        // distance meters behind the target
        transform.position = target.position;
        transform.position -= currentRotation * Vector3.forward * distance;

        // Set the height of the camera
        transform.position = new Vector3(transform.position.x, currentHeight, transform.position.z);

        // Always look at the target
        transform.LookAt(target);
    }
}
  • Create a new script, call it "SC_SmoothFollow" and paste the code below inside it:

SC_SmoothFollow.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SC_SmoothFollow : MonoBehaviour
{
    // The target we are following
    public Transform target;
    // The distance in the x-z plane to the target
    public float distance = 10.0f;
    // the height we want the camera to be above the target
    public float height = 5.0f;
    // How much we 
    public float heightDamping = 2.0f;
    public float rotationDamping = 3.0f;

    // Start is called before the first frame update
    void Start()
    {
        if (!target) return;

        transform.LookAt(target);
    }

    void LateUpdate()
    {
        // Early out if we don't have a target
        if (!target) return;

        // Calculate the current rotation angles
        float wantedRotationAngle = target.eulerAngles.y;
        float wantedHeight = target.position.y + height;

        float currentRotationAngle = transform.eulerAngles.y;
        float currentHeight = transform.position.y;

        // Damp the rotation around the y-axis
        currentRotationAngle = Mathf.LerpAngle(currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);

        // Damp the height
        currentHeight = Mathf.Lerp(currentHeight, wantedHeight, heightDamping * Time.deltaTime);

        // Convert the angle into a rotation
        var currentRotation = Quaternion.Euler(0, currentRotationAngle, 0);

        // Set the position of the camera on the x-z plane to:
        // distance meters behind the target
        transform.position = target.position;
        transform.position -= currentRotation * Vector3.forward * distance;

        // Set the height of the camera
        transform.position = new Vector3(transform.position.x, currentHeight, transform.position.z);

        // Always look at the target
        transform.LookAt(target);
    }
}

Step 2: Create a Worm Character

The next step is to create a worm character:

  • Create a new Sphere (GameObject -> 3D Object -> Sphere) change its position to (0, 0, 0), delete its SphereCollider component, and rename it to "Worm"

  • Duplicate the "Worm" sphere, rename it to "BodyPart1", change its position to (0, -0.1, -0.9), and change its scale to (0.8, 0.8, 0.8)
  • Duplicate the "Worm" sphere again, rename it to "BodyPart2", change its position to (0, -0.2, -1.6), and change its scale to (0.6, 0.6, 0.6)

  • Right-click on the "Worm" object -> Create Empty and rename the newly created object to "Eyes"
  • Duplicate the "BodyPart2" sphere, rename it to "Eye" and move it inside the "Eyes" object, change its position to (-0.24, 0.353, 0.324) and change its scale to (0.4, 0.4, 0.4)
  • Duplicate the "Eye" sphere and change its X position to 0.24

  • For the visualization, you can create a few materials, for example, green for the body and blue for the eyes.

Worm Game in Unity

The Worm Character is ready.

Step 3: Set up the Worm Controller

The last step is to assign the scripts:

  • Attach the SC_CameraFollow script to the Main Camera object and assign the "Worm" Sphere to the target variable:

  • Attach the SC_WormController script to the "Worm" sphere (It will automatically add another component called CharacterController):

  • Attach the SC_SmoothFollow script to the "BodyPart1" sphere and set its values the same as in the screenshot below:

  • Attach the SC_SmoothFollow script to the "BodyPart2" sphere and set its values the same as in the screenshot below:

The controller is now ready, use W, A, S, and D to move around and Space to jump.

The source Unity Package is available below.

Source
📁WormController.unitypackage40.01 KB
Suggested Articles
Player 3D and 2D Wall Jump Tutorial for Unity
Flashlight Tutorial for Unity
Top-Down Player Controller Tutorial for Unity
RTS and MOBA Player Controller for Unity
Helicopter Controller for Unity
Car Controller for Unity
Airplane Controller for Unity