Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exchange with relation targets, more batch ops #342

Merged
merged 12 commits into from
Jan 18, 2024
Merged
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ This change was necessary to get the same performance as before, despite the mor
* Adds functions `ComponentIDs(*World)` and `ResourceIDs(*World)` to get all registered IDs (#329)
* Adds methods `Mask.And`, `Mask.Or` and `Mask.Xor` (#335)
* Adds build tag `tiny` to restrict to 64 components for an extra bit of performance (#338)
* Adds methods `Relations.Exchange()`, `Relations.ExchangeBatch()`, `Relations.ExchangeBatchQ()` for exchange with relation target (#342)
* Generic API adds `Exchange.WithRelation()` and optional target argument for operations with relation target (#342)
* Generic API adds `MapX.AddBatch()`, `MapX.AddBatchQ()`, `MapX.RemoveBatch()`and `MapX.RemoveBatchQ()` (#342)
* Generic API adds optional relation target argument to most `MapX` methods (#342)
* Generic API adds `FilterX.Filter()` to get an `ecs.Filter` from a generic one (#342)

### Performance

Expand Down
14 changes: 8 additions & 6 deletions ecs/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Batch struct {
//
// See also [Batch.AddQ] and [World.Add].
func (b *Batch) Add(filter Filter, comps ...ID) {
b.world.exchangeBatch(filter, comps, nil)
b.world.exchangeBatch(filter, comps, nil, ID{}, false, Entity{})
}

// AddQ adds components to many entities, matching a filter.
Expand All @@ -27,7 +27,7 @@ func (b *Batch) Add(filter Filter, comps ...ID) {
//
// See also [Batch.Add] and [World.Add].
func (b *Batch) AddQ(filter Filter, comps ...ID) Query {
return b.world.exchangeBatchQuery(filter, comps, nil)
return b.world.exchangeBatchQuery(filter, comps, nil, ID{}, false, Entity{})
}

// Remove removes components from many entities, matching a filter.
Expand All @@ -38,7 +38,7 @@ func (b *Batch) AddQ(filter Filter, comps ...ID) Query {
//
// See also [Batch.RemoveQ] and [World.Remove].
func (b *Batch) Remove(filter Filter, comps ...ID) {
b.world.exchangeBatch(filter, nil, comps)
b.world.exchangeBatch(filter, nil, comps, ID{}, false, Entity{})
}

// RemoveQ removes components from many entities, matching a filter.
Expand All @@ -50,7 +50,7 @@ func (b *Batch) Remove(filter Filter, comps ...ID) {
//
// See also [Batch.Remove] and [World.Remove].
func (b *Batch) RemoveQ(filter Filter, comps ...ID) Query {
return b.world.exchangeBatchQuery(filter, nil, comps)
return b.world.exchangeBatchQuery(filter, nil, comps, ID{}, false, Entity{})
}

// SetRelation sets the [Relation] target for many entities, matching a filter.
Expand Down Expand Up @@ -94,8 +94,9 @@ func (b *Batch) SetRelationQ(filter Filter, comp ID, target Entity) Query {
// - when called on a locked world. Do not use during [Query] iteration!
//
// See also [Batch.ExchangeQ] and [World.Exchange].
// For batch-exchange with a relation target, see [Relations.ExchangeBatch].
func (b *Batch) Exchange(filter Filter, add []ID, rem []ID) {
b.world.exchangeBatch(filter, add, rem)
b.world.exchangeBatch(filter, add, rem, ID{}, false, Entity{})
}

// ExchangeQ exchanges components for many entities, matching a filter.
Expand All @@ -109,8 +110,9 @@ func (b *Batch) Exchange(filter Filter, add []ID, rem []ID) {
// - when called on a locked world. Do not use during [Query] iteration!
//
// See also [Batch.Exchange] and [World.Exchange].
// For batch-exchange with a relation target, see [Relations.ExchangeBatchQ].
func (b *Batch) ExchangeQ(filter Filter, add []ID, rem []ID) Query {
return b.world.exchangeBatchQuery(filter, add, rem)
return b.world.exchangeBatchQuery(filter, add, rem, ID{}, false, Entity{})
}

// RemoveEntities removes and recycles all entities matching a filter.
Expand Down
174 changes: 174 additions & 0 deletions ecs/batch_examples_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package ecs_test

import "github.com/mlange-42/arche/ecs"

func ExampleBatch() {
world := ecs.NewWorld()

posID := ecs.ComponentID[Position](&world)
velID := ecs.ComponentID[Velocity](&world)

builder := ecs.NewBuilder(&world, posID, velID)
builder.NewBatch(100)

world.Batch().Remove(ecs.All(posID, velID), velID)
world.Batch().RemoveEntities(ecs.All(posID))
// Output:
}

func ExampleBatch_Add() {
world := ecs.NewWorld()

posID := ecs.ComponentID[Position](&world)
velID := ecs.ComponentID[Velocity](&world)

builder := ecs.NewBuilder(&world, posID)
builder.NewBatch(100)

filter := ecs.All(posID)
world.Batch().Add(filter, velID)
// Output:
}

func ExampleBatch_AddQ() {
world := ecs.NewWorld()

posID := ecs.ComponentID[Position](&world)
velID := ecs.ComponentID[Velocity](&world)

builder := ecs.NewBuilder(&world, posID)
builder.NewBatch(100)

filter := ecs.All(posID)
query := world.Batch().AddQ(filter, velID)

for query.Next() {
pos := (*Position)(query.Get(posID))
pos.X = 100
}
// Output:
}

func ExampleBatch_Remove() {
world := ecs.NewWorld()

posID := ecs.ComponentID[Position](&world)
velID := ecs.ComponentID[Velocity](&world)

builder := ecs.NewBuilder(&world, posID, velID)
builder.NewBatch(100)

filter := ecs.All(posID, velID)
world.Batch().Remove(filter, velID)
// Output:
}

func ExampleBatch_RemoveQ() {
world := ecs.NewWorld()

posID := ecs.ComponentID[Position](&world)
velID := ecs.ComponentID[Velocity](&world)

builder := ecs.NewBuilder(&world, posID, velID)
builder.NewBatch(100)

filter := ecs.All(posID, velID)
query := world.Batch().RemoveQ(filter, velID)

for query.Next() {
pos := (*Position)(query.Get(posID))
pos.X = 100
}
// Output:
}

func ExampleBatch_Exchange() {
world := ecs.NewWorld()

posID := ecs.ComponentID[Position](&world)
velID := ecs.ComponentID[Velocity](&world)

builder := ecs.NewBuilder(&world, posID)
builder.NewBatch(100)

filter := ecs.All(posID)
world.Batch().Exchange(
filter, // Filter
[]ecs.ID{velID}, // Add components
[]ecs.ID{posID}, // Remove components
)
// Output:
}

func ExampleBatch_ExchangeQ() {
world := ecs.NewWorld()

posID := ecs.ComponentID[Position](&world)
velID := ecs.ComponentID[Velocity](&world)

builder := ecs.NewBuilder(&world, posID)
builder.NewBatch(100)

filter := ecs.All(posID)
query := world.Batch().ExchangeQ(
filter, // Filter
[]ecs.ID{velID}, // Add components
[]ecs.ID{posID}, // Remove components
)

for query.Next() {
vel := (*Velocity)(query.Get(velID))
vel.X = 100
}
// Output:
}

func ExampleBatch_RemoveEntities() {
world := ecs.NewWorld()

posID := ecs.ComponentID[Position](&world)

builder := ecs.NewBuilder(&world, posID)
builder.NewBatch(100)

filter := ecs.All(posID)
world.Batch().RemoveEntities(filter)
// Output:
}

func ExampleBatch_SetRelation() {
world := ecs.NewWorld()

posID := ecs.ComponentID[Position](&world)
childID := ecs.ComponentID[ChildOf](&world)

target := world.NewEntity()

builder := ecs.NewBuilder(&world, posID, childID)
builder.NewBatch(100)

filter := ecs.All(childID)
world.Batch().SetRelation(filter, childID, target)
// Output:
}

func ExampleBatch_SetRelationQ() {
world := ecs.NewWorld()

posID := ecs.ComponentID[Position](&world)
childID := ecs.ComponentID[ChildOf](&world)

target := world.NewEntity()

builder := ecs.NewBuilder(&world, posID, childID)
builder.NewBatch(100)

filter := ecs.All(childID)
query := world.Batch().SetRelationQ(filter, childID, target)

for query.Next() {
pos := (*Position)(query.Get(posID))
pos.X = 100
}
// Output:
}
Loading
Loading