Snusmumriken

LOVE2d state-system

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