Add fx components 291-320 and the home scene; Kit.Shot, Kit.Toward
Palette cycling, sky, sun and moon, clouds, starfield, rain, snow, petals, leaves, fireflies, waterfall, ocean, campfire, lava, aurora, lightning, mountains and a season scene; scanlines, vignette, screen shake, flash, dither fades, iris wipes, dissolves, mosaics, glitches, sparkles, explosions and confetti. Home opens on a live scene in the palette's season and a strip of all eight palettes. pixel adds Canvas.Cycled, Sprite.At, SpriteOf, Kit.Toward and Kit.Shot, which spends a cue under Reduce Motion so it never replays; display exports Reduce. Gallery grids and the sidebar are one Tab stop each.
This commit is contained in:
56 files changed
+3324
-101
No files matched your search
+148
@@ -0,0 +1,148 @@
|
||||
package fx_test
|
||||
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/egoist/mygo/ui"
|
||||
|
||||
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/fx"
|
||||
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
|
||||
)
|
||||
|
||||
type clock struct{ t time.Time }
|
||||
|
||||
func (c *clock) now() time.Time { return c.t }
|
||||
|
||||
func newClock() *clock { return &clock{time.Unix(1_800_000_000, 0)} }
|
||||
|
||||
// step is the clock's frame at fps, as pixel counts.
|
||||
func (c *clock) step(fps int64) int { return int(c.t.UnixNano() / (int64(time.Second) / fps)) }
|
||||
|
||||
// tick is one step at fps, just past the edge.
|
||||
func tick(fps int) time.Duration { return time.Second/time.Duration(fps) + time.Microsecond }
|
||||
|
||||
// view builds w×h dots on a fake clock, 2px each.
|
||||
func view(w, h int, pal *pixel.Palette, clk *clock, reduce bool, build func(c *ui.Context)) *ui.Tester {
|
||||
tt := ui.NewTester(func(c *ui.Context) {
|
||||
pixel.Use(c, pixel.Settings{Palette: pal, Now: clk.now})
|
||||
build(c)
|
||||
}, 2*w, 2*h)
|
||||
if reduce {
|
||||
tt.SetPreferences(ui.Preferences{ReduceMotion: true, TextScale: 1})
|
||||
tt.Frame()
|
||||
}
|
||||
return tt
|
||||
}
|
||||
|
||||
// dots reads w×h dots as slots; -1 is off-palette.
|
||||
func dots(img *image.RGBA, pal *pixel.Palette, w, h int) [][]int {
|
||||
out := make([][]int, h)
|
||||
for y := range h {
|
||||
out[y] = make([]int, w)
|
||||
for x := range w {
|
||||
c, s := img.RGBAAt(2*x, 2*y), -1
|
||||
for i, pc := range pal.Colors {
|
||||
if pc.R == c.R && pc.G == c.G && pc.B == c.B {
|
||||
s = i
|
||||
break
|
||||
}
|
||||
}
|
||||
out[y][x] = s
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// count is how many dots of a box hold s.
|
||||
func count(d [][]int, x, y, w, h int, s pixel.Slot) int {
|
||||
n := 0
|
||||
for j := y; j < y+h; j++ {
|
||||
for i := x; i < x+w; i++ {
|
||||
if d[j][i] == int(s) {
|
||||
n++
|
||||
}
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func same(a, b [][]int) bool {
|
||||
for y := range a {
|
||||
for x := range a[y] {
|
||||
if a[y][x] != b[y][x] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func mustPanic(t *testing.T, name string, fn func()) {
|
||||
t.Helper()
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Errorf("%s did not panic", name)
|
||||
}
|
||||
}()
|
||||
fn()
|
||||
}
|
||||
|
||||
// solid is a one-slot w×h box under effects.
|
||||
func solid(c *ui.Context, w, h int, s pixel.Slot) {
|
||||
k := pixel.K(c)
|
||||
ui.Box(c).Size(k.D(w), k.D(h)).Label("content").Draw(func(p *ui.Painter, r ui.Rect) {
|
||||
g := k.Canvas(p, r)
|
||||
g.Rect(0, 0, g.W, g.H, s)
|
||||
})
|
||||
}
|
||||
|
||||
var portal = pixel.MustSprite("agcagc\ncagcag")
|
||||
|
||||
func TestAmbientEffectsMoveButHoldStillUnderReduceMotion(t *testing.T) {
|
||||
for name, build := range map[string]func(c *ui.Context){
|
||||
"PaletteCycle": func(c *ui.Context) {
|
||||
fx.PaletteCycle(c, portal, []pixel.Slot{pixel.Accent, pixel.Good, pixel.Info}, fx.PaletteCycleOptions{})
|
||||
},
|
||||
"SunMoon": func(c *ui.Context) { fx.SunMoon(c, 12, fx.SunMoonOptions{Width: 80, Height: 48}) },
|
||||
"Clouds": func(c *ui.Context) { fx.Clouds(c, fx.CloudsOptions{Width: 80, Height: 48}) },
|
||||
"Starfield": func(c *ui.Context) { fx.Starfield(c, fx.StarfieldOptions{Width: 80, Height: 48}) },
|
||||
"Rain": func(c *ui.Context) { fx.Rain(c, fx.RainOptions{Width: 80, Height: 48}) },
|
||||
"Snow": func(c *ui.Context) { fx.Snow(c, fx.SnowOptions{Width: 80, Height: 48}) },
|
||||
"Petals": func(c *ui.Context) { fx.Petals(c, fx.PetalsOptions{Width: 80, Height: 48}) },
|
||||
"Leaves": func(c *ui.Context) { fx.Leaves(c, fx.LeavesOptions{Width: 80, Height: 48}) },
|
||||
"Fireflies": func(c *ui.Context) { fx.Fireflies(c, fx.FirefliesOptions{Width: 80, Height: 48}) },
|
||||
"Waterfall": func(c *ui.Context) { fx.Waterfall(c, fx.WaterfallOptions{Width: 40, Height: 48}) },
|
||||
"Ocean": func(c *ui.Context) { fx.Ocean(c, fx.OceanOptions{Width: 80, Height: 48}) },
|
||||
"Fire": func(c *ui.Context) { fx.Fire(c, fx.FireOptions{}) },
|
||||
"Lava": func(c *ui.Context) { fx.Lava(c, fx.LavaOptions{Width: 80, Height: 48}) },
|
||||
"Aurora": func(c *ui.Context) { fx.Aurora(c, fx.AuroraOptions{Width: 80, Height: 48}) },
|
||||
"Mountains": func(c *ui.Context) { fx.Mountains(c, fx.MountainsOptions{Width: 80, Height: 48}) },
|
||||
"Season": func(c *ui.Context) { fx.SeasonScene(c, pixel.Winter, 22, fx.SeasonSceneOptions{Width: 80, Height: 48}) },
|
||||
"Sparkle": func(c *ui.Context) { fx.Sparkle(c, fx.SparkleOptions{}) },
|
||||
"Confetti": func(c *ui.Context) { fx.Confetti(c, fx.ConfettiOptions{Width: 80, Height: 48}) },
|
||||
"NightSky": func(c *ui.Context) { fx.Sky(c, fx.SkyOptions{Width: 80, Height: 48}) },
|
||||
"NightSnows": func(c *ui.Context) { fx.Snow(c, fx.SnowOptions{Width: 80, Height: 48}) },
|
||||
} {
|
||||
// A day sky holds still: only stars move.
|
||||
pal := pixel.SpringDay
|
||||
if name == "NightSky" || name == "NightSnows" || name == "Season" {
|
||||
pal = pixel.WinterNight
|
||||
}
|
||||
for _, reduce := range []bool{false, true} {
|
||||
clk := newClock()
|
||||
tt := view(80, 48, pal, clk, reduce, build)
|
||||
first := dots(tt.Image(), pal, 80, 48)
|
||||
moved := false
|
||||
for _, d := range []time.Duration{300, 700, 1300} {
|
||||
clk.t = clk.t.Add(d * time.Millisecond)
|
||||
tt.Frame()
|
||||
moved = moved || !same(first, dots(tt.Image(), pal, 80, 48))
|
||||
}
|
||||
if moved == reduce {
|
||||
t.Errorf("%s, reduce %v: moved %v", name, reduce, moved)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user