Components

A component is a C# class attached to a node. Nodes hold data about where something is; components decide what it is and how it behaves.

Declaring a component

Inherit from Component and give the class a public parameterless constructor (the default one is fine):

namespace Usercode;

public class Health : Component
{
    public int maximum = 100;
    public int Current { get; private set; }

    public override void OnStart() => Current = maximum;

    public void Damage(int amount)
    {
        Current = Math.Max(0, Current - amount);
        if (Current == 0) Node!.IsActive = false;
    }
}

Every component you declare appears in the Inspector's Add Component menu. Group it under a path with [ComponentContextMenu("Gameplay/Health")].

A component's type is identified in scene files by a stable id. For your scripts it comes from the script's .cs.meta file, created automatically the first time the script compiles; engine types declare it with [TypeId("…")]. Either way, renaming the class or moving it to another namespace does not break saved scenes.

Lifecycle

Callback When
OnAttached() Right after the component is attached to a node.
OnAwake() Once, on first attachment — even when inactive. Resolve services here.
OnEnable() The component becomes active; also right after OnAwake when it starts active.
OnStart() Once, on the first frame the component is active, before its first update.
OnFixedUpdate(float fixedDeltaTime) At a fixed 60 Hz step, as many times as the elapsed time requires.
OnUpdate(float deltaTime) Once per frame.
OnLateUpdate(float deltaTime) Once per frame, after every OnUpdate — for cameras that follow moving things.
OnDisable() The component or its node becomes inactive.
OnDetached() Right before the component leaves its node.
OnDestroy() The component is removed or its node destroyed.

Each frame the engine first starts any component that has not started yet, then runs the fixed steps, then OnUpdate over the whole tree, then OnLateUpdate. Inactive nodes and components are skipped. An exception thrown by a component is logged with the component's name and does not stop the game.

Activation

component.IsActive switches one component. node.IsActive switches a node: its components receive OnEnable/OnDisable, and while it is inactive the engine skips the node and all of its descendants.

Talking to other components

var health = Node!.GetComponent<Health>();                 // on the same node, or null
var all = Node.GetComponents<LightComponent>();             // every match on the node
var inChildren = Node.GetComponentsInChildren<Health>();    // the node and its descendants
bool hasCamera = Node.HasComponent<CameraComponent>();

var light = Node.AddComponent<LightComponent>();            // attach at runtime
Node.RemoveComponent(light);

To point at another node, component or data asset, declare a field of its type and drag it onto the slot in the Inspector — just like Unity:

public class Turret : Component
{
    public Node? Target;                  // a node in the scene
    public CameraComponent? Camera;       // a component on another node
    public List<Node?> Waypoints = [];    // lists and arrays work too
    public WeaponData? Weapon;            // a data asset
}

The scene saves these as references, not copies, and wires them up when it loads — including references into another scene loaded additively, which connect as soon as both scenes are loaded. A reference to a node or component that has been destroyed reads as missing (ObjectReferences.IsMissing(target)) and is saved as empty. A reference whose target is not loaded keeps its id, so saving the scene never loses it.

NodeRef<T>, ComponentRef<T> and AssetReference<T> still exist for references you want to resolve yourself, on demand, with Resolve(sceneRoot) or LoadAsync(loader). To store a copy of an object instead of a reference, mark the field [SerializeInline].

Engine services

Scripts reach engine services through RuntimeServices, which works the same in Play Mode and in exported games:

ISceneManager? scenes;

public override void OnAwake() => scenes = RuntimeServices.TryGet<ISceneManager>();

Services available to scripts: ISceneManager (scenes), IAssetLoader (assets), IInputSource and InputActionService (input) and LocaleService (localization). The static facades Input, InputActions and Localization wrap the common calls.

Attributes

Attribute On Effect
[ComponentContextMenu("Path/Name")] class Places the component in the Add Component menu.
[DisallowMultipleComponent] class At most one per node.
[RequireComponent(typeof(T))] class Adding this component also adds T.
[Hide] member Hides a public member from the Inspector.
[Show] member Shows a non-public member.
[ReadOnly] member Shows the value without allowing edits.
[Range(min, max)] number Clamps edits and scrubbing.
[NumericUpDown] number Draws a spinner-style field.
[Button] method Draws a button that calls the parameterless method.
[Expand(false)] member Starts a group collapsed.
[EnumLabel("…")] enum value Overrides the label in dropdowns.

Logging

Log.Logger is a standard Microsoft.Extensions.Logging.ILogger:

Log.Logger.LogInformation("Picked up {Item}", item.Name);
Log.Logger.LogWarning("Health is low: {Current}", Current);

Messages appear in Studio's Output panel and on the console of a running game.

Built-in components

Component Menu Purpose
CameraComponent Rendering/Camera Perspective or orthographic view. The active camera with the highest Priority renders.
FreeFlyCameraComponent¹ Rendering/Camera/Free Fly WASD + mouse fly camera.
FpsCameraComponent Rendering/Camera/FPS First-person look and movement.
OrbitCameraComponent Rendering/Camera/Orbit Orbits a target point; scroll to zoom.
FollowCameraComponent¹ Rendering/Camera/Follow Follows a target node at an offset.

¹ The four camera rigs (Free Fly, FPS, Orbit, Follow) come from the built-in brick org.mass4.turian.cameras (namespace Turian.Cameras), which new projects install. | LightComponent | Rendering/Light | Point or directional light. | | ModelComponent | Rendering/Model | Draws an imported model, with per-submesh material overrides. | | MeshComponent | Rendering/Mesh | Draws a single mesh. | | UiDocumentComponent | UI/UI Document | Renders a .ui document on screen or in the world. See Game UI. | | UiRaycasterComponent | UI/UI Raycaster | Makes a world-space UI document clickable. |

Next steps

  • Scenes — loading, switching and additive scenes.
  • Prefabs — spawning copies at runtime.

← All docs Edit this page