From 19f0c95b1392312a0e76f3b4fa005e6717054584 Mon Sep 17 00:00:00 2001 From: David Briscoe Date: Wed, 22 Jul 2020 22:48:40 -0700 Subject: [PATCH] Add a love2d visualization of the easing functions This demo uses love2d, but of course flux still has no dependencies on love2d. To make it easier to pick which function to use, visualize them in four ways: a plot, translation, alpha, and scale. This is similar to easings.net, but uses the same names as flux, only shows the functions provided by flux, and actually uses flux for rendering so it's definitely accurate. --- main.lua | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 main.lua diff --git a/main.lua b/main.lua new file mode 100644 index 0000000..1a03359 --- /dev/null +++ b/main.lua @@ -0,0 +1,223 @@ +local flux = require "flux" + +local S = {} + +local loop +loop = function(graph) + local dst = S.states.dst[S.states.current] + local src = S.states.src[S.states.current] + graph.tweens[1] = flux.to(graph, S.duration, dst) + :delay(0.5) -- pause to let you see initial state + :ease(graph.kind) + graph.tweens[2] = graph.tweens[1] + :after(S.duration, src) + :delay(0.5) -- pause so you see they all finished + :ease(graph.kind) + :oncomplete(function() + loop(graph) + end) +end + +local function stop_all_loops() + for kind,graph in pairs(S.graphs) do + for key,t in pairs(graph.tweens) do + t:stop() + graph.tweens[key] = nil + end + -- Snap to initial state + for _,keyval in ipairs(S.states.src) do + for key,val in pairs(keyval) do + graph[key] = val + end + end + end + S.is_running = false +end + +local function run_all_loops() + S.states.label:set(S.states.names[S.states.current]) + stop_all_loops() + for kind,graph in pairs(S.graphs) do + loop(graph) + end + S.is_running = true +end + +function love.load() + local font = love.graphics.newFont(20) + S.size = 100 + S.duration = 4 + S.graphs = {} + S.keys = {} + S.states = { + label = love.graphics.newText(font), + names = { + "Translation", + "Alpha", + "Scale", + }, + src = { + { y = 0 }, + { alpha = 1 }, + { size = 10 }, + }, + dst = { + { y = S.size }, + { alpha = 0 }, + { size = 50 }, + }, + + } + S.states.current = 1 + + + for kind,fn in pairs(flux.easing) do + local g = { kind = kind, pts = {}, tweens = {} } + + for x=0,S.size,1 do + table.insert(g.pts, x) + table.insert(g.pts, fn(x/S.size)*S.size) + end + S.graphs[kind] = g + table.insert(S.keys, kind) + end + table.sort(S.keys) + + -- need enough space for all graphs + local dimensions = { 1200, 700 } + love.window.setMode(unpack(dimensions)) + love.window.setTitle('flux - easing functions visualized') + + + S.canvas_color = {1,1,1,1} + S.canvas = love.graphics.newCanvas(unpack(dimensions)) + + love.graphics.setCanvas(S.canvas) + -- Clear to solid black to prevent transparency from causing text aliasing. + -- https://love2d.org/forums/viewtopic.php?p=208884&sid=ac10f765ea06acb7f889a65c5059a610#p208884 + love.graphics.clear(0,0,0,1) + S.draw_static_content() + love.graphics.setCanvas() + + S.canvas_color[4] = 0 + + flux.to(S.canvas_color, 0.5, {[4] = 1}) + run_all_loops() +end + + +function love.update(dt) + if S.is_running then + flux.update(dt) + end +end + + +function love.keypressed(k) + if k == "escape" then + love.event.quit() + elseif k == "n" then + S.states.current = (S.states.current % #S.states.src) + 1 + run_all_loops() + elseif k == "r" then + run_all_loops() + elseif k == "space" then + S.is_running = not S.is_running + end +end + + +function S.draw_static_content() + love.graphics.push() + + local outside_pad = 50 + love.graphics.translate(outside_pad,outside_pad) + love.graphics.push() + local win_width, win_height = love.graphics.getDimensions() + win_width = win_width - outside_pad + win_height = win_height - outside_pad + + local x,y = 0,0 + local white = {1, 1, 1, 1} + local grey = {0.3, 0.3, 0.3, 1} + + local xpad = 60 + local ypad = 50 + for i,kind in ipairs(S.keys) do + local g = S.graphs[kind] + love.graphics.setColor(grey) + love.graphics.line(1,S.size, S.size,S.size) + love.graphics.line(0,S.size, 0,0) + love.graphics.setColor(white) + love.graphics.points(g.pts) + love.graphics.print(g.kind, 0, 100) + + local offset = S.size + xpad + x = x + offset + if x + S.size >= win_width then + x = 0 + y = y + S.size + ypad + love.graphics.pop() + love.graphics.push() + love.graphics.translate(0,y) + else + love.graphics.translate(offset,0) + end + + end + love.graphics.pop() + love.graphics.pop() + + love.graphics.setColor(grey) + love.graphics.printf("n - next mode, space - pause, r - restart", win_width - 400, win_height + 15, 400, "right") +end + +function love.draw() + local white = {1, 1, 1, 1} + local grey = {0.3, 0.3, 0.3, 1} + + love.graphics.setColor(S.canvas_color) + love.graphics.draw(S.canvas) + love.graphics.setBlendMode("replace") + + love.graphics.push() + + local outside_pad = 50 + love.graphics.translate(outside_pad,outside_pad) + love.graphics.push() + local win_width, win_height = love.graphics.getDimensions() + win_width = win_width - outside_pad + win_height = win_height - outside_pad + + local x,y = 0,0 + + local xpad = 60 + local ypad = 50 + for i,kind in ipairs(S.keys) do + local g = S.graphs[kind] + + love.graphics.setColor(1, 1, 1, g.alpha) + love.graphics.rectangle("fill", S.size, g.y, g.size, g.size) + + local offset = S.size + xpad + x = x + offset + if x + S.size >= win_width then + x = 0 + y = y + S.size + ypad + love.graphics.pop() + love.graphics.push() + love.graphics.translate(0,y) + else + love.graphics.translate(offset,0) + end + end + + love.graphics.pop() + love.graphics.pop() + + love.graphics.setColor(white) + love.graphics.draw(S.states.label, win_width/2 - S.states.label:getWidth()/2, win_height) + + love.graphics.setColor(grey) + love.graphics.print("fps: " .. love.timer.getFPS() .. "\n" .. "tweens: " .. #flux.tweens, outside_pad, win_height) +end