diff --git a/internal/sim/door.go b/internal/sim/door.go new file mode 100644 index 0000000..38a5193 --- /dev/null +++ b/internal/sim/door.go @@ -0,0 +1,43 @@ +package sim + +import ( + "time" + + "github.com/jordanorelli/blammo" +) + +type door struct { + *blammo.Log +} + +func (d *door) update(time.Duration) {} + +func (d *door) onStartOverlap(e *entity) { + d.Info("start overlap: %v", e) +} + +func (d *door) onOverlap(e *entity) { + d.Info("overlap: %v", e) +} + +func (d *door) onStopOverlap(e *entity) { + d.Info("stop overlap: %v", e) +} + +/* + + +┌──────────┐ +│··········│ +│··········│ +│··········│ ┌──────┐ +│··········│ │ │ +│··········│ │ │ +│·····d····◇░░░░░░░░◇ │ +│··········│ │ │ +│··········│ │ │ +│··········│ └──────┘ +│··········◇ +└──────────┘ + +*/ diff --git a/internal/sim/entity.go b/internal/sim/entity.go index 5d481f8..8824962 100644 --- a/internal/sim/entity.go +++ b/internal/sim/entity.go @@ -7,13 +7,73 @@ import ( ) type entity struct { - ID int `json:"id"` - Position math.Vec `json:"pos"` - Glyph rune `json:"glyph"` - solid bool `json:"-"` + ID int `json:"id"` + Position math.Vec `json:"pos"` + Glyph rune `json:"glyph"` + solid bool `json:"-"` + overlapped map[int]*entity behavior } +func (e *entity) overlapping(others ...*entity) { + idx := make(map[int]*entity, len(others)) + for i, _ := range others { + e2 := others[i] + if e2 == e { + continue + } + idx[e2.ID] = e2 + } + + for _, e2 := range e.overlapped { + if idx[e2.ID] == nil { + e.stopOverlap(e2) + } + } + + for _, e2 := range idx { + e.overlap(e2) + } + + e.overlapped = idx +} + +func (e *entity) overlap(e2 *entity) { + if e.overlapped == nil { + e.overlapped = make(map[int]*entity, 4) + } + + type overlapStarter interface { + onStartOverlap(*entity) + } + + if e.behavior != nil && e.overlapped[e2.ID] == nil { + if b, ok := e.behavior.(overlapStarter); ok { + b.onStartOverlap(e2) + } + } + + type overlapper interface { + onOverlap(*entity) + } + if e.behavior != nil { + if b, ok := e.behavior.(overlapper); ok { + b.onOverlap(e2) + } + } +} + +func (e *entity) stopOverlap(e2 *entity) { + type overlapStopper interface { + onStopOverlap(*entity) + } + if e.behavior != nil { + if b, ok := e.behavior.(overlapStopper); ok { + b.onStopOverlap(e2) + } + } +} + type behavior interface { // update is the standard tick function update(time.Duration) diff --git a/internal/sim/tile.go b/internal/sim/tile.go index 8c05353..2ca4ebf 100644 --- a/internal/sim/tile.go +++ b/internal/sim/tile.go @@ -1,5 +1,9 @@ package sim +import ( + "time" +) + type tile struct { floor floor here []*entity @@ -26,3 +30,24 @@ func (t *tile) removeEntity(id int) { } t.here = here } + +func (t *tile) update(d time.Duration) { + for _, e := range t.here { + e.update(d) + } +} + +func (t *tile) overlaps() { + switch len(t.here) { + case 0: + return + case 1: + t.here[0].overlapping() + return + default: + } + + for _, e := range t.here { + e.overlapping(t.here...) + } +} diff --git a/internal/sim/world.go b/internal/sim/world.go index 127381c..2fe69c5 100644 --- a/internal/sim/world.go +++ b/internal/sim/world.go @@ -61,6 +61,15 @@ func newWorld(log *blammo.Log) *world { behavior: doNothing{}, }) + foyer.addEntity(&entity{ + ID: -4, + Position: math.Vec{9, 5}, + Glyph: '◇', + behavior: &door{ + Log: log.Child("door"), + }, + }) + hall := room{ Log: log.Child("hall"), name: "hall", @@ -201,14 +210,22 @@ func (w *world) tick(d time.Duration) { } } - // run all object effects + // run all object updates for _, r := range w.rooms { for _, t := range r.tiles { - for _, e := range t.here { - e.update(d) - } + t.update(d) + } + } + + // check all overlapping entities + for _, r := range w.rooms { + for _, t := range r.tiles { + t.overlaps() } + } + // send frame data to all players + for _, r := range w.rooms { frame := wire.Frame{ Entities: r.allEntities(), Players: r.playerAvatars(),