Skip to main content
Every piece of behavior in s&box is a Component — a C# class that inherits from Component and attaches to a GameObject. The GameObject is the container; the component is the logic. This separation lets you mix and match behaviors without building deep inheritance trees.

Creating a component

Inherit from Component and override the lifecycle methods you need. Serializable properties are decorated with [Property] so they appear in the editor inspector.
using Sandbox;

public sealed class HealthComponent : Component
{
    [Property] public float MaxHealth { get; set; } = 100f;
    [Property] public float CurrentHealth { get; private set; }

    protected override void OnAwake()
    {
        CurrentHealth = MaxHealth;
    }

    protected override void OnUpdate()
    {
        if ( CurrentHealth <= 0f )
        {
            Log.Info( $"{GameObject.Name} died." );
            GameObject.Destroy();
        }
    }

    public void TakeDamage( float amount )
    {
        CurrentHealth = Math.Max( 0f, CurrentHealth - amount );
    }
}
Component is abstract — you cannot instantiate it directly. All components must be concrete classes that inherit from it.

The [Property] attribute

[Property] exposes a field or auto-property to:
  • The editor inspector (where it can be edited without recompiling)
  • The serializer (so it is saved to disk as part of the scene or prefab)
  • The Reset() method (which restores all [Property] values to their defaults)
public sealed class MovementComponent : Component
{
    // Float exposed with a range slider in the inspector
    [Property, Range( 0f, 600f )]
    public float Speed { get; set; } = 200f;

    // Resource reference — shows an asset picker
    [Property]
    public Model CharacterModel { get; set; }

    // Another GameObject — shows a scene picker
    [Property]
    public GameObject SpawnPoint { get; set; }

    // A component reference on another object
    [Property]
    public HealthComponent Target { get; set; }
}
Use [Property, Group( "Combat" )] to organize properties into collapsible groups inside the inspector. Group names are display-only and have no effect at runtime.

Useful component properties

Every component has a set of built-in properties that provide access to the rest of the scene:
PropertyTypeDescription
GameObjectGameObjectThe object this component is attached to
SceneSceneShortcut for GameObject.Scene
TransformGameTransformShortcut for GameObject.Transform
ComponentsComponentListAccess all components on the same GameObject
EnabledboolWhether this component is enabled (not the same as active)
ActiveboolTrue when enabled and the GameObject hierarchy is active
TagsITagSetShortcut for GameObject.Tags

Adding and creating components

// Add a new component (starts enabled by default)
var health = go.AddComponent<HealthComponent>();

// Add and immediately configure it
var movement = go.AddComponent<MovementComponent>();
movement.Speed = 350f;

// Add only if one doesn't already exist
var health2 = go.GetOrAddComponent<HealthComponent>();

Querying components

On the same GameObject

// Get first matching component (enabled only by default)
var health = go.GetComponent<HealthComponent>();

// Include disabled components
var health2 = go.GetComponent<HealthComponent>( includeDisabled: true );

// Get all matching components
IEnumerable<HealthComponent> all = go.GetComponents<HealthComponent>();

In the hierarchy

// First match in self and all descendants
var health = go.GetComponentInChildren<HealthComponent>();

// All matches in self and descendants
IEnumerable<HealthComponent> all = go.GetComponentsInChildren<HealthComponent>();

// First match in self and all ancestors
var manager = go.GetComponentInParent<GameManager>();

// All matches up the hierarchy
IEnumerable<GameManager> managers = go.GetComponentsInParent<GameManager>();

Across the whole scene

Use Scene.GetAllComponents<T>() to find every instance of a component type anywhere in the scene:
foreach ( var enemy in Scene.GetAllComponents<EnemyComponent>() )
{
    enemy.Alert();
}
GetAllComponents<T>() scans the full scene directory. Avoid calling it every frame on large scenes — cache the result or use an event-driven approach instead.

Destroying a component

Calling Destroy() on a component removes it from its GameObject. The component is marked invalid and OnDestroy is called before the end of the frame.
myComponent.Destroy();

// Or destroy the whole GameObject from within the component
DestroyGameObject();
Destroy() removes the component from the GameObject but does not destroy the GameObject itself. To destroy the whole object, call GameObject.Destroy() or the component’s helper DestroyGameObject().

Enabling and disabling components

You can toggle a component independently from its parent GameObject:
myComponent.Enabled = false;  // component stops ticking; OnDisabled fires
myComponent.Enabled = true;   // component resumes; OnEnabled fires again
Active reflects the combined state: a component is active only when both it and its parent hierarchy are enabled.

Full example

A self-contained pickup component that spins in place, detects overlap, and grants health to whatever picks it up:
using Sandbox;

public sealed class HealthPickup : Component
{
    [Property] public float HealAmount { get; set; } = 25f;
    [Property] public float SpinSpeed  { get; set; } = 90f;

    protected override void OnUpdate()
    {
        Transform.LocalRotation *= Rotation.FromYaw( SpinSpeed * Time.Delta );
    }

    // Called by a trigger component on the same GameObject
    public void OnPickedUp( GameObject picker )
    {
        var health = picker.GetComponent<HealthComponent>();
        if ( health is null ) return;

        health.TakeDamage( -HealAmount );  // negative damage = heal
        GameObject.Destroy();
    }
}

Component lifecycle

The full order of lifecycle callbacks: OnAwake, OnStart, OnUpdate, and more

Prefabs and resources

Save configured GameObjects as prefabs to instantiate later

Build docs developers (and LLMs) love