Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Branch: master
Fetching contributors…

Cannot retrieve contributors at this time

1053 lines (862 sloc) 24.656 kB
Number.prototype.clamp = (min, max) ->
Math.min (Math.max this, min), max
clone= (obj) ->
if not obj? or typeof obj != 'object'
return obj
temp = obj.constructor()
for key, val of obj
temp[key] = clone val
temp
randInRange = (l, h) ->
l + Math.random() * (h - l)
randNorm = () ->
((Math.random() for i in [1..12]).reduce (t,s) -> t + s) / 12
hsv2rgb = (h, s, v) ->
c = v * s
h_p = h / 60.0
x = c * (1 - Math.abs(h_p%2 - 1))
[r,g,b] = [c,x,0] if 0 <= h_p < 1
[r,g,b] = [x,c,0] if 1 <= h_p < 2
[r,g,b] = [0,c,x] if 2 <= h_p < 3
[r,g,b] = [0,x,c] if 3 <= h_p < 4
[r,g,b] = [x,0,c] if 4 <= h_p < 5
[r,g,b] = [c,0,x] if 5 <= h_p < 6
m = v - c
[r,g,b].map (x) -> Math.round(255*(x+m))
class Rainbow
constructor: (@h = randInRange 0, 359) ->
next: (s = .8, v = .8) ->
@h += 222.49
@h %= 360
[r,g,b] = hsv2rgb @h, s, v
rainbow = new Rainbow
imgs =
bullet: 'bullet.png'
eyeGreen: 'eye_green.png'
head: 'head.png'
lotus: 'lotus.png'
monk: 'monk.png'
buddha1: 'buddha1.png'
wheel: 'wheel.png'
eye: 'eye.png'
title_monk: 'title_monk.png'
tm_light: 'tm_light.png'
tm_dark: 'tm_dark.png'
enlightenment: 'enlightenment.png'
enlightenment_blur: 'enlightenment_blur.png'
sounds =
intro: 'DST-ClubNight.mp3'
level1: 'DST-SpaceBuddha.mp3'
#credits: 'DST-EndingCredits.mp3'
hum: 'hum.mp3'
explosion0: 'explosion0.mp3'
explosion1: 'explosion1.mp3'
handleEvent = (e, dt, s) ->
#Time prefixes
if e.wait?
if not e._wait
e._wait = e.wait
e._wait -= dt
if e._wait > 0
return false
e._wait = e.wait
if e.waitUntil?
if not e.waitUntil(s)
return false
#Action
if e.from?
e.do s, e.from
e.from += e.step ? 1
else if e.draw?
s.to_draw.push e.draw
else if e.do?
e.do s
#Continue?
if e.from?
sign = if e.step > 0 then 1 else -1
if e.to? and sign*e.from <= sign*e.to
return false
if e.repeat?
e.repeat -= 1
if e.repeat > 0
return false
if e.repeatUntil?
if not e.repeatUntil(s)
return false
#Done
true
class Scene
constructor: (events) ->
@events = clone(events)
@ship = undefined
@explosions = []
@bullets = []
@enemies = []
@time = 0
@background = new BackgroundFlat "black"
@to_draw = []
@fade = 0
@fade_speed = 0
update: (dt) ->
@time += dt
if @events.length > 0
if handleEvent @events[0], dt, this
@events.shift()
@background.update dt
@ship?.update dt
x.update dt for x in @explosions
b.update dt for b in @bullets
e.update dt, this for e in @enemies
beam_hit = (@ship?.collideEnemy e for e in @enemies).some (x) -> x
if beam_hit
game.soundOn 'hum', .5
else
game.soundOff 'hum'
collision = (@ship?.collideBullet b for b in @bullets).some (x) -> x
if collision
game.stop()
@explosions = @explosions.filter (b) -> b.alive
@enemies = @enemies.filter (b) -> b.alive
@bullets = @bullets.filter (b) -> b.alive
@fade += @fade_speed * dt
if not (0 < @fade < 1)
@fade = Math.round(@fade)
@fade_speed = 0
if @fade_cb?
do @fade_cb
if @text?
@text_time += dt
if @text_time > @text_dur
@text = null
@text_y += @text_speed * dt
if @text_time < @text_fade_dur
@text_fade = @text_time/@text_fade_dur
else if @text_time > @text_dur - @text_fade_dur
@text_fade = 1 - (@text_time-@text_dur+@text_fade_dur)/@text_fade_dur
else
@text_fade = 1
this
draw: (ctx) ->
@background.draw ctx
d ctx for d in @to_draw
@to_draw = []
@ship?.draw ctx
x.draw ctx for x in @explosions
e.draw ctx for e in @enemies
b.draw ctx for b in @bullets
if @text?
[r,g,b] = @text_color
ctx.font = '16px "Apple Chancery", Mistral'
ctx.fillStyle = "rgba(#{r},#{g},#{b},#{@text_fade})"
i = 1
for t in @text
atom.context.fillText t, @text_x, 20 * i + @text_y
i++
ctx.fillStyle = "rgba(255,255,255,#{@fade})"
ctx.fillRect 0, 0, atom.width, atom.height
spawnBullet: (x, y, bullet) ->
@bullets.push new Bullet x, y, bullet.move, bullet.image
spawnEnemy: (x, y, e) ->
@enemies.push new Enemy x, y, e.move, e.fire, e.bullet, e.animate, e.health, e.die
spawnExplosion: (x, y, n = 60, speed = [50, 200]) ->
while n > 0
n -= 1
theta = randInRange 0, 2 * Math.PI
s= randInRange speed[0], speed[1]
r = randInRange 1, 3
@explosions.push new Explosion x, y, (moveStraight s* Math.cos(theta), s* Math.sin(theta)), r, [254,124,5]
undefined
shipShow: (x = atom.width * .5, y = atom.height * .7) ->
@ship = new Ship x, y
textShow: (text, dur = 5, fade = 2.5, speed = 40) ->
@text = text
@text_time = 0
@text_dur = dur
@text_fade_dur = fade
@text_x = randInRange 10, 200
@text_y = 0
@text_speed = speed
@text_color = do rainbow.next
fadeOut: (duration, callback) ->
@fade = 0
@fade_speed = 1 / duration
@fade_cb = callback
fadeIn: (duration) ->
@fade = 1
@fade_speed = -1 / duration
@fade_cb = null
class Explosion
constructor: (@x, @y, @move, @r, @color = 'red') ->
@t = 2
@alive = true
update: (dt) ->
[@x, @y] = @move @x, @y, dt
@t -= dt
if @t <= 0 or not (0 < @x < atom.width) or not (0 < @y < atom.height)
@alive = false
draw: (ctx) ->
radius = @r * Math.sin(Math.PI*(@t-1))
if radius < 0 then radius = 0
[r,g,b] = @color
ctx.fillStyle = "rgba(#{r},#{g},#{b},#{@t/2})"
do ctx.beginPath
ctx.arc @x, @y, radius, 0, Math.PI * 2, true
do ctx.fill
class Bullet
constructor: (@x, @y, @move, @image) ->
@r = @image.width / 2
@alive = true
@collision = false
update: (dt) ->
[@x, @y] = @move @x, @y, dt
if @x < 0 or @x > atom.width or @y < 0 or @y > atom.height
@alive = false
draw: (ctx) ->
ctx.drawImage @image, @x - @image.width/2, @y - @image.height/2
if @collision
ctx.fillStyle = 'red'
do ctx.beginPath
ctx.arc @x, @y, @r, 0, Math.PI * 2, true
do ctx.closePath
do ctx.fill
class Animation
constructor: (@image) ->
@width = @image.width
@height = @image.height
update: (dt) ->
draw: (ctx, x, y, shake, scale = .1) ->
jitter = shake * randInRange -scale, scale
width = @width * (1 + jitter)
height = @height * (1 - jitter)
ctx.drawImage @image, x - width/2, y - height/2, width, height
class AnimationBlink extends Animation
constructor: (@image, @speed = -.5, @range = [.4, .9]) ->
@blink = @range[1]
super @image
update: (dt) ->
@blink += @speed * dt
if not (@range[0] < @blink < @range[1])
@blink = @blink.clamp @range[0], @range[1]
@speed = -@speed
draw: (ctx, x, y, shake) ->
ctx.globalAlpha = @blink
super ctx, x, y, shake
ctx.globalAlpha = 1
class AnimationRotate extends Animation
constructor: (@image, @rotationSpeed = 2) ->
@rotation = 0
@width = @image.width
@height = @image.height
update: (dt) ->
@rotation += @rotationSpeed*dt
if @rotation >= 2*Math.PI
@rotation = 0
draw: (ctx, x, y, shake, scale) ->
do ctx.save
ctx.translate x, y
ctx.rotate @rotation
super ctx, 0, 0, shake, scale
do ctx.restore
class AnimationRotateScale extends AnimationRotate
constructor: (@image, @rotationSpeed) ->
super image, rotationSpeed
update: (dt) ->
super dt
draw: (ctx, x, y, shake, scale) ->
s = Math.sin @rotation
w = @width
h = @height
@width *= s
@height *= s
super ctx, x, y, shake, scale
@width = w
@height = h
moveStraight = (dx=0, dy=50) ->
(x, y, dt) ->
[x + dx * dt, y + dy * dt]
moveStraightGravity = (dx=0, dy=50, g=200) ->
(x, y, dt) ->
dy += dt*g
[x + dx * dt, y + dy * dt]
moveRandom = (speed = 50, duration = [.2, 2], padx = [50,50], pady = [100, 250]) ->
t = 0
dx = randInRange -speed, speed
dy = randInRange -speed, speed
dur =randInRange .2, 2
(x, y, dt) ->
t += dt
if t > dur
dx = randInRange -speed, speed
dy = randInRange -speed, speed
dur =randInRange duration[0], duration[1]
t = 0
[x,y] = [x + dx * dt, y + dy * dt]
if not (padx[0] < x < atom.width-padx[1])
x = x.clamp padx[0], atom.width - padx[1]
dx = -dx
if not (pady[0] < y < atom.height - pady[1])
y = y.clamp pady[0], atom.height - pady[1]
dy = -dy
[x,y]
bulletStraight = (dx=0, dy=100) ->
{image: game.images.bullet, move: moveStraight dx, dy}
bulletDirect = (s, e, speed = 100) ->
dx = s.ship?.x - e.x
dy = s.ship?.y - e.y
mag = speed / Math.sqrt(dx*dx + dy*dy)
{image: game.images.bullet, move: moveStraight mag * dx, mag * dy}
fireEvery = (fireEvery=1) ->
t = 0
(dt) ->
t += dt
if t > fireEvery
t = 0
true
else false
die =
normal: (e) ->
game.soundStart 'explosion0'
game.scene.spawnExplosion e.x, e.y
massive: (e) ->
game.soundStart 'explosion1'
for i in [0 .. 15]
game.scene.spawnExplosion atom.width * randNorm() + e.x - atom.width/2, atom.height * randNorm() + e.y - atom.height/2
enemy =
basic: (dx, dy, fireRate = .5) ->
move: moveStraight dx, dy
fire: fireEvery fireRate
bullet: [() -> bulletStraight()]
animate: new AnimationRotate game.images.eye, 2
health: 500
die: die.normal
circle: (n=6, speed=100)->
move: moveStraight()
fire: fireEvery 1
bullet: for i in [0 .. n-1]
((i, alt)-> () -> (
alt = if alt == 0 then 1 else 0
theta = 2 * Math.PI * (i + .5*alt) / n
bulletStraight speed * Math.cos(theta), speed * Math.sin(theta)
)
)(i, 1)
animate: new AnimationRotate game.images.wheel
health: 1000
die: die.normal
fan: (dx, dy, n=6, speed=100)->
odd = 1
ret =
move: moveStraight dx, dy
fire: fireEvery .8
bullet: for i in [0 .. n-1]
() -> (
odd = not odd
i = if odd then i + .5 else i
theta = 2 * Math.PI * (i + .5*odd) / n
bulletStraight speed * Math.cos(theta), speed * Math.sin(theta)
)
animate: new AnimationRotate game.images.head, .25
health: 1000
die: die.normal
direct: (dx, dy, g) ->
move: moveStraightGravity dx, dy, g
fire: fireEvery 1
bullet: [(dt, s, e) -> bulletDirect s, e]
animate: new Animation game.images.eyeGreen
health: 1250
die: die.normal
buddha1: (theta0 = 0, theta1 = Math.PI, dtheta = Math.PI/9.5, speed = 100) ->
move: moveRandom()
fire: fireEvery .03
bullet: [
(dt, s, e) ->
theta0 += dtheta
if theta0 >= 2*Math.PI
theta0 -= 2*Math.PI
dx = speed * Math.sin(theta0)
dy = speed * Math.cos(theta0)
bulletStraight dx, dy
,
(dt, s, e) ->
theta1 += dtheta
if theta1 >= 2*Math.PI
theta1 -= 2*Math.PI
dx = speed * Math.sin(theta1)
dy = speed * Math.cos(theta1)
bulletStraight dx, dy
]
animate: new Animation game.images.buddha1
health: 20000
die: die.massive
class Enemy
constructor: (@x, @y, @move, @fire, @bullet, @animate, health, @die) ->
@alive = true
@collision = false
@health = 1
@health_coeff = 1/health
update: (dt, s) ->
@damaged = false
@animate.update dt
@r = @animate.width/2
[@x, @y] = @move @x, @y, dt
if @fire dt
s.spawnBullet @x, @y, b(dt, s, this) for b in @bullet
if @x < 0 or @x > atom.width or @y < 0 or @y > atom.height
@alive = false
draw: (ctx) ->
ctx.globalAlpha = @health * .5 + .5
@animate.draw ctx, @x, @y, @damaged
ctx.globalAlpha = 1
ctx.fillStyle = "orange"
if @collision
ctx.fillRect @x, @y, 10, 10
damage: (dh) ->
@damaged = true
@health -= dh * @health_coeff
if @health <= 0
@alive = false
@die this
class Ship
constructor: (@x, @y) ->
@damage = 10
@speed = 140
@r_max = 12
@o_speed = .05
@do = 0
@o = 1
@body = new AnimationBlink game.images.monk
@lotus = new AnimationRotateScale game.images.lotus
@lotusY = -33
@lotusX = 5
@width = @body.width
@height = @body.height
@beamSpace = 6
collide: ->
game.soundStart 'explosion0'
game.scene.spawnExplosion @x, @y
if not game.immune
game.scene.fadeOut 1, () -> game.sceneChange new Scene title
game.scene.ship = null
collideBullet: (b) ->
dx = b.x - @x - @lotusX
dy = b.y - @y - @lotusY
if b.r*b.r >= dx*dx + dy*dy
do @collide
collideEnemy: (e) ->
dx = e.x - @x - @lotusX
dy = e.y - @y - @lotusY
if e.r*e.r >= dx*dx + dy*dy
do @collide
if e.x + e.r > @x - @r and e.x - e.r < @x + @r and e.y < @y - @height/2 - @beamSpace
e.damage @damage / @o
true
else false
update: (dt) ->
@lotus.update dt
@body.update dt
if atom.input.down 'space'
@do = -1
else
@do = +1
@o += @o_speed * @do
if @o > 1
@o = 1
@do = 0
if @o < .5
@o = .5
@do = 0
@r = @o * @r_max
dt *= @o
if atom.input.down 'left'
@x -= @speed * dt
if atom.input.down 'right'
@x += @speed * dt
if atom.input.down 'up'
@y -= @speed * dt
if atom.input.down 'down'
@y += @speed * dt
f = 8
@x = @x.clamp @width/f, atom.width - @width/f
@y = @y.clamp @height/f, atom.height - @height/f
draw: (ctx) ->
rand = randInRange -.1, .1
ctx.fillStyle = "rgba(0,0,200,#{1.5 - @o + rand})"
ctx.fillRect @x - @r, 0, 2 * @r, @y - @height/2 - @beamSpace
@body.draw ctx, @x, @y, false
@lotus.draw ctx, @x + @lotusX, @y + @lotusY, false
class BackgroundFlat
constructor: (@color) ->
update: (dt) ->
draw: (ctx) ->
ctx.fillStyle = @color
ctx.fillRect 0, 0, atom.width, atom.height
class BackgroundCredits
constructor: () ->
@en_alpha = 0
@en_da = .8
@show = false
@credits = [
'Created by: Daniel Schwartz',
'',
'',
'Photo Credits:',
'',
'Christopher Chan / Foter / CC BY-NC-ND',
'flickr.com/photos/27234114@N03/3200712567',
'flickr.com/photos/pelegrino/3646823338/',
'flickr.com/photos/rahuldb/3128100651/',
'flickr.com/photos/wonderlane/6969928165/',
'',
'',
'Special Thanks:',
'',
'Ankatell',
'Siddhartha Gautama',
]
@scroll = -atom.height
@scrollSpeed = 20
@lineHeight = 20
update: (dt) ->
@en_alpha += dt * @en_da
if @en_alpha > 1
@en_alpha = 1
@en_da = -@en_da
if @en_alpha < 0
@en_alpha = 0
@en_da = -@en_da
@scroll += dt * @scrollSpeed
if @scroll >= 0
@scroll = 0
@show = true
draw: (ctx) ->
ctx.fillStyle = 'white'
ctx.fillRect 0, 0, atom.width, atom.height
i = game.images.title_monk
x = atom.width/2 + 20
y = atom.height - i.height / 2 - 95
ctx.globalAlpha = @en_alpha * .6 + .4
r = 100 * (1.4 - ctx.globalAlpha)
grd = ctx.createRadialGradient x, y, 0, x, y, r
grd.addColorStop 0, 'yellow'
grd.addColorStop 1, 'white'
ctx.fillStyle = grd
do ctx.beginPath
ctx.arc x, y, r, 0, Math.PI * 2, true
do ctx.fill
ctx.globalAlpha = .8
ctx.drawImage i, x - i.width/2 - 20, y - i.height/2 + 95
ctx.font = '16px "Apple Chancery", Mistral'
ctx.fillStyle = 'blue'
i = 1
for c in @credits
atom.context.fillText c, 10, 20 * i - @scroll
i++
if @show
ctx.globalAlpha = @en_alpha
ctx.font = '20px Georgia'
ctx.fillStyle = 'blue'
ctx.fillText 'Press Space', 110, atom.height*.8
ctx.globalAlpha = 1
class BackgroundTitle
constructor: () ->
@orbs = []
@orb_rate = .5
@orb_countdown = 0
@g = -100
@tm_countdown = 0
@tm_light = true
@en_alpha = 0
@en_da = .8
@press_countdown = 2
@press_show = false
update: (dt) ->
@press_countdown -= dt
@orb_countdown -= dt
if @orb_countdown <= 0
@orb_countdown = @orb_rate
[r,g,b] = rainbow.next()
rand = randInRange -60, 60
orb =
x: atom.width/2 + 30 + rand
y: atom.height - 150
dx: rand * 1.5
dy: randInRange(-70, -120)
color: "rgba(#{r}, #{g}, #{b}, .8)"
@orbs.push orb
for orb in @orbs
orb.dy += dt * @g
orb.y += orb.dy * dt
orb.x += orb.dx * dt
@orbs = @orbs.filter ((o) -> o.y > 0)
@tm_countdown -= dt
if @tm_countdown <= 0
@tm_countdown = randInRange .01, .2
@tm_light = not @tm_light
@en_alpha += dt * @en_da
if @en_alpha > 1
@en_alpha = 1
@en_da = -@en_da
if @en_alpha < 0
@en_alpha = 0
@en_da = -@en_da
draw: (ctx) ->
ctx.fillStyle = 'white'
ctx.fillRect 0, 0, atom.width, atom.height
for orb in @orbs
ctx.fillStyle = orb.color
do ctx.beginPath
ctx.arc orb.x, orb.y, 20, 0, Math.PI * 2, true
do ctx.fill
if @tm_light
i = game.images.tm_light
else
i = game.images.tm_dark
ctx.drawImage i, atom.width/2 - i.width/2, 10
i = game.images.enlightenment_blur
ctx.globalAlpha = @en_alpha
ctx.drawImage i, atom.width/2 - i.width/2, game.images.tm_dark.height + 20
i = game.images.enlightenment
ctx.globalAlpha = 1
ctx.drawImage i, atom.width/2 - i.width/2, game.images.tm_dark.height + 20
i = game.images.title_monk
ctx.drawImage i, atom.width/2 - i.width/2, atom.height - i.height
if @press_show
ctx.globalAlpha = @en_alpha
ctx.font = '20px Georgia'
ctx.fillStyle = 'blue'
ctx.fillText 'Press Space', 150, atom.height*.33
ctx.globalAlpha = 1
else
if @press_countdown <= 0 and @en_alpha < .1
@press_show = true
class BackgroundStars
constructor: () ->
@stars = ([randInRange(0, atom.width), randInRange(0, atom.height), randInRange(1, 3)] for i in [1 .. 100])
@speed = 5
@horizon = 0
@horizonSpeed = 2
update: (dt) ->
dy = @speed * dt
for s in @stars
if s[1] < atom.height
s[1] += dy * s[2]
else
s[0] = randInRange 0, atom.width
s[1] = 0
@horizon += dt * @horizonSpeed
draw: (ctx) ->
ctx.fillStyle = "black"
ctx.fillRect 0, 0, atom.width, atom.height
ctx.fillStyle = "white"
for s in @stars
do ctx.beginPath
ctx.arc s[0], s[1], s[2]/2, 0, Math.PI * 2, true
do ctx.fill
grad = ctx.createLinearGradient 0, @horizon, 0, atom.height + @horizon
grad.addColorStop 0, "transparent"
grad.addColorStop 1, "blue"
ctx.fillStyle = grad
ctx.fillRect 0, @horizon, atom.width, atom.height - @horizon
class Game extends atom.Game
constructor: (@scene) ->
super
@preloadImages imgs
@preloadSounds sounds
atom.input.bind atom.key.LEFT_ARROW, 'left'
atom.input.bind atom.key.RIGHT_ARROW, 'right'
atom.input.bind atom.key.UP_ARROW, 'up'
atom.input.bind atom.key.DOWN_ARROW, 'down'
atom.input.bind atom.key.SPACE, 'space'
atom.input.bind atom.key.TAB, 'tab'
atom.input.bind atom.key.S, 's'
atom.input.bind atom.key.D, 'd'
atom.input.bind atom.key.F, 'f'
atom.input.bind atom.key.I, 'i'
@updates = 0
setInterval (=> @fps = @updates; @updates = 0), 1000
if atom.input.pressed 'f'
@time_warp *= 2
@show_data = false
@time_warp = 1
@immune = false
update: (dt) ->
if atom.input.pressed 's'
@time_warp /= 2
if atom.input.pressed 'd'
@time_warp = 1
if atom.input.pressed 'f'
@time_warp *= 2
if atom.input.pressed 'i'
@immune = not @immune
@scene = @scene.update dt * @time_warp
@updates += 1
if atom.input.pressed 'tab'
@show_data = not @show_data
draw: ->
@scene.draw atom.context
if @scene_new?
@scene = @scene_new
@scene_new = undefined
if @show_data
atom.context.font = '12px Georgia'
atom.context.fillStyle = 'blue'
atom.context.fillText "FPS: #{@fps}", 10, 20
atom.context.fillText "Bullets: #{@scene.bullets.length}", 10, 40
atom.context.fillText "Enemies: #{@scene.enemies.length}", 10, 60
atom.context.fillText "Explosions: #{@scene.explosions.length}", 10, 80
atom.context.fillText "Events: #{@scene.events.length}", 10, 100
atom.context.fillText "Time: #{@scene.time}", 10, 120
atom.context.fillText "Time Warp: #{@time_warp}", 10, 140
atom.context.fillText "Immune: #{@immune}", 10, 160
sceneChange: (scene) ->
@scene_new = scene
musicPlay: (source = @music_source) ->
if @music_source == source
@music?.play()
else
@music?.pause()
@music?.currentTime = 0
@music = game.sounds[source]
@music.play()
@music.loop = true
@music_source = source
musicPause: ->
@music?.pause()
soundStart: (sound, gain = 1) ->
a = new Audio
a.src = game.sounds[sound].src
game.sounds[sound].volume = gain
a.play()
soundOn: (sound, gain = 1) ->
game.sounds[sound].play()
game.sounds[sound].volume = gain
soundOff: (sound) ->
game.sounds[sound]?.pause()
preloadImages: (imgs) ->
@images = {}
@imagesNum = 0
@imagesLoaded = 0
for name, url of imgs
@imagesNum++
img = new Image
img.src = url
img.onload = () -> game.imagesLoaded++
@images[name] = img
preloadSounds: (sounds) ->
@sounds = {}
@soundsNum = 0
@soundsLoaded = 0
for name, url of sounds
@soundsNum++
sound = new Audio
if sound.canPlayType 'audio/ogg'
sound.src = url + '.ogg'
else
sound.src = url
sound.preload = 'auto'
sound.addEventListener 'canplaythrough', (-> game.soundsLoaded++), false
@sounds[name] = sound
text =
enemy: ['Your worst enemy cannot','harm you as much as your','own unguarded thoughts.']
peace: ['Peace comes from within.', 'Do not seek it without.']
able: ['He is able who','thinks he is able.']
credits = [
{do: (s) -> s.fadeIn 2},
{do: (s) -> s.background = new BackgroundCredits 'green'},
{do: (s) -> game.musicPlay 'intro'},
{waitUntil: (s) -> atom.input.pressed 'space'},
{do: (s) -> s.fadeOut .5},
{wait: .5},
{do: (s) -> game.sceneChange (new Scene title)},
]
level1 = [
{do: (s) -> s.fadeIn 5},
{do: (s) -> game.musicPlay 'level1'},
{do: (s) -> s.background = new BackgroundStars},
{do: (s) -> do s.shipShow},
{wait: 2},
{do: (s) -> s.textShow text.enemy},
{wait: 2},
{repeat: 7, wait: .5, do: (s) -> s.spawnEnemy 10, 10, (enemy.basic 50)},
{repeat: 7, wait: .5, do: (s) -> s.spawnEnemy 390, 10, (enemy.basic -50)},
{wait: 1},
{wait: 1, from: 100, to: 300, step: 100, do: (s, x) -> s.spawnEnemy x, 10, enemy.circle 8},
{wait: 2},
{from: 50, to: 350, step: 75, do: (s, x) -> s.spawnEnemy x, 10, enemy.basic 0, 50, 1},
{wait: .66},
{from: 87, to: 350, step: 75, do: (s, x) -> s.spawnEnemy x, 10, enemy.basic 0, 50, 1},
{wait: 4},
{repeat: 7, wait: .5, do: (s) -> s.spawnEnemy 10, 10, (enemy.basic 50)},
{wait: .5}
{repeat: 7, wait: .5, do: (s) -> s.spawnEnemy 390, 10, (enemy.basic -50)},
{wait: .5}
{repeat: 7, wait: .5, do: (s) -> s.spawnEnemy 10, 10, (enemy.basic 50)},
{repeat: 7, wait: .5, do: (s) -> s.spawnEnemy 390, 10, (enemy.basic -50)},
{wait: 3},
{from: 200, to: 100, step: -20, wait: .75, do: (s, x) -> s.spawnEnemy x, 10, (enemy.fan 50)},
{from: 200, to: 300, step: 20, wait: .75, do: (s, x) -> s.spawnEnemy x, 10, (enemy.fan -50)},
{wait: 2},
{do: (s) -> s.textShow text.peace},
{wait: 3},
{do: (s) -> s.spawnEnemy 10, 10, enemy.direct 50, 200, -75},
{wait: 1},
{do: (s) -> s.spawnEnemy 300, 10, enemy.direct -50, 200, -75},
{wait: 2},
{do: (s) -> s.spawnEnemy 10, 10, enemy.direct 50, 200, -75},
{wait: 1},
{do: (s) -> s.spawnEnemy 300, 10, enemy.direct -50, 200, -75},
{from: 50, to: 350, step: 75, do: (s, x) -> s.spawnEnemy x, 10, enemy.basic 0, 50, 1},
{wait: .66},
{from: 87, to: 350, step: 75, do: (s, x) -> s.spawnEnemy x, 10, enemy.basic 0, 50, 1},
{wait: 2},
{do: (s) -> s.spawnEnemy 10, 10, enemy.direct 50, 200, -75},
{wait: 1},
{do: (s) -> s.spawnEnemy 300, 10, enemy.direct -50, 200, -75},
{wait: 1, from: 100, to: 300, step: 100, do: (s, x) -> s.spawnEnemy x, 10, enemy.circle 8},
{wait: 2},
{do: (s) -> s.spawnEnemy 10, 10, enemy.direct 50, 200, -75},
{wait: 1},
{do: (s) -> s.spawnEnemy 300, 10, enemy.direct -50, 200, -75},
{from: 50, to: 350, step: 75, do: (s, x) -> s.spawnEnemy x, 10, enemy.basic 0, 50, 1},
{wait: .5},
{wait: 1, from: 100, to: 300, step: 100, do: (s, x) -> s.spawnEnemy x, 10, enemy.circle 8},
{wait: .5},
{from: 200, to: 100, step: -20, wait: .75, do: (s, x) -> s.spawnEnemy x, 10, (enemy.fan 50)},
{waitUntil: (s) -> s.enemies.length <= 0},
{do: (s) -> s.textShow text.able},
{wait: 5},
{do: (s) -> s.spawnEnemy atom.width/2, 150, enemy.buddha1()},
{waitUntil: (s) -> s.enemies.length <= 0},
{wait:2},
{do: (s) -> s.fadeOut 2},
{wait: 3},
{do: (s) -> game.sceneChange (new Scene credits)},
]
title = [
{do: (s) -> s.background = new BackgroundTitle},
{do: (s) -> game.musicPlay 'intro'},
{waitUntil: (s) -> atom.input.pressed 'space'},
{do: (s) -> s.fadeOut .5},
{wait: .5},
{do: (s) -> game.sceneChange (new Scene level1)},
]
loading = [
{do: (s) -> s.background = new BackgroundFlat 'white'},
{
repeatUntil: (s) -> game.imagesNum == game.imagesLoaded and game.soundsNum == game.soundsLoaded
draw: (ctx) ->
percent = Math.round((game.imagesLoaded + game.soundsLoaded)/(game.imagesNum + game.soundsNum)*100)
atom.context.font = '24px "Apple Chancery", Mistral'
ctx.fillStyle = "blue"
ctx.fillText "Loading: #{percent}%", 120, atom.height/2 - 24
},
{do: (s) -> game.sceneChange (new Scene title)},
]
game = new Game(new Scene loading)
window.onblur = ->
game.stop()
game.musicPause()
game.soundOff s for s,v of game.sounds
window.onfocus = ->
game.run()
game.musicPlay()
game.run()
Jump to Line
Something went wrong with that request. Please try again.