GameObjects and Components
Axolotl2D uses a composition model similar to Unity: a GameObject supplies identity, activation, and a Transform; components add behavior and rendering.
Create an object
Instantiate objects from the active scene:
var player = Instantiate("Player");
player.Transform.LocalPosition = new Vector2(100, 80);
var renderer = player.AddComponent<SpriteRenderer>();
renderer.Sprite = new Sprite(assets.Get<Texture2D>("player"));
player.AddComponent<PlayerController>();
The returned object belongs to the scene immediately. Its components receive dependencies from the current scene scope.
Write a component
Every component constructor accepts its owning GameObject. Other parameters can be resolved by DI:
public sealed class PlayerController(
GameObject gameObject,
MovementSettings settings) : Component(gameObject)
{
public override void Update(double deltaTime)
{
var distance = settings.Speed * (float)deltaTime;
Transform.Translate(Vector2.UnitX * distance);
}
}
Use GameObject, Transform, Enabled, IsActiveAndEnabled, and HasStarted from the component base class. Components do not need to locate global state through static accessors.
Find and remove components
var renderer = player.GetComponent<SpriteRenderer>();
if (renderer is not null)
{
renderer.Tint = Color.Red;
}
player.RemoveComponent<PlayerController>();
GetComponent<T>() returns the first matching component. Removing a component invokes its disable and destruction callbacks as applicable, then disposes it.
Activation
GameObject.Active controls all components on the object. Component.Enabled controls one component:
player.Active = false;
renderer.Enabled = false;
IsActiveAndEnabled is true only when both values allow the component to run. State changes trigger OnEnable or OnDisable; they do not repeat Awake or Start.
Custom GameObject types
Use the generic overload when a domain-specific object type is useful:
public sealed class EnemyObject(
IServiceProvider services,
string name,
EnemyCatalog catalog) : GameObject(services, name)
{
public EnemyCatalog Catalog { get; } = catalog;
}
var boss = Instantiate<EnemyObject>("Boss");
The factory passes the requested name and resolves the other constructor arguments from the scene scope. Prefer components for reusable behavior; custom GameObject subclasses are best kept for meaningful domain identity or construction rules.
See Component Lifecycle, Runtime GameObjects, and Transforms and Hierarchies.