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