-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgame.go
More file actions
146 lines (112 loc) · 3.32 KB
/
game.go
File metadata and controls
146 lines (112 loc) · 3.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package main
import (
"fmt"
"github.com/ebitengine/debugui"
"github.com/hajimehoshi/ebiten/v2"
"github.com/rafibayer/ants-again/spatial"
"github.com/rafibayer/ants-again/util"
"github.com/rafibayer/ants-again/vector"
)
const (
TPS = 60
GAME_SIZE = 1000
ANTS = 1000
ANT_FOOD_RADIUS = GAME_SIZE / 200.0 // radius in which an ant will pick up food
ANT_HILL_RADIUS = GAME_SIZE / 30.0 // radius in which an ant will return to hill
FOOD_START = 50 // starting amount per food
)
// spatial hash densities
// these are fairly import perf knobs, especially for pheromones.
// if these are missized the cells either get too crowded or we have to search too many of them
const (
PHEROMONE_HASH_CELL_SIZE = GAME_SIZE / 20.0
FOOD_HASH_CELL_SIZE = GAME_SIZE / 20.0
HILL_HASH_CELL_SIZE = GAME_SIZE / 5.0
OBSTACLE_HASH_CELL_SIZE = GAME_SIZE / 100.0
)
type Game struct {
params *Params
ui debugui.DebugUI
uiCapture bool
cursorModeIndex int
frameCount, tickCount int
camX, camY float64
zoom float64
world *ebiten.Image
px []byte // pixel buffer: width * height * 4 (R,G,B,A)
ants []*Ant
food spatial.Spatial[*Food]
obstacles spatial.Spatial[*Obstacle]
hills spatial.Spatial[vector.Vector]
collectedFood int
foragingPheromone spatial.Spatial[*Pheromone]
returningPheromone spatial.Spatial[*Pheromone]
foragingAntCount int
returningAntCount int
remainingFoodCount int
}
func NewGame(params *Params) *Game {
if params == nil {
params = &DefaultParams
}
ants := []*Ant{}
food := spatial.NewHash[*Food](FOOD_HASH_CELL_SIZE)
hills := spatial.NewHash[vector.Vector](HILL_HASH_CELL_SIZE)
for range ANTS {
ants = append(ants, &Ant{
Vector: vector.Vector{X: GAME_SIZE / 2, Y: GAME_SIZE / 2},
dir: vector.Vector{X: util.Rand(-1, 1), Y: util.Rand(-1, 1)},
state: FORAGE,
pheromoneStored: params.AntPheromoneStart,
})
}
for r := range 30 {
for c := range 10 {
// top left
food.Insert(&Food{
Vector: &vector.Vector{X: GAME_SIZE/5 + float64(r)*1.5, Y: GAME_SIZE/5 + float64(c)*1.5},
amount: FOOD_START,
})
// mid right
food.Insert(&Food{
Vector: &vector.Vector{X: GAME_SIZE*(5.0/6.0) + float64(r)*1.5, Y: GAME_SIZE/2 + float64(c)*1.5},
amount: FOOD_START,
})
// far bottom right
food.Insert(&Food{
Vector: &vector.Vector{X: GAME_SIZE*(9.0/10.0) + float64(r)*1.5, Y: GAME_SIZE*(9.0/10.0) + float64(c)*1.5},
amount: FOOD_START,
})
}
}
hills.Insert(vector.Vector{X: GAME_SIZE / 2, Y: GAME_SIZE / 2})
return &Game{
params: params,
frameCount: 0,
tickCount: 0,
camX: 30,
camY: 170,
zoom: 0.5,
world: ebiten.NewImage(GAME_SIZE, GAME_SIZE),
px: make([]byte, GAME_SIZE*GAME_SIZE*4), // pheromone buffer: 4 bytes per pixel (R,G,B,A)
ants: ants,
food: food,
hills: hills,
obstacles: spatial.NewHash[*Obstacle](OBSTACLE_HASH_CELL_SIZE),
foragingPheromone: spatial.NewHash[*Pheromone](PHEROMONE_HASH_CELL_SIZE),
returningPheromone: spatial.NewHash[*Pheromone](PHEROMONE_HASH_CELL_SIZE),
}
}
func (g *Game) Update() error {
capture, err := g.ui.Update(ui(g))
if err != nil {
return fmt.Errorf("error updating ui: %w", err)
}
g.uiCapture = capture > 0
g.pollInput()
g.updateAnts()
g.updatePheromones()
g.updateFood()
g.tickCount++
return nil
}