-
Notifications
You must be signed in to change notification settings - Fork 153
/
index.coffee
401 lines (332 loc) · 9.89 KB
/
index.coffee
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
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
DEBUG = false
SPEED = 160
GRAVITY = 1100
FLAP = 320
SPAWN_RATE = 1 / 1200
OPENING = 100
SCALE = 1
HEIGHT = 384
WIDTH = 288
GAME_HEIGHT = 336
GROUND_HEIGHT = 64
GROUND_Y = HEIGHT - GROUND_HEIGHT
parent = document.querySelector("#screen")
gameStarted = undefined
gameOver = undefined
deadTubeTops = []
deadTubeBottoms = []
deadInvs = []
bg = null
# credits = null
tubes = null
invs = null
bird = null
ground = null
score = null
scoreText = null
instText = null
gameOverText = null
flapSnd = null
scoreSnd = null
hurtSnd = null
fallSnd = null
swooshSnd = null
tubesTimer = null
githubHtml = """<iframe src="http://ghbtns.com/github-btn.html?user=hyspace&repo=flappy&type=watch&count=true&size=large"
allowtransparency="true" frameborder="0" scrolling="0" width="150" height="30"></iframe>"""
floor = Math.floor
main = ->
spawntube = (openPos, flipped) ->
tube = null
tubeKey = if flipped then "tubeTop" else "tubeBottom"
if flipped
tubeY = floor(openPos - OPENING / 2 - 320)
else
tubeY = floor(openPos + OPENING / 2)
if deadTubeTops.length > 0 and tubeKey == "tubeTop"
tube = deadTubeTops.pop().revive()
tube.reset(game.world.width, tubeY)
else if deadTubeBottoms.length > 0 and tubeKey == "tubeBottom"
tube = deadTubeBottoms.pop().revive()
tube.reset(game.world.width, tubeY)
else
tube = tubes.create(game.world.width, tubeY, tubeKey)
tube.body.allowGravity = false
# Move to the left
tube.body.velocity.x = -SPEED
tube
spawntubes = ->
# check dead tubes
tubes.forEachAlive (tube) ->
if tube.x + tube.width < game.world.bounds.left
deadTubeTops.push tube.kill() if tube.key == "tubeTop"
deadTubeBottoms.push tube.kill() if tube.key == "tubeBottom"
return
invs.forEachAlive (invs) ->
deadInvs.push invs.kill() if invs.x + invs.width < game.world.bounds.left
return
tubeY = game.world.height / 2 + (Math.random()-0.5) * game.world.height * 0.2
# Bottom tube
bottube = spawntube(tubeY)
# Top tube (flipped)
toptube = spawntube(tubeY, true)
# Add invisible thingy
if deadInvs.length > 0
inv = deadInvs.pop().revive().reset(toptube.x + toptube.width / 2, 0)
else
inv = invs.create(toptube.x + toptube.width / 2, 0)
inv.width = 2
inv.height = game.world.height
inv.body.allowGravity = false
inv.body.velocity.x = -SPEED
return
addScore = (_, inv) ->
invs.remove inv
score += 1
scoreText.setText score
scoreSnd.play()
return
setGameOver = ->
gameOver = true
bird.body.velocity.y = 100 if bird.body.velocity.y > 0
bird.animations.stop()
bird.frame = 1
instText.setText "TOUCH\nTO TRY AGAIN"
instText.renderable = true
hiscore = window.localStorage.getItem("hiscore")
hiscore = (if hiscore then hiscore else score)
hiscore = (if score > parseInt(hiscore, 10) then score else hiscore)
window.localStorage.setItem "hiscore", hiscore
gameOverText.setText "GAMEOVER\n\nHIGH SCORE\n\n" + hiscore
gameOverText.renderable = true
# Stop all tubes
tubes.forEachAlive (tube) ->
tube.body.velocity.x = 0
return
invs.forEach (inv) ->
inv.body.velocity.x = 0
return
# Stop spawning tubes
game.time.events.remove(tubesTimer)
# Make bird reset the game
game.time.events.add 1000, ->
game.input.onTap.addOnce ->
reset()
swooshSnd.play()
hurtSnd.play()
return
flap = ->
start() unless gameStarted
unless gameOver
# bird.body.velocity.y = -FLAP
bird.body.gravity.y = 0;
bird.body.velocity.y = -100;
tween = game.add.tween(bird.body.velocity).to(y:-FLAP, 25, Phaser.Easing.Bounce.In,true);
tween.onComplete.add ->
bird.body.gravity.y = GRAVITY
flapSnd.play()
return
preload = ->
assets =
spritesheet:
bird: [
"assets/bird.png"
36
26
]
image:
tubeTop: ["assets/tube1.png"]
tubeBottom: ["assets/tube2.png"]
ground: ["assets/ground.png"]
bg: ["assets/bg.png"]
audio:
flap: ["assets/sfx_wing.mp3"]
score: ["assets/sfx_point.mp3"]
hurt: ["assets/sfx_hit.mp3"]
fall: ["assets/sfx_die.mp3"]
swoosh: ["assets/sfx_swooshing.mp3"]
Object.keys(assets).forEach (type) ->
Object.keys(assets[type]).forEach (id) ->
game.load[type].apply game.load, [id].concat(assets[type][id])
return
return
return
create = ->
console.log("%chttps://github.com/hyspace/flappy", "color: black; font-size: x-large");
ratio = window.innerWidth / window.innerHeight
document.querySelector('#github').innerHTML = githubHtml if ratio > 1.15 or ratio < 0.7
document.querySelector('#loading').style.display = 'none'
# Set world dimensions
Phaser.Canvas.setSmoothingEnabled(game.context, false)
game.stage.scaleMode = Phaser.StageScaleMode.SHOW_ALL
game.stage.scale.setScreenSize(true)
game.world.width = WIDTH
game.world.height = HEIGHT
# Draw bg
bg = game.add.tileSprite(0, 0, WIDTH, HEIGHT, 'bg')
# Credits 'yo
# credits = game.add.text(game.world.width / 2, HEIGHT - GROUND_Y + 50, "",
# font: "8px \"Press Start 2P\""
# fill: "#fff"
# stroke: "#430"
# strokeThickness: 4
# align: "center"
# )
# credits.anchor.x = 0.5
# # Add clouds group
# clouds = game.add.group()
# Add tubes
tubes = game.add.group()
# Add invisible thingies
invs = game.add.group()
# Add bird
bird = game.add.sprite(0, 0, "bird")
bird.anchor.setTo 0.5, 0.5
bird.animations.add "fly", [
0
1
2
], 10, true
bird.body.collideWorldBounds = true
bird.body.setPolygon(
24,1,
34,16,
30,32,
20,24,
12,34,
2,12,
14,2
)
# Add ground
ground = game.add.tileSprite(0, GROUND_Y, WIDTH, GROUND_HEIGHT, "ground")
ground.tileScale.setTo SCALE, SCALE
# Add score text
scoreText = game.add.text(game.world.width / 2, game.world.height / 4, "",
font: "16px \"Press Start 2P\""
fill: "#fff"
stroke: "#430"
strokeThickness: 4
align: "center"
)
scoreText.anchor.setTo 0.5, 0.5
# Add instructions text
instText = game.add.text(game.world.width / 2, game.world.height - game.world.height / 4, "",
font: "8px \"Press Start 2P\""
fill: "#fff"
stroke: "#430"
strokeThickness: 4
align: "center"
)
instText.anchor.setTo 0.5, 0.5
# Add game over text
gameOverText = game.add.text(game.world.width / 2, game.world.height / 2, "",
font: "16px \"Press Start 2P\""
fill: "#fff"
stroke: "#430"
strokeThickness: 4
align: "center"
)
gameOverText.anchor.setTo 0.5, 0.5
gameOverText.scale.setTo SCALE, SCALE
# Add sounds
flapSnd = game.add.audio("flap")
scoreSnd = game.add.audio("score")
hurtSnd = game.add.audio("hurt")
fallSnd = game.add.audio("fall")
swooshSnd = game.add.audio("swoosh")
# Add controls
game.input.onDown.add flap
# RESET!
reset()
return
reset = ->
gameStarted = false
gameOver = false
score = 0
# credits.renderable = true
# credits.setText "see console log\nfor github url"
scoreText.setText "Flappy Bird"
instText.setText "TOUCH TO FLAP\nbird WINGS"
gameOverText.renderable = false
bird.body.allowGravity = false
bird.reset game.world.width * 0.3, game.world.height / 2
bird.angle = 0
bird.animations.play "fly"
tubes.removeAll()
invs.removeAll()
return
start = ->
# credits.renderable = false
bird.body.allowGravity = true
bird.body.gravity.y = GRAVITY
# SPAWN tubeS!
tubesTimer = game.time.events.loop 1 / SPAWN_RATE, spawntubes
# Show score
scoreText.setText score
instText.renderable = false
# START!
gameStarted = true
return
update = ->
if gameStarted
if !gameOver
# Make bird dive
bird.angle = (90 * (FLAP + bird.body.velocity.y) / FLAP) - 180
bird.angle = -30 if bird.angle < -30
if bird.angle > 80
bird.angle = 90
bird.animations.stop()
bird.frame = 1
else
bird.animations.play()
# Check game over
game.physics.overlap bird, tubes, ->
setGameOver()
fallSnd.play()
setGameOver() if not gameOver and bird.body.bottom >= GROUND_Y
# Add score
game.physics.overlap bird, invs, addScore
else
# rotate the bird to make sure its head hit ground
tween = game.add.tween(bird).to(angle: 90, 100, Phaser.Easing.Bounce.Out, true);
if bird.body.bottom >= GROUND_Y + 3
bird.y = GROUND_Y - 13
bird.body.velocity.y = 0
bird.body.allowGravity = false
bird.body.gravity.y = 0
else
bird.y = (game.world.height / 2) + 8 * Math.cos(game.time.now / 200)
bird.angle = 0
# Scroll ground
ground.tilePosition.x -= game.time.physicsElapsed * SPEED unless gameOver
return
render = ->
if DEBUG
game.debug.renderSpriteBody bird
tubes.forEachAlive (tube) ->
game.debug.renderSpriteBody tube
return
invs.forEach (inv) ->
game.debug.renderSpriteBody inv
return
return
state =
preload: preload
create: create
update: update
render: render
game = new Phaser.Game(WIDTH, HEIGHT, Phaser.CANVAS, parent, state, false, false)
return
WebFontConfig =
google:
families: [ 'Press+Start+2P::latin' ]
active: main
(->
wf = document.createElement('script')
wf.src = (if 'https:' == document.location.protocol then 'https' else 'http') +
'://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js'
wf.type = 'text/javascript'
wf.async = 'true'
s = document.getElementsByTagName('script')[0]
s.parentNode.insertBefore(wf, s)
)()