Skip to content

Commit

Permalink
Add examples to demonstrate the use of non-ECS data structures togeth…
Browse files Browse the repository at this point in the history
…er with ECS (#379)
  • Loading branch information
mlange-42 authored Feb 11, 2024
1 parent 3c6be29 commit 088d0f8
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ jobs:
go run ./_examples/filter
go run ./_examples/generic
go run ./_examples/locked_world
go run ./_examples/no_ecs
go run ./_examples/no_ecs_generic
go run ./_examples/parallel
go run ./_examples/random_access
go run ./_examples/random_sampling
Expand Down Expand Up @@ -186,6 +188,8 @@ jobs:
go run -tags tiny ./_examples/filter
go run -tags tiny ./_examples/generic
go run -tags tiny ./_examples/locked_world
go run -tags tiny ./_examples/no_ecs
go run -tags tiny ./_examples/no_ecs_generic
go run -tags tiny ./_examples/parallel
go run -tags tiny ./_examples/random_access
go run -tags tiny ./_examples/random_sampling
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* Adds [BENCHMARKS.md](https://github.com/mlange-42/arche/blob/main/BENCHMARKS.md) for a tabular overview of the runtime cost of typical *Arche* ECS operations (#367, #372)
* Link benchmarking code in `README.md` and benchmarking tables (#375)
* Documents build tags `tiny` and `debug` in package docs of `ecs` (#377)
* Adds examples to demonstrate the use of non-ECS data structures together with ECS (#379)

### Bugfixes

Expand Down
106 changes: 106 additions & 0 deletions _examples/no_ecs/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Demonstrates that ECS can be mixed with non-ECS data structures, as long as they store entities.
// Uses the ID-based API.
package main

import (
"fmt"
"math/rand"

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

// CellCoord component.
type CellCoord struct {
X int
Y int
}

// Grid resource / data structure.
type Grid struct {
Data [][]ecs.Entity
Width int
Height int
}

// NewGrid creates a ner Grid of the given size.
func NewGrid(w, h int) Grid {
grid := make([][]ecs.Entity, w)
for i := 0; i < w; i++ {
grid[i] = make([]ecs.Entity, h)
}
return Grid{
Data: grid,
Width: w,
Height: h,
}
}

func main() {
// Create a new World.
world := ecs.NewWorld()

// Create a non-ECS grid data structure,
// and add is as a resource.
grid := NewGrid(30, 20)
ecs.AddResource(&world, &grid)

// Create enities on the grid.
createGridEntities(&world, 250)

// Run a simulation
run(&world)
}

func createGridEntities(world *ecs.World, count int) {
// Get the grid resource.
gridId := ecs.ResourceID[Grid](world)
grid := world.Resources().Get(gridId).(*Grid)

// Get the CellCoord component ID.
coordId := ecs.ComponentID[CellCoord](world)

// Put some entities into the grid.
cnt := 0
for cnt < count {
// Draw random coordinates.
x, y := rand.Intn(grid.Width), rand.Intn(grid.Height)
// Skip if there is already an entity.
if !grid.Data[x][y].IsZero() {
continue
}
// Create an entity.
entity := world.NewEntity(coordId)
// Place the entity in the grid.
grid.Data[x][y] = entity
// Initialize entity components.
coord := (*CellCoord)(world.Get(entity, coordId))
coord.X, coord.Y = x, y

cnt++
}
}

func run(world *ecs.World) {
// Get the grid resource.
gridId := ecs.ResourceID[Grid](world)
grid := world.Resources().Get(gridId).(*Grid)

// Get the CellCoord component ID.
coordId := ecs.ComponentID[CellCoord](world)

// Print random entities from the grid.
for i := 0; i < 25; i++ {
// Draw random coordinates.
x, y := rand.Intn(grid.Width), rand.Intn(grid.Height)
// Get the entity.
entity := grid.Data[x][y]
// Print zero entity
if entity.IsZero() {
fmt.Printf("(%2d,%2d): zero entity\n", x, y)
continue
}
// Print CellCoord component of non-zero entity.
coord := (*CellCoord)(world.Get(entity, coordId))
fmt.Printf("(%2d,%2d): %+v\n", x, y, coord)
}
}
107 changes: 107 additions & 0 deletions _examples/no_ecs_generic/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Demonstrates that ECS can be mixed with non-ECS data structures, as long as they store entities.
// Uses the generic API.
package main

import (
"fmt"
"math/rand"

"github.com/mlange-42/arche/ecs"
"github.com/mlange-42/arche/generic"
)

// CellCoord component.
type CellCoord struct {
X int
Y int
}

// Grid resource / data structure.
type Grid struct {
Data [][]ecs.Entity
Width int
Height int
}

// NewGrid creates a ner Grid of the given size.
func NewGrid(w, h int) Grid {
grid := make([][]ecs.Entity, w)
for i := 0; i < w; i++ {
grid[i] = make([]ecs.Entity, h)
}
return Grid{
Data: grid,
Width: w,
Height: h,
}
}

func main() {
// Create a new World.
world := ecs.NewWorld()

// Create a non-ECS grid data structure,
// and add is as a resource.
grid := NewGrid(30, 20)
ecs.AddResource(&world, &grid)

// Create enities on the grid.
createGridEntities(&world, 250)

// Run a simulation
run(&world)
}

func createGridEntities(world *ecs.World, count int) {
// Get the grid resource.
gridRes := generic.NewResource[Grid](world)
grid := gridRes.Get()

// Create a generic Map as a builder.
builder := generic.NewMap1[CellCoord](world)

// Put some entities into the grid.
cnt := 0
for cnt < count {
// Draw random coordinates.
x, y := rand.Intn(grid.Width), rand.Intn(grid.Height)
// Skip if there is already an entity.
if !grid.Data[x][y].IsZero() {
continue
}
// Create an entity.
entity := builder.New()
// Place the entity in the grid.
grid.Data[x][y] = entity
// Initialize entity components.
coord := builder.Get(entity)
coord.X, coord.Y = x, y

cnt++
}
}

func run(world *ecs.World) {
// Get the grid resource.
gridRes := generic.NewResource[Grid](world)
grid := gridRes.Get()

// Create a generic Map for component access.
mapper := generic.NewMap1[CellCoord](world)

// Print random entities from the grid.
for i := 0; i < 25; i++ {
// Draw random coordinates.
x, y := rand.Intn(grid.Width), rand.Intn(grid.Height)
// Get the entity.
entity := grid.Data[x][y]
// Print zero entity
if entity.IsZero() {
fmt.Printf("(%2d,%2d): zero entity\n", x, y)
continue
}
// Print CellCoord component of non-zero entity.
coord := mapper.Get(entity)
fmt.Printf("(%2d,%2d): %+v\n", x, y, coord)
}
}

0 comments on commit 088d0f8

Please sign in to comment.