Bunyip a game engine in Go GitHub

Package github.com/matjam/bunyip/tween

tween

Package tween animates values over time. A Tween moves a number from one value to another with an easing curve, and Sequence chains them.

To make a tween, call New with a start, an end, a duration in seconds and an Ease. The usual easing curves are provided, and any func(t float32) float32 works. Call Update each step to advance a tween, then read Value, or set OnDone to be called when it finishes. Use tweens for menus sliding in, health bars draining, cameras easing to a target and damage numbers floating up. NewSequence runs several in order. For keyframed curves over vectors, colours and component fields, see the anim package. Tweens and sequences are not safe for concurrent use; advance them with finite, nonnegative steps on the game loop goroutine.

Index

Types

type Ease source

type Ease func(t float32) float32

Ease maps progress t in [0,1] to eased progress.

var (
	Linear     Ease = func(t float32) float32 { return t }
	InQuad     Ease = func(t float32) float32 { return t * t }
	OutQuad    Ease = func(t float32) float32 { return t * (2 - t) }
	InOutQuad  Ease = func(t float32) float32 { return inOut(t, InQuad, OutQuad) }
	InCubic    Ease = func(t float32) float32 { return t * t * t }
	OutCubic   Ease = func(t float32) float32 { u := 1 - t; return 1 - u*u*u }
	InOutCubic Ease = func(t float32) float32 { return inOut(t, InCubic, OutCubic) }
	InSine     Ease = func(t float32) float32 { return 1 - cos(t*math.Pi/2) }
	OutSine    Ease = func(t float32) float32 { return sin(t * math.Pi / 2) }
	InOutSine  Ease = func(t float32) float32 { return (1 - cos(t*math.Pi)) / 2 }
	Smoothstep Ease = func(t float32) float32 { return t * t * (3 - 2*t) }
	OutBack    Ease = func(t float32) float32 {
		const c1, c3 = 1.70158, 2.70158
		u := t - 1
		return 1 + c3*u*u*u + c1*u*u
	}
	OutElastic Ease = func(t float32) float32 {
		if t <= 0 || t >= 1 {
			return clamp01(t)
		}
		const c4 = 2 * math.Pi / 3
		return pow2(-10*t)*sin((t*10-0.75)*c4) + 1
	}
	OutBounce Ease = func(t float32) float32 {
		const n1, d1 = 7.5625, 2.75
		switch {
		case t < 1/d1:
			return n1 * t * t
		case t < 2/d1:
			t -= 1.5 / d1
			return n1*t*t + 0.75
		case t < 2.5/d1:
			t -= 2.25 / d1
			return n1*t*t + 0.9375
		default:
			t -= 2.625 / d1
			return n1*t*t + 0.984375
		}
	}
)

Easing curves. In* start slowly, Out* end slowly, InOut* do both.

type Of source

type Of[V any] struct {
	*Tween
	From, To V                         // blend endpoints
	Lerp     func(a, b V, t float32) V // required blend function, called with eased progress
}

Of animates any value that can be blended: a position, a colour, a size. It wraps a Tween for the timing (delay, repeats, yo-yo, easing) and a Lerp function for the blend, so gfx.Color.Lerp, lin.Vec3.Lerp or a game's own mix all work:

fade := tween.NewOf(gfx.Transparent, gfx.White, 0.5, tween.OutQuad, gfx.Color.Lerp)
tint := fade.Update(dt)

NewOf source

func NewOf[V any](from, to V, seconds float32, ease Ease, lerp func(a, b V, t float32) V) *Of[V]

NewOf makes a tween over any value with a blend function; a nil ease is linear. The blend function must be non-nil. Delay, Repeat and YoYo have the same behavior as on a scalar Tween.

NewVec2 source

func NewVec2(from, to lin.Vec2, seconds float32, ease Ease) *Of[lin.Vec2]

NewVec2 tweens a 2D vector.

