Add sinking animation for brick.

This commit is contained in:
Sander Schobers 2019-12-29 14:49:54 +01:00
parent 95bc1367c7
commit 214d08f2b3
3 changed files with 51 additions and 27 deletions

View File

@ -9,34 +9,59 @@ import (
type entity struct {
typ entityType
pos geom.Point
scr geom.PointF32
scr entityLoc
}
type entityLoc struct {
pos geom.PointF32
z float32
}
func newEntity(typ entityType, pos geom.Point) *entity {
return &entity{typ, pos, pos.ToF32()}
return &entity{typ, pos, entityLoc{pos.ToF32(), 0}}
}
type entityMoveAnimation struct {
type moveAnimation 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()}
func newMoveAnimation(e *entity, to geom.Point) *moveAnimation {
ani := &moveAnimation{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 {
func (a *moveAnimation) 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
a.e.scr.pos = to
return false
}
a.e.scr = to.Sub(from).Mul(progress).Add(from)
a.e.scr.pos = to.Sub(from).Mul(progress).Add(from)
return true
}
type sinkAnimation struct {
e *entity
}
func newSinkAnimation(e *entity) *sinkAnimation {
return &sinkAnimation{e: e}
}
func (a *sinkAnimation) Animate(start, now time.Duration) bool {
const duration = 70 * time.Millisecond
progress := float32((now-start)*1000/duration) * .001
if progress >= 1 {
a.e.scr.z = 80
return false
}
a.e.scr.z = progress * 80
return true
}

View File

@ -174,40 +174,38 @@ func (l *playLevel) Handle(e allg5.Event) {
}
}
func (l *playLevel) drawSprite(name, partName string, pos geom.PointF32) {
l.drawSpritePart(name, partName, pos, 0)
}
func (l *playLevel) drawSpritePart(name, partName string, pos geom.PointF32, z float32) {
l.ctx.SpriteDrawer.Draw(name, partName, l.posToScreenF32(pos, z), DrawSpriteOptions{Scale: l.scale})
func (l *playLevel) drawSprite(name, partName string, pos entityLoc) {
l.ctx.SpriteDrawer.Draw(name, partName, l.posToScreenF32(pos.pos, pos.z), DrawSpriteOptions{Scale: l.scale})
}
func (l *playLevel) Render(ctx *alui.Context, bounds geom.RectangleF32) {
level := l.state.level
for i, t := range level.tiles {
pos := geom.Pt(i%level.width, i/level.width)
scr := entityLoc{pos.ToF32(), 0}
switch t {
case tileBasic:
if l.state.IsNextToMagma(pos) {
l.drawSprite("lava_brick", "magma", pos.ToF32())
l.drawSprite("lava_brick", "magma", scr)
} else {
l.drawSprite("lava_brick", "lava_brick", pos.ToF32())
l.drawSprite("lava_brick", "lava_brick", scr)
}
case tileMagma:
l.drawSprite("magma", "magma", pos.ToF32())
if l.state.IsFilledUp(pos) {
l.drawSpritePart("brick", "brick", pos.ToF32(), 80)
l.drawSprite("magma", "sunken_overlay", pos.ToF32())
l.drawSprite("magma", "magma", scr)
brick := l.state.FindSunkenBrick(pos)
if brick != nil {
l.drawSprite("brick", "brick", brick.scr)
l.drawSprite("magma", "sunken_overlay", scr)
}
}
}
entities := l.state.Entities()
sort.Slice(entities, func(i, j int) bool {
if entities[i].scr.Y == entities[j].scr.Y {
return entities[i].scr.X < entities[j].scr.X
if entities[i].scr.pos.Y == entities[j].scr.pos.Y {
return entities[i].scr.pos.X < entities[j].scr.pos.X
}
return entities[i].scr.Y < entities[j].scr.Y
return entities[i].scr.pos.Y < entities[j].scr.pos.Y
})
for _, e := range entities {

View File

@ -53,8 +53,8 @@ func (s *playLevelState) Entities() []*entity {
return entities
}
func (s *playLevelState) IsFilledUp(pos geom.Point) bool {
return findEntityAt(s.sunken, pos) != nil
func (s *playLevelState) FindSunkenBrick(pos geom.Point) *entity {
return findEntityAt(s.sunken, pos)
}
func (s *playLevelState) IsNextToMagma(pos geom.Point) bool {
@ -113,7 +113,7 @@ func (s *playLevelState) TryPlayerMove(dir geom.Point, key allg5.Key) {
s.steps++
log.Printf("Moving player to %s", to)
s.ani.StartFn(s.ctx.Tick, newEntityMoveAnimation(s.player, to), func() {
s.ani.StartFn(s.ctx.Tick, newMoveAnimation(s.player, to), func() {
log.Printf("Player movement finished")
if s.player.pos == s.villain.pos {
s.complete = true
@ -129,13 +129,14 @@ func (s *playLevelState) TryPlayerMove(dir geom.Point, key allg5.Key) {
if brick := findEntityAt(s.bricks, to); brick != nil {
log.Printf("Pushing brick at %s", to)
brickTo := to.Add(dir)
s.ani.StartFn(s.ctx.Tick, newEntityMoveAnimation(brick, brickTo), func() {
s.ani.StartFn(s.ctx.Tick, newMoveAnimation(brick, brickTo), func() {
log.Printf("Brick movement finished")
if s.checkTile(brickTo, s.wouldBrickSink) {
log.Printf("Sinking brick at %s", brickTo)
idx := findEntityIdx(s.bricks, brickTo)
s.bricks = append(s.bricks[:idx], s.bricks[idx+1:]...)
s.sunken = append(s.sunken, brick)
s.ani.Start(s.ctx.Tick, newSinkAnimation(brick))
}
})
}