Skip to content

Getting Started

Scripts add behaviour to entities in a scene. This page explains the scripting model, then walks through a first script that drives a Unitree G1 humanoid with the keyboard.

In short

A script is a C# class that derives from Entity and is attached to an entity through a Script component. The engine calls its lifecycle methods, such as OnCreate and OnUpdate, while the scene plays. Install the .NET 9 SDK first; see Creating and building scripts.

The scripting model

Lucky Engine scripts are C# classes that derive from Entity. The scripting API lives in the Hazel namespace, so script files start with using Hazel;. Your own classes can be in any namespace; new scripts use the project's Default Namespace. A compiled script attaches to an entity in the editor through a Script component, and the engine calls the overridden lifecycle methods at the right moments.

A script has access to:

Your first script

This script lets you drive a Unitree G1 with W, A, S and D while the scene plays. The G1's trained walker policy does the walking: W and S move it forward and back, and A and D turn it left and right.

  1. Get a G1 into a scene. Either create a project from the Unitree G1 template on the Welcome screen (see Get Started), or, in an open project, open View → Robots and click Add to scene on the Unitree G1 (click Download first if it is not installed). See Robots.
  2. In the Content Browser, right-click an empty area, choose New → Script, enter WalkerInput as the Class Name, and click Create.
  3. Double-click WalkerInput.cs to open it in the Text Editor, replace its contents with the code below, and save with Ctrl+S. Saving builds the scripts.
  4. Select the robot's root entity, the one with the Robot Controller component. It already has a Script component running the script the robot came with. Set that component's Script Class to WalkerInput.
  5. Press Play in the viewport toolbar (or F5) and drive with W, A, S and D.
using Hazel;

public class WalkerInput : Entity
{
    [Tooltip("Forward speed while holding W or S.")]
    public float ForwardSpeed = 0.5f;

    [Tooltip("Yaw rate while holding A or D.")]
    public float TurnRate = 1.0f;

    // Id of the walker's slot under Policy Slots in the Robot Controller component.
    private const uint k_WalkerSlot = 1u;
    private const uint k_SetVx      = 1u;
    private const uint k_SetVy      = 2u;
    private const uint k_SetYawRate = 3u;

    private RobotControllerComponent? m_Robot;

    protected override void OnCreate()
    {
        m_Robot = GetComponent<RobotControllerComponent>();
        m_Robot?.SetPolicyActive(k_WalkerSlot, true);
    }

    protected override void OnUpdate(float ts)
    {
        if (m_Robot is null)
            return;

        float forwardVelocity = 0.0f;
        float yawRate         = 0.0f;

        if (Input.IsKeyDown(KeyCode.W))
            forwardVelocity = ForwardSpeed;
        if (Input.IsKeyDown(KeyCode.S))
            forwardVelocity = -ForwardSpeed;
        if (Input.IsKeyDown(KeyCode.A))
            yawRate = TurnRate;
        if (Input.IsKeyDown(KeyCode.D))
            yawRate = -TurnRate;

        m_Robot.SetFloat(k_WalkerSlot, k_SetVx,      forwardVelocity);  // m/s
        m_Robot.SetFloat(k_WalkerSlot, k_SetVy,      0.0f);              // m/s
        m_Robot.SetFloat(k_WalkerSlot, k_SetYawRate, yawRate);           // rad/s
    }
}

Check the walker's slot Id

Policy slots are numbered in the order the robot's policies were added, starting at 1. In the Inspector, find the walker under Policy Slots on the Robot Controller component and look at its Id. If it is not 1, change k_WalkerSlot to match.

Conventions used here

Member fields are prefixed m_ and constants k_, and components are cached in OnCreate rather than fetched on every step. These are conventions, not requirements.

What's happening:

Piece Reference
: Entity Entity, the base class for all scripts
OnCreate / OnUpdate Entity lifecycle
RobotControllerComponent RobotControllerComponent, which holds the robot's policies and motion graph
SetPolicyActive / SetFloat Turn a policy slot on, and send it a command value. For the walker, command IDs 1, 2 and 3 are forward velocity, sideways velocity and yaw rate.
Input.IsKeyDown(KeyCode.W) Input

Public fields are editable in the Inspector

ForwardSpeed and TurnRate appear as fields on the Script component, labelled with their C# names. Change them there to retune the robot without touching the code; the editor also writes the new value into the field's initializer in WalkerInput.cs. See Editor attributes for sliders, ranges, tooltips, and other Inspector polish.

Where to go next