Skip to content

Instantly share code, notes, and snippets.

Created July 7, 2014 08:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/30b839d752d2922d0096 to your computer and use it in GitHub Desktop.
Save anonymous/30b839d752d2922d0096 to your computer and use it in GitHub Desktop.
--# EventMngr
-- ############## START of EVENT MANAGER ##################
-- @tnlogy & @JMV38 & @Briarfox
-- example of usage:
-- EventMngr:extend(evMngr) -- extend an existing table with event manager funcs
-- evMngr:on("touch",func) -- register func() to fire on "touch" event
-- evMngr:on("touch", obj.func, obj) -- register obj:func() to fire on "touch" event
-- evMngr:trigger("touch",10,50) -- fires func(10,50) and obj:func(10,50)
-- evMngr:off("touch", func) -- unregister func()
-- evMngr:off("touch", obj.func, obj) -- unregister obj:func()
-- evMngr:off("touch") -- unregister all "touch" listeners
-- evMngr:off(obj.func) -- unregister all listeners with obj.func
-- evMngr:off(obj) -- unregister events with obj listening
-- "all" captures all events and passes the event name as the first param:
-- evMngr:on("all", func)
EventMngr = {}
local fifo = true -- first in (to register) first out (to be triggered)
function EventMngr:on(eventName, fn, obj)
if not self.events then self.events = {} end -- init event table if does not exist
if not self.events[eventName] then self.events[eventName] = {} end -- init this event name
local new = true -- confirm it is a new request
for i,fa in ipairs(self.events[eventName]) do
if fa.func == fn and fa.obj == obj then new = false end
end
local p -- insertion point in the table
if new then
if fifo then p = #self.events[eventName] +1 else p = 1 ; fifo=true end
local listener = {func = fn, obj = obj }
table.insert(self.events[eventName], p, listener)
end
return self
end
function EventMngr:executeNextCallBeforeOthers()
fifo = false
end
function EventMngr:off(nameOrFnOrObj, fn, obj)
local name
local fn,obj = fn,obj -- manage the case when they are nil
local firstType = type(nameOrFnOrObj)
local request
if firstType == "string" or firstType == "number" then
name = nameOrFnOrObj
if name == "all" then request = "remove all events"
elseif fn == nil then request = "remove all instances of this event"
else request = "remove this event" end
elseif firstType == "function" then
fn = nameOrFnOrObj
request = "remove all events with this function"
else
obj = nameOrFnOrObj
request = "remove all events with this object"
end
if request == "remove all instances of this event" then
self.events[name] = nil
elseif request == "remove all events" then
self.events = {}
else
local evs = self.events -- go through all events ...
if name then evs = {evs[name]} end -- ... or through 1 event only
for eventName,fns in pairs(evs) do
local n = #fns
for i=0,n-1 do
local j = n-i -- go backward because of remove, ipairs not suitable
local f = fns[j]
local match
if request == "remove this event"
then match=(f.func==fn and f.obj==obj)
elseif request == "remove all events with this function"
then match=(f.func==fn)
elseif request == "remove all events with this object"
then match=(f.obj==obj)
end
if match then
table.remove(fns,j)
end
end
end
end
return self
end
function EventMngr:trigger(name, ...)
self.lastTrigger = name
local evs = (self.events and self.events[name]) or {}
for i,fa in ipairs(evs) do
local func,obj = fa.func, fa.obj
if obj then func(obj,...)
else func(...) end
end
--trigger all
local evs = (self.events and self.events["all"]) or {}
for i,fa in ipairs(evs) do
local func,obj = fa.func, fa.obj
if obj then func(obj,name,...)
else func(name,...) end
end
end
-- to transform a table into an event manager
function EventMngr:extend(target)
for k, v in pairs(self) do
if type(v) == "function" and v ~= EventMngr.extend
then target[k] = v
end
end
return target
end
-- ############## END of EVENT MANAGER ##################
--# Saver
saver = {}
-- a tool to save simple data
-- first start the saver in your setup(): creates an exit (and save) button
function saver:init()
self.button = Box({name="save", x=5, y=5, w=50, h=30,
textMode=CENTER, txt="EXIT"})
main:on("draw",self.button.draw,self.button)
main:executeNextCallBeforeOthers()
main:on("touched",self.button.touched,self.button)
self.button:on("tap",self.save,self)
self.button:on("tap",function() close() end)
end
-- then only this command is needed to load and save the object to be saved
function saver:load(obj,fields)
self:register(obj,fields)
local name = obj.name
local data = self.data and self.data[name]
--obj:update(data)
return data
end
saver.list = {} -- all objects to be saved
function saver:register(obj,keys)
local name = obj.name
if name == nil then error("obj must have a name to be saved") end
for _,o in ipairs(self.list) do
if o.name == name and o ~= obj then
error("this name ("..name..") is already used")
end
end
table.insert(self.list,obj)
local fields
if keys then
fields = {}
for i,key in pairs(keys) do fields[key] = true end
end
self.list[obj] = fields
end
function saver:saveXYWH()
self:save({"x","y","w","h"})
end
function saver:save(keys)
local txt = {}
local function ins(s) table.insert(txt,s) end
ins( "saver.data = { \n" ) -- all objects saved in this table
local name
for i,obj in ipairs(self.list) do
name = obj.name
local fields = self.list[obj]
ins( "['" .. name .. "'] = {")
for key,value in pairs(obj) do
if (not fields) or fields[key] then
local typ = type(value)
if typ == "number" or typ == "boolean" then
ins( tostring(key) .. " = " .. tostring(value) .. "," )
elseif typ == "string" then
ins( tostring(key) .. " = \"" .. tostring(value) .. "\"," )
end
end
end
ins( "}, \n")
end
ins( "}")
txt = table.concat(txt," ")
saveProjectTab("data",txt)
end
--# Table
-- Table.lua
-- contains various useful functions related to tables
Table = class()
function Table.remove(array,obj,allInstances)
local n = #array
for i = n,1,-1 do
if array[i] == obj then
table.remove(array,i)
if not allInstances then return nil end
end
end
end
-- shallow clone the array
function Table.clone(array)
local clone = {}
for _,elem in ipairs(array) do table.insert(clone,elem) end
return clone
end
-- applyes this func to all elems of the second argument, which is an array
-- func should take as many arguments as the number of arrays that are passed in
function Table.map(func,...)
assert(arg.n > 0,"Table.map called with no arguments")
local result = {}
local n = #arg[1]
for i = 1,n do
-- fixme: isn't there a function that does this for me?
local args = {}
for _,arr in ipairs(arg) do table.insert(args,arr[i]) end
local r = func(unpack(args))
table.insert(result,r)
end
return result
end
function Table.random(array)
local n = #array
local r = math.random(n)
return array[r]
end
function Table.contains(array,obj)
for _,elem in ipairs(array) do
if elem == obj then return true end
end
return false
end
function Table.iPrevious(array,obj)
for i,elem in ipairs(array) do
if elem == obj then return array[i-1] end
end
return false
end
function Table.iNext(array,obj)
for i,elem in ipairs(array) do
if elem == obj then return array[i+1] end
end
return false
end
function Table.size(tab)
local n = 0
for k,v in pairs(tab) do n = n + 1 end
return n
end
--# Stack
-- Stack.lua
-- a generic stack class. Piles of blocks are stacks.
-- Also used to keep track of the user program stack
Stack = class()
function Stack:init()
self.elems = {}
end
-- removes and return the top elem
function Stack:pop()
local elem = self:peek()
table.remove(self.elems,#self.elems)
return elem
end
-- adds a new elem at the top
function Stack:push(elem)
table.insert(self.elems,elem)
end
-- returns the last elem, but doesn't remove it
function Stack:peek(idx)
idx = idx or #self.elems
return self.elems[idx]
end
function Stack:size()
return #self.elems
end
-- returns an iterator over the elems of the stack
function Stack:iter()
local i = 0
local n = self:size()
return function()
i = i + 1
if i <= n then return self.elems[i] end
end
end
--# PositionObj
-- PositionObj.lua
-- a helper class that is subclassed by anything that has a position
PositionObj = class()
function PositionObj:init(x,y)
self.x = x
self.y = y
end
function PositionObj:setXY(x,y)
self.x = x
self.y = y
end
function PositionObj:translate(dx,dy)
self.x = self.x + dx
self.y = self.y + dy
end
function PositionObj:getX()
return self.x
end
function PositionObj:getY()
return self.y
end
function PositionObj:getPos()
return self.x,self.y
end
--# RectObj
-- RectObj.lua
-- RectObj is a helper class that is used by things that have dimensions and angles
RectObj = class(PositionObj)
function RectObj:init(x,y,w,h)
PositionObj.init(self,x,y)
self.w = w
self.h = h
self.mode = CORNER
self.angle = 0 -- in rads
end
---------------------- SETTERS -----------------------
function RectObj:setMode(mode)
self.mode = mode
end
function RectObj:setSize(w,h)
self.w = w
self.h = h
end
-- ang in degrees
function RectObj:rotate(ang)
self.angle = self.angle + math.rad(ang)
end
function RectObj:setAngle(ang)
self.angle = math.rad(ang)
end
-- flips along the x-axis
function RectObj:flipX()
self.x = self.x + self.w
self.w = self.w * (-1)
end
---------------------- GETTERS -----------------------
function RectObj:getW()
return self.w
end
function RectObj:getH()
return self.h
end
function RectObj:getSize()
return self.w,self.h
end
function RectObj:getAngle()
return math.deg(self.angle)
end
function RectObj:inbounds(t)
local x1,y1,x2,y2 = self:boundingBox()
return (t.x>=x1 and t.y>=y1 and t.x<=x2 and t.y<=y2)
end
function RectObj:boundingBox()
local x,y = self.x,self.y
local w,h = self.w,self.h
if w < 0 then
w = -w
x = x - w
end
if h < 0 then
h = -h
y = y - h
end
if mode == CENTER then
x = x - w/2
y = y - h/2
end
return x,y,x+w,y+h
end
--# Xtouch
Xtouch = class()
-- a helper class to extend touch (no instance created)
-- generates these events:
-- onTap, onDrag, onDrop, onEnter, onLeave, onSwipeRight, onSwipeLeft, onSwipeUp, onSwipeDown
local touches = {}
function Xtouch:extend(touch)
-- simple copy
local t = {}
t.id = touch.id
t.x = touch.x
t.y = touch.y
t.prevX = touch.prevX
t.prevY = touch.prevY
t.deltaX = touch.deltaX
t.deltaY = touch.deltaY
t.state = touch.state
t.tapCount = touch.tapCount
-- extensions
t.time = ElapsedTime -- knowing the touch time may be usefull
t.intercepted = false -- to manage touch interception
t.beganOnObj = false -- object on which the touch began (if any)
t.movingOnObj = false -- object on which the touch is moving (if any)
t.endedOnObj = false -- object on which the touch ended (if any)
t.prevOnObj = false -- object touched last time, if any
t.curOnObj = false -- object currently touched, if any
t.Xevent = false -- alternative state
-- memorize the began touches (or current one if no began)
if t.state == BEGAN or touches[t.id] == nil then touches[t.id] = t end
return t
end
function Xtouch:updateFromTouchedObject(t,obj)
if t.state == BEGAN then t.beganOnObj=obj
elseif t.state == MOVING then t.movingOnObj=obj
elseif t.state == ENDED then t.endedOnObj=obj
end
t.curOnObj = obj
t.intercepted = true
end
function Xtouch:events(t)
local t0 = touches[t.id]
t.beganOnObj = t0.beganOnObj
t.prevOnObj = t0.prevOnObj
t0.prevOnObj = t.curOnObj
if t.state == BEGAN then
local obj = t.beganOnObj
t.Xevent = "onEnter"
if obj then obj:Xtouched(t) end
elseif t.state == MOVING then
local obj1 = t.beganOnObj
local obj2 = t.prevOnObj
local obj3 = t.curOnObj
t.Xevent = "onLeave"
if obj2 and (obj3~=obj2) then obj2:Xtouched(t) end
t.Xevent = "onEnter"
if obj3 and (obj3~=obj2) then obj3:Xtouched(t) end
t.Xevent = "onDrag"
if obj1 then obj1:Xtouched(t) end
elseif t.state == ENDED then
local obj1 = t.beganOnObj
local obj2 = t.prevOnObj
local obj3 = t.curOnObj
local obj4 = t.endedOnObj
t.Xevent = "onLeave"
if obj2 and (obj3~=obj2) then obj2:Xtouched(t) end
if obj3 and (obj3==obj2) then obj3:Xtouched(t) end
if (t.time-t0.time)<1.0 then
local v = vec2(t.x-t0.x, t.y-t0.y)
local d = v:len()
local maximumDistanceForATap = 50
if d < maximumDistanceForATap then
t.Xevent = "onTap"
if obj4 == obj1 and obj4 then obj4:Xtouched(t) end
end
local minimumDistanceForASwipe = 75
if d > minimumDistanceForASwipe and obj1 then
v = v:normalize()
if v.x > 0.8 then
t.Xevent = "onSwipeRight"
elseif v.x < -0.8 then
t.Xevent = "onSwipeLeft"
elseif v.y > 0.8 then
t.Xevent = "onSwipeUp"
elseif v.y < -0.8 then
t.Xevent = "onSwipeDown"
end
if obj1 then obj1:Xtouched(t) end
end
end
if obj4 ~= obj1 then
t.Xevent = "onDrop"
if obj1 and obj4 then obj4:Xtouched(t) end
end
elseif t.state == CANCELLED then
local obj1 = t.beganOnObj
local obj2 = t.prevOnObj
t.Xevent = "onLeave"
if obj2 then obj2:Xtouched(t)
elseif obj1 then obj1:Xtouched(t)
end
t.Xevent = "onDrop"
if obj1 then obj1:Xtouched(t) end
end
-- erase the finished touches
if t.state == ENDED or t.state == CANCELLED then touches[t.id] = nil end
end
--# Touchable
-- Touchable.lua
-- a little useful class for objects that know how to handle touches
Touchable = class(RectObj)
function Touchable:init(name,x,y,w,h)
RectObj.init(self,x,y,w,h)
self.name = name
self.touchable = true
self.extras = {left=0,right=0,top=0,bottom=0}
end
function Touchable:setTouchable(bool)
self.touchable = bool
end
function Touchable:getTouchable()
return self.touchable
end
function Touchable:setExtras(extras)
for k,v in pairs(extras) do
self.extras[k] = v
end
end
function Touchable:listenToTouchedFrom(screen)
screen:executeNextCallBeforeOthers() -- obj on top (last) must be checked first
screen:on("touched", self.touched, self)
end
-- standard touch events
function Touchable:onTouched(t) end -- user defined
function Touchable:onEnded(t) end -- user defined
function Touchable:onBegan(t) end -- user defined
function Touchable:onMoving(t) end -- user defined
--[[
-- extended touch events
function Touchable:onTap(t) end -- user defined
function Touchable:onDrag(t) end -- user defined
function Touchable:onDrop(t) end -- user defined
function Touchable:onEnter(t) end -- user defined
function Touchable:onLeave(t) end -- user defined
--]]
function Touchable:touched(t)
if t.intercepted then return false end
if not self.touchable then return false end
if self:inbounds(t) then
self:onTouched(t)
if t.state == BEGAN then self:onBegan(t)
elseif t.state == MOVING then self:onMoving(t)
elseif t.state == ENDED then self:onEnded(t)
end
Xtouch:updateFromTouchedObject(t,self)
return true
end
return false
end
function Touchable:Xtouched(t)
local func = self[ t.Xevent ]
if func then func( self, t) end
end
function Touchable:inbounds(t)
local x1,y1,x2,y2 = self:boundingBox()
x1 = x1 - self.extras.left
y1 = y1 - self.extras.bottom
x2 = x2 + self.extras.right
y2 = y2 + self.extras.top
return (t.x>=x1 and t.y>=y1 and t.x<=x2 and t.y<=y2)
end
--# StyleObj
StyleObj = class()
-- a helper class to add a style component
local mem = {}
local echo = false
function StyleObj:set(field,style,default)
style = style or {}
local value = style[field]
if value == nil then value = self[field] end
if value == nil then value = default end
self[field] = value
if echo then mem[field] = self[field] end
end
-- a setStyle function must be implemented by user, using set() function only
function StyleObj:getStyle()
mem = {} -- reset mem
echo = true -- start echoing
self:setStyle() -- now mem contains the style fields and their values
echo = false -- stop echoing
local style = mem
mem = {} -- change mem table to avoid modifying style later by accident
return style
end
function StyleObj:pushStyle()
self.oldStyle = self:getStyle()
end
function StyleObj:popStyle()
self:setStyle(self.oldStyle)
end
function StyleObj:mixin(target)
-- inject these functions to the target, unless they are already defined
target.set = target.set or self.set
target.getStyle = target.getStyle or self.getStyle
target.pushStyle = target.pushStyle or self.pushStyle
target.popStyle = target.popStyle or self.popStyle
end
--# RectDraw
RectDraw = class(RectObj)
-- component class to define and draw a rectangle
function RectDraw:init(x,y,w,h,style)
RectObj.init(self,x,y,w,h)
StyleObj:mixin(self)
self:setStyle(style)
end
function RectDraw:setStyle(style)
self:set("fill",style,color(0,0,0,0))
self:set("stroke",style,color(255))
self:set("strokeWidth",style,2)
self:set("smooth",style,noSmooth)
end
function RectDraw:draw()
self.smooth()
fill(self.fill)
stroke(self.stroke)
strokeWidth(self.strokeWidth)
rect(self.x,self.y,self.w,self.h)
end
--# RectSprite
RectSprite = class(RectObj)
-- this rect can have rounded corners
function RectSprite:init(x,y,w,h,style)
RectDraw.init(self,x,y,w,h,style)
StyleObj:mixin(self)
self.drawImagePending = true
self:setStyle(style)
end
function RectSprite:setSize(w,h)
RectObj.setSize(self,w,h)
self.drawImagePending = true
end
function RectSprite:setStyle(style)
self:set("fill",style,color(0,0,0,0))
self:set("stroke",style,color(255))
self:set("strokeWidth",style,3)
self:set("smooth",style,smooth)
self:set("radius",style,2)
self.drawImagePending = true
end
function RectSprite:draw()
spriteMode(CORNER)
if self.img then sprite(self.img,self.x,self.y) end
self:drawImage() -- update with 1 frame delay: better smoothness
end
local function rawRect(img,x,y,w,h,r)
setContext(img)
background(0,0,0,0)
fill(255)
translate(x,y)
rect(r,0,w-2*r,h)
rect(0,r,w,h-2*r)
ellipse(r ,r,r*2)
ellipse(w-r,r,r*2)
ellipse(r ,h-r,r*2)
ellipse(w-r,h-r,r*2)
resetMatrix()
setContext()
end
function RectSprite:roundedRect(x,y,w,h,r)
local oldFill = color( fill() )
local oldStroke = color( stroke() )
local oldTint = color( tint() )
local s = strokeWidth()
local ds = math.max(s-1,0)
local img = image(w,h)
local imgOuter = image(w,h)
local imgInner = image(w,h)
local imgStroke = image(w,h)
pushStyle()
resetStyle()
pushMatrix()
resetMatrix()
spriteMode(CORNER)
noStroke()
rawRect(imgOuter,0,0,w,h,r)
rawRect(imgInner, ds, ds, w-2*ds, h-2*ds, r-ds)
setContext(imgStroke)
sprite(imgOuter,0,0)
blendMode(ZERO, ONE_MINUS_SRC_COLOR)
sprite(imgInner,0,0)
setContext()
blendMode(NORMAL)
setContext(img)
tint(oldStroke)
sprite(imgStroke,0,0)
tint(oldFill)
sprite(imgInner,0,0)
setContext()
popMatrix()
popStyle()
return img
end
function RectSprite:drawImage()
-- the main goal of this "pending" is to avoid multiple unecessary redraw (1 only is needed)
if not self.drawImagePending then return end
local img = self.img
if img == nil or img.width ~= self.w or img.height ~= self.h then
self.img = image(self.w, self.h)
end
self.smooth()
fill(self.fill)
stroke(self.stroke)
strokeWidth(self.strokeWidth)
self.img = self:roundedRect(0,0,self.w,self.h,self.radius)
self.drawImagePending = false
end
--# RRectObj
RRectObj = class(RectObj)
-- this is a rect with rounded corners, based on a mesh to keep mem low
function RRectObj:init(x,y,w,h,style)
RectDraw.init(self,x,y,w,h,style)
StyleObj:mixin(self)
self:setStyle(style)
self:meshCreate()
self.meshUpdatePending = true
self:meshUpdate()
end
function RRectObj:setSize(w,h)
RectObj.setSize(self,w,h)
self.meshUpdatePending = true
end
function RRectObj:setStyle(style)
self:set("fill",style,color(0,0,0,0))
self:set("stroke",style,color(255))
self:set("strokeWidth",style,2)
self:set("smooth",style,smooth)
if style and style.radius and style.radius <1 then style.radius = 1 end
self:set("radius",style,10)
self.meshUpdatePending = true
end
function RRectObj:draw()
pushMatrix()
translate(self.x,self.y)
self.mesh:draw()
self:meshUpdate() -- update with 1 frame delay: better smoothness
popMatrix()
end
function RRectObj:meshUpdate()
-- the main goal of this "pending" is to avoid multiple unecessary redraw (1 only is needed)
if not self.meshUpdatePending then return end
self:meshResize(self.w,self.h,self.radius,self.strokeWidth)
self:meshTexture(self.radius)
self.meshUpdatePending = false
end
function RRectObj:meshTexture(r)
d = math.max( math.floor(r), 2)
local w,h = 2*d,2*d
local img = image(w,h)
pushMatrix() pushStyle()
resetMatrix() resetStyle()
setContext(img)
self.smooth()
fill(self.fill)
stroke(self.stroke)
strokeWidth(self.strokeWidth)
if r >= 2 then
ellipseMode(CORNER)
ellipse(0,0,w,h)
else
rectMode(CORNER)
rect(0,0,w,h)
end
setContext()
popMatrix() popStyle()
self.mesh.texture = img
end
function RRectObj:meshCreate()
-- the rect are fake and need resizing
local i
local m = mesh()
local x0,x1,x2 = 0,0.5,0.5
local w0,w1,w2 = 0.5,0,0.5
local y0,y1,y2 = 0,0.5,0.5
local h0,h1,h2 = 0.5,0,0.5
-- bottom line
i = m:addRect(0,0,1,1)
m:setRectTex(i,x0,y0,w0,h0)
i = m:addRect(0,0,1,1)
m:setRectTex(i,x1,y0,w1,h0)
i = m:addRect(0,0,1,1)
m:setRectTex(i,x2,y0,w2,h0)
-- middle line
i = m:addRect(0,0,1,1)
m:setRectTex(i,x0,y1,w0,h1)
i = m:addRect(0,0,1,1)
m:setRectTex(i,x1,y1,w1,h1)
i = m:addRect(0,0,1,1)
m:setRectTex(i,x2,y1,w2,h1)
-- top line
i = m:addRect(0,0,1,1)
m:setRectTex(i,x0,y2,w0,h2)
i = m:addRect(0,0,1,1)
m:setRectTex(i,x1,y2,w1,h2)
i = m:addRect(0,0,1,1)
m:setRectTex(i,x2,y2,w2,h2)
self.mesh = m
end
function RRectObj:meshResize(w,h,r,strkWidth)
-- texture image size must be 2rx2r
local floor, ceil, min, max = math.floor, math.ceil, math.min, math.max
w,h = ceil(w), ceil(h)
r = min( floor(r), floor(w/2), floor(h/2) )
local d = r
local x0,x1,x2 = d/2, w/2, w-d/2
local w0,w1,w2 = d, w-2*d, d
local y0,y1,y2 = d/2, h/2, h-d/2
local h0,h1,h2 = d, h-2*d, d
local i
local m = self.mesh
-- bottom line
i=1
m:setRect(i,x0,y0,w0,h0)
i=i+1
m:setRect(i,x1,y0,w1,h0)
i=i+1
m:setRect(i,x2,y0,w2,h0)
-- middle line
i=i+1
m:setRect(i,x0,y1,w0,h1)
i=i+1
m:setRect(i,x1,y1,w1,h1)
i=i+1
m:setRect(i,x2,y1,w2,h1)
-- top line
i=i+1
m:setRect(i,x0,y2,w0,h2)
i=i+1
m:setRect(i,x1,y2,w1,h2)
i=i+1
m:setRect(i,x2,y2,w2,h2)
end
--# ImgObj
ImgObj = class(RectObj)
function ImgObj:init(x,y,w,h,style)
RectDraw.init(self,x,y,w,h,style)
StyleObj:mixin(self)
self:setStyle(style)
self.img = false -- needs load
end
function ImgObj:load(file)
if file then self.file = file end
local a = self.innerMargin
local w,h = self.w, self.h
self.img = image(w,h)
setContext(self.img)
pushMatrix() pushStyle()
resetMatrix() resetStyle()
spriteMode(CORNER)
sprite(self.file, a, a, w-2*a, h-2*a)
popMatrix() popStyle()
setContext()
end
function ImgObj:setSize(w,h)
RectObj.setSize(self,w,h)
self:load(self.file)
end
function ImgObj:setStyle(style)
self:set("innerMargin",style,0)
end
function ImgObj:draw()
if not self.img then return end
pushMatrix()
spriteMode(CORNER)
translate(self.x,self.y)
sprite(self.img,0,0)
popMatrix()
end
--# TextObj
TextObj = class(PositionObj)
-- component class to define and draw a text
function TextObj:init(txt,x,y,style)
PositionObj.init(self, x or 0, y or 0)
self.value = txt or ""
StyleObj:mixin(self)
self:setStyle(style)
end
function TextObj:setText(txt)
self.value = txt or ""
end
function TextObj:getText()
return self.value
end
function TextObj:setStyle(style)
self:set("font",style,"Futura-CondensedExtraBold")
self:set("fontSize",style,30)
self:set("fill",style,color(255))
self:set("textMode",style,CENTER)
self:set("textWrapWidth",style,-1)
self:set("textAlign",style,CENTER)
end
function TextObj:draw()
pushStyle()
pushMatrix()
translate(self.x, self.y)
smooth()
font(self.font)
fontSize(self.fontSize)
fill(self.fill)
textMode(self.textMode)
textWrapWidth(self.textWrapWidth)
textAlign(self.textAlign)
text(self.value)
popMatrix()
popStyle()
end
--# Button
Button = class(Touchable)
-- this is a button with text inside and can draw itself
function Button:init(name,x,y,w,h,style)
w = w or 200
h = h or 50
x = x or WIDTH/2 -w/2
y = y or HEIGHT/2 -h/2
Touchable.init(self,name,x,y,w,h)
StyleObj:mixin(self)
self:setStyle(style)
self:load()
self.rect = RRectObj(0,0,w,h) -- rect background
self.img = ImgObj(0,0,w,h) -- an image object (no image until self.img:load(file))
self.txt = TextObj(name, w/2, h/2, {textWrapWidth = w-10}) -- text inside
self:setTint()
self:setRectVisible(true)
self:setImgVisible(true)
self:setTxtVisible(true)
self:setBordVisible(false)
self.visible = true
if self.listenToEditor then self:listenToEditor() end
end
function Button:load()
if self.save ~= true then return end
local data = saver:load(self,{"x","y"})
if data == nil then return end
local x,y = data.x, data.y
self:setXY(x,y)
end
function Button:onEnter(t)
self.rect:pushStyle()
self.rect:setStyle({ fill = self.onEnterColor })
end
function Button:onLeave(t)
self.rect:popStyle()
end
function Button:addToScreen(screen)
screen:add(self)
self:listenToDrawFrom(screen)
self:listenToTouchedFrom(screen)
end
function Button:listenToDrawFrom(screen)
screen:on("draw", self.draw, self)
end
function Button:draw()
tint(self.tint)
pushMatrix()
translate(self.x, self.y)
if self.visible then
if self.rectVisible then self.rect:draw() end
if self.imgVisible then self.img:draw() end
if self.txtVisible then self.txt:draw() end
end
if self.bordVisible then self.bord:draw() end
popMatrix()
end
function Button:dragMe(t)
self:translate(t.deltaX,t.deltaY)
end
function Button:doNothing(t) end
---------------------- SETTERS -----------------------
function Button:setVisible(bool)
self.visible = bool
end
function Button:getVisible()
return self.visible
end
function Button:setStyle(style)
style = style or {}
if style.rect then self.rect:setStyle(style.rect) end
if style.txt then self.txt:setStyle(style.txt) end
self:set("onEnterColor", style, color(0, 137, 255, 255) )
local defaultSave = true
if self.name == nil then defaultSave = false end
self:set("save", style, defaultSave )
self:set("hasImg", style, true )
self:set("hasRect", style, true )
self:set("hasText", style, true )
end
function Button:getStyle()
style = {}
style.rect = self.rect:getStyle()
style.txt = self.txt:getStyle()
style.onEnterColor = self.onEnterColor
style.save = self.save
return style
end
function Button:setTint(c)
self.tint = c or color(255)
end
function Button:setRectVisible(bool)
self.rectVisible = bool
end
function Button:setImgVisible(bool)
self.imgVisible = bool
end
function Button:setTxtVisible(bool)
self.txtVisible = bool
end
function Button:setBordVisible(bool)
self.bordVisible = bool
if bool then
local w,h = self.w, self.h
self.bord = RectDraw(-5,-5,w+10,h+10,{strokeWidth=5,stroke=color(255,0,0)}) -- rect around
else
self.bord = nil
end
end
--# presetButtons
-- presetButtons: some 'ready to use' buttons
-- adds a uniform background button to screen, with a swipe method to change screen
function backgroundButton( screen, backColor )
local b
b = Button("no name",0,0,WIDTH,HEIGHT,{save=false})
b.rect:setStyle({strokeWidth=0,radius=1,fill=backColor})
b:setTxtVisible(false)
b:addToScreen(screen)
b.onEnter = b.doNothing
b.onLeave = b.doNothing
b.onSwipeLeft = function(self,t) screen:openNext() end
b.onSwipeRight = function(self,t) screen:openPrevious() end
return b
end
-- adds a button just displaying a long text
function longTextButton( screen, name, w,h, txtStyle, txt )
local b = Button(name,WIDTH/2,HEIGHT/2,50,50)
b:addToScreen(screen)
b:setTouchable(false)
b:setRectVisible(false)
b.txt:setStyle( txtStyle )
b.txt:setStyle( {textWrapWidth=WIDTH} )
b.txt:setText( txt )
return b
end
-- adds a button just displaying a line of text
function noWrapButton( screen, name, w,h, txtStyle, txt )
local b = Button(name,WIDTH/2,HEIGHT/2,50,50)
b:addToScreen(screen)
b:setTouchable(false)
b:setRectVisible(false)
b.txt:setStyle( txtStyle )
b.txt:setStyle( {textWrapWidth=-1} )
b.txt:setText( txt )
return b
end
--# Panel
-- Panel.lua
-- A panel is a container for other panels or objects that can be drawn. Used to form a
-- hierarchical representation of what's in the screen.
-- - The leaves of the hierarchy are typically SpriteObjs
-- - Handles binding and unbinding of events
-- - Forwards things like touched and collided to its elements
Panel = class(PositionObj)
function Panel:init(x,y)
PositionObj.init(self,x,y)
EventMngr:extend(self)
self.touchable = true -- if not active, touch events are not handled
self.visible = true
self.elems = {}
end
-- object should have coordinates relative to this one
function Panel:add(obj)
Table.map(function(x) assert(x~=obj,"adding duplicate obj") end,self.elems)
-- obj:translate(self.x,self.y) -- changed by Jmv38: not compatible with the saver process
table.insert(self.elems,obj)
end
function Panel:remove(obj)
Table.remove(self.elems,obj)
end
function Panel:removeAll()
self.elems = {}
end
function Panel:translate(dx,dy)
PositionObj.translate(self,dx,dy)
Table.map(function(x) x:translate(dx,dy) end,self.elems)
end
function Panel:setActive(bool)
self.touchable = bool
end
function Panel:setTint(c)
Table.map(function(x) if x.setTint then x:setTint(c) end end, self.elems)
end
function Panel:touched(t)
if not self.touchable then return nil end
local elemsClone = Table.clone(self.elems)
Table.map(function(x) if x.touched and x.touchable then x:touched(t) end end,elemsClone)
end
--# Screen
Screen = class(Panel)
-- sends commands: open, close, update, draw, touched
-- extends the touch
local currentScreen
local nextScreen -- for transitions
local screens = {}
function Screen:init(style)
Panel.init(self,0,0)
StyleObj:mixin(self)
table.insert(screens,self)
self:on("draw",function() resetMatrix() translate(self.offsetX,self.offsetY) end)
-- self.background = RRectObj(0,0,WIDTH,HEIGHT,{strokeWidth=0,radius=1})
-- self:on("draw",self.background.draw,self.background)
-- self:createBackgroundButton()
self:setStyle(style)
self:setOffset(0,0)
end
function Screen:setStyle(style)
style = style or {}
-- self:set("backgroundColor", style, color(32,32,32, 255) )
self:set("transitionComming", style, "fromRight" )
-- self.background:setStyle({ fill = self.backgroundColor })
-- self.background.rect:setStyle({ fill = self.backgroundColor })
end
function Screen:setOffset(offsetX,offsetY)
self.offsetX, self.offsetY = offsetX or 0, offsetY or 0
end
-- call when computations are needed
function Screen:update()
if currentScreen then currentScreen:trigger("update") end
if nextScreen then nextScreen:trigger("update") end
end
function Screen:draw()
background(0)
if currentScreen then currentScreen:trigger("draw") end
if nextScreen then nextScreen:trigger("draw") end
end
function Screen:touched(t)
if not currentScreen or not currentScreen.touchable then return end
local t = Xtouch:extend(t)
currentScreen:trigger("touched",t)
Xtouch:events(t) -- must be called after a trigger("touched",t) to fill some fields of t
end
-- actions to be done when opening a screen
function Screen:open(transition)
nextScreen = self
nextScreen:trigger("open")
local dx = 0
transition = transition or self.transitionComming
if transition == "fromRight" then dx = WIDTH
elseif transition == "fromLeft" then dx = -WIDTH
end
nextScreen:setOffset(dx,0)
-- make untouchable
if currentScreen then currentScreen:setTouchable(false) end
if nextScreen then nextScreen:setTouchable(false) end
-- make animation
local easing = tween.easing.quartInOut
local duration = 0.5
if currentScreen then
tween(duration,currentScreen,{offsetX=-dx,offsetY=0},easing)
end
tween(duration,self,{offsetX=0,offsetY=0},easing,function()
if currentScreen then
-- currentScreen:setTouchable(true)
currentScreen:close()
end
currentScreen = nextScreen
currentScreen:setTouchable(true)
nextScreen = nil
end)
end
-- close current screen
function Screen:close()
currentScreen:trigger("close")
-- tween.delay(0.1, function() saver:save() end )
end
function Screen:setTouchable(bool)
self.touchable = bool
end
function Screen:getTouchable()
return self.touchable
end
function Screen:openNext()
local s = Table.iNext(screens,self)
if s then s:open( "fromRight" ) end
end
function Screen:openPrevious()
local s = Table.iPrevious(screens,self)
if s then s:open( "fromLeft" ) end
end
--# Editor
Editor = class()
function Editor:init(show)
EventMngr:extend(self)
self.button = Button("editor",WIDTH-200,HEIGHT-100,150,50)
self.button:listenToEditor()
self.button:setStyle({save=true})
self.button.txt:setStyle({fontSize=20})
self:setState(false)
self.button.onTap = function(b,t)
self:setState( not self.state )
end
self:setVisible(show)
end
function Editor.addEditorButtonToScreen( screen )
if Editor.button then
Editor.button:addToScreen(screen)
screen:on("touched",Editor.toggleVisible)
end
end
function Editor.toggleVisible(t)
if t.state == ENDED and t.tapCount == 3 then
Editor.setVisible(Editor, not Editor.visible )
end
end
-- the editor tab modifies the Button Class too:
function Button:listenToEditor()
if Editor.button and self.save then -- setting self=true makes the buttons not editable
Editor:on("editorOn", self.setEditorOn, self)
Editor:on("editorOff", self.setEditorOff, self)
end
end
function Button:setEditorOn()
self.oldDrag = self.onDrag
self.onDrag = self.dragMe
self.oldTouchable = self.touchable
self:setTouchable(true)
self.oldRectVisible = self.rectVisible
self:setRectVisible(true)
end
function Button:setEditorOff()
self.onDrag = self.oldDrag
if self.oldTouchable~=nil then self:setTouchable( self.oldTouchable ) end
if self.oldRectVisible~=nil then self:setRectVisible( self.oldRectVisible ) end
end
function Editor:setVisible(bool)
self.visible = bool
if self.visible then
self.button:setVisible(true)
self.button:setTouchable(true)
else
self.button:setVisible(false)
self.button:setTouchable(false)
self.savePending = false -- turning invisible cancell the changes
self:setState(false)
end
end
-- this toggles the editor active / not active
function Editor:setState(bool)
self.state = bool
if self.state then
self:trigger("editorOn")
self:setStateButtonOn()
self.savePending = true
else
self:trigger("editorOff")
if self.savePending then
self.savePending = false
self:setStateButtonWait()
tween.delay(0.1, function()saver:save() end)
tween.delay(1, function() self:setStateButtonOff() end)
else
self:setStateButtonOff()
end
end
end
function Editor:setStateButtonOn()
self.button.txt:setText("editor is on")
self.button.rect:setStyle({fill = color(200,0,0) })
end
function Editor:setStateButtonWait()
self.button.txt:setText("saving...")
end
function Editor:setStateButtonOff()
self.button.txt:setText("editor is off")
self.button.rect:setStyle({fill = color(0,0,0,64) })
end
--# screen1
-- screen1
createScreen1 = function()
screen1 = Screen()
local screen = screen1
local b = backgroundButton( screen, color(30, 31, 102, 255))
Editor.addEditorButtonToScreen( screen )
tutoTitle( screen, "button 1.1", "Welcome to Xfc 3.0!")
tutoSubTitle( screen, "button 1.3", "Author: JMV38 - July 2014")
tutoTextCenter( screen, "button 1.2",[[
Xfc 3.0 is a library of buttons for Codea
This is a tutorial for using it
Swipe left to go to next screen
Swipe right to go back to previous screen
]])
end
tutoColor1 = color(103, 31, 31, 255)
tutoColor2 = color(103, 31, 31, 255)
function tutoTitle(screen, name, txt)
noWrapButton( screen, name,300, 50, {fontSize=50}, txt)
end
function tutoSubTitle(screen, name, txt)
noWrapButton( screen, name,300, 50, {fontSize=30, font= "Arial-ItalicMT"}, txt)
end
function tutoTextLeft(screen, name, txt)
longTextButton( screen, name,WIDTH, 300, {fontSize=20, font="ArialMT", textAlign=LEFT}, txt)
end
function tutoTextCenter(screen, name, txt)
longTextButton( screen, name,WIDTH, 300, {fontSize=20, font="ArialMT", textAlign=CENTER}, txt)
end
--# screen2
-- screen2
createScreen2 = function()
-- first step: create a screen to put your buttons into:
screen2 = Screen()
-- then add buttons. Lets start with 2 usefull (but optionnal) special buttons:
-- First a background button:
backgroundButton(screen2, color(103, 31, 31, 255))
-- this button sets the color of the backround and listen to screen touched events.
-- this is the button that will change the screen when you swipe left or right.
-- the next button is special one to help edit your buttons (we'll see how later)
Editor.addEditorButtonToScreen( screen2 )
-- after this you can add your own buttons
tutorial2(screen2)
end
-- tutorial part
tutorial2 = function(screen)
tutoTitle( screen, "button 2.1", "screen2")
tutoSubTitle( screen, "button 2.2", "Setting up a screen")
tutoTextLeft( screen, "button 2.3", [[
-- first step: create a screen to put your buttons into:
screen2 = Screen()
-- then add buttons. Lets start with 2 usefull (but optionnal) special buttons:
-- First a background button:
backgroundButton(screen2, color(103, 31, 31, 255))
-- this button sets the color of the backround and listen to screen touched events.
-- this is the button that will change the screen when you swipe left or right.
-- the next button is special one to help edit your buttons (we'll see how later)
Editor.addEditorButtonToScreen( screen2 )
-- after this you can add your own buttons
(look at tab 'screen2' to get this code)
swipe left to continue...
]])
end
--# screen3
-- screen3
createScreen3 = function()
screen3 = Screen({ backgroundColor = color(30, 31, 102, 255) })
local screen = screen3
backgroundButton( screen, color(30, 31, 102, 255))
Editor.addEditorButtonToScreen( screen )
local name = "myButton 1" -- each button must have a unique name to be easily editable
local x,y,w,h = WIDTH/2-100, HEIGHT-400, 200, 50 -- define button size and position
local b = Button(name) -- this creates the button
b:addToScreen(screen) -- this adds the button to screen (a button can go to several screens)
tutorial3(screen)
end
-- tutorial part
tutorial3 = function(screen)
tutoTitle( screen, "button 3.1", "screen3")
tutoSubTitle( screen, "button 3.2", "adding a button to the screen")
tutoTextLeft( screen, "button 3.3", [[
To create and view a button, you only need 2 lines:
local b = Button("myButton 1") -- each button must have a unique name to be easily editable
b:addToScreen(screen) -- this adds the button to screen (a button can go to several screens)
Here is the result:
]])
tutoTextLeft( screen, "button 3.5", [[
Now let's see how to put the button where you want:
- triple tap on the screen background to show up the editor button. Editor is off.
- tap the editor button to turn it on. Now the touchable region of each button shows up.
- drag your button where you want it
- tap the editor button to turn it off. After 1s the buttons are saved in the tab 'data'.
- triple tap on the screen background to hide the editor button
]])
tutoTextLeft( screen, "button 3.4",
[[(look at tab 'screen3' to get this code) swipe left to continue...]])
end
--# screen4
-- screen4
createScreen4 = function()
screen4 = Screen()
local screen = screen4
backgroundButton( screen, tutoColor1)
Editor.addEditorButtonToScreen( screen )
-- define button position directly
local x,y = 50, HEIGHT-300
local b = Button("myButton 2",x,y)
b:setTxtVisible(false) -- hide text
b:addToScreen(screen)
-- define button size and position
local x,y,w,h = nil,nil, 220, 40
local b = Button("myButton 3",x,y,w,h)
b:setRectVisible(false) -- hide rectangle
b:addToScreen(screen)
-- define rect style
local b = Button("myButton 4")
b.rect:setStyle({fill=color(0,128,0), strokeWidth=5, stroke=color(255,255,0), smooth=noSmooth, radius=20})
b:addToScreen(screen)
-- define text and text style
local b = Button("myButton 5",nil,nil,120,70)
b.txt:setText("new text for myButton 5")
b.txt:setStyle({fill=color(0),font="ArialMT",fontSize=20, textMode=CENTER, textWrapWidth=110, textAlign=LEFT})
b.rect:setStyle({fill=color(192), strokeWidth=0, radius=1})
b:addToScreen(screen)
-- example
local b = Button("myButton 6",nil,nil,60,60)
b.txt:setText("6")
b.txt:setStyle({fontSize=40})
b.rect:setStyle({fill=color(0), strokeWidth=1, radius=30})
b:addToScreen(screen)
-- example
local b = Button("myButton 7",nil,nil,60,60)
b.txt:setText("7")
b.txt:setStyle({fontSize=40})
b.rect:setStyle({fill=color(0), strokeWidth=1, radius=2})
b:addToScreen(screen)
-- example
local b = Button("myButton 8",nil,nil,60,60)
b:setTxtVisible(false)
b.img:setStyle({innerMargin = 5})
b.img:load("Cargo Bot:Command Right")
b.rect:setStyle({strokeWidth=2, radius=5})
b:addToScreen(screen)
-- example
local b = Button("myButton 9",nil,nil,100,100)
b.txt:setText("9")
b:setRectVisible(false)
b.img:load( "Cargo Bot:Codea Icon")
b:addToScreen(screen)
-- define button not editable by setting its name to nil
local x,y = 50, 150
local b = Button(nil,x,y)
b.txt:setText("not editable")
b:addToScreen(screen)
-- a generic button to prove all touch functions work
function testTouch(screen, func)
local b = Button("test_"..func)
b.txt:setText(func)
b.txt:setStyle({font="ArialMT",fontSize=20})
b.onEnter = b.doNothing
b.onLeave = b.doNothing
b[func] = function(self,t)
if not self.waiting then
Button.onEnter(self,t)
self.waiting = true
tween.delay(1, function()
Button.onLeave(self)
self.waiting = false
end)
end
end
b:addToScreen(screen)
end
testTouch(screen, "onBegan")
testTouch(screen, "onMoving")
testTouch(screen, "onEnded")
testTouch(screen, "onTap")
testTouch(screen, "onDrag")
testTouch(screen, "onDrop")
testTouch(screen, "onEnter")
testTouch(screen, "onLeave")
testTouch(screen, "onSwipeLeft")
testTouch(screen, "onSwipeRight")
testTouch(screen, "onSwipeUp")
testTouch(screen, "onSwipeDown")
tutorial4(screen)
end
-- tutorial part
tutorial4 = function(screen)
tutoTitle( screen, "button 4.1", "screen4")
tutoSubTitle( screen, "button 4.2", "changing button properties")
tutoTextLeft( screen, "button 4.3", [[
you can set the button aspect:
]])
tutoTextCenter( screen, "button 4.5",
[[The button b will react to action X if the function b:onX(touch) is defined.
Example: doing the described action turns the button to blue]]
)
tutoTextLeft( screen, "button 4.4",
[[(look at tab 'screen4' to get this code) swipe left to continue...]])
end
--# screen5
createScreen5 = function()
screen5 = Screen()
local screen = screen5
local b = backgroundButton( screen, color(30, 31, 102, 255))
Editor.addEditorButtonToScreen( screen )
tutoTitle( screen, "button 5.1", "Credits")
--tutoSubTitle( screen, "button 5.3", "Author: JMV38 - July 2014")
tutoTextCenter( screen, "button 5.2",[[
The low level classes are from CargoBot.
The panel and screen concept are inspired from cargoBot too.
The eventMngr class is the result of a work from @tnlogy & @JMV38 & @Briarfox
The concepts of 'is a', 'has a', inheritance and mixin were very useful to me
in making this code manageable. Thanks to @Toadkick, @hyrovitaliprotago,
@hpsoft, @luatee, @SkyTheCoder and others on the forum for their help and support!
]])
end
--# Main
-- Main.lua
DEV_MODE = false
supportedOrientations(LANDSCAPE_ANY)
function setup()
displayMode(FULLSCREEN)
-- displayMode(OVERLAY)
Editor:init()
createScreen1()
createScreen2()
createScreen3()
createScreen4()
createScreen5()
screen4:open()
-- screen1:setStyle({transitionComming = "fromLeft"})
end
function draw()
Screen:draw()
local c = CurrentTouch
if c and c.state~=ENDED then
resetMatrix()
fill(255)
ellipse(c.x,c.y,50)
end
end
function touched(t)
Screen:touched(t)
end
--# Notes
-- High level notes on the code
-- =============== Class Hierarchy =================
-- The first class to know about is Screen. It represents an ipad screen on which we
-- can draw stuff. It's main bit of functionality is that it knows how to handle meshes
-- and z-order of objects within these meshes. The current implementation just keeps a
-- different mesh for each texture in each z-order but obviously could be optimized to
-- for example uses an atlas
-- The various games screens are subclasses of Screen: Level, PackSelect, LevelSelect,
-- StartScreen, WinScreen. currentScreen is a global variable that corresponds to
-- the screen that is currently showing
-- Screen subclasses Panel. Panels are simple container objects that hold a bunch of
-- elems and recursively pass on methods to their elements. For example, put a bunch of
-- objects in a panel and by translating the panel you will translate all the elements
-- as well
-- Panels can also contain other other panels of course. So while screens are panels, many
-- of the objects on a screen are panels themselves. Also note that objects can
-- be added to the screen with add(), which is a panel method, but that doesn't mean that
-- they will be drawn (say an invisible button).
-- You could also have objects that are drawn but not added to the screen, for example, a
-- drawing that doesn't respond to any type of event ever doesn't necessarily have to be
-- add()'ed to the screen (but I guess no harm if it was added)
-- The leaves of the panel hierarchy are SpriteObjs. SpriteObjs are first created which
-- just their coordinates but as soon as they are added to a screen with doDraw, they become
-- part of that screen and will contain references to the meshes of that screen. From then on
-- we can set properties of SpriteObjs like position, tint, size and this will automatically
-- get reflected on the screen meshes. Functionality for moving a spriteObj from one screen
-- to another doesn't exist at the moment.
-- Two important subclasses of SpriteObj: Button and ShadowObj
-- Button is a SpriteObj that knows how to handle touches. Touches on a screen (or panels more
-- generally) are passed on to its elems, which can implement the touched method themselves.
-- Buttons do that - its touched metho checks if
-- the touch happened within the boundaries of the button, and forwards the touch to one of
-- its virtual methods: onBegan, onMoving, onEnded.
-- ShadowObj are SpriteObjs which have an internal SpriteObj to represent shadows. It then
-- overwrites all the SpriteObj methods to also apply them to the shadow.
-- The shadowOffset method determines the offset of the shadow relative to the object, given
-- its position. This method can be overwritten if we want to give the impression that the
-- shadow is elsewhere, for example the stage shadow works differently than the startScreen
-- shadow
-- ============= Level configuations ==============
-- The global variables packs and levels specify the parms for each level/pack
-- ============= Stage ==============
-- stages are defined in BaseStage/Stage/Goal and contain things like Piles,Claws,Crate
-- Different types of stage are drawn with different dimensions and sprites, and
-- so we define a config table which contains all the information needed to draw that stage
-- ============= Events ==============
-- Events are bound and triggered using the Events class, which is a static class
-- Note the interaction between the Panel class and Events. When a Panel is bound
-- it calls bindEvents on each of its elems so for each class you have to write
-- all binding of events into a bindEvents method. This also makes sure that the events
-- are easy to find and are not mixed with the rest of the code
--# data
saver.data = {
['editor'] = { x = 780.5, y = 681, },
['button 1.1'] = { y = 584.5, x = 483.5, },
['button 1.3'] = { y = 517, x = 480.5, },
['button 1.2'] = { y = 333, x = 479, },
['button 2.1'] = { y = 644, x = 472.5, },
['button 2.2'] = { y = 581, x = 475.5, },
['button 2.3'] = { y = 284.5, x = 508.5, },
['myButton 1'] = { y = 352, x = 398, },
['button 3.1'] = { y = 658.5, x = 470, },
['button 3.2'] = { y = 590.5, x = 471.5, },
['button 3.3'] = { y = 472, x = 484, },
['button 3.5'] = { y = 204.5, x = 442.5, },
['button 3.4'] = { y = 56, x = 493, },
['myButton 2'] = { y = 464.5, x = 114.5, },
['myButton 3'] = { y = 400.5, x = 36, },
['myButton 4'] = { y = 321, x = 54, },
['myButton 5'] = { y = 232.5, x = 28, },
['myButton 6'] = { y = 232.5, x = 187, },
['myButton 7'] = { y = 152.5, x = 277.5, },
['myButton 8'] = { y = 375, x = 296, },
['myButton 9'] = { y = 237, x = 270.5, },
['test_onBegan'] = { y = 485, x = 440, },
['test_onMoving'] = { y = 422, x = 439.5, },
['test_onEnded'] = { y = 362.5, x = 440, },
['test_onTap'] = { y = 303.5, x = 442, },
['test_onDrag'] = { y = 481, x = 669.5, },
['test_onDrop'] = { y = 420.5, x = 674, },
['test_onEnter'] = { x = 673, y = 362.5, },
['test_onLeave'] = { y = 303.5, x = 674, },
['test_onSwipeLeft'] = { y = 225, x = 441, },
['test_onSwipeRight'] = { y = 159.5, x = 443.5, },
['test_onSwipeUp'] = { y = 154.5, x = 677.5, },
['test_onSwipeDown'] = { y = 229, x = 677, },
['button 4.1'] = { y = 690, x = 502, },
['button 4.2'] = { y = 627.5, x = 504, },
['button 4.3'] = { y = 537, x = 142.5, },
['button 4.5'] = { y = 551.5, x = 654.5, },
['button 4.4'] = { y = 71, x = 472, },
['button 5.1'] = { y = 619.5, x = 490, },
['button 5.2'] = { y = 351.5, x = 506, },
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment