MegaLoler

Love Game Engine

Apr 8th, 2013
227
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --[[
  2.  
  3. engine.lua
  4. Version: 1.2
  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 = 1
  96.     self.fadeSpeed = 0.5
  97.     self.fadeColor = {255, 255, 255}
  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:setScene(scene, ...)
  128.     if self.scene then self.scene:destroy() end
  129.     self.scene = scene:new(self)
  130.     self:positionScene()
  131.     self.scene:setup(...)
  132. end
  133.  
  134. function engine.Engine:toggleFullscreen()
  135.     love.graphics.toggleFullscreen()
  136. end
  137.  
  138. -- Wrapped Love functions
  139.  
  140. function engine.Engine:load()
  141.     self:setup()
  142. end
  143.  
  144. function engine.Engine:quit()
  145. end
  146.  
  147. function engine.Engine:focus(f)
  148.     self.focused = f
  149. end
  150.  
  151. function engine.Engine:keypressed(key, unicode)
  152.     self.scene:onkeypressed(key, unicode)
  153. end
  154.  
  155. function engine.Engine:keyreleased(key)
  156.     self.scene:onkeyreleased(key)
  157. end
  158.  
  159. function engine.Engine:mousepressed(x, y, button)
  160.     self.scene:onmousepressed(x, y, button)
  161. end
  162.  
  163. function engine.Engine:mousereleased(x, y, button)
  164.     self.scene:onmousereleased(x, y, button)
  165. end
  166.  
  167. function engine.Engine:update(dt)
  168.     if self.fading then
  169.         if self.fade >= 1 then
  170.             self.fade = 1
  171.             self.fading = false
  172.             self:setScene(self.fadeTo, self.fadeArgs)
  173.         else
  174.             self.fade = self.fade + self.fadeSpeed * dt
  175.             if self.fade > 1 then self.fade = 1 end
  176.         end
  177.     else
  178.         if self.fade <= 0 then
  179.             self.fade = 0
  180.         else
  181.             self.fade = self.fade - self.fadeSpeed * dt
  182.             if self.fade < 0 then self.fade = 0 end
  183.         end
  184.     end
  185.     self.scene:masterUpdate(dt)
  186. end
  187.  
  188. function engine.Engine:draw()
  189.     self.scene:render()
  190.     love.graphics.setCanvas()
  191.     self.scene:postRender()
  192.     self:drawFade()
  193. end
  194.  
  195. -- Private methods
  196.  
  197. function engine.Engine:positionScene()
  198.     self.scene:setPosition(self.width / 2, self.height / 2)
  199. end
  200.  
  201. function engine.Engine:drawFade()
  202.     love.graphics.setBlendMode("alpha")
  203.     love.graphics.setColor(self.fadeColor[1], self.fadeColor[2], self.fadeColor[3], (math.cos((1 - self.fade) * math.pi) + 1) * 127)
  204.     love.graphics.polygon("fill", 0, 0, self.width, 0, self.width, self.height, 0, self.height)
  205. end
  206.  
  207. -- Virtual methods
  208.  
  209. function engine.Engine:setup()
  210. end
  211.  
  212. -- Entity class
  213.  
  214. engine.Entity = newClass()
  215.  
  216. function engine.Entity:init(engine, container)
  217.     self.engine = engine
  218.     self.container = container
  219.     self:setSize()
  220.     self:setPosition()
  221.     self:setOrientation()
  222.     self:setScale()
  223.     self:setColor()
  224.     self.backgroundAlpha = 255
  225.     self.alpha = 255
  226.     self:setBackgroundColor()
  227.     self.children = {}
  228.     self.selectable = false
  229.     self.selected = false
  230.     self.clearCanvas = true
  231.     self.hasBackground = false
  232.     self.staticDrawing = true
  233.     self.refreshRequested = true
  234. end
  235.  
  236. -- Entity methods
  237.  
  238. function engine.Entity:addChild(child, ...)
  239.     table.insert(self.children, child)
  240.     child:setup(...)
  241. end
  242.  
  243. function engine.Entity:removeChild(child)
  244.     table.remove(self.children, child)
  245.     child:destroy()
  246. end
  247.  
  248. function engine.Entity:refresh()
  249.     self.refreshRequested = true
  250. end
  251.  
  252. function engine.Entity:setColor(color)
  253.     self.color = color or {255, 255, 255}
  254. end
  255.  
  256. function engine.Entity:setBackgroundColor(color)
  257.     local r, g, b = love.graphics.getBackgroundColor()
  258.     self.backgroundColor = color or {r, g, b}
  259. end
  260.  
  261. function engine.Entity:setPosition(x, y)
  262.     local dx = self.engine.width / 2
  263.     local dy = self.engine.height / 2
  264.     if self.container then
  265.         dx = self.container.width / 2
  266.         dy = self.container.height / 2
  267.     end
  268.     self.x = x or dx
  269.     self.y = y or dy
  270. end
  271.  
  272. function engine.Entity:move(x, y)
  273.     self.x = self.x + x
  274.     self.y = self.y + y
  275. end
  276.  
  277. function engine.Entity:setOrientation(r)
  278.     self.orientation = r or 0
  279. end
  280.  
  281. function engine.Entity:setScale(x, y)
  282.     self.scaleX = x or 1
  283.     self.scaleY = y or 1
  284. end
  285.  
  286. function engine.Entity:setSize(width, height)
  287.     self.width = width or self.engine.width
  288.     self.height = height or self.engine.height
  289.     self.canvas = love.graphics.newCanvas(self.width, self.height)
  290. end
  291.  
  292. function engine.Entity:masterUpdate(dt)
  293.     for k, v in pairs(self.children) do
  294.         v:masterUpdate(dt)
  295.     end
  296.     self:update(dt)
  297. end
  298.  
  299. function engine.Entity:render()
  300.     if not self.staticDrawing or self.refreshRequested then
  301.         self.refreshRequested = false
  302.         love.graphics.setCanvas(self.canvas)
  303.         if self.clearCanvas then self.canvas:clear() end
  304.         if self.hasBackground then
  305.             love.graphics.setColor(self.backgroundColor[1], self.backgroundColor[2], self.backgroundColor[3], self.backgroundAlpha)
  306.             love.graphics.setBlendMode("alpha")
  307.             love.graphics.polygon("fill", 0, 0, self.width, 0, self.width, self.height, 0, self.height)
  308.         end
  309.        
  310.         self:preDraw()
  311.        
  312.         for k, v in pairs(self.children) do
  313.             v:render()
  314.             love.graphics.setCanvas(self.canvas)
  315.             v:postRender()
  316.         end
  317.        
  318.         self:draw()
  319.     end
  320. end
  321.  
  322. function engine.Entity:postRender()
  323.     love.graphics.setBlendMode("alpha")
  324.     love.graphics.setColor(self.color[1], self.color[2], self.color[3], self.alpha)
  325.     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.width / 2, self.height / 2)
  326. end
  327.  
  328. function engine.Entity:onkeypressed(key, unicode)
  329.     self:keypressed(key, unicode)
  330.     if self.selectedChild then self.selectedChild:onkeypressed(key, unicode) end
  331. end
  332.  
  333. function engine.Entity:onkeyreleased(key)
  334.     self:keyreleased(key)
  335.     if self.selectedChild then self.selectedChild:onkeyreleased(key) end
  336. end
  337.  
  338. function engine.Entity:onmousepressed(x, y, button)
  339.     local oldSelectedChild = self.selectedChild
  340.     self:mousepressed(x, y, button)
  341.     if self.selectedChild then self.selectedChild.selected = false end
  342.     self.selectedChild = self:getChildAtLocation(x, y)
  343.     if self.selectedChild and not self.selectedChild.selectable then self.selectedChild = nil end
  344.     if self.selectedChild then
  345.         self.selectedChild.selected = true
  346.         x, y = self:localCoordsToChildCoords(x, y, self.selectedChild)
  347.         self.selectedChild:onmousepressed(x, y, button)
  348.     end
  349.     if self.selectedChild ~= oldSelectedChild then
  350.         if oldSelectedChild then oldSelectedChild:focus(false) end
  351.         if self.selectedChild then self.selectedChild:focus(true) end
  352.     end
  353. end
  354.  
  355. function engine.Entity:onmousereleased(x, y, button)
  356.     self:mousereleased(x, y, button)
  357.     if self.selectedChild then
  358.         x, y = self:localCoordsToChildCoords(x, y, self.selectedChild)
  359.         self.selectedChild:onmousereleased(x, y, button)
  360.         if self.selectedChild:inBounds(x, y) then self.selectedChild:mouseclicked(x, y, button) end
  361.     end
  362. end
  363.  
  364. -- Private methods
  365.  
  366. function engine.Entity:inBounds(x, y)
  367.     return x >= 0 and x < self.width and y >= 0 and y < self.height
  368. end
  369.  
  370. function engine.Entity:getChildAtLocation(x, y)
  371.     for i = 1, #self.children do
  372.         local child = self.children[#self.children - (i - 1)]
  373.         local cx, cy = self:localCoordsToChildCoords(x, y, child)
  374.         if child:inBounds(cx, cy) then return child end
  375.     end
  376. end
  377.  
  378. function engine.Entity:localCoordsToChildCoords(x, y, child)
  379.     x = (x - child.x) / child.scaleX
  380.     y = (y - child.y) / child.scaleY
  381.    
  382.     distance = math.sqrt((x * x) + (y * y))
  383.     angle = math.atan2(y, x) - child.orientation
  384.    
  385.     x = math.cos(angle) * distance
  386.     y = math.sin(angle) * distance
  387.    
  388.     x = x + child.width / 2
  389.     y = y + child.height / 2
  390.    
  391.     return x, y
  392. end
  393.  
  394. -- Virtual methods
  395.  
  396. function engine.Entity:setup(...)
  397. end
  398.  
  399. function engine.Entity:destroy()
  400. end
  401.  
  402. function engine.Entity:focus(f)
  403. end
  404.  
  405. function engine.Entity:keypressed(key, unicode)
  406. end
  407.  
  408. function engine.Entity:keyreleased(key)
  409. end
  410.  
  411. function engine.Entity:mousepressed(x, y, button)
  412. end
  413.  
  414. function engine.Entity:mousereleased(x, y, button)
  415. end
  416.  
  417. function engine.Entity:mouseclicked(x, y, button)
  418. end
  419.  
  420. function engine.Entity:update(dt)
  421. end
  422.  
  423. function engine.Entity:preDraw()
  424. end
  425.  
  426. function engine.Entity:draw()
  427. end
Advertisement
Add Comment
Please, Sign In to add comment