diff options
| -rw-r--r-- | README.md | 11 | ||||
| -rw-r--r-- | draw.go | 10 | ||||
| -rw-r--r-- | entity.go | 1 | ||||
| -rw-r--r-- | main.go | 40 | ||||
| -rw-r--r-- | spawn.go | 59 |
5 files changed, 107 insertions, 14 deletions
@@ -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 @@ -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) + } } } @@ -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 { @@ -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 + } +} |
