AgentSkillsCN

engine-component

为这款游戏引擎创建全新的 ECS 组件。当用户提出新增组件的需求、希望自定义组件数据,或需要为实体赋予全新行为时,可使用此技能。组件负责存储数据,而系统则负责对这些数据进行处理与运算。

SKILL.md
--- frontmatter
name: engine-component
description: Create new ECS components for this game engine. Use when the user asks to add a new component, create component data, or needs a new behavior that attaches to entities. Components store data; systems process them.

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 FormatEffect
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

  1. Components = Data Only: No methods that modify game state
  2. Sensible Defaults: Always provide New<Name>() constructor
  3. Inspector Tags: Add for anything designers should tweak
  4. Serialization: Use json:"-" for runtime-only fields
  5. Naming: Use <Name>Data for struct, <Name> for ComponentType variable
  6. 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