Drawing with a pen on a pendulum


The kids have been playing with a pen on a pendulum, and I started wanting to tweak the friction on it.

-- We have a surface we view through a viewport.
-- The surface has the same dimensions as the viewport: Carousel's Safe_width x Safe_height.
local w = Safe_width/2
local h = Safe_height/2
-- (w, h) in surface coordinates is at (center.x, center.y) in viewport coordinates
local center = {type='viewport', x=w, y=h}
local vel = {x=0, y=0}
local mx0,my0
local V = 2  -- velocity coefficient when dragging
function s(vp)
  assert(vp.type == 'viewport')
  return {type='surface',
    x=w - center.x + vp.x,
    y=h - center.y + vp.y}
end
function v(sp)
  assert(sp.type == 'surface')
  return {type='viewport',
    x=center.x - w + sp.x,
    y=center.y - w + sp.y}
end
local points = {}  -- in surface coordinates
local State = {name='init'}  -- move draw
local niters = 1000000
local K = 1  -- Hooke's constant
local f = 0.01  -- 0 = no friction
local colors = {
  {0,0,0},  -- black
  {1,0,0},  -- red
  {0,1,0},  -- green
  {0.2,0.2,1},  -- blue
}
local color_index = 1  -- black at the start
function draw_colors()
  for i, c in ipairs(colors) do
    if i == color_index then
      color(0.8,0.8,0.8)
      rect('fill', 50-20, 50+i*50-20, 40,40, 2,2)
    end
    color(unpack(c))
    circle('fill', 50, 50+i*50, 20)
  end
end
function change_color(mx,my)
  for i, c in ipairs(colors) do
    if dist(mx,my, 50, 50+i*50) < 20 then
      color_index = i
      return true
    end end end
function car.draw()
  draw_colors()
  color(0.5,0.5,0.5)
  rect('line', center.x-w, center.y-h, w*2, h*2)
  line(center.x-w, center.y, center.x+w, center.y)
  line(center.x, center.y-h, center.x, center.y+h)
  color(0,0,0)
  local p1
  for _,p2 in ipairs(points) do
    color(unpack(p2.color))
    local vp2 = v(p2)
    if p1 then
      local vp1 = v(p1)
      line(vp1.x, vp1.y, vp2.x, vp2.y)
    end
    p1 = p2
  end
  if State.name == 'draw' then
    circle('fill', w,h, 2)
  end
end
function car.mousepressed(mx,my)
  if change_color(mx,my) then return end
  mx0,my0 = mx,my
  if State.name ~= 'init' then return end
  points = {}
  State = {name='move', x=mx, y=my}
end
function car.mousereleased(mx,my)
  if mx0 == nil then return end
  vel.x = (mx-mx0)*V
  vel.y = (my-my0)*V
  mx0,my0 = nil
end
function car.update(dt)
  local s = State.name
  if s == 'move' then
    umove(dt)
  elseif s == 'draw' then
    udraw(dt)
  end
end
function umove(dt)
  if abs(center.x - 2*w + State.x) < 1 then
    State = {name='draw', iters = 0}
    return
  end
  center.x = center.x - (State.x - w)*dt
  center.y = center.y - (State.y - h)*dt
end
function udraw(dt)
  State.iters = State.iters+1
  if State.iters >= niters then
    State = {name='init'}
    center = {type='viewport', x=w, y=h}
    vel = {type='viewport', x=0, y=0}
    return
  end
  local ax = -K*(center.x-w)
  local ay = -K*(center.y-h)
  vel.x = (1 - f*dt) * (vel.x + ax*dt)
  vel.y = (1 - f*dt)  * (vel.y + ay*dt)
  local x = center.x + vel.x*dt
  local y = center.y + vel.y*dt
  local p = s{type='viewport', x=w, y=w}
  p.color = colors[color_index]
  table.insert(points, p)
  center.x, center.y = x, y
end
function dist(x1,y1, x2,y2)
  return math.sqrt((x1-x2)^2 + (y1-y2)^2)
end

Don't forget to first run the abbreviations on one of the example screens. Or if you've deleted that screen, here are the abbreviations I used in this post:

g = love.graphics
line = g.line
rect = g.rectangle
circle = g.circle
color = g.setColor
abs = math.abs

Files

carousel2-ak.love 103 kB
10 days ago

Get Lua Carousel

Leave a comment

Log in with itch.io to leave a comment.