aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2025-07-09 07:27:47 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2025-07-09 07:27:47 +0200
commit1a4f1f3bd5814af2deaac4b8ccd4be33264793a8 (patch)
tree9d1810f9234784fb2cd36387f4ecf76188cead2c
parent11fe00e83fe2d5e621fe9b7aeda273b0c0a0cea2 (diff)
Entity builders
-rw-r--r--entity.go63
-rw-r--r--main.go51
-rw-r--r--spawn.go22
3 files changed, 81 insertions, 55 deletions
diff --git a/entity.go b/entity.go
index 185efdb..e111f06 100644
--- a/entity.go
+++ b/entity.go
@@ -3,6 +3,7 @@ package main
import (
"age_of_empires/ecs"
"age_of_empires/physics"
+ "image/color"
"github.com/hajimehoshi/ebiten/v2"
)
@@ -25,3 +26,65 @@ func (e Entity) Bounds() physics.Rectangle {
Max: e.Position.Value.Add(e.Image.Value.Bounds().Size()),
}
}
+
+type EntityBuilder Entity
+
+func (b EntityBuilder) WithPosition(position physics.Point) EntityBuilder {
+ b.Position = ecs.C(position)
+ return b
+}
+
+func (b EntityBuilder) WithImage(image *ebiten.Image) EntityBuilder {
+ b.Image = ecs.C(image)
+ return b
+}
+
+var red = color.RGBA{0xff, 0x00, 0x00, 0xff}
+
+func (b EntityBuilder) WithSelection(haloKind string) EntityBuilder {
+ b.Selection = ecs.C(Selection{
+ IsSelected: false,
+ Halo: nil,
+ })
+ switch haloKind {
+ case "round":
+ b.Selection.Value.Halo = NewStrokeCircleImage(110, SELECTION_HALO_WIDTH, red)
+ case "square":
+ b.Selection.Value.Halo = NewStrokeRectangleImage(physics.Point{X: 110, Y: 110}, SELECTION_HALO_WIDTH, red)
+ }
+ return b
+}
+
+func (b EntityBuilder) WithResourceStorage() EntityBuilder {
+ b.ResourceStorage = ecs.C(ResourceStorage{})
+ return b
+}
+
+func (b EntityBuilder) WithResourceSource(amount int) EntityBuilder {
+ b.ResourceSource = ecs.C(ResourceSource{Remaining: amount})
+ return b
+}
+
+func (b EntityBuilder) WithSpawn(spawn Spawn) EntityBuilder {
+ b.Spawn = ecs.C(spawn)
+ return b
+}
+
+func (b EntityBuilder) WithMove() EntityBuilder {
+ b.Move = ecs.C(physics.Move{IsActive: false})
+ return b
+}
+
+func (b EntityBuilder) WithOrder() EntityBuilder {
+ b.Order.IsEnabled = true
+ return b
+}
+
+func (b EntityBuilder) WithResourceGatherer(maxCapacity int) EntityBuilder {
+ b.ResourceGatherer = ecs.C(ResourceGatherer{MaxCapacity: maxCapacity})
+ return b
+}
+
+func (b EntityBuilder) Build() Entity {
+ return Entity(b)
+}
diff --git a/main.go b/main.go
index a5bde3e..122e95a 100644
--- a/main.go
+++ b/main.go
@@ -42,8 +42,7 @@ type Game struct {
Selection GlobalSelection
ResourceAmount int
FaceSource *text.GoTextFaceSource
- personImage *ebiten.Image
- personSelectionHalo *ebiten.Image
+ UnitBuilder EntityBuilder
}
func DrawMove(screen *ebiten.Image, e *Entity) {
@@ -209,7 +208,7 @@ func main() {
f, err := os.Create("cpu.prof")
kcore.Expect(err, "could not create CPU profile")
defer f.Close()
- kcore.Expect(pprof.StartCPUProfile(f), "could not start CPU profile")
+ kcore.Expect(pprof.StartCPUProfile(f), "could not start CPU profile")
defer pprof.StopCPUProfile()
}
}
@@ -227,47 +226,19 @@ func main() {
s, err := text.NewGoTextFaceSource(bytes.NewReader(goregular.TTF))
kcore.Expect(err, "failed to create font source")
game.FaceSource = s
- ironImage := NewFilledRectangleImage(physics.Point{X: 100, Y: 100}, color.RGBA{0x80, 0x80, 0x80, 0xff})
- ironSelectionHalo := NewStrokeRectangleImage(physics.Point{X: 110, Y: 110}, SELECTION_HALO_WIDTH, color.RGBA{0xff, 0x00, 0x00, 0xff})
- ironMine := Entity{
- Position: ecs.C(physics.Point{X: 1000, Y: 1000}),
- Image: ecs.C(ironImage),
- ResourceSource: ecs.C(ResourceSource{Remaining: 1000}),
- Selection: ecs.C(Selection{IsSelected: false, Halo: ironSelectionHalo}),
- }
+ ironMine := EntityBuilder{}.WithPosition(physics.Point{X: 1000, Y: 1000}).WithImage(NewFilledRectangleImage(physics.Point{X: 100, Y: 100}, color.RGBA{0x80, 0x80, 0x80, 0xff})).WithResourceSource(1000).WithSelection("square").Build()
game.Entities = append(game.Entities, &ironMine)
- townCenterImage := NewFilledRectangleImage(physics.Point{X: 100, Y: 100}, color.RGBA{0x00, 0x00, 0xff, 0xff})
- townCenter := Entity{
- Position: ecs.C(physics.Point{X: 1000, Y: 2000}),
- Image: ecs.C(townCenterImage),
- ResourceStorage: ecs.C(ResourceStorage{}),
- Selection: ecs.C(Selection{IsSelected: false, Halo: NewStrokeRectangleImage(physics.Point{X: 110, Y: 110}, SELECTION_HALO_WIDTH, color.RGBA{0xff, 0x00, 0x00, 0xff})}),
- Spawn: ecs.C(NewSpawn(50, 5*time.Second)),
- }
+ townCenter := EntityBuilder{}.WithPosition(physics.Point{X: 1000, Y: 2000}).WithImage(NewFilledRectangleImage(physics.Point{X: 100, Y: 100}, color.RGBA{0x0, 0x0, 0xff, 0xff})).WithResourceStorage().WithSelection("square").WithSpawn(NewSpawn(50, 5*time.Second)).Build()
game.Entities = append(game.Entities, &townCenter)
- var order Order
- game.personImage = NewFilledCircleImage(100, color.RGBA{0xff, 0xff, 0xff, 0xff})
- game.personSelectionHalo = NewStrokeCircleImage(110, SELECTION_HALO_WIDTH, color.RGBA{0xff, 0x00, 0x00, 0xff})
spawnPosition, _ := game.Closest(townCenter.Position.Value, physics.AdjacentPoints(townCenter.Position.Value))
- person1 := Entity{
- Position: ecs.C(spawnPosition),
- Image: ecs.C(game.personImage),
- Selection: ecs.C(Selection{IsSelected: false, Halo: game.personSelectionHalo}),
- Move: ecs.C(physics.Move{IsActive: false}),
- Order: ecs.C(order),
- ResourceGatherer: ecs.C(ResourceGatherer{MaxCapacity: 15}),
- }
- game.Entities = append(game.Entities, &person1)
- spawnPosition, _ = game.Closest(townCenter.Position.Value, physics.AdjacentPoints(townCenter.Position.Value))
- person2 := Entity{
- Position: ecs.C(spawnPosition),
- Image: ecs.C(game.personImage),
- Selection: ecs.C(Selection{IsSelected: false, Halo: game.personSelectionHalo}),
- Move: ecs.C(physics.Move{IsActive: false}),
- Order: ecs.C(order),
- ResourceGatherer: ecs.C(ResourceGatherer{MaxCapacity: 15}),
+ game.UnitBuilder = EntityBuilder{}.WithImage(NewFilledCircleImage(100, color.White)).WithSelection("round").WithMove().WithOrder().WithResourceGatherer(15)
+ for i := 0; i < 2; i++ {
+ spawnPosition, _ = game.Closest(townCenter.Position.Value, physics.AdjacentPoints(townCenter.Position.Value))
+ person := game.UnitBuilder.Build()
+ person.Position = ecs.C(spawnPosition)
+ game.Entities = append(game.Entities, &person)
}
- game.Entities = append(game.Entities, &person2)
game.CurrentAction = Selecting
+ ebiten.SetRunnableOnUnfocused(true)
kcore.Expect(ebiten.RunGame(game), "failed to run game")
}
diff --git a/spawn.go b/spawn.go
index 0ee93d7..85ce24e 100644
--- a/spawn.go
+++ b/spawn.go
@@ -11,16 +11,16 @@ type spawnRequest struct {
}
type Spawn struct {
- UnitResourceCost int
+ UnitResourceCost int
UnitSpawnDuration time.Duration
- Requests []spawnRequest
+ Requests []spawnRequest
}
func NewSpawn(unitResourceCost int, unitSpawnDuration time.Duration) Spawn {
return Spawn{
- UnitResourceCost: unitResourceCost,
+ UnitResourceCost: unitResourceCost,
UnitSpawnDuration: unitSpawnDuration,
- Requests: make([]spawnRequest, 0),
+ Requests: make([]spawnRequest, 0),
}
}
@@ -32,7 +32,7 @@ func (spawn *Spawn) AddRequest(g *Game) {
spawn.Requests = append(spawn.Requests, spawnRequest{start: time.Now()})
}
-func UpdateSpawn(g *Game,spawn *ecs.Component[Spawn], position ecs.Component[physics.Point]) {
+func UpdateSpawn(g *Game, spawn *ecs.Component[Spawn], position ecs.Component[physics.Point]) {
if !spawn.IsEnabled || !position.IsEnabled {
return
}
@@ -40,17 +40,9 @@ func UpdateSpawn(g *Game,spawn *ecs.Component[Spawn], position ecs.Component[phy
if len(spawn.Value.Requests) == 0 || now.Sub(spawn.Value.Requests[0].start) < time.Duration(spawn.Value.UnitSpawnDuration) {
return
}
- // TODO: builder
- var order Order
spawnPosition, _ := g.Closest(position.Value, physics.AdjacentPoints(position.Value))
- unit := Entity{
- Position: ecs.C(spawnPosition),
- Image: ecs.C(g.personImage),
- Selection: ecs.C(Selection{IsSelected: false, Halo: g.personSelectionHalo}),
- Move: ecs.C(physics.Move{IsActive: false}),
- Order: ecs.C(order),
- ResourceGatherer: ecs.C(ResourceGatherer{MaxCapacity: 15}),
- }
+ unit := g.UnitBuilder.Build()
+ unit.Position = ecs.C(spawnPosition)
g.Entities = append(g.Entities, &unit)
spawn.Value.Requests = spawn.Value.Requests[1:]
if len(spawn.Value.Requests) > 0 {