Advertisement
SkyTheCoder

Flickable.lua

Aug 26th, 2014
323
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.20 KB | None | 0 0
  1.  
  2. --# Library
  3. Flickable
  4.  
  5. = {angleOffset = 0, constant = false, useCorners = true}
  6.  
  7. local touches = {}
  8. local debugtouch = {}
  9.  
  10. local sign = function(n)
  11.     return n / math.abs(n)
  12. end
  13.  
  14. local inRange = function(x, y, s, px, py)
  15.     --return math.abs(x - px) <= w / 2 and math.abs(y - py) <= h / 2
  16.     return vec2(x, y):dist(vec2(px, py)) <= s
  17. end
  18.  
  19. function getDebugFromID(id)
  20.     return debugtouch[id]
  21. end
  22.  
  23. function getDebugFromTouch(touch)
  24.     return debugtouch[touch.id]
  25. end
  26.  
  27. function getTouchFromID(id)
  28.     return touches[id]
  29. end
  30.  
  31. function getTouchFromDebug(deb)
  32.     return touches[deb.id]
  33. end
  34.  
  35. function getNameFromMotion(x, y, human)
  36.     local ret = ""
  37.     if y > 7.5 then
  38.         ret = ret .. "up"
  39.     end
  40.     if y < -7.5 then
  41.         ret = ret .. "down"
  42.     end
  43.     if x > 7.5 then
  44.         if human and ret ~= "" then
  45.             ret = ret .. "-"
  46.         end
  47.         ret = ret .. "right"
  48.     end
  49.     if x < -7.5 then
  50.         if human and ret ~= "" then
  51.             ret = ret .. "-"
  52.         end
  53.         ret = ret .. "left"
  54.     end
  55.     return ret
  56. end
  57.  
  58. function getNameFromAngle(angle, human)
  59.     local ret = ""
  60.     local a = angle + Flickable.angleOffset
  61.     local tolerance = 45
  62.     if Flickable.useCorners then
  63.         tolerance = 67.5
  64.     end
  65.     if a > 90 - tolerance and a < 90 + tolerance then
  66.         ret = ret .. "up"
  67.     end
  68.     if a < -90 + tolerance and a > -90 - tolerance then
  69.         ret = ret .. "down"
  70.     end
  71.     if a < tolerance and a > -tolerance then
  72.         if human and ret ~= "" then
  73.             ret = ret .. "-"
  74.         end
  75.         ret = ret .. "right"
  76.     end
  77.     if a > 180 - tolerance or a < -180 + tolerance then
  78.         if human and ret ~= "" then
  79.             ret = ret .. "-"
  80.         end
  81.         ret = ret .. "left"
  82.     end
  83.     return ret
  84. end
  85.  
  86. function getBoolFromMotion(x, y)
  87.     return {up = y > 7.5, down = y < -7.5, right = x > 7.5, left = x < -7.5}
  88. end
  89.  
  90. function getBoolFromAngle(angle)
  91.     local a = angle + Flickable.angleOffset
  92.     local tolerance = 45
  93.     if Flickable.useCorners then
  94.         tolerance = 67.5
  95.     end
  96.     return {up = a > 90 - tolerance and a < 90 + tolerance, down = a < -90 + tolerance and a > -90 - tolerance, right = a < tolerance and a > -tolerance, left = a > 180 - tolerance or a < -180 + tolerance}
  97. end
  98.  
  99. local nextf = function(f)
  100.     tween.delay(0, function()
  101.         pcall(f)
  102.     end)
  103. end
  104.    
  105. local handle = function(touch)
  106.     touches[touch.id] = touch
  107.     if touch.state == BEGAN and debugtouch[touch.id] == nil then
  108.         debugtouch[touch.id] = {id = touch.id, start = ElapsedTime, startX = touch.x, startY = touch.y, motX = 0, motY = 0, long = false}
  109.     end
  110.     local deb = debugtouch[touch.id]
  111.     local still = inRange(deb.startX, deb.startY, 20, touch.x, touch.y) and math.abs(deb.motX) <= 15 and math.abs(deb.motY) <= 15
  112.     if debugtouch[touch.id] ~= nil then
  113.         if sign(touch.deltaX) ~= sign(deb.motX) then
  114.             debugtouch[touch.id].motX = debugtouch[touch.id].motX * 0.2 + 0.8 * touch.deltaX
  115.         else
  116.             debugtouch[touch.id].motX = debugtouch[touch.id].motX * 0.9 + 0.1 * touch.deltaX
  117.         end
  118.         if sign(touch.deltaY) ~= sign(deb.motY) then
  119.             debugtouch[touch.id].motY = debugtouch[touch.id].motY * 0.2 + 0.8 * touch.deltaY
  120.         else
  121.             debugtouch[touch.id].motY = debugtouch[touch.id].motY * 0.9 + 0.1 * touch.deltaY
  122.         end
  123.         local rad = math.atan2(deb.motY, deb.motX)
  124.         local deg = math.deg(rad)
  125.         local offX, offY = math.cos(rad), math.sin(rad)
  126.         debugtouch[touch.id].rad = rad
  127.         debugtouch[touch.id].deg = deg
  128.         debugtouch[touch.id].direction = vec2(offX, offY)
  129.         still = inRange(deb.startX, deb.startY, 20, touch.x, touch.y) and math.abs(deb.motX) <= 15 and math.abs(deb.motY) <= 15
  130.         if ElapsedTime - deb.start >= 0.8 then
  131.             if still and not deb.long then
  132.                 if type(longPressed) == "function" then
  133.                     longPressed(touch, deb)
  134.                     debugtouch[touch.id].long = true
  135.                 end
  136.             end
  137.         end
  138.         if deb.long then
  139.             if type(longPressing) == "function" then
  140.                 longPressing(touch, deb)
  141.             end
  142.         end
  143.     end
  144.     if touch.state == ENDED or touch.state == CANCELLED then
  145.         if still then
  146.             if ElapsedTime - deb.start <= 0.3 then
  147.                 if type(tapped) == "function" then
  148.                     tapped(touch, deb)
  149.                 end
  150.             end
  151.             if ElapsedTime - deb.start >= 0.8 and not deb.long then
  152.                 if type(longPressed) == "function" then
  153.                     longPressed(touch, deb)
  154.                     debugtouch[touch.id].long = true
  155.                 end
  156.             end
  157.         end
  158.         if deb.long then
  159.             if type(longPressing) == "function" then
  160.                 longPressing(touch, deb)
  161.             end
  162.         end
  163.         if ElapsedTime - deb.start <= 0.5 then
  164.             if (not inRange(deb.startX, deb.startY, 10, touch.x, touch.y)) and (not     (math.abs(deb.motX) + math.abs(deb.motY) <= 10)) then
  165.                 if type(swiped) == "function" then
  166.                     swiped({id = touch.id, x = touch.x, y = touch.y, startX = deb.startX, startY = deb.startY, motX = deb.motX, motY = deb.motY, rad = deb.rad, deg = deb.deg, direction = deb.direction          }, deb)
  167.                 end
  168.             end
  169.         end
  170.         nextf(function()
  171.             touches[touch.id] = nil
  172.             debugtouch[touch.id] = nil
  173.         end)
  174.     end
  175.     if type(debtouched) == "function" then
  176.         debtouched(debugtouch[touch.id])
  177.     end
  178. end
  179.  
  180. tween.delay(0, function()
  181.     local _touched = touched or function() end
  182.    
  183.     touched = function(...)
  184.         handle(...)
  185.         _touched(...)
  186.     end
  187.    
  188.     local _draw = draw or function() end
  189.    
  190.     draw = function(...)
  191.         if Flickable.constant then
  192.             for k, v in pairs(touches) do
  193.                 if v.state == BEGAN or v.state == MOVING then
  194.                     handle(v)
  195.                 end
  196.             end
  197.         end
  198.         _draw(...)
  199.     end
  200. end)
  201.  
  202. --# Main
  203. -- Flickable
  204.  
  205. --[[
  206.  
  207. #### DOCUMENTATION ####
  208.  
  209.    ## API FEATURES ##
  210.  
  211.     #    GLOBALS    #
  212.  
  213. Flickable: table:
  214. // Table for storing values to customize the Flickable API
  215. -angleOffset: number, offset of angles when using getNameFromAngle(...), getBoolFromAngle(...)
  216. -constant: boolean, whether to update touches every frame rather than when they move (recommended for detecting long presses moving)
  217. -useCorners: boolean, whether corners should be a possibility when using getNameFromAngle(...), getBoolFromAngle(...)
  218.  
  219.     #  FUNCTIONS  #
  220.  
  221. getDebugFromID(id):
  222. //Get a debug value from a touch ID (see debtouched(deb))
  223. -id: number, ID of the touch
  224.  
  225. getDebugFromTouch(touch):
  226. //Get a debug value from a touch (see debtouched(deb))
  227. -touch: default "touch" metatable
  228.  
  229. getTouchFromID(id):
  230. //Get a default "touch" metatable from a debug value ID (see debtouched(deb))
  231. -id: number, ID of the debug value
  232.  
  233. getTouchFromDebug(debug):
  234. //Get a default "touch" metatable from a debug value (see debtouched(deb))
  235. -debug: see debtouched(deb)
  236.  
  237. getNameFromMotion(x, y, human):
  238. // Get the names of the direction of a motion (output order for corners: horizontal-vertical) (simpler, innaccurate)
  239. -x, y: numbers, x and y values of the motion
  240. -human: boolean, whether the output should be optimized for humans
  241.  
  242. getNameFromAngle(angle, human):
  243. // Get the names of the direction of an angle (output order for corners: horizontal-vertical) (complicated, accurate)
  244. -angle: number, angle in degrees of the motion
  245. -human: boolean, whether the output should be optimized for humans
  246.  
  247. getBoolFromMotion(x, y):
  248. // Returns a table of booleans {top, bottom, right, left}, each value determines whether the motion is moving in its direction (simpler, innaccurate)
  249. -x, y: numbers, x and y values of the motion
  250.  
  251. getBoolFromAngle(angle):
  252. // Returns a table of booleans {top, bottom, right, left}, each value determines whether the angle is pointing in its direction (complicated, accurate)
  253. -angle: number, angle in degrees of the motion
  254.  
  255.    ## USER-DEFINED ##
  256.  
  257. (parameters are supplied by Flickable)
  258.  
  259. debtouched(deb):
  260. // Called alongside touched(touch), debug information
  261. -deb: table, contains debug information:
  262. --id: number, ID of the debug value/touch
  263. --start: number, ElapsedTime from when touch started
  264. --startX: number, X coordinate from when touch started
  265. --startY: number, Y coordinate from when touch started
  266. --motX: number, X motion of touch
  267. --motY: number, Y motion of touch
  268. --long: boolean, whether the touch had been deemed a long press
  269.  
  270. tapped(tap, deb):
  271. // Called when a finger has tapped the screen
  272. -tap: default "touch" metatable
  273. -deb: see debtouched(deb)
  274.  
  275. swiped(swipe, deb):
  276. // Called when a finger has swiped the screen
  277. -swipe: table, stores information about the swipe
  278. --id: number, ID of the touch
  279. --x: number, X position from when touch ended
  280. --y: number, Y position from when touch ended
  281. --startX: number, X position from when touch started
  282. --startY: number, Y position from when touch started
  283. --motX: number, X motion of touch
  284. --motY: number, Y motion of touch
  285. --rad: number, angle of the touch's direction in radians
  286. --deg: number, angle of the touch's direction in degrees
  287. --direction: vec2, UV version of motX and motY, sine/cosine of rad
  288. -deb: see debtouched(deb)
  289.  
  290. longPressed(press, deb):
  291. // Called when a finger has long pressed the screen (on start of long press qualify)
  292. -press: default "touch" metatable
  293. -deb: see debtouched(deb)
  294.  
  295. longPressing(press, deb):
  296. // Called when a touch qualified as a long press moves (or if Flickable.constant is true, every frame a touch qualified as long is on the screen), useful for long-press-to-move functionality, such as on the app screen of your iPad
  297. -press: default "touch" metatable
  298. -deb: see debtouched(deb)
  299.  
  300. --]]
  301.  
  302. rectMode(CENTER)
  303.  
  304. -- Use this function to perform your initial setup
  305. function setup()
  306.     print("Tap to make the cube bounce")
  307.     print("Swipe to make the cube move (diagonally works too!)")
  308.     print("Long press the cube to move it around")
  309.     Flickable.constant = true
  310.     --Flickable.useCorners = false
  311.     gridSize = 8
  312.     pos = {x = WIDTH / 2 + WIDTH / gridSize / 2, y = HEIGHT / 2 + HEIGHT / gridSize / 2}
  313.     vis = {x = pos.x, y = pos.y}
  314.     next = {x = pos.x, y = pos.y}
  315.     size = {s = 1}
  316.     img = image(512, 512)
  317.     setContext(img)
  318.     background(255)
  319.     fill(0)
  320.     font("ArialRoundedMTBold")
  321.     fontSize(36)
  322.     textMode(CORNER)
  323.     text("Easy touch library\nBy SkyTheCoder", 8, 8)
  324.     local w, h = textSize("Easy touch library\nBy SkyTheCoder")
  325.     strokeWidth(2)
  326.     stroke(0)
  327.     line(0, h + 16, 512, h + 16)
  328.     fontSize(72)
  329.     textMode(CENTER)
  330.     text("Flickable", 256, 256 + (h + 16) / 2)
  331.     setContext()
  332.     saveImage("Project:Icon", img)
  333. end
  334.  
  335. -- This function gets called once every frame
  336. function draw()
  337.     background(255)
  338.    
  339.     stroke(0)
  340.     strokeWidth(1)
  341.     for i = 1, gridSize - 1 do
  342.         line(0, i / gridSize * HEIGHT, WIDTH, i / gridSize * HEIGHT)
  343.     end
  344.     for i = 1, gridSize - 1 do
  345.         line(i / gridSize * WIDTH, 0, i / gridSize * WIDTH, HEIGHT)
  346.     end
  347.    
  348.     pushMatrix()
  349.     --translate(vis.x + WIDTH / gridSize / 2, vis.y + HEIGHT / gridSize / 2)
  350.     translate(vis.x, vis.y)
  351.     scale(size.s)
  352.     noStroke()
  353.     fill(0)
  354.     rect(0, 0, WIDTH / gridSize, HEIGHT / gridSize)
  355.     fill(255)
  356.     font("ArialRoundedMTBold")
  357.     fontSize(12)
  358.     text("Flickable")
  359.     popMatrix()
  360.     tint(255, 255 - (ElapsedTime - 4) * 127)
  361.     sprite(img, WIDTH / 2, HEIGHT / 2)
  362. end
  363.  
  364. function swiped(swipe)
  365.     --print("Swiped: " .. swipe.x .. ", " .. swipe.y)
  366.     print("Swiped " .. getNameFromAngle(swipe.deg, true))
  367.     if tPos ~= nil then
  368.         tween.stop(tPos)
  369.         pos.x = next.x
  370.         pos.y = next.y
  371.         vis.x = pos.x
  372.         vis.y = pos.y
  373.         tPos = nil
  374.     end
  375.     local bools = getBoolFromAngle(swipe.deg)
  376.     local target = {x = pos.x, y = pos.y}
  377.     if bools.up then
  378.         target.y = pos.y + HEIGHT / gridSize
  379.     end
  380.     if bools.down then
  381.         target.y = pos.y - HEIGHT / gridSize
  382.     end
  383.     if bools.right then
  384.         target.x = pos.x + WIDTH / gridSize
  385.     end
  386.     if bools.left then
  387.         target.x = pos.x - WIDTH / gridSize
  388.     end
  389.     --[[target.x = target.x or pos.x
  390.     target.y = target.y or pos.y--]]
  391.     next.x = target.x
  392.     next.y = target.y
  393.     tPos = tween(0.25, vis, target, tween.easing.quadIn, function()
  394.         pos.x, pos.y = vis.x, vis.y
  395.         tPos = nil
  396.     end)
  397. end
  398.  
  399. function tapped(tap)
  400.     if tSize ~= nil then
  401.         tween.stop(tSize)
  402.         tSize = nil
  403.         size = {s = 1}
  404.     end
  405.     tSize = tween(0.15, size, {s = 0.75}, tween.easing.quadInOut, function()
  406.         tSize = tween(0.5, size, {s = 1}, tween.easing.elasticOut, function()
  407.             tSize = nil
  408.         end)
  409.     end)
  410. end
  411.  
  412. function longPressed(press)
  413.     vis.x, vis.y = press.x, press.y
  414.     if tSize ~= nil then
  415.         tween.stop(tSize)
  416.         tSize = nil
  417.         size = {s = 1}
  418.     end
  419.     tSize = tween(0.5, size, {s = 1.25}, tween.easing.bounceOut, function()
  420.         tSize = nil
  421.     end)
  422. end
  423.  
  424. function longPressing(press)
  425.     if tPos ~= nil then
  426.         tween.stop(tPos)
  427.         tPos = nil
  428.     end
  429.     vis.x, vis.y = press.x, press.y
  430.     next.x = math.floor(vis.x / WIDTH * gridSize) * WIDTH / gridSize + WIDTH / gridSize / 2
  431.     next.y = math.floor(vis.y / HEIGHT * gridSize) * HEIGHT / gridSize + HEIGHT / gridSize / 2
  432.     if press.state == ENDED or press.state == CANCELLED then
  433.         if tSize ~= nil then
  434.             tween.stop(tSize)
  435.             tSize = nil
  436.             size = {s = 1.25}
  437.         end
  438.         tSize = tween(0.5, size, {s = 1}, tween.easing.elasticOut, function()
  439.             tSize = nil
  440.         end)
  441.         tPos = tween(0.25, vis, next, tween.easing.quadIn, function()
  442.             pos.x, pos.y = vis.x, vis.y
  443.             tPos = nil
  444.         end)
  445.     end
  446. end
  447.  
  448. --[[function debtouched(deb)
  449.     for k, v in pairs(deb) do
  450.         if type(v) ~= "userdata" then
  451.             print(k .. ": " .. tostring(v))
  452.         end
  453.     end
  454. end--]]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement