Components are reusable logic blocks you attach to GameObjects. Learn how to create, configure, and query them in C#.
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.
Inherit from Component and override the lifecycle methods you need. Serializable properties are decorated with [Property] so they appear in the editor inspector.
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.
// Add a new component (starts enabled by default)var health = go.AddComponent<HealthComponent>();// Add and immediately configure itvar movement = go.AddComponent<MovementComponent>();movement.Speed = 350f;// Add only if one doesn't already existvar health2 = go.GetOrAddComponent<HealthComponent>();
// Components.Create<T> is the underlying method AddComponent<T> callsvar comp = go.Components.Create<HealthComponent>( startEnabled: true );
// Get first matching component (enabled only by default)var health = go.GetComponent<HealthComponent>();// Include disabled componentsvar health2 = go.GetComponent<HealthComponent>( includeDisabled: true );// Get all matching componentsIEnumerable<HealthComponent> all = go.GetComponents<HealthComponent>();
// First match in self and all descendantsvar health = go.GetComponentInChildren<HealthComponent>();// All matches in self and descendantsIEnumerable<HealthComponent> all = go.GetComponentsInChildren<HealthComponent>();// First match in self and all ancestorsvar manager = go.GetComponentInParent<GameManager>();// All matches up the hierarchyIEnumerable<GameManager> managers = go.GetComponentsInParent<GameManager>();
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.
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 componentDestroyGameObject();
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().
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