Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
FogNetwork
GitHub Repository: FogNetwork/Tsunami
Path: blob/main/public/games/files/flappy-bird/index.coffee
1036 views
1
DEBUG = false
2
SPEED = 160
3
GRAVITY = 1100
4
FLAP = 320
5
SPAWN_RATE = 1 / 1200
6
OPENING = 100
7
SCALE = 1
8
9
HEIGHT = 384
10
WIDTH = 288
11
GAME_HEIGHT = 336
12
GROUND_HEIGHT = 64
13
GROUND_Y = HEIGHT - GROUND_HEIGHT
14
15
parent = document.querySelector("#screen")
16
gameStarted = undefined
17
gameOver = undefined
18
19
deadTubeTops = []
20
deadTubeBottoms = []
21
deadInvs = []
22
23
bg = null
24
# credits = null
25
tubes = null
26
invs = null
27
bird = null
28
ground = null
29
30
score = null
31
scoreText = null
32
instText = null
33
gameOverText = null
34
35
flapSnd = null
36
scoreSnd = null
37
hurtSnd = null
38
fallSnd = null
39
swooshSnd = null
40
41
tubesTimer = null
42
43
githubHtml = """<iframe src="http://ghbtns.com/github-btn.html?user=hyspace&repo=flappy&type=watch&count=true&size=large"
44
allowtransparency="true" frameborder="0" scrolling="0" width="150" height="30"></iframe>"""
45
46
floor = Math.floor
47
48
main = ->
49
spawntube = (openPos, flipped) ->
50
tube = null
51
52
tubeKey = if flipped then "tubeTop" else "tubeBottom"
53
if flipped
54
tubeY = floor(openPos - OPENING / 2 - 320)
55
else
56
tubeY = floor(openPos + OPENING / 2)
57
58
if deadTubeTops.length > 0 and tubeKey == "tubeTop"
59
tube = deadTubeTops.pop().revive()
60
tube.reset(game.world.width, tubeY)
61
else if deadTubeBottoms.length > 0 and tubeKey == "tubeBottom"
62
tube = deadTubeBottoms.pop().revive()
63
tube.reset(game.world.width, tubeY)
64
else
65
tube = tubes.create(game.world.width, tubeY, tubeKey)
66
tube.body.allowGravity = false
67
68
# Move to the left
69
tube.body.velocity.x = -SPEED
70
tube
71
72
spawntubes = ->
73
# check dead tubes
74
tubes.forEachAlive (tube) ->
75
if tube.x + tube.width < game.world.bounds.left
76
deadTubeTops.push tube.kill() if tube.key == "tubeTop"
77
deadTubeBottoms.push tube.kill() if tube.key == "tubeBottom"
78
return
79
invs.forEachAlive (invs) ->
80
deadInvs.push invs.kill() if invs.x + invs.width < game.world.bounds.left
81
return
82
83
tubeY = game.world.height / 2 + (Math.random()-0.5) * game.world.height * 0.2
84
85
# Bottom tube
86
bottube = spawntube(tubeY)
87
88
# Top tube (flipped)
89
toptube = spawntube(tubeY, true)
90
91
# Add invisible thingy
92
if deadInvs.length > 0
93
inv = deadInvs.pop().revive().reset(toptube.x + toptube.width / 2, 0)
94
else
95
inv = invs.create(toptube.x + toptube.width / 2, 0)
96
inv.width = 2
97
inv.height = game.world.height
98
inv.body.allowGravity = false
99
inv.body.velocity.x = -SPEED
100
return
101
102
addScore = (_, inv) ->
103
invs.remove inv
104
score += 1
105
scoreText.setText score
106
scoreSnd.play()
107
return
108
109
setGameOver = ->
110
gameOver = true
111
bird.body.velocity.y = 100 if bird.body.velocity.y > 0
112
bird.animations.stop()
113
bird.frame = 1
114
instText.setText "TOUCH\nTO TRY AGAIN"
115
instText.renderable = true
116
hiscore = window.localStorage.getItem("hiscore")
117
hiscore = (if hiscore then hiscore else score)
118
hiscore = (if score > parseInt(hiscore, 10) then score else hiscore)
119
window.localStorage.setItem "hiscore", hiscore
120
gameOverText.setText "GAMEOVER\n\nHIGH SCORE\n\n" + hiscore
121
gameOverText.renderable = true
122
123
# Stop all tubes
124
tubes.forEachAlive (tube) ->
125
tube.body.velocity.x = 0
126
return
127
128
invs.forEach (inv) ->
129
inv.body.velocity.x = 0
130
return
131
132
133
# Stop spawning tubes
134
game.time.events.remove(tubesTimer)
135
136
# Make bird reset the game
137
game.time.events.add 1000, ->
138
game.input.onTap.addOnce ->
139
reset()
140
swooshSnd.play()
141
142
hurtSnd.play()
143
return
144
145
flap = ->
146
start() unless gameStarted
147
unless gameOver
148
# bird.body.velocity.y = -FLAP
149
bird.body.gravity.y = 0;
150
bird.body.velocity.y = -100;
151
tween = game.add.tween(bird.body.velocity).to(y:-FLAP, 25, Phaser.Easing.Bounce.In,true);
152
tween.onComplete.add ->
153
bird.body.gravity.y = GRAVITY
154
flapSnd.play()
155
return
156
157
preload = ->
158
assets =
159
spritesheet:
160
bird: [
161
"assets/bird.png"
162
36
163
26
164
]
165
166
image:
167
tubeTop: ["assets/tube1.png"]
168
tubeBottom: ["assets/tube2.png"]
169
ground: ["assets/ground.png"]
170
bg: ["assets/bg.png"]
171
172
audio:
173
flap: ["assets/sfx_wing.mp3"]
174
score: ["assets/sfx_point.mp3"]
175
hurt: ["assets/sfx_hit.mp3"]
176
fall: ["assets/sfx_die.mp3"]
177
swoosh: ["assets/sfx_swooshing.mp3"]
178
179
Object.keys(assets).forEach (type) ->
180
Object.keys(assets[type]).forEach (id) ->
181
game.load[type].apply game.load, [id].concat(assets[type][id])
182
return
183
184
return
185
186
return
187
188
create = ->
189
console.log("%chttps://github.com/hyspace/flappy", "color: black; font-size: x-large");
190
ratio = window.innerWidth / window.innerHeight
191
document.querySelector('#github').innerHTML = githubHtml if ratio > 1.15 or ratio < 0.7
192
document.querySelector('#loading').style.display = 'none'
193
194
# Set world dimensions
195
Phaser.Canvas.setSmoothingEnabled(game.context, false)
196
game.stage.scaleMode = Phaser.StageScaleMode.SHOW_ALL
197
game.stage.scale.setScreenSize(true)
198
game.world.width = WIDTH
199
game.world.height = HEIGHT
200
201
# Draw bg
202
bg = game.add.tileSprite(0, 0, WIDTH, HEIGHT, 'bg')
203
204
# Credits 'yo
205
# credits = game.add.text(game.world.width / 2, HEIGHT - GROUND_Y + 50, "",
206
# font: "8px \"Press Start 2P\""
207
# fill: "#fff"
208
# stroke: "#430"
209
# strokeThickness: 4
210
# align: "center"
211
# )
212
# credits.anchor.x = 0.5
213
214
215
# # Add clouds group
216
# clouds = game.add.group()
217
218
# Add tubes
219
tubes = game.add.group()
220
221
# Add invisible thingies
222
invs = game.add.group()
223
224
# Add bird
225
bird = game.add.sprite(0, 0, "bird")
226
bird.anchor.setTo 0.5, 0.5
227
bird.animations.add "fly", [
228
0
229
1
230
2
231
], 10, true
232
bird.body.collideWorldBounds = true
233
bird.body.setPolygon(
234
24,1,
235
34,16,
236
30,32,
237
20,24,
238
12,34,
239
2,12,
240
14,2
241
)
242
243
# Add ground
244
ground = game.add.tileSprite(0, GROUND_Y, WIDTH, GROUND_HEIGHT, "ground")
245
ground.tileScale.setTo SCALE, SCALE
246
247
# Add score text
248
scoreText = game.add.text(game.world.width / 2, game.world.height / 4, "",
249
font: "16px \"Press Start 2P\""
250
fill: "#fff"
251
stroke: "#430"
252
strokeThickness: 4
253
align: "center"
254
)
255
scoreText.anchor.setTo 0.5, 0.5
256
257
# Add instructions text
258
instText = game.add.text(game.world.width / 2, game.world.height - game.world.height / 4, "",
259
font: "8px \"Press Start 2P\""
260
fill: "#fff"
261
stroke: "#430"
262
strokeThickness: 4
263
align: "center"
264
)
265
instText.anchor.setTo 0.5, 0.5
266
267
# Add game over text
268
gameOverText = game.add.text(game.world.width / 2, game.world.height / 2, "",
269
font: "16px \"Press Start 2P\""
270
fill: "#fff"
271
stroke: "#430"
272
strokeThickness: 4
273
align: "center"
274
)
275
gameOverText.anchor.setTo 0.5, 0.5
276
gameOverText.scale.setTo SCALE, SCALE
277
278
# Add sounds
279
flapSnd = game.add.audio("flap")
280
scoreSnd = game.add.audio("score")
281
hurtSnd = game.add.audio("hurt")
282
fallSnd = game.add.audio("fall")
283
swooshSnd = game.add.audio("swoosh")
284
285
# Add controls
286
game.input.onDown.add flap
287
288
# RESET!
289
reset()
290
return
291
292
reset = ->
293
gameStarted = false
294
gameOver = false
295
score = 0
296
# credits.renderable = true
297
# credits.setText "see console log\nfor github url"
298
scoreText.setText "Flappy Bird"
299
instText.setText "TOUCH TO FLAP\nbird WINGS"
300
gameOverText.renderable = false
301
bird.body.allowGravity = false
302
bird.reset game.world.width * 0.3, game.world.height / 2
303
bird.angle = 0
304
bird.animations.play "fly"
305
tubes.removeAll()
306
invs.removeAll()
307
return
308
309
start = ->
310
311
# credits.renderable = false
312
bird.body.allowGravity = true
313
bird.body.gravity.y = GRAVITY
314
315
# SPAWN tubeS!
316
tubesTimer = game.time.events.loop 1 / SPAWN_RATE, spawntubes
317
318
319
# Show score
320
scoreText.setText score
321
instText.renderable = false
322
323
# START!
324
gameStarted = true
325
return
326
327
update = ->
328
if gameStarted
329
if !gameOver
330
# Make bird dive
331
bird.angle = (90 * (FLAP + bird.body.velocity.y) / FLAP) - 180
332
bird.angle = -30 if bird.angle < -30
333
if bird.angle > 80
334
bird.angle = 90
335
bird.animations.stop()
336
bird.frame = 1
337
else
338
bird.animations.play()
339
340
# Check game over
341
game.physics.overlap bird, tubes, ->
342
setGameOver()
343
fallSnd.play()
344
setGameOver() if not gameOver and bird.body.bottom >= GROUND_Y
345
346
# Add score
347
game.physics.overlap bird, invs, addScore
348
349
else
350
# rotate the bird to make sure its head hit ground
351
tween = game.add.tween(bird).to(angle: 90, 100, Phaser.Easing.Bounce.Out, true);
352
if bird.body.bottom >= GROUND_Y + 3
353
bird.y = GROUND_Y - 13
354
bird.body.velocity.y = 0
355
bird.body.allowGravity = false
356
bird.body.gravity.y = 0
357
358
else
359
bird.y = (game.world.height / 2) + 8 * Math.cos(game.time.now / 200)
360
bird.angle = 0
361
362
363
# Scroll ground
364
ground.tilePosition.x -= game.time.physicsElapsed * SPEED unless gameOver
365
return
366
367
render = ->
368
if DEBUG
369
game.debug.renderSpriteBody bird
370
tubes.forEachAlive (tube) ->
371
game.debug.renderSpriteBody tube
372
return
373
374
invs.forEach (inv) ->
375
game.debug.renderSpriteBody inv
376
return
377
378
return
379
380
state =
381
preload: preload
382
create: create
383
update: update
384
render: render
385
386
game = new Phaser.Game(WIDTH, HEIGHT, Phaser.CANVAS, parent, state, false, false)
387
return
388
389
WebFontConfig =
390
google:
391
families: [ 'Press+Start+2P::latin' ]
392
active: main
393
(->
394
wf = document.createElement('script')
395
wf.src = (if 'https:' == document.location.protocol then 'https' else 'http') +
396
'://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js'
397
wf.type = 'text/javascript'
398
wf.async = 'true'
399
s = document.getElementsByTagName('script')[0]
400
s.parentNode.insertBefore(wf, s)
401
)()
402