First Module
Create your first module using the 4-struct pattern. For full pattern documentation, see Module Pattern.
Quick Start
- Right-click in the Project window
- Create > C# Module (or use
Pixel Engine / Generate Module) - Name it
HealthSystem - Unity generates the full Module Pattern boilerplate
Don't see the Create menu item? Run
Pixel Engine / Install Script Templatesand restart Unity. See Project Setup.
Example: HealthSystem
using PixelEngine.Architecture;
using System;
public class HealthSystem : IDisposable
{
[Serializable]
public readonly struct Configuration : IConfiguration
{
public readonly int maxHealth;
public readonly float regenRate;
public static readonly Configuration Default = new Configuration(
maxHealth: 100,
regenRate: 0f
);
public Configuration(int maxHealth, float regenRate)
{
this.maxHealth = maxHealth;
this.regenRate = regenRate;
}
}
[Serializable]
public readonly struct Reference : IReference
{
public static readonly Reference Default = new Reference();
}
public struct State : IState
{
public int currentHealth;
public bool isDead;
}
public class Components : IComponents { }
private Configuration _configuration;
private Reference _reference;
private State _state;
public Configuration configuration => _configuration;
public Reference reference => _reference;
public State state => _state;
public Components components { get; private set; }
// Events — event-driven, no polling
public event Action<int> HealthChanged;
public event Action Died;
public HealthSystem()
: this(Configuration.Default, Reference.Default) { }
public HealthSystem(in Configuration configuration)
: this(in configuration, Reference.Default) { }
public HealthSystem(in Configuration configuration, in Reference reference)
{
_configuration = configuration;
_reference = reference;
_state = new State();
this.components = new Components();
Init();
}
public void SetConfiguration(in Configuration configuration)
{
_configuration = configuration;
}
public void Init()
{
_state.currentHealth = configuration.maxHealth;
_state.isDead = false;
}
public void TakeDamage(int amount)
{
if (_state.isDead) return;
_state.currentHealth = Math.Max(0, _state.currentHealth - amount);
HealthChanged?.Invoke(_state.currentHealth);
if (_state.currentHealth <= 0)
{
_state.isDead = true;
Died?.Invoke();
}
}
public void Dispose()
{
// cleanup in LIFO order
}
}
Key Takeaways
| Pattern Element | Applied Here |
|---|---|
readonly struct Configuration |
Immutable settings with constructor init |
in keyword |
SetConfiguration(in Configuration) -- zero-copy |
struct State with public fields |
External reads via property, internal mutation via _state field |
event Action<T> |
HealthChanged and Died -- no polling |
No Update() |
Fully event-driven |
IDisposable |
Explicit cleanup |
Next Steps
- Module Pattern -- full pattern documentation with both variants
- Script Templates -- auto-generate modules from the Create menu
- Cheat Sheet -- quick reference for all conventions