/
sequence.go
140 lines (121 loc) · 3.53 KB
/
sequence.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package render
import (
"image"
"image/draw"
"time"
"github.com/oakmound/oak/v4/event"
"github.com/oakmound/oak/v4/render/mod"
"github.com/oakmound/oak/v4/timing"
)
// A Sequence is a series of modifiables drawn as an animation. It is more
// primitive than animation, but less efficient.
type Sequence struct {
LayeredPoint
pauseBool
InterruptBool
rs []Modifiable
lastChange time.Time
sheetPos int
frameTime int64
event.CallerID
}
// NewSequence returns a new sequence from the input modifiables, playing at
// the given fps rate.
func NewSequence(fps float64, mods ...Modifiable) *Sequence {
return &Sequence{
LayeredPoint: NewLayeredPoint(0, 0, 0),
pauseBool: pauseBool{
playing: true,
},
InterruptBool: InterruptBool{
Interruptable: true,
},
sheetPos: 0,
frameTime: timing.FPSToNano(fps),
rs: mods,
lastChange: time.Now(),
}
}
// SetFPS sets the number of frames that should advance per second to be
// the input fps
func (sq *Sequence) SetFPS(fps float64) {
sq.frameTime = timing.FPSToNano(fps)
}
// GetDims of a Sequence returns the dims of the current Renderable for the sequence
func (sq *Sequence) GetDims() (int, int) {
return sq.rs[sq.sheetPos].GetDims()
}
// Copy copies each modifiable inside this sequence in order to produce a new
// copied sequence
func (sq *Sequence) Copy() Modifiable {
newSq := new(Sequence)
*newSq = *sq
newRs := make([]Modifiable, len(sq.rs))
for i, r := range sq.rs {
newRs[i] = r.Copy()
}
newSq.rs = newRs
newSq.LayeredPoint = sq.LayeredPoint.Copy()
return newSq
}
var AnimationEnd = event.RegisterEvent[struct{}]()
// SetTriggerID sets the ID that AnimationEnd will be triggered on when this
// sequence loops over from its last frame to its first
func (sq *Sequence) SetTriggerID(id event.CallerID) {
sq.CallerID = id
}
func (sq *Sequence) update() {
if sq.playing && time.Since(sq.lastChange).Nanoseconds() > sq.frameTime {
sq.lastChange = time.Now()
sq.sheetPos = (sq.sheetPos + 1) % len(sq.rs)
if sq.sheetPos == (len(sq.rs)-1) && sq.CallerID != 0 {
// TODO: not default bus
event.TriggerForCallerOn(event.DefaultBus, sq.CallerID, AnimationEnd, struct{}{})
}
}
}
// Get returns the Modifiable stored at this sequence's ith index. If the sequence
// does not have an ith index this returns nil
func (sq *Sequence) Get(i int) Modifiable {
if i < 0 || i >= len(sq.rs) {
return nil
}
return sq.rs[i]
}
// Draw draws this sequence at +xOff, +yOff
func (sq *Sequence) Draw(buff draw.Image, xOff, yOff float64) {
sq.update()
sq.rs[sq.sheetPos].Draw(buff, sq.X()+xOff, sq.Y()+yOff)
}
// GetRGBA returns the RGBA of the currently showing frame of this sequence
func (sq *Sequence) GetRGBA() *image.RGBA {
return sq.rs[sq.sheetPos].GetRGBA()
}
// Modify alters each renderable in this sequence by the given
// modifications
func (sq *Sequence) Modify(ms ...mod.Mod) Modifiable {
for _, r := range sq.rs {
r.Modify(ms...)
}
return sq
}
// Filter filters each element in the sequence by the inputs
func (sq *Sequence) Filter(fs ...mod.Filter) {
for _, r := range sq.rs {
r.Filter(fs...)
}
}
// IsStatic returns false for sequences
func (sq *Sequence) IsStatic() bool {
return false
}
// TweenSequence returns a sequence that is the tweening between the input images
// at the given frame rate over the given frame count.
func TweenSequence(a, b image.Image, frames int, fps float64) *Sequence {
images := Tween(a, b, frames)
ms := make([]Modifiable, len(images))
for i, v := range images {
ms[i] = NewSprite(0, 0, v)
}
return NewSequence(fps, ms...)
}