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