diff --git a/cmd/test/trianlge.go b/cmd/test/trianlge.go index 103cf63..bb22223 100644 --- a/cmd/test/trianlge.go +++ b/cmd/test/trianlge.go @@ -94,7 +94,7 @@ func (t *Tri) OnUpdate(c Context) { tt := *t tt.Spawned = true tt.Disconnect() - if e.Spawn(&tt) == nil { + if e.Spawn(&tt) { counter++ } } diff --git a/engine.go b/engine.go index 55cd04e..d575917 100644 --- a/engine.go +++ b/engine.go @@ -37,10 +37,6 @@ type WindowConfig struct { VSync bool } -type Objects struct { - store []Object -} - // The main structure that represents // current state of [game] engine. type Engine struct { @@ -49,7 +45,7 @@ type Engine struct { // The main holder for objects. // Uses the map structure to quickly // delete and create new objects. - Objects *Objects + objects *Objects // The main camera to display in window. // If is set to nil then the engine will panic. @@ -114,7 +110,7 @@ func NewEngine( ret.wcfg = cfg ret.outerEvents = make(EventChan) ret.handleEvents = make(EventChan) - ret.Objects = &Objects{} + ret.objects = NewObjects() ret.buttons = MouseButtonMap{} return ret } @@ -133,30 +129,32 @@ func (e *Engine) EventInput() EventChan { return e.outerEvents } -// Add new object to the Engine's view. -func (e *Engine) Spawn(o Object) error { - /*if e.Objects.Has(b) { - return ObjectExistErr - }*/ +func (e *Engine) Exist(object Object) bool { + return e.objects.has(object) +} - o.OnStart(Context{ +// Add new objects to the Engine's view. +func (e *Engine) Spawn(object Object) bool { + + ctx := Context{ engine: e, - }) - e.Objects.store = append(e.Objects.store, o) + } + ok := e.objects.add(object) + object.OnStart(ctx) - return nil + return ok } // Delete object from Engine. -func (e *Engine) Delete(b Object) error { - /*if !e.Objects.Has(b) { - return ObjectNotExistErr +func (e *Engine) Delete(object Object) bool { + + ctx := Context{ + engine: e, } + ok := e.objects.remove(object) + object.OnDelete(ctx) - b.Delete(&Context{Engine: e}) - e.Objects.Del(b)*/ - - return nil + return ok } var ( @@ -329,7 +327,7 @@ func (e *engine) Update() error { engine: eng, events: events, } - for _, object := range e.Objects.store { + for _, object := range e.objects.store { object.OnUpdate(c) } @@ -358,7 +356,7 @@ func (e *engine) Draw(img *ebiten.Image) { e.drawdt = time.Since(e.drawLastTime) eng := (*Engine)(e) m := map[Layer][]Drawer{} - for _, object := range eng.Objects.store { + for _, object := range eng.objects.store { // Skipping the ones we do not need to draw. if !object.IsVisible() { continue diff --git a/errors.go b/errors.go index 5183591..6329769 100644 --- a/errors.go +++ b/errors.go @@ -5,8 +5,7 @@ import ( ) var ( - ObjectExistErr = errors.New("the object already exists") - ObjectNotExistErr = errors.New("the object does not exist") - ObjectNotImplementedErr = errors.New("none of object methods are implemented") + ErrObjectExist = errors.New("the object already exists") + ErrObjectNotExist = errors.New("the object does not exist") ) diff --git a/objects.go b/objects.go new file mode 100644 index 0000000..a1d830f --- /dev/null +++ b/objects.go @@ -0,0 +1,58 @@ +package gg + +// The structure to store objects +// with O(1) add, remove and search operations. +type Objects struct { + // The place to store all the objects. + store []Object + + // Find index by Object. + searchMap map[Object] int + + // Available nil values in the store. + freeIndexes []int +} + +func NewObjects() *Objects { + ret := &Objects{} + ret.searchMap = map[Object] int {} + return ret +} + +func (objects *Objects) has(object Object) bool { + _, ok := objects.searchMap[object] + return ok +} + +func (objects *Objects) add(object Object) bool { + if objects.has(object) { + return false + } + if len(objects.freeIndexes) > 0 { + freeIndex := objects.freeIndexes[0] + objects.freeIndexes = objects.freeIndexes[1:] + + objects.store[freeIndex] = object + objects.searchMap[object] = freeIndex + } else { + objects.store = append(objects.store, object) + objects.searchMap[object] = len(objects.store)-1 + } + return true +} + +func (objects *Objects) remove(object Object) bool { + objectIndex, ok := objects.searchMap[object] + if !ok { + return false + } + + objects.store[objectIndex] = nil + objects.freeIndexes = append( + objects.freeIndexes, + objectIndex, + ) + + return true +} +