anim overhaul, again
This commit is contained in:
parent
d89a1c2e71
commit
df5afe11c1
9 changed files with 179 additions and 157 deletions
|
@ -3,42 +3,51 @@ package engine
|
||||||
import "encoding/gob"
|
import "encoding/gob"
|
||||||
|
|
||||||
// Ensure Anim satisfies Animer.
|
// Ensure Anim satisfies Animer.
|
||||||
var _ Animer = &Anim{}
|
var _ interface {
|
||||||
|
Cell() int
|
||||||
|
Reset()
|
||||||
|
Updater
|
||||||
|
} = &Anim{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
gob.Register(&Anim{})
|
gob.Register(&Anim{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnimFrame describes a frame in an animation.
|
// AnimDef defines an animation, as a sequence of steps and other information.
|
||||||
type AnimFrame struct {
|
type AnimDef struct {
|
||||||
Frame int // show this frame
|
Steps []AnimStep
|
||||||
|
OneShot bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAnim spawns a new anim using this def, or nil if d is nil.
|
||||||
|
func (d *AnimDef) NewAnim() *Anim {
|
||||||
|
if d == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &Anim{Def: d}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnimStep describes a step in an animation.
|
||||||
|
type AnimStep struct {
|
||||||
|
Cell int // show this cell
|
||||||
Duration int // for this long, in ticks
|
Duration int // for this long, in ticks
|
||||||
}
|
}
|
||||||
|
|
||||||
// Anim is n animation being displayed, together with the current state.
|
// Anim is the current state of an animation being played (think of it as an
|
||||||
// A nil *Anim can be used, but always returns 0 for the current frame.
|
// instance of an AnimDef). nil *Anim can be used, but always returns 0 for the
|
||||||
|
// current frame.
|
||||||
type Anim struct {
|
type Anim struct {
|
||||||
Frames []AnimFrame
|
Def *AnimDef
|
||||||
OneShot bool
|
Index int // current step index
|
||||||
Index int
|
Ticks int // ticks spent at this step
|
||||||
Ticks int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy makes a shallow copy of the anim.
|
// Cell returns the cell index for the current step.
|
||||||
func (a *Anim) Copy() *Anim {
|
func (a *Anim) Cell() int {
|
||||||
if a == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
a2 := *a
|
|
||||||
return &a2
|
|
||||||
}
|
|
||||||
|
|
||||||
// CurrentFrame returns the frame number for the current index.
|
|
||||||
func (a *Anim) CurrentFrame() int {
|
|
||||||
if a == nil {
|
if a == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return a.Frames[a.Index].Frame
|
return a.Def.Steps[a.Index].Cell
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset resets both Index and Ticks to 0.
|
// Reset resets both Index and Ticks to 0.
|
||||||
|
@ -55,15 +64,15 @@ func (a *Anim) Update() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
a.Ticks++
|
a.Ticks++
|
||||||
if a.OneShot && a.Index == len(a.Frames)-1 {
|
if a.Def.OneShot && a.Index == len(a.Def.Steps)-1 {
|
||||||
// on the last frame of a one shot so remain on final frame
|
// on the last frame of a one shot so remain on final frame
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if a.Ticks >= a.Frames[a.Index].Duration {
|
if a.Ticks >= a.Def.Steps[a.Index].Duration {
|
||||||
a.Ticks = 0
|
a.Ticks = 0
|
||||||
a.Index++
|
a.Index++
|
||||||
}
|
}
|
||||||
if !a.OneShot && a.Index >= len(a.Frames) {
|
if !a.Def.OneShot && a.Index >= len(a.Def.Steps) {
|
||||||
a.Index = 0
|
a.Index = 0
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
package engine
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/gob"
|
|
||||||
"io/fs"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO: tidy this crap up
|
|
||||||
// Anims probably belong with Sheet
|
|
||||||
|
|
||||||
var (
|
|
||||||
animCache = make(map[assetKey]Anim)
|
|
||||||
|
|
||||||
_ interface {
|
|
||||||
Animer
|
|
||||||
Loader
|
|
||||||
} = &AnimRef{}
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
gob.Register(&AnimRef{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// AnimRef manages an Anim using a premade AnimDef from the cache.
|
|
||||||
type AnimRef struct {
|
|
||||||
Path string
|
|
||||||
|
|
||||||
anim Anim
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *AnimRef) Load(assets fs.FS) error {
|
|
||||||
// Fast path: set r.anim to a copy
|
|
||||||
anim, found := animCache[assetKey{assets, r.Path}]
|
|
||||||
if found {
|
|
||||||
r.anim = anim
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// Slow path: load from gobz file
|
|
||||||
if err := LoadGobz(&r.anim, assets, r.Path); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
animCache[assetKey{assets, r.Path}] = r.anim
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CurrentFrame returns the value of CurrentFrame from r.anim.
|
|
||||||
func (r *AnimRef) CurrentFrame() int { return r.anim.CurrentFrame() }
|
|
||||||
|
|
||||||
// Reset calls Reset on r.anim.
|
|
||||||
func (r *AnimRef) Reset() { r.anim.Reset() }
|
|
||||||
|
|
||||||
// Update calls Update on r.anim.
|
|
||||||
func (r *AnimRef) Update() error { return r.anim.Update() }
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
var (
|
var (
|
||||||
// TypeOf(pointer to interface).Elem() is "idiomatic" -
|
// TypeOf(pointer to interface).Elem() is "idiomatic" -
|
||||||
// see https://pkg.go.dev/reflect#example-TypeOf
|
// see https://pkg.go.dev/reflect#example-TypeOf
|
||||||
AnimerType = reflect.TypeOf((*Animer)(nil)).Elem()
|
|
||||||
BounderType = reflect.TypeOf((*Bounder)(nil)).Elem()
|
BounderType = reflect.TypeOf((*Bounder)(nil)).Elem()
|
||||||
ColliderType = reflect.TypeOf((*Collider)(nil)).Elem()
|
ColliderType = reflect.TypeOf((*Collider)(nil)).Elem()
|
||||||
DisablerType = reflect.TypeOf((*Disabler)(nil)).Elem()
|
DisablerType = reflect.TypeOf((*Disabler)(nil)).Elem()
|
||||||
|
@ -28,7 +27,6 @@ var (
|
||||||
|
|
||||||
// Behaviours lists all the behaviours that can be queried with Game.Query.
|
// Behaviours lists all the behaviours that can be queried with Game.Query.
|
||||||
Behaviours = []reflect.Type{
|
Behaviours = []reflect.Type{
|
||||||
AnimerType,
|
|
||||||
BounderType,
|
BounderType,
|
||||||
ColliderType,
|
ColliderType,
|
||||||
DisablerType,
|
DisablerType,
|
||||||
|
@ -44,14 +42,6 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Animer components have a current frame index.
|
|
||||||
type Animer interface {
|
|
||||||
Updater
|
|
||||||
|
|
||||||
CurrentFrame() int
|
|
||||||
Reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bounder components have a bounding rectangle.
|
// Bounder components have a bounding rectangle.
|
||||||
type Bounder interface {
|
type Bounder interface {
|
||||||
BoundingRect() image.Rectangle
|
BoundingRect() image.Rectangle
|
||||||
|
|
|
@ -13,24 +13,33 @@ var _ interface {
|
||||||
|
|
||||||
// Sheet handles images that consist of a grid of equally sized regions
|
// Sheet handles images that consist of a grid of equally sized regions
|
||||||
// (cells) and can produce subimages for the cell at an index. This is useful
|
// (cells) and can produce subimages for the cell at an index. This is useful
|
||||||
// for various applications such as sprite animation and tile maps.
|
// for various applications such as sprite animation and tile maps. Additionally
|
||||||
|
// each sheet carries a collection of animations that use the sheet.
|
||||||
type Sheet struct {
|
type Sheet struct {
|
||||||
|
AnimDefs map[string]*AnimDef
|
||||||
CellSize image.Point
|
CellSize image.Point
|
||||||
Src ImageRef
|
Src ImageRef
|
||||||
|
|
||||||
w int // width as measured in number of cells
|
w int // width as measured in number of cells
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAnim returns a new Anim for the given key, or nil if not found in
|
||||||
|
// AnimDefs.
|
||||||
|
func (s *Sheet) NewAnim(key string) *Anim {
|
||||||
|
return s.AnimDefs[key].NewAnim()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare computes the width of the image (in cells).
|
||||||
func (s *Sheet) Prepare(*Game) error {
|
func (s *Sheet) Prepare(*Game) error {
|
||||||
s.w, _ = s.Src.Image().Size()
|
s.w, _ = s.Src.Image().Size()
|
||||||
s.w /= s.CellSize.X
|
s.w /= s.CellSize.X
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scan returns the Src.
|
||||||
func (s *Sheet) Scan() []interface{} { return []interface{}{&s.Src} }
|
func (s *Sheet) Scan() []interface{} { return []interface{}{&s.Src} }
|
||||||
|
|
||||||
// SubImage returns an *ebiten.Image corresponding to the cell at the given
|
// SubImage returns an *ebiten.Image corresponding to the given cell index.
|
||||||
// index.
|
|
||||||
func (s *Sheet) SubImage(i int) *ebiten.Image {
|
func (s *Sheet) SubImage(i int) *ebiten.Image {
|
||||||
p := pmul(image.Pt(i%s.w, i/s.w), s.CellSize)
|
p := pmul(image.Pt(i%s.w, i/s.w), s.CellSize)
|
||||||
r := image.Rectangle{p, p.Add(s.CellSize)}
|
r := image.Rectangle{p, p.Add(s.CellSize)}
|
||||||
|
|
|
@ -30,10 +30,12 @@ type Sprite struct {
|
||||||
anim *Anim
|
anim *Anim
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw draws the current cell to the screen.
|
||||||
func (s *Sprite) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
|
func (s *Sprite) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
|
||||||
screen.DrawImage(s.Sheet.SubImage(s.anim.CurrentFrame()), opts)
|
screen.DrawImage(s.Sheet.SubImage(s.anim.Cell()), opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scan returns the Actor and the Sheet.
|
||||||
func (s *Sprite) Scan() []interface{} {
|
func (s *Sprite) Scan() []interface{} {
|
||||||
return []interface{}{
|
return []interface{}{
|
||||||
&s.Actor,
|
&s.Actor,
|
||||||
|
@ -41,6 +43,8 @@ func (s *Sprite) Scan() []interface{} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetAnim sets the Anim to use for the sprite. If it is not the same as the
|
||||||
|
// one currently set, it resets the new anim.
|
||||||
func (s *Sprite) SetAnim(a *Anim) {
|
func (s *Sprite) SetAnim(a *Anim) {
|
||||||
if s.anim != a {
|
if s.anim != a {
|
||||||
a.Reset()
|
a.Reset()
|
||||||
|
@ -48,11 +52,12 @@ func (s *Sprite) SetAnim(a *Anim) {
|
||||||
s.anim = a
|
s.anim = a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transform returns a translation by the FrameOffset.
|
||||||
func (s *Sprite) Transform() (opts ebiten.DrawImageOptions) {
|
func (s *Sprite) Transform() (opts ebiten.DrawImageOptions) {
|
||||||
opts.GeoM.Translate(pfloat(s.Actor.Pos.Add(s.FrameOffset)))
|
opts.GeoM.Translate(pfloat(s.Actor.Pos.Add(s.FrameOffset)))
|
||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
|
|
||||||
// anim can change a bit so we don't tell Game about it, but that means it must
|
// Update updates the Sprite's anim. anim can change a bit so we don't tell Game
|
||||||
// be updated here.
|
// about it, but that means it must be updated manually.
|
||||||
func (s *Sprite) Update() error { return s.anim.Update() }
|
func (s *Sprite) Update() error { return s.anim.Update() }
|
||||||
|
|
|
@ -2,7 +2,9 @@ package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
|
"io/fs"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2"
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
)
|
)
|
||||||
|
@ -23,7 +25,7 @@ var (
|
||||||
_ interface {
|
_ interface {
|
||||||
Tile
|
Tile
|
||||||
Scanner
|
Scanner
|
||||||
} = AnimatedTile{}
|
} = &AnimatedTile{}
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -77,11 +79,27 @@ func (t *Tilemap) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
|
||||||
geom.Concat(og)
|
geom.Concat(og)
|
||||||
opts.GeoM = geom
|
opts.GeoM = geom
|
||||||
|
|
||||||
src := t.Sheet.SubImage(tile.CellIndex())
|
src := t.Sheet.SubImage(tile.Cell())
|
||||||
screen.DrawImage(src, opts)
|
screen.DrawImage(src, opts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load instantiates animations for all AnimatedTiles.
|
||||||
|
func (t *Tilemap) Load(fs.FS) error {
|
||||||
|
for _, tile := range t.Map {
|
||||||
|
at, ok := tile.(*AnimatedTile)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ad, found := t.Sheet.AnimDefs[at.AnimKey]
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("anim key %q not in sheet AnimDefs", at.AnimKey)
|
||||||
|
}
|
||||||
|
at.anim = ad.NewAnim()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Scan returns a slice containing Src and all non-nil tiles.
|
// Scan returns a slice containing Src and all non-nil tiles.
|
||||||
func (t *Tilemap) Scan() []interface{} {
|
func (t *Tilemap) Scan() []interface{} {
|
||||||
c := make([]interface{}, 1, len(t.Map)+1)
|
c := make([]interface{}, 1, len(t.Map)+1)
|
||||||
|
@ -116,20 +134,22 @@ func (t *Tilemap) TileBounds(wc image.Point) image.Rectangle {
|
||||||
|
|
||||||
// Tile is the interface needed by Tilemap.
|
// Tile is the interface needed by Tilemap.
|
||||||
type Tile interface {
|
type Tile interface {
|
||||||
CellIndex() int
|
Cell() int
|
||||||
}
|
}
|
||||||
|
|
||||||
// StaticTile returns a fixed tile index.
|
// StaticTile returns a fixed tile index.
|
||||||
type StaticTile int
|
type StaticTile int
|
||||||
|
|
||||||
func (s StaticTile) CellIndex() int { return int(s) }
|
func (s StaticTile) Cell() int { return int(s) }
|
||||||
|
|
||||||
// AnimatedTile uses an Anim to choose a tile index.
|
// AnimatedTile uses an Anim to choose a tile index.
|
||||||
type AnimatedTile struct {
|
type AnimatedTile struct {
|
||||||
Anim Animer
|
AnimKey string
|
||||||
|
|
||||||
|
anim *Anim
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AnimatedTile) CellIndex() int { return a.Anim.CurrentFrame() }
|
func (a *AnimatedTile) Cell() int { return a.anim.Cell() }
|
||||||
|
|
||||||
// Scan returns a.Anim.
|
// Scan returns a.anim.
|
||||||
func (a AnimatedTile) Scan() []interface{} { return []interface{}{a.Anim} }
|
func (a *AnimatedTile) Scan() []interface{} { return []interface{}{a.anim} }
|
||||||
|
|
|
@ -99,7 +99,7 @@ type WallUnit struct {
|
||||||
|
|
||||||
// Draw draws this wall unit.
|
// Draw draws this wall unit.
|
||||||
func (u *WallUnit) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
|
func (u *WallUnit) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
|
||||||
screen.DrawImage(u.wall.Sheet.SubImage(u.Tile.CellIndex()), opts)
|
screen.DrawImage(u.wall.Sheet.SubImage(u.Tile.Cell()), opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan returns the Tile.
|
// Scan returns the Tile.
|
||||||
|
|
68
game/aw.go
68
game/aw.go
|
@ -2,6 +2,8 @@ package game
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
@ -182,39 +184,41 @@ func (aw *Awakeman) realUpdate() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aw *Awakeman) Prepare(game *engine.Game) error {
|
func (aw *Awakeman) Prepare(game *engine.Game) error {
|
||||||
aw.camera = game.Component(aw.CameraID).(*engine.Camera)
|
cam, ok := game.Component(aw.CameraID).(*engine.Camera)
|
||||||
aw.toast, _ = game.Component(aw.ToastID).(*engine.DebugToast)
|
if !ok {
|
||||||
|
return fmt.Errorf("component %q not *engine.Camera", aw.CameraID)
|
||||||
|
}
|
||||||
|
aw.camera = cam
|
||||||
|
tst, ok := game.Component(aw.ToastID).(*engine.DebugToast)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("component %q not *engine.DebugToast", aw.ToastID)
|
||||||
|
}
|
||||||
|
aw.toast = tst
|
||||||
|
|
||||||
aw.animIdleLeft = &engine.Anim{Frames: []engine.AnimFrame{
|
aw.animIdleLeft = aw.Sprite.Sheet.NewAnim("idle_left")
|
||||||
{Frame: 1, Duration: 60},
|
if aw.animIdleLeft == nil {
|
||||||
}}
|
return errors.New("missing anim idle_left")
|
||||||
aw.animIdleRight = &engine.Anim{Frames: []engine.AnimFrame{
|
}
|
||||||
{Frame: 0, Duration: 60},
|
aw.animIdleRight = aw.Sprite.Sheet.NewAnim("idle_right")
|
||||||
}}
|
if aw.animIdleRight == nil {
|
||||||
aw.animRunLeft = &engine.Anim{Frames: []engine.AnimFrame{
|
return errors.New("missing anim idle_right")
|
||||||
{Frame: 14, Duration: 3},
|
}
|
||||||
{Frame: 15, Duration: 5},
|
aw.animRunLeft = aw.Sprite.Sheet.NewAnim("run_left")
|
||||||
{Frame: 16, Duration: 3},
|
if aw.animRunLeft == nil {
|
||||||
{Frame: 17, Duration: 3},
|
return errors.New("missing anim run_left")
|
||||||
}}
|
}
|
||||||
aw.animRunRight = &engine.Anim{Frames: []engine.AnimFrame{
|
aw.animRunRight = aw.Sprite.Sheet.NewAnim("run_right")
|
||||||
{Frame: 10, Duration: 3},
|
if aw.animRunRight == nil {
|
||||||
{Frame: 11, Duration: 5},
|
return errors.New("missing anim run_right")
|
||||||
{Frame: 12, Duration: 3},
|
}
|
||||||
{Frame: 13, Duration: 3},
|
aw.animWalkRight = aw.Sprite.Sheet.NewAnim("walk_left")
|
||||||
}}
|
if aw.animWalkRight == nil {
|
||||||
aw.animWalkRight = &engine.Anim{Frames: []engine.AnimFrame{
|
return errors.New("missing anim walk_left")
|
||||||
{Frame: 2, Duration: 6},
|
}
|
||||||
{Frame: 3, Duration: 6},
|
aw.animWalkLeft = aw.Sprite.Sheet.NewAnim("walk_right")
|
||||||
{Frame: 4, Duration: 6},
|
if aw.animWalkLeft == nil {
|
||||||
{Frame: 5, Duration: 6},
|
return errors.New("missing anim walk_right")
|
||||||
}}
|
}
|
||||||
aw.animWalkLeft = &engine.Anim{Frames: []engine.AnimFrame{
|
|
||||||
{Frame: 6, Duration: 6},
|
|
||||||
{Frame: 7, Duration: 6},
|
|
||||||
{Frame: 8, Duration: 6},
|
|
||||||
{Frame: 9, Duration: 6},
|
|
||||||
}}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
82
main.go
82
main.go
|
@ -73,32 +73,21 @@ func main() {
|
||||||
|
|
||||||
// writeLevel1 dumps a test level into level1.gobz
|
// writeLevel1 dumps a test level into level1.gobz
|
||||||
func writeLevel1() {
|
func writeLevel1() {
|
||||||
redTileAnim := &engine.Anim{Frames: []engine.AnimFrame{
|
|
||||||
{Frame: 3, Duration: 12},
|
|
||||||
{Frame: 4, Duration: 12},
|
|
||||||
{Frame: 5, Duration: 12},
|
|
||||||
{Frame: 6, Duration: 12},
|
|
||||||
}}
|
|
||||||
greenTileAnim := &engine.Anim{Frames: []engine.AnimFrame{
|
|
||||||
{Frame: 0, Duration: 16},
|
|
||||||
{Frame: 1, Duration: 16},
|
|
||||||
{Frame: 2, Duration: 16},
|
|
||||||
}}
|
|
||||||
denseTiles := [][]engine.Tile{
|
denseTiles := [][]engine.Tile{
|
||||||
{engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.StaticTile(9)},
|
{engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.StaticTile(9)},
|
||||||
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.AnimatedTile{Anim: redTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, &engine.AnimatedTile{AnimKey: "red_tile"}, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
||||||
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.AnimatedTile{Anim: redTileAnim.Copy()}, nil, nil, nil},
|
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, &engine.AnimatedTile{AnimKey: "red_tile"}, nil, nil, nil},
|
||||||
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
||||||
{nil, nil, engine.AnimatedTile{Anim: greenTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
{nil, nil, &engine.AnimatedTile{AnimKey: "green_tile"}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
||||||
{nil, nil, nil, nil, nil, engine.AnimatedTile{Anim: redTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
{nil, nil, nil, nil, nil, &engine.AnimatedTile{AnimKey: "red_tile"}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
||||||
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.AnimatedTile{Anim: greenTileAnim.Copy()}, nil, nil, nil, nil, nil, nil},
|
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, &engine.AnimatedTile{AnimKey: "green_tile"}, nil, nil, nil, nil, nil, nil},
|
||||||
{nil, nil, nil, nil, engine.AnimatedTile{Anim: greenTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
{nil, nil, nil, nil, &engine.AnimatedTile{AnimKey: "green_tile"}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
||||||
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.AnimatedTile{Anim: greenTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
{nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, &engine.AnimatedTile{AnimKey: "green_tile"}, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
||||||
{nil, engine.AnimatedTile{Anim: redTileAnim.Copy()}, nil, nil, nil, nil, nil, nil, engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
{nil, &engine.AnimatedTile{AnimKey: "red_tile"}, nil, nil, nil, nil, nil, nil, engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
||||||
{nil, nil, nil, nil, nil, engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.StaticTile(9), nil, nil, nil},
|
{nil, nil, nil, nil, nil, engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, engine.StaticTile(9), nil, nil, nil},
|
||||||
{nil, nil, nil, nil, engine.StaticTile(9), engine.StaticTile(9), engine.StaticTile(9), nil, nil, nil, engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
{nil, nil, nil, nil, engine.StaticTile(9), engine.StaticTile(9), engine.StaticTile(9), nil, nil, nil, engine.StaticTile(9), nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
||||||
{engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.AnimatedTile{Anim: redTileAnim.Copy()}, engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8)},
|
{engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), &engine.AnimatedTile{AnimKey: "red_tile"}, engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8), engine.StaticTile(8)},
|
||||||
{engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.AnimatedTile{Anim: redTileAnim.Copy()}, engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.AnimatedTile{Anim: greenTileAnim.Copy()}, engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7)},
|
{engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), &engine.AnimatedTile{AnimKey: "red_tile"}, engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), &engine.AnimatedTile{AnimKey: "green_tile"}, engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7)},
|
||||||
{engine.StaticTile(9), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(9)},
|
{engine.StaticTile(9), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(7), engine.StaticTile(9)},
|
||||||
}
|
}
|
||||||
tiles := make(map[image.Point]engine.Tile)
|
tiles := make(map[image.Point]engine.Tile)
|
||||||
|
@ -135,6 +124,22 @@ func writeLevel1() {
|
||||||
ZOrder: 2,
|
ZOrder: 2,
|
||||||
Map: tiles,
|
Map: tiles,
|
||||||
Sheet: engine.Sheet{
|
Sheet: engine.Sheet{
|
||||||
|
AnimDefs: map[string]*engine.AnimDef{
|
||||||
|
"red_tile": {
|
||||||
|
Steps: []engine.AnimStep{
|
||||||
|
{Cell: 3, Duration: 12},
|
||||||
|
{Cell: 4, Duration: 12},
|
||||||
|
{Cell: 5, Duration: 12},
|
||||||
|
{Cell: 6, Duration: 12},
|
||||||
|
}},
|
||||||
|
"green_tile": {
|
||||||
|
Steps: []engine.AnimStep{
|
||||||
|
{Cell: 0, Duration: 16},
|
||||||
|
{Cell: 1, Duration: 16},
|
||||||
|
{Cell: 2, Duration: 16},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
CellSize: image.Pt(16, 16),
|
CellSize: image.Pt(16, 16),
|
||||||
Src: engine.ImageRef{Path: "assets/boxes.png"},
|
Src: engine.ImageRef{Path: "assets/boxes.png"},
|
||||||
},
|
},
|
||||||
|
@ -160,12 +165,45 @@ func writeLevel1() {
|
||||||
Pos: image.Pt(100, 100),
|
Pos: image.Pt(100, 100),
|
||||||
Size: image.Pt(8, 16),
|
Size: image.Pt(8, 16),
|
||||||
},
|
},
|
||||||
ZOrder: 3,
|
|
||||||
FrameOffset: image.Pt(-1, 0),
|
FrameOffset: image.Pt(-1, 0),
|
||||||
Sheet: engine.Sheet{
|
Sheet: engine.Sheet{
|
||||||
|
AnimDefs: map[string]*engine.AnimDef{
|
||||||
|
|
||||||
|
"idle_left": {Steps: []engine.AnimStep{
|
||||||
|
{Cell: 1, Duration: 60},
|
||||||
|
}},
|
||||||
|
"idle_right": {Steps: []engine.AnimStep{
|
||||||
|
{Cell: 0, Duration: 60},
|
||||||
|
}},
|
||||||
|
"run_left": {Steps: []engine.AnimStep{
|
||||||
|
{Cell: 14, Duration: 3},
|
||||||
|
{Cell: 15, Duration: 5},
|
||||||
|
{Cell: 16, Duration: 3},
|
||||||
|
{Cell: 17, Duration: 3},
|
||||||
|
}},
|
||||||
|
"run_right": {Steps: []engine.AnimStep{
|
||||||
|
{Cell: 10, Duration: 3},
|
||||||
|
{Cell: 11, Duration: 5},
|
||||||
|
{Cell: 12, Duration: 3},
|
||||||
|
{Cell: 13, Duration: 3},
|
||||||
|
}},
|
||||||
|
"walk_left": {Steps: []engine.AnimStep{
|
||||||
|
{Cell: 2, Duration: 6},
|
||||||
|
{Cell: 3, Duration: 6},
|
||||||
|
{Cell: 4, Duration: 6},
|
||||||
|
{Cell: 5, Duration: 6},
|
||||||
|
}},
|
||||||
|
"walk_right": {Steps: []engine.AnimStep{
|
||||||
|
{Cell: 6, Duration: 6},
|
||||||
|
{Cell: 7, Duration: 6},
|
||||||
|
{Cell: 8, Duration: 6},
|
||||||
|
{Cell: 9, Duration: 6},
|
||||||
|
}},
|
||||||
|
},
|
||||||
CellSize: image.Pt(10, 16),
|
CellSize: image.Pt(10, 16),
|
||||||
Src: engine.ImageRef{Path: "assets/aw.png"},
|
Src: engine.ImageRef{Path: "assets/aw.png"},
|
||||||
},
|
},
|
||||||
|
ZOrder: 3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue