Skip to content

Commit

Permalink
add shorter named method, Each and First. (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
yohamta authored Dec 10, 2022
1 parent 77736c0 commit d5a1431
Show file tree
Hide file tree
Showing 26 changed files with 73 additions and 48 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ Components can be added and removed through `Entry` objects.
```go
// Fetch the first entity with PlayerTag component
query := donburi.NewQuery(filter.Contains(PlayerTag))
// Query.FirstEntity() returns only the first entity that
// Query.First() returns only the first entity that
// matches the query.
if entry, ok := donburi.FirstEntity(world); ok {
if entry, ok := donburi.First(world); ok {
donburi.Add(entry, Position, &PositionData{
X: 100,
Y: 100,
Expand All @@ -126,7 +126,7 @@ if SomeLogic.IsDead(world, someEntity) {
}
```

Entities can be retrieved using the `First` and `EachEntity` methods of Components as follows:
Entities can be retrieved using the `First` and `Each` methods of Components as follows:

```go
// GameState Component
Expand All @@ -153,7 +153,7 @@ if entry, ok := GameState.First(world); ok {
}

// Query all Bullet entities
Bullet.EachEntity(world, func(entry *donburi.Entry) {
Bullet.Each(world, func(entry *donburi.Entry) {
bullet := Bullet.Get(entry)
// .. do stuff with the bullet entity
})
Expand All @@ -168,7 +168,7 @@ Queries allow for high performance and expressive iteration through the entities
query := donburi.NewQuery(filter.Contains(Position, Velocity))

// Iterate through the entities found in the world
query.EachEntity(world, func(entry *donburi.Entry) {
query.Each(world, func(entry *donburi.Entry) {
// An entry is an accessor to entity and its components.
position := Position.Get(entry)
velocity := Velocity.Get(entry)
Expand Down Expand Up @@ -207,7 +207,7 @@ query := donburi.NewQuery(
)

// In our query we can check if the entity has some of the optional components before attempting to retrieve them
query.EachEntity(world, func(entry *donburi.Entry) {
query.Each(world, func(entry *donburi.Entry) {
// We'll always be able to access Position and Size
position := Position.Get(entry)
size := Size.Get(entry)
Expand Down Expand Up @@ -251,7 +251,7 @@ var EnemyTag = donburi.NewTag()
world.CreateMany(100, EnemyTag, Position, Velocity)

// Search entities with EnemyTag
EnemyTag.EachEntity(world, func(entry *donburi.Entry) {
EnemyTag.Each(world, func(entry *donburi.Entry) {
// Perform some operation on the Entities with the EnemyTag component.
}
```
Expand Down
29 changes: 22 additions & 7 deletions component.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,26 +44,41 @@ func (c *ComponentType[T]) Set(entry *Entry, compoennt *T) {
entry.SetComponent(c, unsafe.Pointer(compoennt))
}

// EachEntity iterates over the entities that have the component.
// Each iterates over the entities that have the component.
func (c *ComponentType[T]) Each(w World, callback func(*Entry)) {
c.query.Each(w, callback)
}

// deprecated: use Each instead
func (c *ComponentType[T]) EachEntity(w World, callback func(*Entry)) {
c.query.EachEntity(w, callback)
c.Each(w, callback)
}

// First returns the first entity that has the component.
func (c *ComponentType[T]) First(w World) (*Entry, bool) {
return c.query.First(w)
}

// FirstEntity returns the first entity that has the component.
// deprecated: use First instead
func (c *ComponentType[T]) FirstEntity(w World) (*Entry, bool) {
return c.query.FirstEntity(w)
return c.First(w)
}

// MustFirstEntity returns the first entity that has the component or panics.
func (c *ComponentType[T]) MustFirstEntity(w World) *Entry {
e, ok := c.query.FirstEntity(w)
// MustFirst returns the first entity that has the component or panics.
func (c *ComponentType[T]) MustFirst(w World) *Entry {
e, ok := c.query.First(w)
if !ok {
panic(fmt.Sprintf("no entity has the component %s", c.name))
}

return e
}

// deprecated: use MustFirst instead
func (c *ComponentType[T]) MustFirstEntity(w World) *Entry {
return c.MustFirst(w)
}

// SetValue sets the value of the component.
func (c *ComponentType[T]) SetValue(entry *Entry, value T) {
comp := c.Get(entry)
Expand Down
2 changes: 1 addition & 1 deletion examples/bunnymark/system/bounce.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func NewBounce(bounds *image.Rectangle) *Bounce {
}

func (b *Bounce) Update(w donburi.World) {
b.query.EachEntity(w, func(entry *donburi.Entry) {
b.query.Each(w, func(entry *donburi.Entry) {
position := component.Position.Get(entry)
velocity := component.Velocity.Get(entry)
sprite := component.Sprite.Get(entry)
Expand Down
2 changes: 1 addition & 1 deletion examples/bunnymark/system/gravity.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func NewGravity() *Gravity {
}

func (g *Gravity) Update(w donburi.World) {
g.query.EachEntity(w, func(entry *donburi.Entry) {
g.query.Each(w, func(entry *donburi.Entry) {
gravity := component.Gravity.Get(entry)
velocity := component.Velocity.Get(entry)

Expand Down
2 changes: 1 addition & 1 deletion examples/bunnymark/system/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func NewMetrics(bounds *image.Rectangle) *Metrics {

func (m *Metrics) Update(w donburi.World) {
if m.settings == nil {
if entry, ok := component.Settings.FirstEntity(w); ok {
if entry, ok := component.Settings.First(w); ok {
m.settings = component.Settings.Get(entry)
} else {
panic("no settings")
Expand Down
2 changes: 1 addition & 1 deletion examples/bunnymark/system/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func NewRender() *Render {
}

func (r *Render) Draw(w donburi.World, screen *ebiten.Image) {
r.query.EachEntity(w, func(entry *donburi.Entry) {
r.query.Each(w, func(entry *donburi.Entry) {
position := component.Position.Get(entry)
hue := component.Hue.Get(entry)
sprite := component.Sprite.Get(entry)
Expand Down
2 changes: 1 addition & 1 deletion examples/bunnymark/system/spawn.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (s *Spawn) Update(w donburi.World) {

func (s *Spawn) addBunnies(w donburi.World) {
if s.settings == nil {
if entry, ok := component.Settings.FirstEntity(w); ok {
if entry, ok := component.Settings.First(w); ok {
s.settings = component.Settings.Get(entry)
} else {
panic("no settings")
Expand Down
2 changes: 1 addition & 1 deletion examples/bunnymark/system/velocity.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func NewVelocity() *Velocity {
}

func (v *Velocity) Update(w donburi.World) {
v.query.EachEntity(w, func(entry *donburi.Entry) {
v.query.Each(w, func(entry *donburi.Entry) {
position := component.Position.Get(entry)
velocity := component.Velocity.Get(entry)

Expand Down
2 changes: 1 addition & 1 deletion examples/bunnymark_ecs/system/bounce.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func NewBounce(bounds *image.Rectangle) *bounce {
}

func (b *bounce) Update(ecs *ecs.ECS) {
b.query.EachEntity(ecs.World, func(entry *donburi.Entry) {
b.query.Each(ecs.World, func(entry *donburi.Entry) {
position := component.Position.Get(entry)
velocity := component.Velocity.Get(entry)
sprite := component.Sprite.Get(entry)
Expand Down
2 changes: 1 addition & 1 deletion examples/bunnymark_ecs/system/gravity.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var Gravity *gravity = &gravity{
}

func (g *gravity) Update(ecs *ecs.ECS) {
g.query.EachEntity(ecs.World, func(entry *donburi.Entry) {
g.query.Each(ecs.World, func(entry *donburi.Entry) {
gravity := component.Gravity.Get(entry)
velocity := component.Velocity.Get(entry)

Expand Down
2 changes: 1 addition & 1 deletion examples/bunnymark_ecs/system/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func NewMetrics(bounds *image.Rectangle) *Metrics {

func (m *Metrics) Update(ecs *ecs.ECS) {
if m.settings == nil {
if entry, ok := component.Settings.FirstEntity(ecs.World); ok {
if entry, ok := component.Settings.First(ecs.World); ok {
m.settings = component.Settings.Get(entry)
}
}
Expand Down
2 changes: 1 addition & 1 deletion examples/bunnymark_ecs/system/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ var Render = &render{
}

func (r *render) Draw(ecs *ecs.ECS, screen *ebiten.Image) {
r.query.EachEntity(ecs.World, func(entry *donburi.Entry) {
r.query.Each(ecs.World, func(entry *donburi.Entry) {
position := component.Position.Get(entry)
hue := component.Hue.Get(entry)
sprite := component.Sprite.Get(entry)
Expand Down
2 changes: 1 addition & 1 deletion examples/bunnymark_ecs/system/spawn.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (s *Spawn) Update(ecs *ecs.ECS) {

func (s *Spawn) addBunnies(ecs *ecs.ECS) {
if s.settings == nil {
if entry, ok := component.Settings.FirstEntity(ecs.World); ok {
if entry, ok := component.Settings.First(ecs.World); ok {
s.settings = component.Settings.Get(entry)
}
}
Expand Down
2 changes: 1 addition & 1 deletion examples/bunnymark_ecs/system/velocity.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var Velocity = &velocity{
}

func (v *velocity) Update(ecs *ecs.ECS) {
v.query.EachEntity(ecs.World, func(entry *donburi.Entry) {
v.query.Each(ecs.World, func(entry *donburi.Entry) {
position := component.Position.Get(entry)
velocity := component.Velocity.Get(entry)

Expand Down
2 changes: 1 addition & 1 deletion examples/platformer/systems/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func DrawDebug(ecs *ecs.ECS, screen *ebiten.Image) {
if !settings.Debug {
return
}
spaceEntry, ok := components.Space.FirstEntity(ecs.World)
spaceEntry, ok := components.Space.First(ecs.World)
if !ok {
return
}
Expand Down
2 changes: 1 addition & 1 deletion examples/platformer/systems/objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

func UpdateObjects(ecs *ecs.ECS) {
components.Object.EachEntity(ecs.World, func(e *donburi.Entry) {
components.Object.Each(ecs.World, func(e *donburi.Entry) {
obj := dresolv.GetObject(e)
obj.Update()
})
Expand Down
6 changes: 3 additions & 3 deletions examples/platformer/systems/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

func UpdateFloatingPlatform(ecs *ecs.ECS) {
tags.FloatingPlatform.EachEntity(ecs.World, func(e *donburi.Entry) {
tags.FloatingPlatform.Each(ecs.World, func(e *donburi.Entry) {
tw := components.Tween.Get(e)
// Platform movement needs to be done first to make sure there's no space between the top and the player's bottom; otherwise, an alternative might
// be to have the platform detect to see if the Player's resting on it, and if so, move the player up manually.
Expand All @@ -28,15 +28,15 @@ func UpdateFloatingPlatform(ecs *ecs.ECS) {
}

func DrawPlatform(ecs *ecs.ECS, screen *ebiten.Image) {
tags.Platform.EachEntity(ecs.World, func(e *donburi.Entry) {
tags.Platform.Each(ecs.World, func(e *donburi.Entry) {
o := dresolv.GetObject(e)
drawColor := color.RGBA{180, 100, 0, 255}
ebitenutil.DrawRect(screen, o.X, o.Y, o.W, o.H, drawColor)
})
}

func DrawFloatingPlatform(ecs *ecs.ECS, screen *ebiten.Image) {
tags.FloatingPlatform.EachEntity(ecs.World, func(e *donburi.Entry) {
tags.FloatingPlatform.Each(ecs.World, func(e *donburi.Entry) {
o := dresolv.GetObject(e)
drawColor := color.RGBA{180, 100, 0, 255}
ebitenutil.DrawRect(screen, o.X, o.Y, o.W, o.H, drawColor)
Expand Down
4 changes: 2 additions & 2 deletions examples/platformer/systems/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (

func UpdatePlayer(ecs *ecs.ECS) {
// Now we update the Player's movement. This is the real bread-and-butter of this example, naturally.
playerEntry, _ := components.Player.FirstEntity(ecs.World)
playerEntry, _ := components.Player.First(ecs.World)
player := components.Player.Get(playerEntry)
playerObject := dresolv.GetObject(playerEntry)

Expand Down Expand Up @@ -273,7 +273,7 @@ func UpdatePlayer(ecs *ecs.ECS) {
}

func DrawPlayer(ecs *ecs.ECS, screen *ebiten.Image) {
tags.Player.EachEntity(ecs.World, func(e *donburi.Entry) {
tags.Player.Each(ecs.World, func(e *donburi.Entry) {
player := components.Player.Get(e)
o := dresolv.GetObject(e)
playerColor := color.RGBA{0, 255, 60, 255}
Expand Down
2 changes: 1 addition & 1 deletion examples/platformer/systems/ramp.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

func DrawRamp(ecs *ecs.ECS, screen *ebiten.Image) {
tags.Ramp.EachEntity(ecs.World, func(e *donburi.Entry) {
tags.Ramp.Each(ecs.World, func(e *donburi.Entry) {
o := dresolv.GetObject(e)
drawColor := color.RGBA{255, 50, 100, 255}
tri := o.Shape.(*resolv.ConvexPolygon)
Expand Down
4 changes: 2 additions & 2 deletions examples/platformer/systems/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ func UpdateSettings(ecs *ecs.ECS) {
}

func GetOrCreateSettings(ecs *ecs.ECS) *components.SettingsData {
if _, ok := components.Settings.FirstEntity(ecs.World); !ok {
if _, ok := components.Settings.First(ecs.World); !ok {
ent := ecs.World.Entry(ecs.World.Create(components.Settings))
components.Settings.SetValue(ent, components.SettingsData{
ShowHelpText: true,
})
}

ent, _ := components.Settings.FirstEntity(ecs.World)
ent, _ := components.Settings.First(ecs.World)
return components.Settings.Get(ent)
}
2 changes: 1 addition & 1 deletion examples/platformer/systems/wall.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

func DrawWall(ecs *ecs.ECS, screen *ebiten.Image) {
tags.Wall.EachEntity(ecs.World, func(e *donburi.Entry) {
tags.Wall.Each(ecs.World, func(e *donburi.Entry) {
o := dresolv.GetObject(e)
drawColor := color.RGBA{60, 60, 60, 255}
ebitenutil.DrawRect(screen, o.X, o.Y, o.W, o.H, drawColor)
Expand Down
4 changes: 2 additions & 2 deletions features/events/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ var (

// ProcessAllEvents processes all events.
func ProcessAllEvents(w donburi.World) {
eventQuery.EachEntity(w, func(e *donburi.Entry) {
eventQuery.Each(w, func(e *donburi.Entry) {
eventType := getEventType(e)
eventType.process(w)
})
Expand Down Expand Up @@ -106,7 +106,7 @@ func (e *EventType[T]) ProcessEvents(w donburi.World) {
}

func (e *EventType[T]) mustFindEventBus(w donburi.World) *eventBusData[T] {
eventBus, ok := e.eventBusQuery.FirstEntity(w)
eventBus, ok := e.eventBusQuery.First(w)
if !ok {
panic("event bus not found")
}
Expand Down
2 changes: 1 addition & 1 deletion features/hierarchy/hierarchy.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var HierarchySystem = &hierarchySystem{
// You don't need to use this system function when you use
// hierarchy.RemoveRecursive() or hierarchy.RemoveChildrenRecursive() instead.
func (hs *hierarchySystem) RemoveChildren(ecs *ecs.ECS) {
hs.query.EachEntity(ecs.World, func(entry *donburi.Entry) {
hs.query.Each(ecs.World, func(entry *donburi.Entry) {
if !entry.Valid() {
return
}
Expand Down
18 changes: 14 additions & 4 deletions query.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ func NewQuery(filter filter.LayoutFilter) *Query {
}
}

// EachEntity iterates over all entities that match the query.
func (q *Query) EachEntity(w World, callback func(*Entry)) {
// Each iterates over all entities that match the query.
func (q *Query) Each(w World, callback func(*Entry)) {
accessor := w.StorageAccessor()
result := q.evaluateQuery(w, &accessor)
iter := storage.NewEntityIterator(0, accessor.Archetypes, result)
Expand All @@ -48,6 +48,11 @@ func (q *Query) EachEntity(w World, callback func(*Entry)) {
}
}

// deprecated: use Each instead
func (q *Query) EachEntity(w World, callback func(*Entry)) {
q.Each(w, callback)
}

// Count returns the number of entities that match the query.
func (q *Query) Count(w World) int {
accessor := w.StorageAccessor()
Expand All @@ -61,8 +66,8 @@ func (q *Query) Count(w World) int {
return ret
}

// FirstEntity returns the first entity that matches the query.
func (q *Query) FirstEntity(w World) (entry *Entry, ok bool) {
// First returns the first entity that matches the query.
func (q *Query) First(w World) (entry *Entry, ok bool) {
accessor := w.StorageAccessor()
result := q.evaluateQuery(w, &accessor)
iter := storage.NewEntityIterator(0, accessor.Archetypes, result)
Expand All @@ -78,6 +83,11 @@ func (q *Query) FirstEntity(w World) (entry *Entry, ok bool) {
return nil, false
}

// deprecated: use First instead
func (q *Query) FirstEntity(w World) (entry *Entry, ok bool) {
return q.First(w)
}

func (q *Query) evaluateQuery(world World, accessor *StorageAccessor) []storage.ArchetypeIndex {
w := world.Id()
if _, ok := q.layout_matches[w]; !ok {
Expand Down
Loading

0 comments on commit d5a1431

Please sign in to comment.