-
Notifications
You must be signed in to change notification settings - Fork 0
/
Act.lua
276 lines (235 loc) · 9.35 KB
/
Act.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
-----------------------------------------------------------------------------------------
--
-- Act.lua
--
-- The Act class is a base class for all activities (acts) in the Mars App.
-----------------------------------------------------------------------------------------
-- Get local reference to the game globals
local game = globalGame
-- Required Corona modules
local composer = require( "composer" )
-- The Act class table
local Act = {
-- Display metrics
dyTitleBar = 40, -- height of standard view title bar
}
-- Create a new instance of the Act class
function Act:new()
local act = {}
setmetatable( act, self )
self.__index = self
return act
end
------------------------- Activity Methods --------------------------------
-- Make an new imageRect display object with the given filename, and options:
-- parent -- display group, default is act.group
-- folder -- subfolder where filename is located, default is media/actName
-- x, y -- initial position of the center of the object, default is act center
-- anchorX, anchorY -- anchor location (default 0.5 for center)
-- width, height -- display object size (default to original size/aspect)
-- allowFail -- set to true to just return nil if image not found instead of error
-- If only one of width or height is included, the other is calculated to retain the aspect.
function Act:newImage( filename, options )
-- Check the parameter types
assert( type( filename ) == "string" )
assert( not options or (type( options ) == "table") )
-- Get some default values
options = options or {}
local parent = options.parent or self.group
local folder = options.folder or "media/" .. self.name
local width = options.width
local height = options.height
-- Determine file path
local path = folder .. "/".. filename
-- Do we need to calculate width or height from the original image size?
if not width or not height then
-- TODO: Replace this with a more efficient implementation (read PNG/JPG header)
local image = display.newImage( parent, path, 0, 0, true )
if image then
if not width and not height then
width = image.width
height = image.height
elseif not width then
width = height * image.width / image.height
else
assert( not height )
height = width * image.height / image.width
end
image:removeSelf()
end
end
-- Now make the imageRect at the desired size and position
width = width or self.width
height = height or self.height
local image = display.newImageRect( parent, path, width, height )
if not image then
if options.allowFail then
return nil
end
error( "Image not found: " .. path, 2 ) -- report runtime error at the calling location
else
image.x = options.x or self.xCenter
image.y = options.y or self.yCenter
image.anchorX = options.anchorX or 0.5
image.anchorY = options.anchorY or 0.5
end
return image
end
-- Make a new text object in the Act at the given position and font size
-- The font is always system font and the fontSize defaults to 14.
function Act:newText( text, x, y, fontSize )
return display.newText( self.group, text, x, y, native.systemFont, (fontSize or 14) )
end
-- Make and return a display sub-group with the given parent (default act.group)
function Act:newGroup( parent )
parent = parent or self.group
local g = display.newGroup()
parent:insert( g )
return g
end
-- Make and return a solid white background for the act.
function Act:whiteBackground()
-- Background for the whole view
local bg = display.newRect( self.group, self.xCenter, self.yCenter, self.width, self.height )
bg:setFillColor( 1 ) -- white
return bg
end
-- Make and return a background with the given grayscale shade (0-1, default 0.7) for the act.
function Act:grayBackground( gray )
-- Background for the whole view
local bg = display.newRect( self.group, self.xCenter, self.yCenter, self.width, self.height )
bg:setFillColor( gray or 0.7 )
return bg
end
-- Make a background title bar for a game view with the given title string (default empty).
-- If backListener is passed, include a back button and call backListener when pressed.
-- Return a display group containing all the title bar elements.
function Act:makeTitleBar( title, backListener )
-- Make a display group to hold all the title bar elements
local group = self:newGroup()
-- Colored bar
local bar = display.newRect( group, self.xMin, self.yMin, self.width, self.dyTitleBar )
bar.anchorX = 0
bar.anchorY = 0
bar:setFillColor( game.themeColor.r, game.themeColor.g, game.themeColor.b )
bar:addEventListener( "touch", game.eatTouch ) -- eat touches on title bar
bar:addEventListener( "tap", game.eatTouch ) -- and taps too
-- Title bar text
title = title or ""
self.title = display.newText( group, title,
self.xCenter, self.yMin + self.dyTitleBar / 2,
native.systemFontBold, 18 )
self.title:setFillColor( 1 ) -- white
-- Back button if requested
if backListener then
local bb = self:newImage( "backArrow.png", {
parent = group,
folder = "media/game",
height = self.dyTitleBar * 0.6
} )
bb.x = self.xMin + 17
bb.y = self.yMin + self.dyTitleBar / 2
bb:addEventListener( "tap", backListener )
end
return group
end
-- Load and return a sound file with the given filename.
-- Use the folder if given, else media/actName
function Act:loadSound( filename, folder )
folder = folder or ("media/" .. self.name)
return audio.loadSound( folder .. "/" .. filename )
end
------------------------- Game Activity Management --------------------------------
-- Go to the given scene with transition options (see composer.gotoScene)
function game.gotoScene( scene, options )
composer.gotoScene( scene, options )
end
-- Go to a given act on the main tab, with transition options (see composer.gotoScene)
function game.gotoAct( act, options )
game.currentMainAct = act -- Remember the current act running on the main tab
composer.gotoScene( act, options ) -- CRASH? If you get 'sceneName' nil here then you
-- forgot to return act.scene from your act file.
end
-- Destroy the given act scene
function game.removeAct( name )
composer.removeScene( name )
end
-- Return the current act name
function game.currentActName()
return composer.getSceneName( "current" )
end
-- Call this to create an act object inside the act's source file
function game.newAct()
-- The act object to return
local act = Act:new()
-- Calculate dimentions of act area (full device above the tab bar)
act.width = game.width
act.height = game.height - game.dyTabBar
act.xMin = game.xMin
act.xMax = game.xMax
act.yMin = game.yMin
act.yMax = game.yMax - game.dyTabBar
act.xCenter = (act.xMin + act.xMax) / 2
act.yCenter = (act.yMin + act.yMax) / 2
-- Create a composer scene for the act and link them together
local scene = composer.newScene()
act.scene = scene
scene.act = act
-- Add the composer event listeners
scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )
scene:addEventListener( "destroy", scene )
-- Set the composer scene creation function
function scene:create( event )
local act = self.act
act.group = scene.view -- store the scene display group
act.name = composer.getSceneName( "current" )
act:init() -- call the act init function (required)
end
-- Set the composer show function
function scene:show( event )
-- When the scene is on-screen and ready to go...
local act = self.act
if event.phase == "will" then
-- Make sure game state is current before the new view starts
game.updateState()
-- Call the act prepare function, if any
if act.prepare then
act:prepare()
end
elseif event.phase == "did" then
-- Add an enterFrame listener for the act object
Runtime:addEventListener( "enterFrame", act )
-- Call the act start function, if any
if act.start then
act:start()
end
end
end
-- Set the composer hide function
function scene:hide( event )
-- When scene goes inactive...
local act = self.act
if event.phase == "will" then
-- Remove the enterFrame listener for the act object
Runtime:removeEventListener( "enterFrame", act )
-- Call the act stop function, if any
if act.stop then
act:stop()
end
end
end
-- Set the composer destroy function
function scene:destroy( event )
-- Call the act destroy function, if any
local act = self.act
if act.destroy then
act:destroy()
end
end
-- Return the act object
return act
end
------------------------- End of Methods --------------------------------
return Act