Skip to content

Commit

Permalink
added parenting capabilities for BasicEntity
Browse files Browse the repository at this point in the history
  • Loading branch information
Noofbiz committed Feb 14, 2019
1 parent 98cdd51 commit 93415f8
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 4 deletions.
26 changes: 22 additions & 4 deletions entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ import (
)

var (
idInc uint64
idInc uint64
)

// A BasicEntity is simply a set of components with a unique ID attached to it,
// nothing more. It belongs to any amount of Systems, and has a number of
// Components
type BasicEntity struct {
// Entity ID.
id uint64
id uint64
parent *BasicEntity
children []BasicEntity
}

// Identifier is an interface for anything that implements the basic ID() uint64,
Expand All @@ -39,9 +41,9 @@ func NewBasic() BasicEntity {
func NewBasics(amount int) []BasicEntity {
entities := make([]BasicEntity, amount)

lastId := atomic.AddUint64(&idInc, uint64(amount))
lastID := atomic.AddUint64(&idInc, uint64(amount))
for i := 0; i < amount; i++ {
entities[i].id = lastId - uint64(amount) + uint64(i) + 1
entities[i].id = lastID - uint64(amount) + uint64(i) + 1
}

return entities
Expand All @@ -63,6 +65,22 @@ func (e *BasicEntity) GetBasicEntity() *BasicEntity {
return e
}

// AppendChild appends a child to the BasicEntity
func (e *BasicEntity) AppendChild(child *BasicEntity) {
child.parent = e
e.children = append(e.children, *child)
}

// Children returns the children of the BasicEntity
func (e *BasicEntity) Children() []BasicEntity {
return e.children
}

// Parent returns the parent of the BasicEntity
func (e *BasicEntity) Parent() *BasicEntity {
return e.parent
}

// Len returns the length of the underlying slice
// part of the sort.Interface
func (is IdentifierSlice) Len() int {
Expand Down
23 changes: 23 additions & 0 deletions entity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,29 @@ func TestSystemEntityFiltering(t *testing.T) {
assert.Equal(t, 0, e12x12x2.D, "e12x12x2 was updated by system 12")
}

// TestParentChild tests parenting of BasicEntities
func TestParentChild(t *testing.T) {
parent := NewBasic()
children := NewBasics(3)
if len(parent.Children()) != 0 {
t.Errorf("Children did not initalize to a zero value")
}
if parent.Parent() != nil {
t.Errorf("Parent did not initalize as nil")
}
parent.AppendChild(&children[0])
parent.AppendChild(&children[1])
parent.AppendChild(&children[2])
if len(parent.Children()) != 3 {
t.Errorf("Failed to add all three children to parent")
}
for i := 0; i < 3; i++ {
if children[i].Parent() != &parent {
t.Errorf("Parent was not updated properly for children.")
}
}
}

func BenchmarkIdiomatic(b *testing.B) {
preload := func() {}
setup := func(w *World) {
Expand Down
122 changes: 122 additions & 0 deletions system_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package ecs

import "testing"

type PriorityComponent struct {
throughFirstSystem bool
}

type PriorityEntity struct {
BasicEntity
*PriorityComponent
}

type SystemPriorityFirst struct {
e PriorityEntity
}

func (s *SystemPriorityFirst) Priority() int { return 500 }

func (s *SystemPriorityFirst) Add(b BasicEntity, p *PriorityComponent) {
s.e = PriorityEntity{b, p}
}

func (s *SystemPriorityFirst) Remove(basic BasicEntity) {}

func (s *SystemPriorityFirst) Update(dt float32) {
s.e.throughFirstSystem = true
}

type SystemPrioritySecond struct {
e PriorityEntity
pass bool
}

func (s *SystemPrioritySecond) Priority() int { return 1 }

func (s *SystemPrioritySecond) Add(b BasicEntity, p *PriorityComponent) {
s.e = PriorityEntity{b, p}
}

func (s *SystemPrioritySecond) Remove(basic BasicEntity) {}

func (s *SystemPrioritySecond) Update(dt float32) {
if s.e.throughFirstSystem {
s.pass = true
}
}

// TestSystemPriority tests if systems get added based on priority
func TestSystemPriority(t *testing.T) {
w := &World{}
sys2 := SystemPrioritySecond{}
w.AddSystem(&sys2)
w.AddSystem(&SystemPriorityFirst{})
ent := struct {
BasicEntity
PriorityComponent
}{
BasicEntity: NewBasic(),
}
for _, system := range w.Systems() {
switch sys := system.(type) {
case *SystemPriorityFirst:
sys.Add(ent.BasicEntity, &ent.PriorityComponent)
case *SystemPrioritySecond:
sys.Add(ent.BasicEntity, &ent.PriorityComponent)
}
}
w.Update(1)
if !sys2.pass {
t.Error("Systems were not run in order after updated by the world.")
}
}

type SystemAddRemove struct {
entities []PriorityEntity
}

func (s *SystemAddRemove) Add(b BasicEntity, p *PriorityComponent) {
s.entities = append(s.entities, PriorityEntity{b, p})
}

func (s *SystemAddRemove) Remove(basic BasicEntity) {
delete := -1
for index, e := range s.entities {
if e.BasicEntity.ID() == basic.ID() {
delete = index
break
}
}
if delete >= 0 {
s.entities = append(s.entities[:delete], s.entities[delete+1:]...)
}
}

func (s *SystemAddRemove) Update(dt float32) {}

// TestAddRemove tests adding and removing entities in systems that don't implement
// SystemAddByInterfacer to the world.
func TestAddRemove(t *testing.T) {
w := &World{}
sys := SystemAddRemove{}
w.AddSystem(&sys)
ent := struct {
BasicEntity
PriorityComponent
}{
BasicEntity: NewBasic(),
}
w.AddEntity(ent)
if len(sys.entities) != 0 {
t.Error("Entity was added even though the system does not implement SystemAddByInterfacer")
}
sys.Add(ent.BasicEntity, &ent.PriorityComponent)
if len(sys.entities) != 1 {
t.Error("Failed to add entity to system")
}
w.RemoveEntity(ent.BasicEntity)
if len(sys.entities) != 0 {
t.Error("Removing the entity from the world did not remove it from the system.")
}
}

0 comments on commit 93415f8

Please sign in to comment.