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