MegaLoler

Love Game Engine

Apr 9th, 2013
249
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --[[
  2.  
  3. engine.lua
  4. Version: 1.3
  5.  
  6. Author: MegaLoler
  7.  
  8. A game engine for Love that manages game scenes and entities.
  9.  
  10. If requires that you use the class.lua file:
  11. require("class.lua")
  12.  
  13. Make sure you have this in your code:
  14. require("engine.lua")
  15.  
  16. Create a game by creating a subclass of the Engine class.
  17. MyGame = engine.newClass(engine.Engine)
  18.  
  19. Define the setup method:
  20. function MyGame:setup()
  21.     -- Initalize your game here.
  22. end
  23.  
  24. Make sure to call the setGame function of your game class in your main.lua:
  25. MyGame:setGame()  -- This will make the game engine take over.
  26.  
  27. Create a scene by subclassing the Entity class:
  28. TestScene = newClass(engine.Entity)
  29.  
  30. Define the setup, update, draw, and any other methods that you wish:
  31. function TestScene:setup() ... end
  32. function TestScene:update(dt) ... end
  33. function TestScene:draw() ... end
  34.  
  35. Call the setScene method somewhere in your game's setup method to set the inital scene on launch:
  36. self:setScene(TestScene) -- Pass the class itself, not an instance of it
  37.  
  38. Add children entities to a scene or entity preferably in its setup method with the addChild method:
  39. local child = TestEntity:new(self.engine, self) -- Parameters are game engine and parent entity
  40. self:addChild(child)
  41.  
  42. --]]
  43.  
  44. require("class")
  45.  
  46. engine = {} -- Engine package
  47.  
  48. -- Love wrappers
  49.  
  50. function love.load()
  51.     engine.game:load()
  52. end
  53.  
  54. function love.quit()
  55.     engine.game:quit()
  56. end
  57.  
  58. function love.focus(f)
  59.     engine.game:focus(f)
  60. end
  61.  
  62. function love.keypressed(key, unicode)
  63.     engine.game:keypressed(key, unicode)
  64. end
  65.  
  66. function love.keyreleased(key)
  67.     engine.game:keyreleased(key)
  68. end
  69.  
  70. function love.mousepressed(x, y, button)
  71.     engine.game:mousepressed(x, y, button)
  72. end
  73.  
  74. function love.mousereleased(x, y, button)
  75.     engine.game:mousereleased(x, y, button)
  76. end
  77.  
  78. function love.update(dt)
  79.     engine.game:update(dt)
  80. end
  81.  
  82. function love.draw()
  83.     engine.game:draw()
  84. end
  85.  
  86. -- Engine class
  87.  
  88. engine.Engine = newClass()
  89.  
  90. function engine.Engine:init()
  91.     self:setSize()
  92.     self:setTitle()
  93.     self.focused = true
  94.     self.fading = false
  95.     self.fade = 0
  96.     self.fadeSpeed = 2
  97.     self:setFadeColor()
  98.     self:setScene(engine.Entity)
  99. end
  100.  
  101. -- Sets the engine subclass to load
  102.  
  103. function engine.Engine:setGame()
  104.     engine.game = self:new()
  105. end
  106.  
  107. -- Engine methods
  108.  
  109. function engine.Engine:setTitle(title)
  110.     self.title = title or "Game Engine"
  111.     love.graphics.setCaption(self.title)
  112. end
  113.  
  114. function engine.Engine:setSize(width, height)
  115.     self.width = width or 640
  116.     self.height = height or 480
  117.     love.graphics.setMode(self.width, self.height)
  118.     if self.scene then self:positionScene() end
  119. end
  120.  
  121. function engine.Engine:fadeToScene(scene, ...)
  122.     self.fadeTo = scene
  123.     self.fadeArgs = ...
  124.     self.fading = true
  125. end
  126.  
  127. function engine.Engine:setFadeColor(color)
  128.     self.fadeColor = color or {0, 0, 0}
  129. end
  130.  
  131. function engine.Engine:setScene(scene, ...)
  132.     if self.scene then self.scene:destroy() end
  133.     self.scene = scene:new(self)
  134.     self:positionScene()
  135.     self.scene:setup(...)
  136. end
  137.  
  138. function engine.Engine:toggleFullscreen()
  139.     love.graphics.toggleFullscreen()
  140. end
  141.  
  142. -- Wrapped Love functions
  143.  
  144. function engine.Engine:load()
  145.     self:setup()
  146. end
  147.  
  148. function engine.Engine:quit()
  149. end
  150.  
  151. function engine.Engine:focus(f)
  152.     self.focused = f
  153. end
  154.  
  155. function engine.Engine:keypressed(key, unicode)
  156.     self.scene:onkeypressed(key, unicode)
  157. end
  158.  
  159. function engine.Engine:keyreleased(key)
  160.     self.scene:onkeyreleased(key)
  161. end
  162.  
  163. function engine.Engine:mousepressed(x, y, button)
  164.     self.scene:onmousepressed(x, y, button)
  165. end
  166.  
  167. function engine.Engine:mousereleased(x, y, button)
  168.     self.scene:onmousereleased(x, y, button)
  169. end
  170.  
  171. function engine.Engine:update(dt)
  172.     if self.fading then
  173.         if self.fade >= 1 then
  174.             self.fade = 1
  175.             self.fading = false
  176.             self:setScene(self.fadeTo, self.fadeArgs)
  177.         else
  178.             self.fade = self.fade + self.fadeSpeed * dt
  179.             if self.fade > 1 then self.fade = 1 end
  180.         end
  181.     else
  182.         if self.fade <= 0 then
  183.             self.fade = 0
  184.         else
  185.             self.fade = self.fade - self.fadeSpeed * dt
  186.             if self.fade < 0 then self.fade = 0 end
  187.         end
  188.     end
  189.     self.scene:masterUpdate(dt)
  190. end
  191.  
  192. function engine.Engine:draw()
  193.     self.scene:render()
  194.     love.graphics.setCanvas()
  195.     self.scene:postRender()
  196.     self:drawFade()
  197. end
  198.  
  199. -- Private methods
  200.  
  201. function engine.Engine:positionScene()
  202.     self.scene:setPosition(self.width / 2, self.height / 2)
  203. end
  204.  
  205. function engine.Engine:drawFade()
  206.     love.graphics.setBlendMode("alpha")
  207.     love.graphics.setColor(self.fadeColor[1], self.fadeColor[2], self.fadeColor[3], (math.cos((1 - self.fade) * math.pi) + 1) * 127)
  208.     love.graphics.polygon("fill", 0, 0, self.width, 0, self.width, self.height, 0, self.height)
  209. end
  210.  
  211. -- Virtual methods
  212.  
  213. function engine.Engine:setup()
  214. end
  215.  
  216. -- Entity class
  217.  
  218. engine.Entity = newClass()
  219.  
  220. function engine.Entity:init(engine, container)
  221.     self.engine = engine
  222.     self.container = container
  223.     self:setPosition()
  224.     self:setSize()
  225.     self:setOrientation()
  226.     self:setScale()
  227.     self:setColor()
  228.     self.backgroundAlpha = 255
  229.     self.alpha = 255
  230.     self:setBackgroundColor()
  231.     self.children = {}
  232.     self.selectable = false
  233.     self.selected = false
  234.     self.clearCanvas = true
  235.     self.hasBackground = false
  236.     self.staticDrawing = true
  237.     self.refreshRequested = true
  238.     self.tick = 0
  239.     self.time = 0
  240. end
  241.  
  242. -- Entity methods
  243.  
  244. function engine.Entity:addChild(child, ...)
  245.     table.insert(self.children, child)
  246.     child:setup(...)
  247. end
  248.  
  249. function engine.Entity:removeChild(child)
  250.     table.remove(self.children, child)
  251.     child:destroy()
  252. end
  253.  
  254. function engine.Entity:refresh()
  255.     self.refreshRequested = true
  256. end
  257.  
  258. function engine.Entity:setColor(color)
  259.     self.color = color or {255, 255, 255}
  260. end
  261.  
  262. function engine.Entity:setBackgroundColor(color)
  263.     local r, g, b = love.graphics.getBackgroundColor()
  264.     self.backgroundColor = color or {r, g, b}
  265. end
  266.  
  267. function engine.Entity:setPosition(x, y)
  268.     local dx = self.engine.width / 2
  269.     local dy = self.engine.height / 2
  270.     if self.container then
  271.         dx = self.container.width / 2
  272.         dy = self.container.height / 2
  273.     end
  274.     self.x = x or dx
  275.     self.y = y or dy
  276. end
  277.  
  278. function engine.Entity:move(x, y)
  279.     self.x = self.x + x
  280.     self.y = self.y + y
  281. end
  282.  
  283. function engine.Entity:setOrigin(x, y)
  284.     self.originX = x or self.width / 2
  285.     self.originY = y or self.height / 2
  286. end
  287.  
  288. function engine.Entity:setOrientation(r)
  289.     self.orientation = r or 0
  290. end
  291.  
  292. function engine.Entity:setScale(x, y)
  293.     self.scaleX = x or 1
  294.     self.scaleY = y or 1
  295. end
  296.  
  297. function engine.Entity:setSize(width, height)
  298.     self.width = width or self.engine.width
  299.     self.height = height or self.engine.height
  300.     self.canvas = love.graphics.newCanvas(self.width, self.height)
  301.     self:setOrigin()
  302. end
  303.  
  304. function engine.Entity:masterUpdate(dt)
  305.     self.time = self.time + dt
  306.     for k, v in pairs(self.children) do
  307.         v:masterUpdate(dt)
  308.     end
  309.     self:update(dt)
  310.     self.tick = self.tick + 1
  311. end
  312.  
  313. function engine.Entity:render()
  314.     if not self.staticDrawing or self.refreshRequested then
  315.         self.refreshRequested = false
  316.         love.graphics.setCanvas(self.canvas)
  317.         if self.clearCanvas then self.canvas:clear() end
  318.         if self.hasBackground then
  319.             love.graphics.setColor(self.backgroundColor[1], self.backgroundColor[2], self.backgroundColor[3], self.backgroundAlpha)
  320.             love.graphics.setBlendMode("alpha")
  321.             love.graphics.polygon("fill", 0, 0, self.width, 0, self.width, self.height, 0, self.height)
  322.         end
  323.        
  324.         self:preDraw()
  325.        
  326.         for k, v in pairs(self.children) do
  327.             v:render()
  328.             love.graphics.setCanvas(self.canvas)
  329.             v:postRender()
  330.         end
  331.        
  332.         self:draw()
  333.     end
  334. end
  335.  
  336. function engine.Entity:postRender()
  337.     love.graphics.setBlendMode("alpha")
  338.     love.graphics.setColor(self.color[1], self.color[2], self.color[3], self.alpha)
  339.     love.graphics.drawq(self.canvas, love.graphics.newQuad(0, 0, self.width, self.height, self.width, self.height), self.x, self.y , self.orientation, self.scaleX, self.scaleY, self.originX, self.originY)
  340. end
  341.  
  342. function engine.Entity:onkeypressed(key, unicode)
  343.     self:keypressed(key, unicode)
  344.     if self.selectedChild then self.selectedChild:onkeypressed(key, unicode) end
  345. end
  346.  
  347. function engine.Entity:onkeyreleased(key)
  348.     self:keyreleased(key)
  349.     if self.selectedChild then self.selectedChild:onkeyreleased(key) end
  350. end
  351.  
  352. function engine.Entity:onmousepressed(x, y, button)
  353.     local oldSelectedChild = self.selectedChild
  354.     self:mousepressed(x, y, button)
  355.     if self.selectedChild then self.selectedChild.selected = false end
  356.     self.selectedChild = self:getChildAtLocation(x, y)
  357.     if self.selectedChild and not self.selectedChild.selectable then self.selectedChild = nil end
  358.     if self.selectedChild then
  359.         self.selectedChild.selected = true
  360.         x, y = self:localCoordsToChildCoords(x, y, self.selectedChild)
  361.         self.selectedChild:onmousepressed(x, y, button)
  362.     end
  363.     if self.selectedChild ~= oldSelectedChild then
  364.         if oldSelectedChild then oldSelectedChild:focus(false) end
  365.         if self.selectedChild then self.selectedChild:focus(true) end
  366.     end
  367. end
  368.  
  369. function engine.Entity:onmousereleased(x, y, button)
  370.     self:mousereleased(x, y, button)
  371.     if self.selectedChild then
  372.         x, y = self:localCoordsToChildCoords(x, y, self.selectedChild)
  373.         self.selectedChild:onmousereleased(x, y, button)
  374.         if self.selectedChild:inBounds(x, y) then self.selectedChild:mouseclicked(x, y, button) end
  375.     end
  376. end
  377.  
  378. -- Private methods
  379.  
  380. function engine.Entity:inBounds(x, y)
  381.     return x >= 0 and x < self.width and y >= 0 and y < self.height
  382. end
  383.  
  384. function engine.Entity:getChildAtLocation(x, y)
  385.     for i = 1, #self.children do
  386.         local child = self.children[#self.children - (i - 1)]
  387.         local cx, cy = self:localCoordsToChildCoords(x, y, child)
  388.         if child:inBounds(cx, cy) then return child end
  389.     end
  390. end
  391.  
  392. function engine.Entity:localCoordsToChildCoords(x, y, child)
  393.     x = (x - child.x) / child.scaleX
  394.     y = (y - child.y) / child.scaleY
  395.    
  396.     distance = math.sqrt((x * x) + (y * y))
  397.     angle = math.atan2(y, x) - child.orientation
  398.    
  399.     x = math.cos(angle) * distance
  400.     y = math.sin(angle) * distance
  401.    
  402.     x = x + child.originX
  403.     y = y + child.originY
  404.    
  405.     return x, y
  406. end
  407.  
  408. -- Virtual methods
  409.  
  410. function engine.Entity:setup(...)
  411. end
  412.  
  413. function engine.Entity:destroy()
  414. end
  415.  
  416. function engine.Entity:focus(f)
  417. end
  418.  
  419. function engine.Entity:keypressed(key, unicode)
  420. end
  421.  
  422. function engine.Entity:keyreleased(key)
  423. end
  424.  
  425. function engine.Entity:mousepressed(x, y, button)
  426. end
  427.  
  428. function engine.Entity:mousereleased(x, y, button)
  429. end
  430.  
  431. function engine.Entity:mouseclicked(x, y, button)
  432. end
  433.  
  434. function engine.Entity:update(dt)
  435. end
  436.  
  437. function engine.Entity:preDraw()
  438. end
  439.  
  440. function engine.Entity:draw()
  441. end
Advertisement
Add Comment
Please, Sign In to add comment