mirror of
https://github.com/mvvasilev/last_light.git
synced 2025-04-18 20:29:52 +03:00
Add ECS
This commit is contained in:
parent
6396c63d73
commit
6af69a9169
4 changed files with 1024 additions and 17 deletions
282
engine/ecs/ecs.go
Normal file
282
engine/ecs/ecs.go
Normal file
|
@ -0,0 +1,282 @@
|
|||
package ecs
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
||||
/* ===================== ECSError ===================== */
|
||||
|
||||
type ECSError struct {
|
||||
err string
|
||||
}
|
||||
|
||||
func ecsError(err string) *ECSError {
|
||||
return &ECSError{
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ECSError) Error() string {
|
||||
return e.err
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
/* ====================== Types ======================= */
|
||||
|
||||
type ComponentType uint64
|
||||
|
||||
type SystemOrder uint8
|
||||
|
||||
type EntityId uint64
|
||||
|
||||
type ComponentMask uint64
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
/* ================== ComponentMask =================== */
|
||||
|
||||
func MaskOf(ids ...ComponentType) ComponentMask {
|
||||
mask := uint64(0)
|
||||
|
||||
for _, id := range ids {
|
||||
mask |= uint64(id)
|
||||
}
|
||||
|
||||
return ComponentMask(mask)
|
||||
}
|
||||
|
||||
func (c ComponentMask) CombinedWithMask(mask ComponentMask) ComponentMask {
|
||||
return ComponentMask(uint64(c) | uint64(mask))
|
||||
}
|
||||
|
||||
func (c ComponentMask) CombinedWithType(id ComponentType) ComponentMask {
|
||||
return ComponentMask(uint64(c) | uint64(id))
|
||||
}
|
||||
|
||||
func (c ComponentMask) Contains(id ComponentType) bool {
|
||||
return (uint64(id) & uint64(c)) == uint64(id)
|
||||
}
|
||||
|
||||
func (c ComponentMask) ContainsMultiple(ids ComponentMask) bool {
|
||||
return (uint64(ids) & uint64(c)) == uint64(ids)
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
/* ===================== System ======================= */
|
||||
|
||||
type System interface {
|
||||
Name() string
|
||||
Order() int
|
||||
Input(world *World, e tcell.EventKey)
|
||||
Tick(world *World, deltaTime int64)
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
/* =================== Component ====================== */
|
||||
|
||||
type Component interface {
|
||||
Type() ComponentType
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
/* ================== BasicEntity ===================== */
|
||||
|
||||
type BasicEntity struct {
|
||||
id EntityId
|
||||
containedComponents ComponentMask
|
||||
components map[ComponentType]Component
|
||||
}
|
||||
|
||||
func CreateRandomEntityId() EntityId {
|
||||
return EntityId(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
func createEntity(components ...Component) *BasicEntity {
|
||||
ent := &BasicEntity{
|
||||
id: CreateRandomEntityId(),
|
||||
components: make(map[ComponentType]Component, 0),
|
||||
}
|
||||
|
||||
for _, c := range components {
|
||||
ent.components[c.Type()] = c
|
||||
}
|
||||
|
||||
return ent
|
||||
}
|
||||
|
||||
func (ent *BasicEntity) Id() EntityId {
|
||||
return ent.id
|
||||
}
|
||||
|
||||
func (ent *BasicEntity) ContainedComponents() ComponentMask {
|
||||
return ComponentMask(ent.containedComponents)
|
||||
}
|
||||
|
||||
func (ent *BasicEntity) AddComponent(c Component) {
|
||||
ent.components[c.Type()] = c
|
||||
}
|
||||
|
||||
func (ent *BasicEntity) AllComponents() []Component {
|
||||
vals := make([]Component, len(ent.components))
|
||||
|
||||
for _, v := range ent.components {
|
||||
vals = append(vals, v)
|
||||
}
|
||||
|
||||
return vals
|
||||
}
|
||||
|
||||
func (ent *BasicEntity) QueryComponents(componentIds ...ComponentType) (components []Component, err *ECSError) {
|
||||
comps := make([]Component, len(componentIds))
|
||||
|
||||
for _, id := range componentIds {
|
||||
comp := ent.components[id]
|
||||
|
||||
if comp == nil {
|
||||
return nil, ecsError("Failure: Entity does not contain all of requested types")
|
||||
}
|
||||
|
||||
comps = append(comps, comp)
|
||||
}
|
||||
|
||||
return comps, nil
|
||||
}
|
||||
|
||||
func (ent *BasicEntity) ContainsComponents(mask ComponentMask) bool {
|
||||
return ent.containedComponents.ContainsMultiple(mask)
|
||||
}
|
||||
|
||||
func (ent *BasicEntity) FetchComponent(id ComponentType) (component Component, err *ECSError) {
|
||||
comp := ent.components[id]
|
||||
|
||||
if comp == nil {
|
||||
return nil, ecsError("Failure: Entity does not contain requested component")
|
||||
}
|
||||
|
||||
return comp, nil
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
/* ==================== World ========================= */
|
||||
|
||||
type World struct {
|
||||
registeredComponentTypes ComponentMask
|
||||
registeredComponentNames map[ComponentType]string
|
||||
|
||||
entities map[EntityId]*BasicEntity
|
||||
components map[ComponentType][]Component
|
||||
systems []System
|
||||
}
|
||||
|
||||
func CreateWorld() *World {
|
||||
return &World{
|
||||
entities: make(map[EntityId]*BasicEntity, 0),
|
||||
systems: make([]System, 0),
|
||||
components: make(map[ComponentType][]Component, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (w *World) QueryComponents(componentIds ...ComponentType) (components map[ComponentType][]Component, err *ECSError) {
|
||||
if !w.registeredComponentTypes.ContainsMultiple(MaskOf(componentIds...)) {
|
||||
return nil, ecsError("Failure: One of the provided queries component types has not been registered")
|
||||
}
|
||||
|
||||
comps := make(map[ComponentType][]Component, 0)
|
||||
|
||||
for _, id := range componentIds {
|
||||
comp := w.components[id]
|
||||
|
||||
// No components of the requested type exist, that's ok, add an empty slice for that type
|
||||
if comp == nil {
|
||||
comps[id] = make([]Component, 0)
|
||||
continue
|
||||
}
|
||||
|
||||
comps[id] = comp
|
||||
}
|
||||
|
||||
return comps, nil
|
||||
}
|
||||
|
||||
func (w *World) RegisterComponentType(t ComponentType, name string) (err *ECSError) {
|
||||
if w.registeredComponentTypes.Contains(t) {
|
||||
return ecsError("Failure: ComponentType conflict, another component already exists with that type number")
|
||||
}
|
||||
|
||||
w.registeredComponentTypes = w.registeredComponentTypes.CombinedWithType(t)
|
||||
w.registeredComponentNames[t] = name
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *World) AddComponentToEntity(ent *BasicEntity, comp Component) (modifiedEntity *BasicEntity, err *ECSError) {
|
||||
if !w.registeredComponentTypes.Contains(comp.Type()) {
|
||||
return nil, ecsError("Failure: Attempting to add unknown component to an entity.")
|
||||
}
|
||||
|
||||
if ent.ContainsComponents(ComponentMask(comp.Type())) {
|
||||
return nil, ecsError("Failure: Entity already contains component")
|
||||
}
|
||||
|
||||
ent.AddComponent(comp)
|
||||
|
||||
if w.components[comp.Type()] == nil {
|
||||
w.components[comp.Type()] = make([]Component, 0)
|
||||
}
|
||||
|
||||
w.components[comp.Type()] = append(w.components[comp.Type()], comp)
|
||||
|
||||
return ent, nil
|
||||
}
|
||||
|
||||
func (w *World) AddSystem(s System) (err *ECSError) {
|
||||
w.systems = append(w.systems, s)
|
||||
|
||||
slices.SortFunc(w.systems, func(a System, b System) int { return a.Order() - b.Order() })
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *World) CreateEntity(comps ...Component) *BasicEntity {
|
||||
ent := createEntity(comps...)
|
||||
|
||||
w.entities[ent.Id()] = ent
|
||||
|
||||
return ent
|
||||
}
|
||||
|
||||
func (w *World) FindEntityById(id EntityId) (entity *BasicEntity, err *ECSError) {
|
||||
ent := w.entities[id]
|
||||
|
||||
if ent == nil {
|
||||
return nil, ecsError("Failure: No entity with request id exists")
|
||||
}
|
||||
|
||||
return ent, nil
|
||||
}
|
||||
|
||||
func (w *World) RemoveEntity(id EntityId) {
|
||||
delete(w.entities, id)
|
||||
}
|
||||
|
||||
func (w *World) Tick(dt int64) {
|
||||
for _, s := range w.systems {
|
||||
s.Tick(w, dt)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *World) Input(e tcell.EventKey) {
|
||||
for _, s := range w.systems {
|
||||
s.Input(w, e)
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
742
engine/ecs/ecs_test.go
Normal file
742
engine/ecs/ecs_test.go
Normal file
|
@ -0,0 +1,742 @@
|
|||
package ecs
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
||||
func Test_ecsError(t *testing.T) {
|
||||
type args struct {
|
||||
err string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *ECSError
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := ecsError(tt.args.err); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("ecsError() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestECSError_Error(t *testing.T) {
|
||||
type fields struct {
|
||||
err string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
e := &ECSError{
|
||||
err: tt.fields.err,
|
||||
}
|
||||
if got := e.Error(); got != tt.want {
|
||||
t.Errorf("ECSError.Error() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaskOf(t *testing.T) {
|
||||
type args struct {
|
||||
ids []ComponentType
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want ComponentMask
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := MaskOf(tt.args.ids...); got != tt.want {
|
||||
t.Errorf("MaskOf() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestComponentMask_CombinedWithMask(t *testing.T) {
|
||||
type args struct {
|
||||
mask ComponentMask
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
c ComponentMask
|
||||
args args
|
||||
want ComponentMask
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.c.CombinedWithMask(tt.args.mask); got != tt.want {
|
||||
t.Errorf("ComponentMask.CombinedWithMask() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestComponentMask_CombinedWithType(t *testing.T) {
|
||||
type args struct {
|
||||
id ComponentType
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
c ComponentMask
|
||||
args args
|
||||
want ComponentMask
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.c.CombinedWithType(tt.args.id); got != tt.want {
|
||||
t.Errorf("ComponentMask.CombinedWithType() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestComponentMask_Contains(t *testing.T) {
|
||||
type args struct {
|
||||
id ComponentType
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
c ComponentMask
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.c.Contains(tt.args.id); got != tt.want {
|
||||
t.Errorf("ComponentMask.Contains() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestComponentMask_ContainsMultiple(t *testing.T) {
|
||||
type args struct {
|
||||
ids ComponentMask
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
c ComponentMask
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.c.ContainsMultiple(tt.args.ids); got != tt.want {
|
||||
t.Errorf("ComponentMask.ContainsMultiple() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateRandomEntityId(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want EntityId
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := CreateRandomEntityId(); got != tt.want {
|
||||
t.Errorf("CreateRandomEntityId() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_createEntity(t *testing.T) {
|
||||
type args struct {
|
||||
components []Component
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *BasicEntity
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := createEntity(tt.args.components...); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("createEntity() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBasicEntity_Id(t *testing.T) {
|
||||
type fields struct {
|
||||
id EntityId
|
||||
containedComponents ComponentMask
|
||||
components map[ComponentType]Component
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want EntityId
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ent := &BasicEntity{
|
||||
id: tt.fields.id,
|
||||
containedComponents: tt.fields.containedComponents,
|
||||
components: tt.fields.components,
|
||||
}
|
||||
if got := ent.Id(); got != tt.want {
|
||||
t.Errorf("BasicEntity.Id() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBasicEntity_ContainedComponents(t *testing.T) {
|
||||
type fields struct {
|
||||
id EntityId
|
||||
containedComponents ComponentMask
|
||||
components map[ComponentType]Component
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want ComponentMask
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ent := &BasicEntity{
|
||||
id: tt.fields.id,
|
||||
containedComponents: tt.fields.containedComponents,
|
||||
components: tt.fields.components,
|
||||
}
|
||||
if got := ent.ContainedComponents(); got != tt.want {
|
||||
t.Errorf("BasicEntity.ContainedComponents() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBasicEntity_AddComponent(t *testing.T) {
|
||||
type fields struct {
|
||||
id EntityId
|
||||
containedComponents ComponentMask
|
||||
components map[ComponentType]Component
|
||||
}
|
||||
type args struct {
|
||||
c Component
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ent := &BasicEntity{
|
||||
id: tt.fields.id,
|
||||
containedComponents: tt.fields.containedComponents,
|
||||
components: tt.fields.components,
|
||||
}
|
||||
ent.AddComponent(tt.args.c)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBasicEntity_AllComponents(t *testing.T) {
|
||||
type fields struct {
|
||||
id EntityId
|
||||
containedComponents ComponentMask
|
||||
components map[ComponentType]Component
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want []Component
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ent := &BasicEntity{
|
||||
id: tt.fields.id,
|
||||
containedComponents: tt.fields.containedComponents,
|
||||
components: tt.fields.components,
|
||||
}
|
||||
if got := ent.AllComponents(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("BasicEntity.AllComponents() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBasicEntity_QueryComponents(t *testing.T) {
|
||||
type fields struct {
|
||||
id EntityId
|
||||
containedComponents ComponentMask
|
||||
components map[ComponentType]Component
|
||||
}
|
||||
type args struct {
|
||||
componentIds []ComponentType
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantComponents []Component
|
||||
wantErr *ECSError
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ent := &BasicEntity{
|
||||
id: tt.fields.id,
|
||||
containedComponents: tt.fields.containedComponents,
|
||||
components: tt.fields.components,
|
||||
}
|
||||
gotComponents, gotErr := ent.QueryComponents(tt.args.componentIds...)
|
||||
if !reflect.DeepEqual(gotComponents, tt.wantComponents) {
|
||||
t.Errorf("BasicEntity.QueryComponents() gotComponents = %v, want %v", gotComponents, tt.wantComponents)
|
||||
}
|
||||
if !reflect.DeepEqual(gotErr, tt.wantErr) {
|
||||
t.Errorf("BasicEntity.QueryComponents() gotErr = %v, want %v", gotErr, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBasicEntity_ContainsComponents(t *testing.T) {
|
||||
type fields struct {
|
||||
id EntityId
|
||||
containedComponents ComponentMask
|
||||
components map[ComponentType]Component
|
||||
}
|
||||
type args struct {
|
||||
mask ComponentMask
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ent := &BasicEntity{
|
||||
id: tt.fields.id,
|
||||
containedComponents: tt.fields.containedComponents,
|
||||
components: tt.fields.components,
|
||||
}
|
||||
if got := ent.ContainsComponents(tt.args.mask); got != tt.want {
|
||||
t.Errorf("BasicEntity.ContainsComponents() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBasicEntity_FetchComponent(t *testing.T) {
|
||||
type fields struct {
|
||||
id EntityId
|
||||
containedComponents ComponentMask
|
||||
components map[ComponentType]Component
|
||||
}
|
||||
type args struct {
|
||||
id ComponentType
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantComponent Component
|
||||
wantErr *ECSError
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ent := &BasicEntity{
|
||||
id: tt.fields.id,
|
||||
containedComponents: tt.fields.containedComponents,
|
||||
components: tt.fields.components,
|
||||
}
|
||||
gotComponent, gotErr := ent.FetchComponent(tt.args.id)
|
||||
if !reflect.DeepEqual(gotComponent, tt.wantComponent) {
|
||||
t.Errorf("BasicEntity.FetchComponent() gotComponent = %v, want %v", gotComponent, tt.wantComponent)
|
||||
}
|
||||
if !reflect.DeepEqual(gotErr, tt.wantErr) {
|
||||
t.Errorf("BasicEntity.FetchComponent() gotErr = %v, want %v", gotErr, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateWorld(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want *World
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := CreateWorld(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("CreateWorld() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorld_QueryComponents(t *testing.T) {
|
||||
type fields struct {
|
||||
registeredComponentTypes ComponentMask
|
||||
registeredComponentNames map[ComponentType]string
|
||||
entities map[EntityId]*BasicEntity
|
||||
components map[ComponentType][]Component
|
||||
systems []System
|
||||
}
|
||||
type args struct {
|
||||
componentIds []ComponentType
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantComponents map[ComponentType][]Component
|
||||
wantErr *ECSError
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := &World{
|
||||
registeredComponentTypes: tt.fields.registeredComponentTypes,
|
||||
registeredComponentNames: tt.fields.registeredComponentNames,
|
||||
entities: tt.fields.entities,
|
||||
components: tt.fields.components,
|
||||
systems: tt.fields.systems,
|
||||
}
|
||||
gotComponents, gotErr := w.QueryComponents(tt.args.componentIds...)
|
||||
if !reflect.DeepEqual(gotComponents, tt.wantComponents) {
|
||||
t.Errorf("World.QueryComponents() gotComponents = %v, want %v", gotComponents, tt.wantComponents)
|
||||
}
|
||||
if !reflect.DeepEqual(gotErr, tt.wantErr) {
|
||||
t.Errorf("World.QueryComponents() gotErr = %v, want %v", gotErr, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorld_RegisterComponentType(t *testing.T) {
|
||||
type fields struct {
|
||||
registeredComponentTypes ComponentMask
|
||||
registeredComponentNames map[ComponentType]string
|
||||
entities map[EntityId]*BasicEntity
|
||||
components map[ComponentType][]Component
|
||||
systems []System
|
||||
}
|
||||
type args struct {
|
||||
t ComponentType
|
||||
name string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr *ECSError
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := &World{
|
||||
registeredComponentTypes: tt.fields.registeredComponentTypes,
|
||||
registeredComponentNames: tt.fields.registeredComponentNames,
|
||||
entities: tt.fields.entities,
|
||||
components: tt.fields.components,
|
||||
systems: tt.fields.systems,
|
||||
}
|
||||
if gotErr := w.RegisterComponentType(tt.args.t, tt.args.name); !reflect.DeepEqual(gotErr, tt.wantErr) {
|
||||
t.Errorf("World.RegisterComponentType() = %v, want %v", gotErr, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorld_AddComponentToEntity(t *testing.T) {
|
||||
type fields struct {
|
||||
registeredComponentTypes ComponentMask
|
||||
registeredComponentNames map[ComponentType]string
|
||||
entities map[EntityId]*BasicEntity
|
||||
components map[ComponentType][]Component
|
||||
systems []System
|
||||
}
|
||||
type args struct {
|
||||
ent *BasicEntity
|
||||
comp Component
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantModifiedEntity *BasicEntity
|
||||
wantErr *ECSError
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := &World{
|
||||
registeredComponentTypes: tt.fields.registeredComponentTypes,
|
||||
registeredComponentNames: tt.fields.registeredComponentNames,
|
||||
entities: tt.fields.entities,
|
||||
components: tt.fields.components,
|
||||
systems: tt.fields.systems,
|
||||
}
|
||||
gotModifiedEntity, gotErr := w.AddComponentToEntity(tt.args.ent, tt.args.comp)
|
||||
if !reflect.DeepEqual(gotModifiedEntity, tt.wantModifiedEntity) {
|
||||
t.Errorf("World.AddComponentToEntity() gotModifiedEntity = %v, want %v", gotModifiedEntity, tt.wantModifiedEntity)
|
||||
}
|
||||
if !reflect.DeepEqual(gotErr, tt.wantErr) {
|
||||
t.Errorf("World.AddComponentToEntity() gotErr = %v, want %v", gotErr, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorld_AddSystem(t *testing.T) {
|
||||
type fields struct {
|
||||
registeredComponentTypes ComponentMask
|
||||
registeredComponentNames map[ComponentType]string
|
||||
entities map[EntityId]*BasicEntity
|
||||
components map[ComponentType][]Component
|
||||
systems []System
|
||||
}
|
||||
type args struct {
|
||||
s System
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr *ECSError
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := &World{
|
||||
registeredComponentTypes: tt.fields.registeredComponentTypes,
|
||||
registeredComponentNames: tt.fields.registeredComponentNames,
|
||||
entities: tt.fields.entities,
|
||||
components: tt.fields.components,
|
||||
systems: tt.fields.systems,
|
||||
}
|
||||
if gotErr := w.AddSystem(tt.args.s); !reflect.DeepEqual(gotErr, tt.wantErr) {
|
||||
t.Errorf("World.AddSystem() = %v, want %v", gotErr, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorld_CreateEntity(t *testing.T) {
|
||||
type fields struct {
|
||||
registeredComponentTypes ComponentMask
|
||||
registeredComponentNames map[ComponentType]string
|
||||
entities map[EntityId]*BasicEntity
|
||||
components map[ComponentType][]Component
|
||||
systems []System
|
||||
}
|
||||
type args struct {
|
||||
comps []Component
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want *BasicEntity
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := &World{
|
||||
registeredComponentTypes: tt.fields.registeredComponentTypes,
|
||||
registeredComponentNames: tt.fields.registeredComponentNames,
|
||||
entities: tt.fields.entities,
|
||||
components: tt.fields.components,
|
||||
systems: tt.fields.systems,
|
||||
}
|
||||
if got := w.CreateEntity(tt.args.comps...); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("World.CreateEntity() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorld_FindEntityById(t *testing.T) {
|
||||
type fields struct {
|
||||
registeredComponentTypes ComponentMask
|
||||
registeredComponentNames map[ComponentType]string
|
||||
entities map[EntityId]*BasicEntity
|
||||
components map[ComponentType][]Component
|
||||
systems []System
|
||||
}
|
||||
type args struct {
|
||||
id EntityId
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantEntity *BasicEntity
|
||||
wantErr *ECSError
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := &World{
|
||||
registeredComponentTypes: tt.fields.registeredComponentTypes,
|
||||
registeredComponentNames: tt.fields.registeredComponentNames,
|
||||
entities: tt.fields.entities,
|
||||
components: tt.fields.components,
|
||||
systems: tt.fields.systems,
|
||||
}
|
||||
gotEntity, gotErr := w.FindEntityById(tt.args.id)
|
||||
if !reflect.DeepEqual(gotEntity, tt.wantEntity) {
|
||||
t.Errorf("World.FindEntityById() gotEntity = %v, want %v", gotEntity, tt.wantEntity)
|
||||
}
|
||||
if !reflect.DeepEqual(gotErr, tt.wantErr) {
|
||||
t.Errorf("World.FindEntityById() gotErr = %v, want %v", gotErr, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorld_RemoveEntity(t *testing.T) {
|
||||
type fields struct {
|
||||
registeredComponentTypes ComponentMask
|
||||
registeredComponentNames map[ComponentType]string
|
||||
entities map[EntityId]*BasicEntity
|
||||
components map[ComponentType][]Component
|
||||
systems []System
|
||||
}
|
||||
type args struct {
|
||||
id EntityId
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := &World{
|
||||
registeredComponentTypes: tt.fields.registeredComponentTypes,
|
||||
registeredComponentNames: tt.fields.registeredComponentNames,
|
||||
entities: tt.fields.entities,
|
||||
components: tt.fields.components,
|
||||
systems: tt.fields.systems,
|
||||
}
|
||||
w.RemoveEntity(tt.args.id)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorld_Tick(t *testing.T) {
|
||||
type fields struct {
|
||||
registeredComponentTypes ComponentMask
|
||||
registeredComponentNames map[ComponentType]string
|
||||
entities map[EntityId]*BasicEntity
|
||||
components map[ComponentType][]Component
|
||||
systems []System
|
||||
}
|
||||
type args struct {
|
||||
dt int64
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := &World{
|
||||
registeredComponentTypes: tt.fields.registeredComponentTypes,
|
||||
registeredComponentNames: tt.fields.registeredComponentNames,
|
||||
entities: tt.fields.entities,
|
||||
components: tt.fields.components,
|
||||
systems: tt.fields.systems,
|
||||
}
|
||||
w.Tick(tt.args.dt)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorld_Input(t *testing.T) {
|
||||
type fields struct {
|
||||
registeredComponentTypes ComponentMask
|
||||
registeredComponentNames map[ComponentType]string
|
||||
entities map[EntityId]*BasicEntity
|
||||
components map[ComponentType][]Component
|
||||
systems []System
|
||||
}
|
||||
type args struct {
|
||||
e tcell.EventKey
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := &World{
|
||||
registeredComponentTypes: tt.fields.registeredComponentTypes,
|
||||
registeredComponentNames: tt.fields.registeredComponentNames,
|
||||
entities: tt.fields.entities,
|
||||
components: tt.fields.components,
|
||||
systems: tt.fields.systems,
|
||||
}
|
||||
w.Input(tt.args.e)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package logic
|
||||
|
||||
import (
|
||||
"mvvasilev/last_light/game/model"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
||||
type LogicSnippet[T model.Entity] interface {
|
||||
Input(e *tcell.EventKey)
|
||||
Tick(dt int64, entity T)
|
||||
}
|
|
@ -19,10 +19,6 @@ func CreateNPC(pos engine.Position) *NPC {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *NPC) Position() engine.Position {
|
||||
return c.Positioned.Position()
|
||||
}
|
||||
|
||||
func (c *NPC) MoveTo(newPosition engine.Position) {
|
||||
c.Positioned.SetPosition(newPosition)
|
||||
}
|
||||
|
@ -32,7 +28,6 @@ func (c *NPC) UniqueId() uuid.UUID {
|
|||
}
|
||||
|
||||
func (c *NPC) Input(e *tcell.EventKey) {
|
||||
|
||||
}
|
||||
|
||||
func (c *NPC) Tick(dt int64) {
|
||||
|
|
Loading…
Add table
Reference in a new issue