Files
GoRetro/component_animator.go
2022-03-27 19:38:38 +01:00

156 lines
3.4 KiB
Go

package GoRetro
/*
* --------------------
* Animator
* --------------------
* Handles sprites and their associated animation sequences
*/
import (
"encoding/json"
"fmt"
"time"
"github.com/veandco/go-sdl2/sdl"
)
type animator struct {
container *Element
sequences map[string]*Sequence // All of the available sequences
current string // The current sequence
lastFrameChange time.Time // When we last ticked between frames
finished bool // We're on the last frame
tex *sdl.Texture // The frames
}
func NewAnimator(
container *Element,
imagepath string,
sequences map[string]*Sequence,
defaultSequence string,
renderer *sdl.Renderer) (*animator, error) {
var an animator
tex, err := loadTextureFromBMP(imagepath, renderer)
if err != nil {
return nil, err
}
an.tex = tex
an.container = container
an.sequences = sequences
an.current = defaultSequence
an.lastFrameChange = time.Now()
return &an, nil
}
func (an *animator) onUpdate() error {
sequence := an.sequences[an.current]
// Calculate time per frame
frameInterval := float64(time.Second) / sequence.sampleRate
// If we've exceeded that time since the last frame, bump it along one
if time.Since(an.lastFrameChange) >= time.Duration(frameInterval) {
an.finished = sequence.nextFrame()
an.lastFrameChange = time.Now()
}
return nil
}
func (an *animator) onDraw() error {
Position := an.container.Position
if !an.container.PositionAbsolute {
Position = vectorAdd(an.container.Position, ViewPort.Position)
}
return drawTexture(
an.tex,
VectorInt32{an.sequences[an.current].frames[an.sequences[an.current].frame].W, an.sequences[an.current].frames[an.sequences[an.current].frame].H},
VectorInt32{an.sequences[an.current].frames[an.sequences[an.current].frame].X, an.sequences[an.current].frames[an.sequences[an.current].frame].Y},
Position,
an.container.Rotation,
an.container.Renderer)
}
func (an *animator) onCollision(other *Element) error {
return nil
}
func (an *animator) setSequence(name string) bool {
_, ok := an.sequences[name]
if ok {
// If we *are* changing sequence, change the name and reset the frame
if an.current != name {
// Reset the old sequence to frame 0
sequence := an.sequences[an.current]
sequence.resetFrame()
// Use the new sequence
an.current = name
an.lastFrameChange = time.Now()
}
}
return ok
}
//-----------------------------------------------------------------------------
type SequenceFrame struct {
X int32 `json:"x"`
Y int32 `json:"y"`
W int32 `json:"w"`
H int32 `json:"h"`
}
type Sequence struct {
frame int // Current frame
sampleRate float64 // Frames per second
loop bool // Does this sequence play continuously?
frames []SequenceFrame
}
func NewSequence(
indexpath string,
sampleRate float64,
loop bool) (*Sequence, error) {
var seq Sequence
jsonFile, err := GetFile(indexpath)
if err != nil {
return nil, fmt.Errorf("loading sequence %v: %v", indexpath, err)
}
json.Unmarshal(jsonFile.Data, &seq.frames)
seq.frame = 0
seq.sampleRate = sampleRate
seq.loop = loop
return &seq, nil
}
func (seq *Sequence) resetFrame() {
seq.frame = 0
}
func (seq *Sequence) nextFrame() bool {
// If we're at the end
if seq.frame == len(seq.frames)-1 {
if seq.loop {
// Reset for a looping sequence
seq.resetFrame()
} else {
return true
}
} else {
seq.frame++
}
return false
}