Skip to content

Getting Started

The scripting model

Lucky Engine scripts are C# classes in the Hazel namespace that derive from Entity. A compiled script attaches to an entity in the editor via a Script component, and the engine calls the overridden lifecycle methods at the right moments.

A script has access to:

Your first script

Open the UnitreeG1 sample scene from ContentVault, attach this script to the G1 entity (the one carrying RobotControllerComponent), and press Play. The robot's trained walker policy responds to WASD: W and S move forward and back, A and D turn left and right.

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;

    // Slot 1 is the walker policy on the UnitreeG1 prefab.
    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
    }
}

Conventions used here

Member fields are prefixed m_, constants k_, and components are cached in OnCreate rather than fetched every frame. This is the same pattern the engine's own templates use (HumanoidWalkDriver, walker_Policy).

What's happening:

Piece Reference
: Entity Entity, the base class for all scripts
OnCreate / OnUpdate Entity lifecycle
RobotControllerComponent RobotControllerComponent, the wrapper around a robot's loaded policies
SetPolicyActive / SetFloat The policy command surface. Slot 1 is the walker; command IDs 1, 2, 3 are forward velocity, strafe velocity, and yaw rate.
Input.IsKeyDown(KeyCode.W) Input

Public fields are editable per entity

ForwardSpeed and TurnRate appear as fields on the script in the Inspector. Edit them per entity to retune without recompiling. See Editor attributes for sliders, ranges, tooltips, and other Inspector polish.

Where to go next