Skip to content

Commit

Permalink
refactor: moved tests into test dir, added brevity aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
gravestench committed Feb 23, 2022
1 parent e83e004 commit 4ae5a35
Show file tree
Hide file tree
Showing 12 changed files with 126 additions and 102 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# A Golang Entity Component System
A Golang Entity Component System implementation

## tl;dr
**If you really want to just see how to use this package,
skip ahead to the Examples section.**

This ECS implementation provides at-runtime entityy/component association
without heavy use of reflection.

## What is ECS?
[Entity Component System is a design pattern.](https://en.wikipedia.org/wiki/Entity_component_system)

Expand Down Expand Up @@ -163,7 +167,7 @@ Systems are fairly simple in that they need only implement this interface:
type System interface {
Active() bool
SetActive(bool)
Process()
Update()
}
```

Expand Down Expand Up @@ -192,7 +196,7 @@ type ExampleSystem struct {
*BaseSystem
}

func (s *ExampleSystem) Process() {
func (s *ExampleSystem) Update() {
// do stuff
}
```
Expand Down
10 changes: 10 additions & 0 deletions brevity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package akara

// for brevity
type (
W = World
E = EntityID
C = Component
CID = ComponentID
S = System
)
28 changes: 0 additions & 28 deletions component_filter_builder_test.go

This file was deleted.

16 changes: 8 additions & 8 deletions subscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ type empty struct{} // intentionally empty!
// NewSubscription creates a new subscription with the given component filter
func NewSubscription(cf *ComponentFilter) *Subscription {
return &Subscription{
Filter: cf,
entityMap: make(entityMap),
entities: make([]EID, 0),
Filter: cf,
entityMap: make(entityMap),
entities: make([]EID, 0),
ignoredEntities: make(entityMap),
}
}

// Subscription is a component filter and a slice of entity ID's for which the filter applies
type Subscription struct {
Filter *ComponentFilter
entityMap // we use (abuse) the lookup ability of maps for adding/removing EIDs
entities []EID // we sort the map keys when GetEntities is called, only if dirty==true
dirty bool
Filter *ComponentFilter
entityMap // we use (abuse) the lookup ability of maps for adding/removing EIDs
entities []EID // we sort the map keys when GetEntities is called, only if dirty==true
dirty bool
ignoredEntities entityMap
mutex sync.Mutex
mutex sync.Mutex
}

// AddEntity adds an entity to the subscription entity map
Expand Down
6 changes: 5 additions & 1 deletion system.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ import "time"
type System interface {
systemInfo
systemControls
systemFrequencyControl
Update()
}

type systemControls interface {
systemStatusControls
systemFrequencyControl
}

type systemStatusControls interface {
Active() bool
Activate()
Deactivate()
Expand Down
8 changes: 4 additions & 4 deletions system_base.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@ import "time"
type timeManagement struct {
TimeDelta time.Duration
tickFrequency float64
tickPeriod time.Duration
tickPeriod time.Duration
lastTick time.Time
preTickCallback func()
tickCallback func()
tickCallback func()
postTickCallback func()
}

type systemDebugging struct {
tickCount uint
uptime time.Duration
uptime time.Duration
}

// BaseSystem is the base system type
type BaseSystem struct {
*World
timeManagement
systemDebugging
active bool
active bool
}

var DefaultTickRate float64 = 100
Expand Down
27 changes: 14 additions & 13 deletions component_factory_test.go → tests/component_factory_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package akara
package tests

import (
"fmt"
"github.com/gravestench/akara"
"math"
"math/rand"
"testing"
Expand All @@ -13,9 +14,9 @@ func TestComponentFactory_Add_Get_Remove(t *testing.T) {
rand.Seed(int64(0xdeadbeef))

Convey("Within an ECS world", t, func() {
cfg := NewWorldConfig().With(nil)
w := NewWorld(cfg)
var e EID
cfg := akara.NewWorldConfig().With(nil)
w := akara.NewWorld(cfg)
var e akara.EID

Convey("Where there exists a registered component type with Component ID 0", func() {
cid := w.RegisterComponent(&testComponent{})
Expand Down Expand Up @@ -54,8 +55,8 @@ func TestComponentFactory_Add_Get_Remove(t *testing.T) {
func benchComMapAdd(_ int, b *testing.B) {
rand.Seed(int64(0xdeadbeef))

cfg := NewWorldConfig().With(nil)
w := NewWorld(cfg)
cfg := akara.NewWorldConfig().With(nil)
w := akara.NewWorld(cfg)
cid := w.RegisterComponent(&testComponent{})
cf := w.GetComponentFactory(cid)

Expand All @@ -68,8 +69,8 @@ func benchComMapAdd(_ int, b *testing.B) {
func benchComMapGet(i int, b *testing.B) {
rand.Seed(int64(0xdeadbeef))

cfg := NewWorldConfig().With(nil)
w := NewWorld(cfg)
cfg := akara.NewWorldConfig().With(nil)
w := akara.NewWorld(cfg)
cid := w.RegisterComponent(&testComponent{})
cf := w.GetComponentFactory(cid)

Expand All @@ -79,19 +80,19 @@ func benchComMapGet(i int, b *testing.B) {

b.ResetTimer()
for n := 0; n < b.N; n++ {
cf.Get(EID(n % i))
cf.Get(akara.EID(n % i))
}
}

func benchComMapRemove(i int, b *testing.B) {
rand.Seed(int64(0xdeadbeef))

cfg := NewWorldConfig().With(nil)
w := NewWorld(cfg)
cfg := akara.NewWorldConfig().With(nil)
w := akara.NewWorld(cfg)
cf := w.GetComponentFactory(w.RegisterComponent(&testComponent{}))

randNums := randIndices(i)
eids := make([]EID, len(randNums))
eids := make([]akara.EID, len(randNums))

for idx := range randNums {
eids[idx] = w.NewEntity()
Expand Down Expand Up @@ -135,6 +136,6 @@ func BenchmarkComponentFactory_RemoveAll(b *testing.B) {

type testComponent struct{}

func (c *testComponent) New() Component {
func (c *testComponent) New() akara.Component {
return &testComponent{}
}
29 changes: 29 additions & 0 deletions tests/component_filter_builder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package tests

import (
"github.com/gravestench/akara"
"testing"

"github.com/gravestench/bitset"

. "github.com/smartystreets/goconvey/convey"
)

func TestComponentFilterBuilder(t *testing.T) {
Convey("Given an Arbitrary BitSet", t, func() {
bs := bitset.NewBitSet()

Convey("A component filter may be created with any combination of requirements/restrictions", func() {
So(akara.NewComponentFilter(bs, nil, nil), ShouldNotBeNil)
So(akara.NewComponentFilter(nil, bs, nil), ShouldNotBeNil)
So(akara.NewComponentFilter(nil, nil, bs), ShouldNotBeNil)

So(akara.NewComponentFilter(bs, bs, nil), ShouldNotBeNil)
So(akara.NewComponentFilter(nil, bs, bs), ShouldNotBeNil)
So(akara.NewComponentFilter(bs, nil, bs), ShouldNotBeNil)

So(akara.NewComponentFilter(bs, bs, bs), ShouldNotBeNil)
So(akara.NewComponentFilter(nil, nil, nil), ShouldNotBeNil)
})
})
}
17 changes: 9 additions & 8 deletions component_filter_test.go → tests/component_filter_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package akara
package tests

import (
"fmt"
"github.com/gravestench/akara"
"github.com/gravestench/bitset"
"math"
"math/rand"
Expand Down Expand Up @@ -32,7 +33,7 @@ func TestComponentFilter_Allow(t *testing.T) {
B := bitset.NewBitSet(1, 2, 3, 4)

Convey("Where the filter imposes no requirements or restrictions", func() {
cf := NewComponentFilter(nil, nil, nil)
cf := akara.NewComponentFilter(nil, nil, nil)

Convey("The filter will allow any bitset", func() {
So(cf.Allow(A), ShouldEqual, true)
Expand All @@ -41,7 +42,7 @@ func TestComponentFilter_Allow(t *testing.T) {
})

Convey("With a ComponentFilter that requires all bits from BitSet A", func() {
cf1 := NewComponentFilter(A, nil, nil)
cf1 := akara.NewComponentFilter(A, nil, nil)

Convey("the component filter should allow bitset A", func() {
So(cf1.Allow(A), ShouldEqual, true)
Expand All @@ -53,7 +54,7 @@ func TestComponentFilter_Allow(t *testing.T) {
})

Convey("With a ComponentFilter that requires all bits from BitSet B", func() {
cf1 := NewComponentFilter(B, nil, nil)
cf1 := akara.NewComponentFilter(B, nil, nil)

Convey("the component filter should NOT allow bitset A", func() {
So(cf1.Allow(A), ShouldEqual, false)
Expand All @@ -70,7 +71,7 @@ func TestComponentFilter_Equals(t *testing.T) {
bs1 := bitset.NewBitSet(1, 2, 3)
bs2 := bitset.NewBitSet(1, 2, 3, 4)

cf1 := NewComponentFilter(bs1, nil, nil)
cf1 := akara.NewComponentFilter(bs1, nil, nil)

if !cf1.Allow(bs2) {
t.Error("component filter should allow bitset which is superset of it's Required bitset")
Expand All @@ -84,7 +85,7 @@ func benchComponentFilterAllow(i int, b *testing.B) {
bs1 := bitset.NewBitSet(randIndices(i)...)
bs2 := bitset.NewBitSet(randIndices(i)...)
bs3 := bitset.NewBitSet(randIndices(i)...)
cf1 := NewComponentFilter(bs1, bs2, bs3)
cf1 := akara.NewComponentFilter(bs1, bs2, bs3)

// ... then we need to reset the timer...
b.ResetTimer()
Expand Down Expand Up @@ -112,8 +113,8 @@ func benchComponentFilterEquals(i int, b *testing.B) {
bs5 := bitset.NewBitSet(randIndices(i)...)
bs6 := bitset.NewBitSet(randIndices(i)...)

cf1 := NewComponentFilter(bs1, bs2, bs3)
cf2 := NewComponentFilter(bs4, bs5, bs6)
cf1 := akara.NewComponentFilter(bs1, bs2, bs3)
cf2 := akara.NewComponentFilter(bs4, bs5, bs6)

b.ResetTimer()
for n := 0; n < b.N; n++ {
Expand Down
Loading

0 comments on commit 4ae5a35

Please sign in to comment.