Files
metro-puzzle-jp/internal/game/text.go
claude b67493fddb
All checks were successful
release / build-release (push) Successful in 1m42s
M3: japanska skyltar – pixelfont, ordbok, kunskap, delvis översättning, hjälp
- resources/text/fonts: PixelMplus 10/12 px (M+ FONT LICENSE) + licens;
  all text ritas via text/v2 på heltalspositioner, debugfonten är borta
- internal/lang: ordbok (60 ord, validerad), tokenisering med längsta
  matchning, Knowledge (ord + kana, nivå 0–5, hintar), Render (kända ord
  markerade/översatta, okända kvar, kana som romaji), EnglishShare/
  ShowEnglish per svårighet (deterministiskt per bana+position),
  HelpSeconds; datatest kräver att all japanska i banorna finns i ordboken
- sim.Run: AskHelp (H) med väntetid efter nivå, avbryts om man går,
  avslöjar skylten och lär första okända ordet; Knowledge delas mellan banor
- game: skylt- och avgångstavlor renderade genom kunskapen med färgkodning,
  engelsk rad på lätta banor, hjälp-förlopp, "Nytt ord"-notis, HUD visar
  resmålet på japanska från nivå 1 och japanska-nivå; meny med svårighet;
  pixelbaserad radbrytning av färgade textsegment; -know-flagga
- tools/shots: tre skyltbilder (skylt, hjälp, nytt ord) med förkunskap
- docs/README/wiki uppdaterade

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-23 20:14:36 +02:00

138 lines
3.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package game
import (
"image/color"
"strings"
"github.com/hajimehoshi/ebiten/v2"
"gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/lang"
)
type drawTarget = *ebiten.Image
// Färger för text.
var (
colText = color.RGBA{255, 255, 255, 255}
colDim = color.RGBA{139, 155, 180, 255} // oöversatt / sekundärt
colKnown = color.RGBA{254, 174, 52, 255} // kända ord / översättning
colReading = color.RGBA{99, 199, 77, 255} // kana som kan läsas men inte förstås
colEnglish = color.RGBA{44, 232, 245, 255}
colBad = color.RGBA{228, 59, 68, 255}
colGood = color.RGBA{99, 199, 77, 255}
colWarn = color.RGBA{254, 174, 52, 255}
colPanel = color.RGBA{24, 20, 37, 230}
colBar = color.RGBA{58, 68, 102, 255}
)
// span är en textbit med färg; en rad är flera spans.
type span struct {
text string
col color.Color
}
type line []span
// plainLine gör en rad av en enda sträng.
func plainLine(s string, col color.Color) line { return line{{s, col}} }
// shownLine gör en rad av språksystemets segment med färg efter kunskap.
// Med readings visas läsningen (romaji) efter kända ord – hinten från nivå 2.
func shownLine(shown []lang.Shown, base color.Color, readings bool) line {
var l line
for _, sh := range shown {
col := base
switch {
case sh.Reading:
col = colReading
case sh.Known && lang.IsJapanese(sh.Text):
col = colKnown
case sh.Known:
col = base
default:
col = colDim
}
l = append(l, span{sh.Text, col})
if readings && sh.Romaji != "" {
l = append(l, span{"(" + sh.Romaji + ")", colDim})
}
}
return l
}
// wrapLine radbryter en rad till maxW pixlar. Bryter vid mellanslag, och
// mitt i ett ord bara om ordet ensamt är för långt (japanska saknar mellanslag).
func (a *Assets) wrapLine(l line, maxW int) []line {
var out []line
var cur line
curW := 0
flush := func() {
if len(cur) > 0 {
out = append(out, cur)
cur, curW = nil, 0
}
}
add := func(s string, col color.Color) {
w := a.Width(s)
if curW+w > maxW && curW > 0 {
flush()
s = strings.TrimLeft(s, " ")
w = a.Width(s)
}
if s == "" {
return
}
if n := len(cur); n > 0 && cur[n-1].col == col {
cur[n-1].text += s
} else {
cur = append(cur, span{s, col})
}
curW += w
}
for _, sp := range l {
for _, tok := range tokens(sp.text) {
if a.Width(tok) <= maxW {
add(tok, sp.col)
continue
}
for _, r := range tok { // för långt ord: bryt per tecken
add(string(r), sp.col)
}
}
}
flush()
return out
}
// tokens delar en sträng i ord och mellanslagsrunor, båda bevarade.
func tokens(s string) []string {
var out []string
cur := ""
for _, r := range s {
if r == ' ' {
if cur != "" {
out = append(out, cur)
cur = ""
}
out = append(out, " ")
continue
}
cur += string(r)
}
if cur != "" {
out = append(out, cur)
}
return out
}
// drawLines ritar rader från (x, y) med radhöjd LineH.
func (a *Assets) drawLines(dst drawTarget, lines []line, x, y int) {
for i, l := range lines {
cx := x
for _, sp := range l {
a.Draw(dst, sp.text, cx, y+i*LineH, sp.col)
cx += a.Width(sp.text)
}
}
}