At least this is something that also runs with loveCodea on Linux. The problems under Linux seem to be sprite related, I think.
Visit this inspirational page to see what you can expect from the code below:
http://www.jasondavies.com/animated-bezier/
(And I leave you wondering if this posting is more about loveCodea or Bezier Curves.)
if require then
require("loveCodea")
end
-- Interactive Bezier Curve Animation, loosely inspired by this:
-- http://www.jasondavies.com/animated-bezier/
-- Tap on circle to create a new node.
-- Drag node to X to delete.
BEZIER_STEP = 0.01
STARTING_DOTS = 4
dots = {}
-- animation progess, 0 ... 1
p = 0
touches = {}
touched_dots = {}
function setup()
for i = 1, STARTING_DOTS do NewDot() end
-- for drawing fine lines
noSmooth()
end
function draw()
p = p + 0.01
if p > 1 then p = 0 end
background(255, 255, 230, 255)
local curve = {}
for i,d in ipairs(dots) do
table.insert(curve, d.x)
table.insert(curve, d.y)
end
Bezier(curve, p)
-- green O in upper right
fill(0, 255, 0)
ellipse(WIDTH - 20, HEIGHT - 20, 40, 40)
-- red X in lower right
stroke(255, 0, 0)
line(WIDTH, 0, WIDTH - 40, 40)
line(WIDTH, 40, WIDTH - 40, 0)
end
function touched(touch)
if touch.state == ENDED then
touches[touch.id] = nil
touched_dots[touch.id] = nil
-- Circle touched, create a node
if touch.x > WIDTH - 40 and touch.y > HEIGHT - 40 then
NewDot()
end
else
touches[touch.id] = touch
local td = touched_dots[touch.id]
-- Touch has hit nothing yet, try finding a dot nearby
if td == nil then
touched_dots[touch.id] = FindDot(touch.x, touch.y)
else
td.x = touch.x
td.y = touch.y
-- Dragging to X, delete node
if td:Contains(WIDTH - 20, 20) then
for i,d in ipairs(dots) do
if d == td then
table.remove(dots, i)
break
end
end
end
end
end
end
-- Creates a new dot somewhere
function NewDot()
table.insert(dots, Dot(math.random(500), math.random(500)))
end
-- Returns if a there's a dot at x/y
function FindDot(x, y)
local dot = nil
for i,d in ipairs(dots) do
if d:Contains(x, y) then dot = d end
end
return dot
end
-- Draws Bezier and helper lines.
-- xy_list: list with x/y coordinates of the nodes
-- p: progress (0 ... 1)
function Bezier(xy_list, p)
DrawBezierOverlay(xy_list, p)
DrawBezier(xy_list, p)
end
-- Draws Bezier Curve
function DrawBezier(xy_list, p)
if #xy_list == 0 then return end
stroke(0, 0, 0)
strokeWidth(3)
local x0, y0
for i = 0, p, BEZIER_STEP do
local x, y = ReduceChain(xy_list, i)
if i > 0 then
line(x0, y0, x, y)
end
x0, y0 = x, y
end
end
-- Reduces the xy_list to a single x/y coordinate at progress p.
function ReduceChain(xy_list, p)
local n_coords = #xy_list / 2
while n_coords > 1 do
xy_list = ReduceChainBy1(xy_list, p)
n_coords = n_coords - 1
end
return xy_list[1], xy_list[2]
end
function DrawBezierOverlay(xy_list, p)
local n_coords = #xy_list / 2
local r = 20
while n_coords > 0 do
DrawChain(xy_list, r)
xy_list = ReduceChainBy1(xy_list, p)
n_coords = n_coords - 1
r = 10
end
end
-- Reduces the xy_list by one coordinate at progress p,
-- returning the reduced list.
function ReduceChainBy1(xy_list, p)
local reduced = {}
local n_coords = #xy_list / 2
local x0, y0
for i = 1, n_coords do
local x = xy_list[i * 2 - 1]
local y = xy_list[i * 2]
-- skip first point, cannot draw a line with only 1 point
if i > 1 then
local xi = x0 + (x - x0) * p
local yi = y0 + (y - y0) * p
table.insert(reduced, xi)
table.insert(reduced, yi)
end
x0, y0 = x, y
end
return reduced
end
-- Draws a chain, i.e. a series of dots linked by lines.
-- Draws the primary nodes as well as the reduced chain.
function DrawChain(xy_list, r)
local n_coords = #xy_list / 2
local x0
local y0
stroke(255, 100, 0)
strokeWidth(1)
fill(255, 100, 0)
if n_coords == 1 then
fill(100, 100, 100)
end
for i = 1, n_coords do
local x = xy_list[i * 2 - 1]
local y = xy_list[i * 2]
if i > 1 then
line(x0, y0, x, y)
end
ellipse(x, y, r)
x0, y0 = x, y
end
end
Dot = class()
function Dot:init(x, y)
self.x = x
self.y = y
self.r = 20
end
function Dot:Contains(x, y)
local dx = x - self.x
local dy = y - self.y
return (dx * dx) + (dy * dy) <= (self.r * self.r)
end