package tins2021 import ( "math/rand" "time" "opslag.de/schobers/geom" "opslag.de/schobers/zntg/ui" ) type AnimatedTexture struct { Texture ui.Texture Frames []geom.RectangleF32 } func NewAnimatedTexture(texture ui.Texture, n int) AnimatedTexture { frames := make([]geom.RectangleF32, 0, n) height := float32(texture.Height()) width := float32(texture.Width()) for i := 0; i < n; i++ { left := width * float32(i) / float32(n) right := width * float32(i+1) / float32(n) frames = append(frames, geom.RectF32(left, 0, right, height)) } return AnimatedTexture{Texture: texture, Frames: frames} } func FitAnimatedTexture(textures *ui.Textures, name string, scale float32, n int) AnimatedTexture { height := float32(textures.Texture(name).Height()) scale = geom.Round32(height*scale) / height // clip scale to integer width/height return NewAnimatedTexture(textures.ScaledByName(name, scale), n) } func (t AnimatedTexture) Scale(scale float32) AnimatedTexture { frames := make([]geom.RectangleF32, 0, len(t.Frames)) for _, frame := range t.Frames { frames = append(frames, geom.RectangleF32{Min: frame.Min.Mul(scale), Max: frame.Max.Mul(scale)}) } return AnimatedTexture{ Texture: t.Texture, Frames: frames, } } func (t AnimatedTexture) Draw(renderer ui.Renderer, pos geom.PointF32, frame int) { renderer.DrawTexturePointOptions(t.Texture, pos, ui.DrawOptions{Source: &t.Frames[frame]}) } type Animation struct { LastUpdate time.Time Frame int } type Animations struct { Values map[geom.Point]*Animation Interval time.Duration Frames int AutoReset bool RandomInit bool } func NewAnimations(interval time.Duration, frames int, autoReset, randomInit bool) *Animations { return &Animations{ Values: map[geom.Point]*Animation{}, Interval: interval, Frames: frames, AutoReset: autoReset, RandomInit: randomInit, } } func (a *Animations) Update() { now := time.Now() update := now.Add(-a.Interval) for _, value := range a.Values { if value.Frame == a.Frames { break } for value.LastUpdate.Before(update) { value.LastUpdate = value.LastUpdate.Add(a.Interval) value.Frame = value.Frame + 1 if value.Frame == a.Frames { if a.AutoReset { value.Frame = 0 } else { break } } } } } func (a *Animations) newAnimation() *Animation { if a.RandomInit { return &Animation{ LastUpdate: time.Now().Add(time.Duration(-rand.Int63n(int64(a.Interval)))), Frame: rand.Intn(a.Frames), } } return &Animation{ LastUpdate: time.Now(), Frame: 0, } } func (a *Animations) Frame(pos geom.Point) int { value, ok := a.Values[pos] if !ok { value = a.newAnimation() a.Values[pos] = value } return value.Frame }