aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md11
-rw-r--r--draw.go10
-rw-r--r--entity.go1
-rw-r--r--main.go40
-rw-r--r--spawn.go59
5 files changed, 107 insertions, 14 deletions
diff --git a/README.md b/README.md
index 236eb4e..b81d5f9 100644
--- a/README.md
+++ b/README.md
@@ -5,11 +5,18 @@
## TODO
- atm, stops moving if someone settles at destination
-- an entity may spawn other entities with a cost
+- spawn may register a target, on spawn unit will do as a right click on target (move, gather, ...)
+- time must come from engine, not now
+- selection priority: selecting units + building -> select only units
+- see the current action (debug?)
+- keyboard config
- spawn order
- bigger map
- move the map view
-- bug: select A, gather, move to B, (it stops), gather (no storage)
+
+## Bugs
+- select A, gather, move to B, (it stops), gather (no storage)
+- if B is < 1 cell away, it will go and merge with A
## Dependencies
diff --git a/draw.go b/draw.go
index 9af35f5..90c1134 100644
--- a/draw.go
+++ b/draw.go
@@ -29,5 +29,15 @@ func (e *Entity) Draw(g *Game, screen *ebiten.Image) {
Size: 40,
}, op)
}
+ if e.Spawn.IsEnabled {
+ spawnText := fmt.Sprintf("%d", len(e.Spawn.Value.Requests))
+ op := &text.DrawOptions{}
+ op.GeoM.Translate(float64(e.Position.Value.X+5), float64(e.Position.Value.Y+70))
+ op.ColorScale.ScaleWithColor(color.White)
+ text.Draw(screen, spawnText, &text.GoTextFace{
+ Source: g.FaceSource,
+ Size: 40,
+ }, op)
+ }
}
}
diff --git a/entity.go b/entity.go
index b784c04..185efdb 100644
--- a/entity.go
+++ b/entity.go
@@ -16,6 +16,7 @@ type Entity struct {
ResourceGatherer ecs.Component[ResourceGatherer]
ResourceSource ecs.Component[ResourceSource]
ResourceStorage ecs.Component[ResourceStorage]
+ Spawn ecs.Component[Spawn]
}
func (e Entity) Bounds() physics.Rectangle {
diff --git a/main.go b/main.go
index 09eb16d..1ceddf1 100644
--- a/main.go
+++ b/main.go
@@ -10,6 +10,7 @@ import (
_ "image/jpeg"
"math"
"os"
+ "time"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil"
@@ -40,6 +41,8 @@ type Game struct {
Selection GlobalSelection
ResourceAmount int
FaceSource *text.GoTextFaceSource
+ personImage *ebiten.Image
+ personSelectionHalo *ebiten.Image
}
func DrawMove(screen *ebiten.Image, e *Entity) {
@@ -123,6 +126,14 @@ func (g *Game) updateSelecting(cursor physics.Point, moveMap physics.MoveMap) {
}
g.Selection.IsActive = false
}
+ if inpututil.IsKeyJustReleased(ebiten.KeyS) {
+ for _, e := range g.Entities {
+ if !e.Selection.IsEnabled || !e.Selection.Value.IsSelected || !e.Spawn.IsEnabled {
+ continue
+ }
+ e.Spawn.Value.AddRequest(g)
+ }
+ }
}
func (g *Game) updatePatrolling(cursor physics.Point) {
@@ -156,6 +167,7 @@ func (g *Game) Update() error {
for _, e := range g.Entities {
physics.UpdateMove(&e.Move, &e.Position, moveMap)
e.UpdateOrder(g)
+ UpdateSpawn(g, &e.Spawn, e.Position)
}
return nil
}
@@ -214,29 +226,33 @@ func main() {
Selection: ecs.C(Selection{IsSelected: false, Halo: ironSelectionHalo}),
}
game.Entities = append(game.Entities, &ironMine)
- storageImage := NewFilledRectangleImage(physics.Point{X: 100, Y: 100}, color.RGBA{0x00, 0x00, 0xff, 0xff})
- storage := Entity{
+ 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(storageImage),
+ 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)),
}
- game.Entities = append(game.Entities, &storage)
+ game.Entities = append(game.Entities, &townCenter)
var order Order
- personImage := NewFilledCircleImage(100, color.RGBA{0xff, 0xff, 0xff, 0xff})
- personSelectionHalo := NewStrokeCircleImage(110, SELECTION_HALO_WIDTH, color.RGBA{0xff, 0x00, 0x00, 0xff})
+ 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(physics.Point{X: 2000, Y: 2000}),
- Image: ecs.C(personImage),
- Selection: ecs.C(Selection{IsSelected: false, Halo: personSelectionHalo}),
+ 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(physics.Point{X: 2200, Y: 2200}),
- Image: ecs.C(personImage),
- Selection: ecs.C(Selection{IsSelected: false, Halo: personSelectionHalo}),
+ 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}),
diff --git a/spawn.go b/spawn.go
new file mode 100644
index 0000000..0ee93d7
--- /dev/null
+++ b/spawn.go
@@ -0,0 +1,59 @@
+package main
+
+import (
+ "age_of_empires/ecs"
+ "age_of_empires/physics"
+ "time"
+)
+
+type spawnRequest struct {
+ start time.Time
+}
+
+type Spawn struct {
+ UnitResourceCost int
+ UnitSpawnDuration time.Duration
+ Requests []spawnRequest
+}
+
+func NewSpawn(unitResourceCost int, unitSpawnDuration time.Duration) Spawn {
+ return Spawn{
+ UnitResourceCost: unitResourceCost,
+ UnitSpawnDuration: unitSpawnDuration,
+ Requests: make([]spawnRequest, 0),
+ }
+}
+
+func (spawn *Spawn) AddRequest(g *Game) {
+ if g.ResourceAmount < spawn.UnitResourceCost {
+ return
+ }
+ g.ResourceAmount -= spawn.UnitResourceCost
+ spawn.Requests = append(spawn.Requests, spawnRequest{start: time.Now()})
+}
+
+func UpdateSpawn(g *Game,spawn *ecs.Component[Spawn], position ecs.Component[physics.Point]) {
+ if !spawn.IsEnabled || !position.IsEnabled {
+ return
+ }
+ now := time.Now()
+ 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}),
+ }
+ g.Entities = append(g.Entities, &unit)
+ spawn.Value.Requests = spawn.Value.Requests[1:]
+ if len(spawn.Value.Requests) > 0 {
+ spawn.Value.Requests[0].start = now
+ }
+}