Added win condition.
Renamed entities on disk & added missing sprites. Moved entity and animations to separate code unit.
This commit is contained in:
parent
aa47e2cabb
commit
356b510286
@ -21,10 +21,12 @@ func NewMargins(target Control, margins ...float32) *Margins {
|
||||
m.Top, m.Left, m.Bottom, m.Right = margins[0], margins[0], margins[0], margins[0]
|
||||
case 2:
|
||||
m.Top, m.Left, m.Bottom, m.Right = margins[0], margins[1], margins[0], margins[1]
|
||||
case 3:
|
||||
m.Top, m.Left, m.Bottom, m.Right = margins[0], margins[1], margins[2], margins[1]
|
||||
case 4:
|
||||
m.Top, m.Left, m.Bottom, m.Right = margins[0], margins[1], margins[2], margins[3]
|
||||
default:
|
||||
panic("expected 1 (all same), 2 (vertical, horizontal) or 4 margins (all separately specified)")
|
||||
panic("expected 1 (all same), 2 (vertical, horizontal), 3 (top, horizontal, bottom) or 4 margins (all separately specified)")
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ func newSettingsHeader(label string) alui.Control {
|
||||
header := &settingsHeader{}
|
||||
header.Font = "header"
|
||||
header.Text = label
|
||||
return alui.NewMargins(header, 3*margin, 0, 2*margin, 0)
|
||||
return alui.NewMargins(header, 3*margin, 0, 2*margin)
|
||||
}
|
||||
|
||||
type settingsRow struct {
|
||||
|
42
cmd/krampus19/entity.go
Normal file
42
cmd/krampus19/entity.go
Normal file
@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"opslag.de/schobers/geom"
|
||||
)
|
||||
|
||||
type entity struct {
|
||||
typ entityType
|
||||
pos geom.Point
|
||||
scr geom.PointF32
|
||||
}
|
||||
|
||||
func newEntity(typ entityType, pos geom.Point) *entity {
|
||||
return &entity{typ, pos, pos.ToF32()}
|
||||
}
|
||||
|
||||
type entityMoveAnimation struct {
|
||||
e *entity
|
||||
from, to geom.Point
|
||||
pos geom.PointF32
|
||||
}
|
||||
|
||||
func newEntityMoveAnimation(e *entity, to geom.Point) *entityMoveAnimation {
|
||||
ani := &entityMoveAnimation{e: e, from: e.pos, to: to, pos: e.pos.ToF32()}
|
||||
ani.e.pos = to
|
||||
return ani
|
||||
}
|
||||
|
||||
func (a *entityMoveAnimation) Animate(start, now time.Duration) bool {
|
||||
const duration = 270 * time.Millisecond
|
||||
|
||||
progress := float32((now-start)*1000/duration) * .001
|
||||
from, to := a.from.ToF32(), a.to.ToF32()
|
||||
if progress >= 1 {
|
||||
a.e.scr = to
|
||||
return false
|
||||
}
|
||||
a.e.scr = to.Sub(from).Mul(progress).Add(from)
|
||||
return true
|
||||
}
|
@ -149,8 +149,9 @@ func (g *game) loadSprites(names ...string) error {
|
||||
func (g *game) loadAssets() error {
|
||||
log.Println("Loading textures...")
|
||||
err := g.loadTextures(map[string]string{
|
||||
"entity_brick.png": "brick",
|
||||
"entity_main_character.png": "main_character",
|
||||
"entity_brick.png": "brick",
|
||||
"entity_dragon.png": "dragon",
|
||||
"entity_villain.png": "villain",
|
||||
|
||||
"tile_lava_brick.png": "lava_brick",
|
||||
"tile_magma.png": "magma",
|
||||
@ -177,7 +178,7 @@ func (g *game) loadAssets() error {
|
||||
log.Printf("Loaded %d fonts.\n", g.ui.Fonts().Len())
|
||||
|
||||
log.Println("Loading sprites")
|
||||
err = g.loadSprites("brick", "lava_brick", "magma", "main_character", "ui")
|
||||
err = g.loadSprites("brick", "dragon", "lava_brick", "magma", "ui", "villain")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -12,6 +12,23 @@ type levelPack struct {
|
||||
levels map[string]level
|
||||
}
|
||||
|
||||
func (p levelPack) find(level string) int {
|
||||
for i, l := range p.order {
|
||||
if l == level {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (p levelPack) FindNext(level string) (string, bool) {
|
||||
idx := p.find(level)
|
||||
if idx == -1 || idx == len(p.order)-1 {
|
||||
return "", false
|
||||
}
|
||||
return p.order[idx+1], true
|
||||
}
|
||||
|
||||
type parseLevelPackContext struct {
|
||||
name string
|
||||
levels []string
|
||||
|
@ -21,7 +21,6 @@ func (s *levelSelect) Enter(ctx *Context) error {
|
||||
s.Init()
|
||||
name := func(id string) string { return fmt.Sprintf("Level %s", id) }
|
||||
for _, id := range s.pack.order {
|
||||
// level := s.pack[id]
|
||||
levelID := id
|
||||
s.Add(name(levelID), func() {
|
||||
s.ctx.Navigation.PlayLevel(s.packID, levelID)
|
||||
|
@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"opslag.de/schobers/allg5"
|
||||
"opslag.de/schobers/geom"
|
||||
@ -17,6 +16,7 @@ type playLevel struct {
|
||||
init bool
|
||||
|
||||
menu *alui.Menu
|
||||
end alui.Control
|
||||
showMenu bool
|
||||
|
||||
packID string
|
||||
@ -39,43 +39,6 @@ func (s keyPressedState) CountPressed(keys ...allg5.Key) int {
|
||||
return cnt
|
||||
}
|
||||
|
||||
type entity struct {
|
||||
typ entityType
|
||||
pos geom.Point
|
||||
scr geom.PointF32
|
||||
}
|
||||
|
||||
func newEntity(typ entityType, pos geom.Point) *entity {
|
||||
return &entity{typ, pos, pos.ToF32()}
|
||||
}
|
||||
|
||||
type posToScrFn func(geom.Point) geom.PointF32
|
||||
|
||||
type entityMoveAnimation struct {
|
||||
e *entity
|
||||
from, to geom.Point
|
||||
pos geom.PointF32
|
||||
}
|
||||
|
||||
func newEntityMoveAnimation(e *entity, to geom.Point) *entityMoveAnimation {
|
||||
ani := &entityMoveAnimation{e: e, from: e.pos, to: to, pos: e.pos.ToF32()}
|
||||
ani.e.pos = to
|
||||
return ani
|
||||
}
|
||||
|
||||
func (a *entityMoveAnimation) Animate(start, now time.Duration) bool {
|
||||
const duration = 210 * time.Millisecond
|
||||
|
||||
progress := float32((now-start)*1000/duration) * .001
|
||||
from, to := a.from.ToF32(), a.to.ToF32()
|
||||
if progress >= 1 {
|
||||
a.e.scr = to
|
||||
return false
|
||||
}
|
||||
a.e.scr = to.Sub(from).Mul(progress).Add(from)
|
||||
return true
|
||||
}
|
||||
|
||||
func (l *playLevel) Enter(ctx *Context) error {
|
||||
l.ctx = ctx
|
||||
|
||||
@ -88,12 +51,27 @@ func (l *playLevel) Enter(ctx *Context) error {
|
||||
l.menu.OnEscape = func() { l.showMenu = false }
|
||||
|
||||
l.init = true
|
||||
l.state.Init(l.ctx, l.packID, l.levelID)
|
||||
l.state.Init(l.ctx, l.packID, l.levelID, l.onComplete)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *playLevel) Leave() {}
|
||||
|
||||
func (l *playLevel) onComplete() {
|
||||
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{Text: fmt.Sprintf("You've completed the level in %d steps", l.state.steps), TextAlign: allg5.AlignCenter}, 0, 0, 2*margin))
|
||||
|
||||
nextID, ok := l.state.pack.FindNext(l.levelID)
|
||||
if ok {
|
||||
menu.Add("Continue with next", func() { l.ctx.Navigation.PlayLevel(l.packID, nextID) })
|
||||
}
|
||||
menu.Add("Select level", func() { l.ctx.Navigation.SelectLevel(l.packID) })
|
||||
menu.Add("Go to main menu", func() { l.ctx.Navigation.ShowMainMenu() })
|
||||
|
||||
l.end = menu
|
||||
}
|
||||
|
||||
func (l *playLevel) posToScreenF32(p geom.PointF32, z float32) geom.PointF32 {
|
||||
pos := l.posToCabinet(p.Add2D(.5, .5)).Add2D(0, z)
|
||||
return pos.Mul(l.scale).Add(l.offset)
|
||||
@ -156,25 +134,27 @@ func (l *playLevel) Handle(e allg5.Event) {
|
||||
l.state.ReleaseKey(e.KeyCode)
|
||||
}
|
||||
|
||||
if l.showMenu {
|
||||
switch {
|
||||
case l.showMenu:
|
||||
l.menu.Handle(e)
|
||||
return
|
||||
}
|
||||
|
||||
switch e := e.(type) {
|
||||
case *allg5.KeyCharEvent:
|
||||
switch e.KeyCode {
|
||||
case allg5.KeyEscape:
|
||||
l.showMenu = true
|
||||
l.menu.Activate(0)
|
||||
case l.ctx.Settings.Controls.MoveUp:
|
||||
l.state.TryPlayerMove(geom.Pt(0, -1), e.KeyCode)
|
||||
case l.ctx.Settings.Controls.MoveRight:
|
||||
l.state.TryPlayerMove(geom.Pt(1, 0), e.KeyCode)
|
||||
case l.ctx.Settings.Controls.MoveDown:
|
||||
l.state.TryPlayerMove(geom.Pt(0, 1), e.KeyCode)
|
||||
case l.ctx.Settings.Controls.MoveLeft:
|
||||
l.state.TryPlayerMove(geom.Pt(-1, 0), e.KeyCode)
|
||||
case l.state.complete:
|
||||
l.end.Handle(e)
|
||||
default:
|
||||
switch e := e.(type) {
|
||||
case *allg5.KeyCharEvent:
|
||||
switch e.KeyCode {
|
||||
case allg5.KeyEscape:
|
||||
l.showMenu = true
|
||||
l.menu.Activate(0)
|
||||
case l.ctx.Settings.Controls.MoveUp:
|
||||
l.state.TryPlayerMove(geom.Pt(0, -1), e.KeyCode)
|
||||
case l.ctx.Settings.Controls.MoveRight:
|
||||
l.state.TryPlayerMove(geom.Pt(1, 0), e.KeyCode)
|
||||
case l.ctx.Settings.Controls.MoveDown:
|
||||
l.state.TryPlayerMove(geom.Pt(0, 1), e.KeyCode)
|
||||
case l.ctx.Settings.Controls.MoveLeft:
|
||||
l.state.TryPlayerMove(geom.Pt(-1, 0), e.KeyCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -217,10 +197,12 @@ func (l *playLevel) Render(ctx *alui.Context, bounds geom.RectangleF32) {
|
||||
|
||||
for _, e := range entities {
|
||||
switch e.typ {
|
||||
case entityTypeCharacter:
|
||||
l.drawSprite("main_character", "main_character", e.scr)
|
||||
case entityTypeBrick:
|
||||
l.drawSprite("brick", "brick", e.scr)
|
||||
case entityTypeCharacter:
|
||||
l.drawSprite("dragon", "dragon", e.scr)
|
||||
case entityTypeVillain:
|
||||
l.drawSprite("villain", "villain", e.scr)
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,8 +210,12 @@ func (l *playLevel) Render(ctx *alui.Context, bounds geom.RectangleF32) {
|
||||
steps := fmt.Sprintf("STEPS: %d", l.state.Steps())
|
||||
ctx.Fonts.DrawAlignFont(font, bounds.Min.X, 24, bounds.Max.X, ctx.Palette.Text, allg5.AlignCenter, steps)
|
||||
|
||||
if l.showMenu {
|
||||
switch {
|
||||
case l.showMenu:
|
||||
allg5.DrawFilledRectangle(bounds.Min.X, bounds.Min.Y, bounds.Max.X, bounds.Max.Y, allg5.NewColorAlpha(0, 0, 0, 0xaf))
|
||||
l.menu.Render(ctx, bounds)
|
||||
case l.state.complete:
|
||||
allg5.DrawFilledRectangle(bounds.Min.X, bounds.Min.Y, bounds.Max.X, bounds.Max.Y, allg5.NewColorAlpha(0, 0, 0, 0xaf))
|
||||
l.end.Render(ctx, bounds)
|
||||
}
|
||||
}
|
||||
|
@ -29,13 +29,17 @@ func findEntityIdx(entities []*entity, pos geom.Point) int {
|
||||
type playLevelState struct {
|
||||
ctx *Context
|
||||
|
||||
pack levelPack
|
||||
level level
|
||||
player *entity
|
||||
villain *entity
|
||||
bricks []*entity
|
||||
sunken []*entity
|
||||
steps int
|
||||
pack levelPack
|
||||
level level
|
||||
player *entity
|
||||
villain *entity
|
||||
bricks []*entity
|
||||
sunken []*entity
|
||||
|
||||
steps int
|
||||
complete bool
|
||||
onComplete func()
|
||||
|
||||
tick time.Duration
|
||||
ani gut.Animations
|
||||
keysDown keyPressedState
|
||||
@ -44,9 +48,7 @@ type playLevelState struct {
|
||||
func (s *playLevelState) Entities() []*entity {
|
||||
var entities []*entity
|
||||
entities = append(entities, s.player)
|
||||
if s.villain != nil {
|
||||
entities = append(entities, s.villain)
|
||||
}
|
||||
entities = append(entities, s.villain)
|
||||
entities = append(entities, s.bricks...)
|
||||
return entities
|
||||
}
|
||||
@ -62,7 +64,7 @@ func (s *playLevelState) IsNextToMagma(pos geom.Point) bool {
|
||||
s.checkTile(pos.Add2D(0, 1), s.isMagma)
|
||||
}
|
||||
|
||||
func (s *playLevelState) Init(ctx *Context, pack, level string) {
|
||||
func (s *playLevelState) Init(ctx *Context, pack, level string, onComplete func()) {
|
||||
s.ctx = ctx
|
||||
s.pack = ctx.Levels[pack]
|
||||
s.level = s.pack.levels[level]
|
||||
@ -79,6 +81,7 @@ func (s *playLevelState) Init(ctx *Context, pack, level string) {
|
||||
}
|
||||
}
|
||||
s.keysDown = keyPressedState{}
|
||||
s.onComplete = onComplete
|
||||
}
|
||||
|
||||
func (s *playLevelState) Level() level { return s.level }
|
||||
@ -112,7 +115,12 @@ func (s *playLevelState) TryPlayerMove(dir geom.Point, key allg5.Key) {
|
||||
log.Printf("Moving player to %s", to)
|
||||
s.ani.StartFn(s.ctx.Tick, newEntityMoveAnimation(s.player, to), func() {
|
||||
log.Printf("Player movement finished")
|
||||
if s.keysDown[key] && s.keysDown.CountPressed(s.ctx.Settings.Controls.MovementKeys()...) == 1 {
|
||||
if s.player.pos == s.villain.pos {
|
||||
s.complete = true
|
||||
if onComplete := s.onComplete; onComplete != nil {
|
||||
onComplete()
|
||||
}
|
||||
} else if s.keysDown[key] && s.keysDown.CountPressed(s.ctx.Settings.Controls.MovementKeys()...) == 1 {
|
||||
log.Printf("Key %s is still down, moving further", gut.KeyToString(key))
|
||||
s.TryPlayerMove(dir, key)
|
||||
}
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@ -1,8 +1,8 @@
|
||||
sprite:
|
||||
texture: main_character
|
||||
texture: dragon
|
||||
|
||||
part:
|
||||
name: main_character
|
||||
name: dragon
|
||||
sub_texture: 0,0,200,400
|
||||
anchor: 100,350
|
||||
scale: 2
|
11
cmd/krampus19/res/sprites/villain.txt
Normal file
11
cmd/krampus19/res/sprites/villain.txt
Normal file
@ -0,0 +1,11 @@
|
||||
sprite:
|
||||
texture: villain
|
||||
|
||||
part:
|
||||
name: villain
|
||||
sub_texture: 0,0,200,400
|
||||
anchor: 100,350
|
||||
scale: 2
|
||||
:part
|
||||
|
||||
:sprite
|
Loading…
Reference in New Issue
Block a user