Files
8bitMyGoUI/game/compass.go
T
ZacharyZhang-NY f48075230f Add game components 246-268; data.DrawSlot, Canvas.TextVeil
Health, mana and experience bars, quarter hearts, lives, a spinning
coin counter, score board, stage timer, minimap with fog, compass,
hotbar, paper-doll equipment, skill tree, skill buttons with cooldown
wipes, status effects, a boss bar, damage numbers, quest log and
tracker, party frames, character sheet, level-up screen and shop.
data exports DrawSlot so every slot looks alike; pixel adds TextVeil
for dissolving text. Messages the font cannot draw are fixed and
TestMessagesHaveGlyphs holds every message to the font.
2026-10-12 01:53:20 -04:00

79 lines
2.1 KiB
Go

package game
import (
"fmt"
"math"
"strconv"
"strings"
"github.com/egoist/mygo/ui"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
)
// Bearing marks a direction on a compass, in degrees.
type Bearing struct {
Degrees float64
Slot pixel.Slot
}
type CompassOptions struct {
// Width is in dots; zero means 120. It shows 180°.
Width int
}
// Compass is a heading strip with letters and markers.
func Compass(c *ui.Context, text string, heading float64, marks []Bearing, o CompassOptions) *ui.Element {
k := pixel.K(c)
for _, v := range append([]float64{heading}, bearings(marks)...) {
if math.IsNaN(v) || math.IsInf(v, 0) {
panic(fmt.Sprintf("game: Compass bearing %v", v))
}
}
w := pixel.Or("Compass Width", o.Width, 120)
letters := strings.Fields(k.Msg("compass"))
heading = math.Mod(math.Mod(heading, 360)+360, 360)
// x places bearing b; false means off the strip.
x := func(b float64) (int, bool) {
d := math.Mod(math.Mod(b-heading, 360)+540, 360) - 180
return w/2 + int(math.Round(d*float64(w)/180)), d >= -90 && d <= 90
}
top := tagH(letters[0]) + 3
return ui.Box(c).Role(ui.RoleImage).Label(text).Description(strconv.Itoa(int(math.Round(heading)))+"°").Size(k.D(w), k.D(top+10)).Draw(func(p *ui.Painter, r ui.Rect) {
g := k.Canvas(p, r)
g.Frame(0, top, w, 10, pixel.Sunken, pixel.Well)
for b := 0; b < 360; b += 15 {
at, ok := x(float64(b))
if !ok || at < 1 || at > w-2 {
continue
}
tall := 3
if b%45 == 0 {
tall = 6
}
g.VLine(at, top+10-1-tall, tall, pixel.Edge)
if b%90 == 0 {
l := letters[b/90]
tag(g, max(0, min(w-tagW(l), at-tagW(l)/2)), 0, l, pixel.Ink)
}
}
for _, m := range marks {
if at, ok := x(m.Degrees); ok {
g.Rect(max(1, min(w-4, at-1)), top+2, 3, 3, m.Slot)
}
}
// The heading's own mark points down at the middle.
g.Rect(w/2-2, top-1, 5, 1, pixel.Accent)
g.Rect(w/2-1, top, 3, 1, pixel.Accent)
g.Dot(w/2, top+1, pixel.Accent)
})
}
func bearings(marks []Bearing) []float64 {
out := make([]float64, len(marks))
for i, m := range marks {
out[i] = m.Degrees
}
return out
}