Creating Engine Components
This skill guides creation of ECS components for the Donburi-based game engine.
Component Architecture
Components are data containers attached to entities. Systems query for entities with specific components and process their data. Components should NOT contain logic.
Pattern: Define data struct → Create ComponentType variable → Register with engine → Use in systems
Step-by-Step Process
1. Create Component Data File
Location: game/component/<name>.go (or your game module's component folder)
go
package component
import "github.com/TheLazyLemur/engine/math"
// <Name>Data holds the component data
// Use `inspector:` struct tags for editor UI
type <Name>Data struct {
Speed float32 `inspector:"Speed,min:0,max:100,step:1"`
Direction math.Vector3 `inspector:"Direction,type:vector3"`
Enabled bool `inspector:"Enabled"`
}
// New<Name> creates a component with sensible defaults
func New<Name>() <Name>Data {
return <Name>Data{
Speed: 10.0,
Direction: math.NewVector3(0, 1, 0),
Enabled: true,
}
}
2. Register the ComponentType
In game/component/components.go:
go
package component
import "github.com/yohamta/donburi"
var (
// ... existing components ...
<Name> = donburi.NewComponentType[<Name>Data]()
)
3. Register with Engine for Serialization
In game/components.go:
go
package game
import (
gameComponent "game/component"
engine "github.com/TheLazyLemur/engine/core"
)
func RegisterComponents(eng *engine.Engine) {
// ... existing registrations ...
engine.RegisterComponent(eng, "<Name>", gameComponent.<Name>)
}
Inspector Tag Reference
| Tag Format | Effect |
|---|---|
inspector:"Label" | Field shown with custom label |
inspector:"...,min:0,max:10" | Numeric range limits |
inspector:"...,step:0.1" | Slider step increment |
inspector:"...,type:vector3" | 3D vector editor |
inspector:"...,type:euler" | Euler angle editor |
inspector:"...,type:dropdown" | Dropdown selector |
inspector:"...,registry:mesh" | Mesh ID dropdown |
inspector:"...,registry:material" | Material ID dropdown |
inspector:"...,registry:shader" | Shader ID dropdown |
inspector:"...,type:layermask" | Collision layer mask |
| (no tag) | Field hidden from inspector |
json:"-" | Exclude from serialization |
Common Patterns
Reference Component (references other entities)
go
type TargetFollowerData struct {
TargetEntity uint64 `inspector:"Target Entity ID"`
FollowSpeed float32 `inspector:"Follow Speed,min:0,max:50"`
}
Timer Component
go
type SpawnTimerData struct {
Interval float32 `inspector:"Spawn Interval (sec),min:0.1,max:60"`
Elapsed float32 `json:"-"` // Runtime only, not serialized
SpawnCount int `json:"-"`
}
State Component
go
type EnemyStateData struct {
State int `inspector:"State,type:dropdown,options:Idle|Patrol|Chase|Attack"`
StateTimer float32 `json:"-"`
}
Physics Component
go
type VelocityData struct {
Linear math.Vector3 `inspector:"Linear Velocity,type:vector3"`
Angular math.Vector3 `inspector:"Angular Velocity,type:vector3"`
}
Important Rules
- •Components = Data Only: No methods that modify game state
- •Sensible Defaults: Always provide
New<Name>()constructor - •Inspector Tags: Add for anything designers should tweak
- •Serialization: Use
json:"-"for runtime-only fields - •Naming: Use
<Name>Datafor struct,<Name>for ComponentType variable - •Registration Order: ComponentType declaration → Engine registration
Example: Complete Rotator Component
See existing implementation at:
- •Data:
game/component/rotator.go - •Registry:
game/component/components.go - •Registration:
game/components.go