M12: ljud, inställningar och release v0.1.0
All checks were successful
release / build-release (push) Successful in 1m35s

tools/gensound syntetiserar 21 ljud: fyra stationsmelodier i klockklang
(en per station via melody-fältet eller banans id), ankomstjingel,
ding-dong vid inrullning, dörrsignal vid avgång, spärrens pip och
nekande, kiosk, toalett, lärt ord, bekräfta/varning, byte, personal,
vinst, förlust, flygplan, sorl och menymusik. sfx.go spelar effekter
utifrån vad som hänt i sim.Run sedan förra bildrutan. Ljudlagret har
huvudvolym × effekter/musik och byter inte slinga i onödan.
Inställningar (S på bankartan, sparas): volymer, språk sv/en som laddas
om direkt, fönsterskala, fullskärm (F11 överallt) och tangentöversikt.
Fönsterikon från genart. CHANGELOG.md. Tester för ljudfiler, melodival
och inställningar. Docs, wiki och skärmdumpar uppdaterade.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 08:31:38 +01:00
parent 36a45563ec
commit 86f8130735
47 changed files with 800 additions and 107 deletions

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"image"
"image/color"
"image/png"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/text/v2"
@@ -15,8 +16,8 @@ import (
"gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/sim"
)
// UILang är UI-språket (sv/en) – blir en inställning i M12.
const UILang = "sv"
// UILang är UI-språket (sv/en), från inställningarna (Assets.LoadLang).
var UILang = "sv"
// Radhöjd för 10-pixelsfonten.
const LineH = 12
@@ -49,6 +50,7 @@ type Assets struct {
Rails *ebiten.Image // rälsruta (horisontell), roteras för vertikala spår
Posters []*ebiten.Image // affischer för visuell röra (ritas över väggrutor)
Plane *ebiten.Image // flygplanet i slutscenen
Icon image.Image // fönsterikonen (nil om den saknas)
Player [4][3]*ebiten.Image // [riktning: ner, upp, vänster, höger][bildruta: stilla, gå1, gå2]
Text map[string]string
Dict *lang.Dictionary
@@ -103,9 +105,12 @@ func LoadAssets() (*Assets, error) {
}
}
if err := res.LoadJSON(&a.Text, UILang+".json"); err != nil {
if err := res.LoadJSON(&a.Text, "text", UILang+".json"); err != nil {
return nil, err
if err := a.LoadLang(UILang); err != nil {
return nil, err
}
if b, err := res.ReadFile("sprites", "icon.png"); err == nil {
if img, err := png.Decode(bytes.NewReader(b)); err == nil {
a.Icon = img
}
}
@@ -159,6 +164,19 @@ func (a *Assets) drawFace(dst *ebiten.Image, face *text.GoTextFace, s string, x,
// Width är textens bredd i pixlar med 10-pixelsfonten.
func (a *Assets) Width(s string) int { return int(text.Advance(s, a.Font)) }
// LoadLang läser UI-texterna för ett språk och gör det till UILang.
func (a *Assets) LoadLang(lang string) error {
texts := map[string]string{}
if err := res.LoadJSON(&texts, lang+".json"); err != nil {
if err := res.LoadJSON(&texts, "text", lang+".json"); err != nil {
return err
}
}
a.Text = texts
UILang = lang
return nil
}
// T slår upp en UI-text; saknas nyckeln visas nyckeln själv så att det syns.
func (a *Assets) T(key string) string {
if s, ok := a.Text[key]; ok {