NewVec3 source

func NewVec3(from, to lin.Vec3, seconds float32, ease Ease) *Of[lin.Vec3]

NewVec3 tweens a 3D vector.

OnDone source

func (o *Of[V]) OnDone(f func()) *Of[V]

OnDone replaces the completion callback and returns the same typed tween for chaining. It follows Tween.OnDone's callback timing.

Example
package main

import (
	"fmt"

	"github.com/matjam/bunyip/lin"
	"github.com/matjam/bunyip/tween"
)

func main() {
	done := false
	move := tween.NewVec2(lin.V2(0, 0), lin.V2(10, 20), 1, nil).
		OnDone(func() { done = true })
	move.Repeat, move.YoYo = 1, true
	fmt.Println(move.Update(1), done)
	fmt.Println(move.Update(1), done)
}
Output
{10 20} false
{0 0} true

Update source

func (o *Of[V]) Update(dt float32) V

Update advances the tween and returns the blended value.

Value source

func (o *Of[V]) Value() V

Value is the blended value at the tween's current progress.

type Sequence source

type Sequence struct {
	// contains filtered or unexported fields
}

Sequence plays tweens one after another.

Example
package main

import (
	"fmt"

	"github.com/matjam/bunyip/tween"
)

func main() {
	// Fade in, hold, fade out: each step starts when the previous ends.
	fade := tween.NewSequence(
		tween.New(0, 1, 0.5, nil),
		tween.New(1, 1, 1, nil),
		tween.New(1, 0, 0.5, nil),
	)
	for !fade.Done() {
		fade.Update(0.5)
	}
	fmt.Println(fade.Update(0))
}
Output
0

NewSequence source

func NewSequence(steps ...*Tween) *Sequence

NewSequence chains tweens.

Done source

func (s *Sequence) Done() bool

Done reports whether every step has finished.

Reset source

func (s *Sequence) Reset()

Reset restarts from the first step.

Update source

func (s *Sequence) Update(dt float32) float32

Update advances the sequence and returns the current tween's value.

type Tween source

type Tween struct {
	From, To float32 // endpoints of the forward play
	Duration float32 // seconds per play; nonpositive completes after Delay
	Ease     Ease    // progress mapping; nil means linear
	Delay    float32 // seconds before movement starts
	Repeat   int     // extra plays after the first; -1 forever
	YoYo     bool    // alternate direction on repeats
	// contains filtered or unexported fields
}

Tween moves a value from From to To over Duration seconds.

Example
package main

import (
	"fmt"

	"github.com/matjam/bunyip/tween"
)

func main() {
	// Slide a value from 0 to 100 over one second with an ease-out curve.
	slide := tween.New(0, 100, 1, tween.OutQuad)
	for range 4 {
		fmt.Printf("%.0f ", slide.Update(0.25))
	}
	fmt.Println(slide.Done())
}
Output
44 75 94 100 true

New source

func New(from, to, seconds float32, ease Ease) *Tween

New makes a tween; a nil ease is linear.

Done source

func (tw *Tween) Done() bool

Done reports whether the tween has finished.

OnDone source

func (tw *Tween) OnDone(f func()) *Tween

OnDone replaces the callback called synchronously by the Update that finishes the tween. Registration after completion does not invoke it; Reset permits it to run again on the next completed playthrough.

Progress source

func (tw *Tween) Progress() float32

Progress is eased progress. The input to Ease is clamped to [0,1], but curves such as OutBack and OutElastic may overshoot that range. A nonpositive Duration reports 1, including while Delay is pending.

Reset source

func (tw *Tween) Reset()

Reset starts the tween over, forwards.

Update source

func (tw *Tween) Update(dt float32) float32

Update advances by dt seconds and returns the current value.

Value source

func (tw *Tween) Value() float32

Value is the current value.

Source files

example_test.go of.go of_test.go review_test.go tween.go tween_test.go