• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mlange-42 / ark-pixel / 13710361931

06 Mar 2025 11:36PM CUT coverage: 21.025% (-58.0%) from 79.07%
13710361931

push

github

web-flow
Add Controls and Monitor (#3)

51 of 480 new or added lines in 3 files covered. (10.63%)

119 of 566 relevant lines covered (21.02%)

6.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/plot/controls.go
1
package plot
2

3
import (
4
        "fmt"
5
        "image/color"
6
        "math"
7

8
        px "github.com/gopxl/pixel/v2"
9
        "github.com/gopxl/pixel/v2/backends/opengl"
10
        "github.com/gopxl/pixel/v2/ext/imdraw"
11
        "github.com/gopxl/pixel/v2/ext/text"
12
        "github.com/mlange-42/ark-tools/app"
13
        "github.com/mlange-42/ark/ecs"
14
)
15

16
// Controls adds UI and keyboard input for controlling the simulation.
17
// UI controls are displayed in the bottom right corner of the window.
18
//
19
// Pause and resume the simulation via a button or by pressing SPACE.
20
// Manipulate simulation speed (TPS) using buttons or UP/DOWN keys.
21
//
22
// Expects a world resource of type Systems ([github.com/mlange-42/arche-model/model.Systems]).
23
type Controls struct {
24
        Scale      float64 // Spatial scaling: cell size in screen pixels. Optional, default 1.
25
        drawer     imdraw.IMDraw
26
        systemsRes ecs.Resource[app.Systems]
27
        text       *text.Text
28
}
29

30
// Initialize the system
NEW
31
func (c *Controls) Initialize(w *ecs.World, win *opengl.Window) {
×
NEW
32
        c.systemsRes = ecs.NewResource[app.Systems](w)
×
NEW
33
        if !c.systemsRes.Has() {
×
NEW
34
                panic("resource of type Systems expected in Controls drawer")
×
35
        }
36

NEW
37
        if c.Scale <= 0 {
×
NEW
38
                c.Scale = 1
×
NEW
39
        }
×
40

NEW
41
        c.drawer = *imdraw.New(nil)
×
NEW
42
        c.text = text.New(px.V(0, 0), defaultFont)
×
43

44
}
45

46
// Update the drawer.
NEW
47
func (c *Controls) Update(w *ecs.World) {}
×
48

49
// UpdateInputs handles input events of the previous frame update.
NEW
50
func (c *Controls) UpdateInputs(w *ecs.World, win *opengl.Window) {
×
NEW
51
        sys := c.systemsRes.Get()
×
NEW
52
        if win.JustPressed(px.KeySpace) {
×
NEW
53
                sys.Paused = !sys.Paused
×
NEW
54
                return
×
NEW
55
        }
×
NEW
56
        if win.JustPressed(px.KeyUp) {
×
NEW
57
                sys.TPS = calcTps(sys.TPS, true)
×
NEW
58
                return
×
NEW
59
        }
×
NEW
60
        if win.JustPressed(px.KeyDown) {
×
NEW
61
                sys.TPS = calcTps(sys.TPS, false)
×
NEW
62
                return
×
NEW
63
        }
×
64

NEW
65
        if win.JustPressed(px.MouseButton1) {
×
NEW
66
                width := win.Canvas().Bounds().W()
×
NEW
67
                height := win.Canvas().Bounds().H()
×
NEW
68

×
NEW
69
                mouse := win.MousePosition()
×
NEW
70
                if c.pauseBounds(width, height).Contains(mouse.X, mouse.Y) {
×
NEW
71
                        sys.Paused = !sys.Paused
×
NEW
72
                } else if c.upButton(width, height).Contains(mouse.X, mouse.Y) {
×
NEW
73
                        sys.TPS = calcTps(sys.TPS, true)
×
NEW
74
                } else if c.downButton(width, height).Contains(mouse.X, mouse.Y) {
×
NEW
75
                        sys.TPS = calcTps(sys.TPS, false)
×
NEW
76
                }
×
77
        }
78
}
79

80
// Draw the system
NEW
81
func (c *Controls) Draw(w *ecs.World, win *opengl.Window) {
×
NEW
82
        width := win.Canvas().Bounds().W()
×
NEW
83
        height := win.Canvas().Bounds().H()
×
NEW
84

×
NEW
85
        sys := c.systemsRes.Get()
×
NEW
86
        text := "Pause"
×
NEW
87
        if sys.Paused {
×
NEW
88
                text = "Resume"
×
NEW
89
        }
×
NEW
90
        c.drawButton(c.pauseBounds(width, height), text, win)
×
NEW
91

×
NEW
92
        c.drawButton(c.upButton(width, height), "+", win)
×
NEW
93
        c.drawButton(c.downButton(width, height), "-", win)
×
NEW
94
        c.drawButton(c.tpsButton(width, height), fmt.Sprintf("%.0f TPS", sys.TPS), win)
×
95
}
96

NEW
97
func (c *Controls) drawButton(b *button, text string, win *opengl.Window) {
×
NEW
98
        dr := &c.drawer
×
NEW
99

×
NEW
100
        dr.Color = color.Black
×
NEW
101
        dr.Push(px.V(b.X, b.Y), px.V(b.X+b.W, b.Y+b.H))
×
NEW
102
        dr.Rectangle(0)
×
NEW
103
        dr.Reset()
×
NEW
104

×
NEW
105
        dr.Color = color.White
×
NEW
106
        dr.Push(px.V(b.X, b.Y), px.V(b.X+b.W, b.Y+b.H))
×
NEW
107
        dr.Rectangle(1)
×
NEW
108
        dr.Reset()
×
NEW
109

×
NEW
110
        dr.Draw(win)
×
NEW
111
        dr.Clear()
×
NEW
112

×
NEW
113
        c.text.Clear()
×
NEW
114
        fmt.Fprint(c.text, text)
×
NEW
115

×
NEW
116
        wTxt := c.text.Bounds().W()
×
NEW
117
        hTxt := c.text.Bounds().H()
×
NEW
118
        cx, cy := b.Center()
×
NEW
119
        c.text.Draw(win, px.IM.Scaled(px.V(wTxt/2, hTxt/2), c.Scale).Moved(px.V(math.Floor(cx-wTxt/2), math.Floor(cy-hTxt/2))))
×
NEW
120
}
×
121

NEW
122
func (c *Controls) pauseBounds(w, h float64) *button {
×
NEW
123
        return &button{
×
NEW
124
                w - 85*c.Scale,
×
NEW
125
                5 + 15*c.Scale,
×
NEW
126
                60 * c.Scale,
×
NEW
127
                30 * c.Scale,
×
NEW
128
        }
×
NEW
129
}
×
130

NEW
131
func (c *Controls) upButton(w, h float64) *button {
×
NEW
132
        return &button{
×
NEW
133
                w - 25*c.Scale,
×
NEW
134
                5 + 30*c.Scale,
×
NEW
135
                20 * c.Scale,
×
NEW
136
                15 * c.Scale,
×
NEW
137
        }
×
NEW
138
}
×
139

NEW
140
func (c *Controls) downButton(w, h float64) *button {
×
NEW
141
        return &button{
×
NEW
142
                w - 25*c.Scale,
×
NEW
143
                5 + 15*c.Scale,
×
NEW
144
                20 * c.Scale,
×
NEW
145
                15 * c.Scale,
×
NEW
146
        }
×
NEW
147
}
×
148

NEW
149
func (c *Controls) tpsButton(w, h float64) *button {
×
NEW
150
        return &button{
×
NEW
151
                w - 85*c.Scale,
×
NEW
152
                5,
×
NEW
153
                80 * c.Scale,
×
NEW
154
                15 * c.Scale,
×
NEW
155
        }
×
NEW
156
}
×
157

158
type button struct {
159
        X float64
160
        Y float64
161
        W float64
162
        H float64
163
}
164

NEW
165
func (b *button) Center() (float64, float64) {
×
NEW
166
        return b.X + b.W/2, b.Y + b.H/2
×
NEW
167
}
×
168

NEW
169
func (b *button) Contains(x, y float64) bool {
×
NEW
170
        return x >= b.X && y >= b.Y && x <= b.X+b.W && y <= b.Y+b.H
×
NEW
171
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc