Added progress tracking.

This commit is contained in:
Sander Schobers 2019-12-29 10:57:20 +01:00
parent 8ef4e4ea3a
commit 1f26980ba3
8 changed files with 150 additions and 34 deletions

View File

@ -26,6 +26,7 @@ type Context struct {
Textures map[string]texture Textures map[string]texture
Sprites map[string]sprite Sprites map[string]sprite
Levels map[string]levelPack Levels map[string]levelPack
Progress progress
SpriteDrawer SpriteDrawer SpriteDrawer SpriteDrawer
Settings settings Settings settings
Palette *alui.Palette Palette *alui.Palette

View File

@ -196,6 +196,10 @@ func (g *game) Init(disp *allg5.Display, settings settings, res vfs.CopyDir, con
g.ctx = &Context{Resources: res, Textures: map[string]texture{}, Settings: settings, Navigation: navigation{game: g}} g.ctx = &Context{Resources: res, Textures: map[string]texture{}, Settings: settings, Navigation: navigation{game: g}}
g.ctx.DisplaySize = geom.Pt(disp.Width(), disp.Height()) g.ctx.DisplaySize = geom.Pt(disp.Width(), disp.Height())
g.ctx.SpriteDrawer.ctx = g.ctx g.ctx.SpriteDrawer.ctx = g.ctx
err := g.ctx.Progress.load()
if err != nil {
log.Printf("Unable to load previous progress.")
}
if err := g.initUI(disp, cons, fps); err != nil { if err := g.initUI(disp, cons, fps); err != nil {
return err return err
} }

50
cmd/krampus19/io.go Normal file
View File

@ -0,0 +1,50 @@
package main
import (
"encoding/json"
"os"
"path/filepath"
)
func decodeJSON(path string, v interface{}) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
err = json.NewDecoder(f).Decode(v)
if err != nil {
return err
}
return nil
}
func encodeJSON(path string, v interface{}) error {
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
return json.NewEncoder(f).Encode(v)
}
func userDir() (string, error) {
config, err := os.UserConfigDir()
if err != nil {
return "", err
}
dir := filepath.Join(config, "krampus19")
err = os.MkdirAll(dir, 0600)
if err != nil {
return "", err
}
return dir, nil
}
func userFile(name string) (string, error) {
dir, err := userDir()
if err != nil {
return "", err
}
return filepath.Join(dir, name), nil
}

View File

@ -48,7 +48,7 @@ func run() error {
} }
err = settings.StoreDefault() err = settings.StoreDefault()
if err != nil { if err != nil {
log.Printf("Unable to store settings.") log.Printf("Unable to store settings; err: %v", err)
} }
log.Printf("Creating display.") log.Printf("Creating display.")

View File

@ -19,10 +19,15 @@ func (s *levelSelect) Enter(ctx *Context) error {
s.ctx = ctx s.ctx = ctx
s.pack = s.ctx.Levels[s.packID] s.pack = s.ctx.Levels[s.packID]
s.Init() s.Init()
name := func(id string) string { return fmt.Sprintf("Level %s", id) } name := func(id string, steps int) string {
if steps == 0 {
return fmt.Sprintf("Level %s", id)
}
return fmt.Sprintf("Level %s (%d)", id, steps)
}
for _, id := range s.pack.order { for _, id := range s.pack.order {
levelID := id levelID := id
s.Add(name(levelID), func() { s.Add(name(levelID, s.ctx.Progress.Level(s.packID, levelID).Steps), func() {
s.ctx.Navigation.PlayLevel(s.packID, levelID) s.ctx.Navigation.PlayLevel(s.packID, levelID)
}) })
} }

View File

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"log"
"sort" "sort"
"opslag.de/schobers/allg5" "opslag.de/schobers/allg5"
@ -60,7 +61,22 @@ func (l *playLevel) Leave() {}
func (l *playLevel) onComplete() { func (l *playLevel) onComplete() {
menu := alui.NewMenu() menu := alui.NewMenu()
menu.AddChild(alui.NewMargins(&alui.Label{ControlBase: alui.ControlBase{Font: "header"}, Text: "Congratulations", TextAlign: allg5.AlignCenter}, 3*margin, 0, 2*margin)) menu.AddChild(alui.NewMargins(&alui.Label{ControlBase: alui.ControlBase{Font: "header"}, Text: "Congratulations", TextAlign: allg5.AlignCenter}, 3*margin, 0, 2*margin))
menu.AddChild(alui.NewMargins(&alui.Label{Text: fmt.Sprintf("You've completed the level in %d steps", l.state.steps), TextAlign: allg5.AlignCenter}, 0, 0, 2*margin)) menu.AddChild(alui.NewMargins(&alui.Label{Text: fmt.Sprintf("You've completed the level in %d steps.", l.state.steps), TextAlign: allg5.AlignCenter}, 0, 0, 2*margin))
progress := l.ctx.Progress.Level(l.packID, l.levelID)
if l.state.steps < progress.Steps || progress.Steps == 0 {
var improvement = progress.Steps - l.state.steps
if improvement > 0 { // first time it is lower than zero (no previous record).
menu.AddChild(alui.NewMargins(&alui.Label{Text: fmt.Sprintf("This is an improvement of %d steps.", improvement), TextAlign: allg5.AlignCenter}, 0, 0, 2*margin))
}
err := l.ctx.Progress.Update(l.packID, l.levelID, func(p *levelProgress) {
p.Steps = l.state.steps
})
if err != nil {
log.Printf("Unable to store progress; err: %v", err)
}
}
nextID, ok := l.state.pack.FindNext(l.levelID) nextID, ok := l.state.pack.FindNext(l.levelID)
if ok { if ok {

67
cmd/krampus19/progress.go Normal file
View File

@ -0,0 +1,67 @@
package main
type progress struct {
Packs map[string]packProgress
}
func (p *progress) Pack(packID string) packProgress {
if p.Packs == nil {
p.Packs = map[string]packProgress{}
}
return p.Packs[packID]
}
func (p *progress) Level(packID, levelID string) levelProgress {
pack := p.Pack(packID)
return pack.Level(levelID)
}
func (p *progress) Update(packID, levelID string, update func(*levelProgress)) error {
pack := p.Pack(packID)
pack.Update(levelID, update)
p.Packs[packID] = pack
return p.store()
}
type packProgress struct {
Levels map[string]levelProgress
}
func (p *packProgress) Level(id string) levelProgress {
if p.Levels == nil {
p.Levels = map[string]levelProgress{}
}
return p.Levels[id]
}
func (p *packProgress) Update(id string, update func(*levelProgress)) {
level := p.Level(id)
update(&level)
p.Levels[id] = level
}
type levelProgress struct {
Steps int
}
func (p *progress) store() error {
path, err := userFile("progress.json")
if err != nil {
return err
}
return encodeJSON(path, p)
}
func (p *progress) load() error {
path, err := userFile("progress.json")
if err != nil {
return err
}
var fromFile progress
err = decodeJSON(path, &fromFile)
if err != nil {
return err
}
*p = fromFile
return nil
}

View File

@ -1,10 +1,6 @@
package main package main
import ( import (
"encoding/json"
"os"
"path/filepath"
"opslag.de/schobers/allg5" "opslag.de/schobers/allg5"
) )
@ -28,27 +24,11 @@ type settings struct {
Video video Video video
} }
func (s *settings) DefaultPath() (string, error) { func (s *settings) DefaultPath() (string, error) { return userFile("settings.json") }
config, err := os.UserConfigDir()
if err != nil {
return "", err
}
dir := filepath.Join(config, "krampus19")
err = os.MkdirAll(dir, 0600)
if err != nil {
return "", err
}
return filepath.Join(dir, "settings.json"), nil
}
func (s *settings) Load(path string) error { func (s *settings) Load(path string) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
var fromFile settings var fromFile settings
err = json.NewDecoder(f).Decode(&fromFile) err := decodeJSON(path, &fromFile)
if err != nil { if err != nil {
return err return err
} }
@ -64,14 +44,7 @@ func (s *settings) LoadDefault() error {
return s.Load(path) return s.Load(path)
} }
func (s *settings) Store(path string) error { func (s *settings) Store(path string) error { return encodeJSON(path, s) }
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
return json.NewEncoder(f).Encode(&s)
}
func (s *settings) StoreDefault() error { func (s *settings) StoreDefault() error {
path, err := s.DefaultPath() path, err := s.DefaultPath()