Skip to content

Commit

Permalink
Merge pull request #46 from yohamta/develop
Browse files Browse the repository at this point in the history
ECS layer system
  • Loading branch information
yohamta authored Oct 19, 2022
2 parents 7289120 + 327454b commit 1124132
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 73 deletions.
77 changes: 50 additions & 27 deletions ecs/ecs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ package ecs
import (
"github.com/hajimehoshi/ebiten/v2"
"github.com/yohamta/donburi"
"github.com/yohamta/donburi/filter"
"github.com/yohamta/donburi/internal/component"
"github.com/yohamta/donburi/query"
)

type DrawLayer int
// LayerID is used to specify a layer.
type LayerID int

// ECS represents an entity-component-system.
type ECS struct {
Expand All @@ -16,19 +20,28 @@ type ECS struct {
// UpdateCount is the number of times Update is called.
UpdateCount int64

layers []*Layer
systems []UpdateSystem
layers []*layer
startupSystems []UpdateSystem
}

// NewQuery creates a new query.
func NewQuery(l LayerID, f filter.LayoutFilter) *query.Query {
layerFilter := filter.Contains(getLayer(l).tag)
if f == nil {
return query.NewQuery(layerFilter)
}
return query.NewQuery(filter.And(layerFilter, f))
}

// NewECS creates a new ECS with the specified world.
func NewECS(w donburi.World) *ECS {
ecs := &ECS{
World: w,
Time: NewTime(),

systems: []UpdateSystem{},
layers: []*layer{},
layers: []*Layer{},
startupSystems: []UpdateSystem{},
}

Expand All @@ -49,25 +62,11 @@ func (ecs *ECS) AddSystem(s System) *ECS {
ecs.addUpdateSystem(s.Update)
}
if s.Draw != nil {
ecs.addDrawSystem(s.DrawLayer, s.Draw)
ecs.addDrawSystem(s.Layer, s.Draw)
}
return ecs
}

// AddUpdateSystem adds new update system
func (ecs *ECS) addUpdateSystem(systems ...UpdateSystem) *ECS {
for _, s := range systems {
ecs.systems = append(ecs.systems, s)
}
return ecs
}

// AddDrawSystem adds new draw system
func (ecs *ECS) addDrawSystem(l DrawLayer, s DrawSystem) *ECS {
ecs.getLayer(l).addDrawSystem(s)
return ecs
}

// Update runs systems
func (ecs *ECS) Update() {
ecs.Time.Update()
Expand All @@ -77,17 +76,41 @@ func (ecs *ECS) Update() {
}

// Draw calls draw
func (ecs *ECS) Draw(l DrawLayer, screen *ebiten.Image) {
ecs.getLayer(l).Draw(ecs, screen)
func (ecs *ECS) Draw(l LayerID, screen *ebiten.Image) {
ecs.getLayer(l).draw(ecs, screen)
}

func (ecs *ECS) getLayer(l DrawLayer) *layer {
if int(l) >= len(ecs.layers) {
// expand layers slice
ecs.layers = append(ecs.layers, make([]*layer, int(l)-len(ecs.layers)+1)...)
// Create creates a new entity
func (ecs *ECS) Create(l LayerID, components ...*donburi.ComponentType) donburi.Entity {
entry := ecs.World.Entry(ecs.World.Create(components...))
entry.AddComponent(ecs.getLayer(l).tag)
return entry.Entity()
}

// Create creates a new entity
func (ecs *ECS) CreateMany(l LayerID, n int, components ...*component.ComponentType) []donburi.Entity {
comps := append(components, ecs.getLayer(l).tag)
return ecs.World.CreateMany(n, comps...)
}

func (ecs *ECS) getLayer(layerID LayerID) *Layer {
if int(layerID) >= len(ecs.layers) {
ecs.layers = append(ecs.layers, make([]*Layer, int(layerID)-len(ecs.layers)+1)...)
}
if ecs.layers[layerID] == nil {
ecs.layers[layerID] = newLayer(getLayer(layerID))
}
if ecs.layers[l] == nil {
ecs.layers[l] = newLayer()
return ecs.layers[layerID]
}

func (ecs *ECS) addUpdateSystem(systems ...UpdateSystem) *ECS {
for _, s := range systems {
ecs.systems = append(ecs.systems, s)
}
return ecs.layers[l]
return ecs
}

func (ecs *ECS) addDrawSystem(l LayerID, s DrawSystem) *ECS {
ecs.getLayer(l).addDrawSystem(s)
return ecs
}
74 changes: 65 additions & 9 deletions ecs/ecs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import (

"github.com/hajimehoshi/ebiten/v2"
"github.com/yohamta/donburi"
"github.com/yohamta/donburi/filter"
"github.com/yohamta/donburi/query"
)

func TestECS(t *testing.T) {
world := donburi.NewWorld()
ecs := NewECS(world)

systems := []struct {
layer DrawLayer
layer LayerID
system *testSystem
}{
{1, &testSystem{}},
Expand All @@ -22,9 +24,9 @@ func TestECS(t *testing.T) {

for _, sys := range systems {
ecs.AddSystem(System{
Update: sys.system.Update,
DrawLayer: sys.layer,
Draw: sys.system.Draw,
Update: sys.system.Update,
Layer: sys.layer,
Draw: sys.system.Draw,
})
}

Expand Down Expand Up @@ -74,24 +76,74 @@ func TestECS(t *testing.T) {
}
}

func TestECSLayer(t *testing.T) {
world := donburi.NewWorld()
ecs := NewECS(world)

var (
layer0 LayerID = 0
layer1 LayerID = 1
)

c1 := donburi.NewTag()

ecs.Create(layer0, c1)
ecs.Create(layer1, c1)

systems := []struct {
layer LayerID
system *testSystem
}{
{layer0, &testSystem{
Query: NewQuery(layer0, filter.Contains(c1)),
}},
{layer1, &testSystem{
Query: NewQuery(layer1, filter.Contains(c1)),
}},
}

for _, sys := range systems {
ecs.AddSystem(System{
Update: sys.system.Update,
Layer: sys.layer,
Draw: sys.system.Draw,
})
}

ecs.Draw(layer0, ebiten.NewImage(1, 1))
if systems[0].system.QueryCountDraw != 1 {
t.Errorf("expected query count draw %d, got %d", 1, systems[0].system.QueryCountDraw)
}
if systems[1].system.QueryCountDraw != 0 {
t.Errorf("expected query count draw %d, got %d", 0, systems[1].system.QueryCountDraw)
}
}

var (
testUpdatedIndex int
testDrawedIndex int
)

type testSystem struct {
UpdatedIndex int
DrawedIndex int
DrawImage *ebiten.Image
UpdateCount int
DrawCount int
UpdatedIndex int
DrawedIndex int
DrawImage *ebiten.Image
UpdateCount int
DrawCount int
Query *query.Query
QueryCountUpdate int
QueryCountDraw int
}

func (ts *testSystem) Update(ecs *ECS) {
ts.UpdatedIndex = testUpdatedIndex
ts.UpdateCount++

testUpdatedIndex++

if ts.Query != nil {
ts.QueryCountUpdate = ts.Query.Count(ecs.World)
}
}

func (ts *testSystem) Draw(ecs *ECS, image *ebiten.Image) {
Expand All @@ -100,4 +152,8 @@ func (ts *testSystem) Draw(ecs *ECS, image *ebiten.Image) {
ts.DrawCount++

testDrawedIndex++

if ts.Query != nil {
ts.QueryCountDraw = ts.Query.Count(ecs.World)
}
}
42 changes: 31 additions & 11 deletions ecs/layer.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,50 @@
package ecs

import (
"fmt"

"github.com/hajimehoshi/ebiten/v2"
"github.com/yohamta/donburi"
)

type layer struct {
type Layer struct {
*layer
systems []DrawSystem
image *ebiten.Image
}

func newLayer() *layer {
return &layer{
systems: []DrawSystem{},
}
func newLayer(l *layer) *Layer {
return &Layer{l, []DrawSystem{}}
}

func (l *layer) Draw(e *ECS, i *ebiten.Image) {
func (l *Layer) draw(e *ECS, i *ebiten.Image) {
screen := i
if l.image != nil {
screen = l.image
}
for _, s := range l.systems {
s(e, screen)
}
}

func (l *layer) addDrawSystem(s DrawSystem) {
func (l *Layer) addDrawSystem(s DrawSystem) {
l.systems = append(l.systems, s)
}

var (
layers []*layer
)

type layer struct {
id LayerID
tag *donburi.ComponentType
}

func getLayer(layerID LayerID) *layer {
if int(layerID) >= len(layers) {
layers = append(layers, make([]*layer, int(layerID)-len(layers)+1)...)
}
if layers[layerID] == nil {
layers[layerID] = &layer{
id: layerID,
tag: donburi.NewTag().SetName(fmt.Sprintf("Layer%d", layerID)),
}
}
return layers[layerID]
}
21 changes: 21 additions & 0 deletions ecs/layer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ecs

import "testing"

func TestLayer(t *testing.T) {
l := getLayer(0)
ll := getLayer(1)

if l.id != 0 {
t.Errorf("layer id is not 0")
}
if ll.id != 1 {
t.Errorf("layer id is not 1")
}
if l.tag == ll.tag {
t.Errorf("layer tag is same")
}
if l.tag.Name() != "Layer0" {
t.Errorf("layer tag name is not Layer0")
}
}
6 changes: 3 additions & 3 deletions ecs/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type DrawSystem func(ecs *ECS, screen *ebiten.Image)

// System represents a system.
type System struct {
Update UpdateSystem
DrawLayer DrawLayer
Draw DrawSystem
Layer LayerID
Update UpdateSystem
Draw DrawSystem
}
9 changes: 9 additions & 0 deletions examples/bunnymark_ecs/layers/layers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package layers

import "github.com/yohamta/donburi/ecs"

const (
LayerBackground ecs.LayerID = iota
LayerBunnies
LayerMetrics
)
Loading

0 comments on commit 1124132

Please sign in to comment.