Snusmumriken

LOVE2d state-system

Jul 2nd, 2016 (edited)
614
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 4.43 KB | None | 0 0
  1. --[[
  2.     This lib provides state-automato into love2d, with autotracking
  3.     and autogenerating handlers, like love.update/love.mousemoved etc.
  4.     Wroted by Tommy (aka Snusmumriken aka HDPLocust)
  5.     If you see it, you will go to jail.
  6.  
  7. Reference manual:
  8.  Using:
  9.  --initialisation state-system
  10.  state = require 'states'
  11.  
  12.  --initialisation table for state #1
  13.  local stateA = {}
  14.  function stateA:load()
  15.     self.x, self.y = 0.0
  16.  end
  17.  function stateA:update(dt)
  18.     self.x, self.y = self.x + dt, self.y + dt^2
  19.  end
  20.  function stateA:draw()
  21.     if love.keyboard.isDown('2') then state:set('B') end
  22.     love.graphics.rectangle('line', self.x, self.y)
  23.  end
  24.  
  25.  --initialisation table for state #2
  26.  local stateB = {}
  27.  function stateB:load()
  28.     self.rect = {10, 20, 40, 30}
  29.     self.bool = false
  30.  end
  31.  function stateB:keypressed(key, unicode, isrepeat) -- Any arguments that any version of LOVE send it
  32.     if key == ' ' then self.bool = not self.bool end
  33.     if key == '1' then state:set('A') end
  34.  end
  35.  function stateB:draw()
  36.     if self.bool then
  37.      love.graphics.setColor(100, 200, 100)
  38.     else
  39.      love.graphics.setColor(200, 100, 100)
  40.     end
  41.     love.graphics.rectangle('line', unpack(self.rect))
  42.  
  43.     -- attaching states:
  44.     state:new('A', stateA)
  45.     state:new('B', stateB)
  46.     state:set('A')
  47.  end
  48. ]]
  49.  
  50. local type = type
  51. local love = require'love'
  52.  
  53. if not love then error('This lib only for LOVE2D framework. download it here: https://love2d.org', 2) end
  54.  
  55. local function err(v, str, ...)
  56.     if not v then error(str:format(...), 3) end
  57. end
  58.  
  59. local callbacks = {'update', 'draw'}
  60.  
  61. --track love.handlers of current version of LOVE2d
  62. for k, _ in pairs(love.handlers) do
  63.     callbacks[#callbacks + 1] = tostring(k)
  64. end
  65.  
  66. --Initialise state defaults
  67. local function state(t, name, global)
  68.     local s = t or {}
  69.     s.State = global
  70.     s.Name  = name
  71.     s.Break = {}
  72.     return s
  73. end
  74.  
  75. --State manager
  76. local states = {}
  77.  
  78. function states:__new()
  79.     self.state = {} --state list
  80.     self.stack = {} --current stack
  81.     self.debug = true
  82.     self.__index = self
  83.     return self
  84. end
  85.  
  86. --Self and additional love callback initialisation
  87. --(load/update/draw/keypressed/keyreleased etc)
  88. function states:init()
  89.     local temp_stack = {}
  90.    
  91.     for _, k in ipairs(callbacks) do
  92.         --initialisation self methods like self:update(dt)
  93.         self[k] = function(self, ...)
  94.             for i = 1, #temp_stack do temp_stack[i] = nil end
  95.             for i = 1, #self.stack do temp_stack[i] = self.stack[i] end
  96.            
  97.             local startStackPosition = 1
  98.             -- roll back and find first callback-overrider state
  99.             for i = #temp_stack, 1, -1 do
  100.                 local v = temp_stack[i]
  101.                 if v.Break and v.Break[k] then
  102.                     startStackPosition = i
  103.                     break
  104.                 end
  105.             end
  106.  
  107.             -- call callbacks from all states in stack, start from first overrider
  108.             for i = startStackPosition, #temp_stack do
  109.                 local s = temp_stack[i]
  110.                 if type(s[k]) == 'function' then
  111.                     s[k](s, ...)
  112.                 end
  113.             end
  114.         end
  115.  
  116.         --optional addition methods for love, if not defined
  117.         if not love[k] then
  118.             love[k] = function(...)
  119.                 self[k](self, ...)
  120.             end
  121.         end
  122.     end
  123.     return self
  124. end
  125.  
  126. function states:new(n, t, ...)
  127.     err(type(n) == 'string', 'Arg#1: State name expected, got "%s"',  type(n))
  128.     err(type(t) == 'table',  'Arg#2: State table expected, got "%s"', type(t))
  129.  
  130.     local st = state(t, n, self)
  131.  
  132.     self.state[n] = st
  133.     if type(st.init) == 'function' then
  134.         st:init(...)
  135.     end
  136.     return st
  137. end
  138.  
  139. function states:set(name, ...)
  140.     err(type(name) == 'string', 'Arg#1: State name expected, got: "%s"', type(name))
  141.  
  142.     local s = self.state[name]
  143.     err(s,'Arg#1: Name of defined state required, got: "%s"', tostring(name))
  144.  
  145.     if self.debug then love.window.setTitle(name) end
  146.     for i = #self.stack, 1, -1 do
  147.         local s = self.stack[i]
  148.         if type(s.unload) == 'function' then
  149.             s:unload()
  150.         end
  151.     end
  152.     self.stack = {s}
  153.     if type(s.load) == 'function' then
  154.         s:load(...)
  155.     end
  156. end
  157.  
  158. -- override_table is table with callback-keys, if key [keypressed] == true then after that state this callback brakes
  159. function states:push(name, ...)
  160.     local s = self.state[name]
  161.     err(s, 'Arg#1: Name of defined state required, got: "%s"', type(name))
  162.     self.stack[#self.stack + 1] = s
  163.     if type(s.load) == 'function' then
  164.         s:load(...)
  165.     end
  166. end
  167.  
  168. function states:pop(...)
  169.     err(#self.stack > 0, 'More pops then pushes')
  170.     local s = table.remove(self.stack)
  171.     if type(s.unload) == 'function' then
  172.         s:unload(...)
  173.     end
  174. end
  175.  
  176. function states:getStack()
  177.     return self.stack
  178. end
  179.  
  180. return states:__new():init()
Add Comment
Please, Sign In to add comment