{
   "code" : "(\r\ns = Server.local;\r\ns.options.sampleRate_(44100);\r\ns.newBusAllocators;\r\ns.waitForBoot({\r\n\tvar win = Window.new(\"\", Window.screenBounds, false).fullScreen\r\n\t.front\r\n\t.onClose_({CmdPeriod.run;})\r\n\t.background_(Color.blue(0.1));\r\n\tvar winW = win.view.bounds.width, winH = win.view.bounds.height, hudH=50, hud, hudRect = Rect(0, winH-hudH, winW, hudH);\r\n\r\n\tvar keycodes = Platform.case(\r\n\t\t//<-, ->, ↓, ↑\r\n\t\t\\osx, {[123,124,125,126,49]},\r\n\t\t\\linux, {[65361,65363,65364,65362,32]},\r\n\t\t\\windows, {[37,39,40,38,32]}\r\n\t);\r\n\r\n\tvar alienLaserArray = Array.newClear;\r\n\r\n\t//colors\r\n\r\n\tvar spriteSize=36, radius = spriteSize/2;\r\n\r\n\tvar enemyArray = [Rect.aboutPoint(win.view.bounds.width.rand@0,radius, radius)], explosions = Array.newClear;\r\n\r\n\tvar numLives=3;\r\n\r\n\tvar sqrtHalfPi = sqrt(pi/2);\r\n\r\n\tvar level = 1;\r\n\r\n\tvar boostView, boostFuel=1, boostD=5, boostR=5, boost=1.5, canBoost=true;\r\n\r\n\tvar score = 0;\r\n\r\n\r\n\t//more vars\r\n\r\n\tvar laserHitBox = Array(40), canFire=true, playerState=\\alive;\r\n\r\n\tvar starSpeed = 20;\r\n\r\n\tvar playerSpeed = 6, enemySpeed = 4;\r\n\r\n\tvar laserArray = Array(40);\r\n\r\n\tvar laserSpeed = playerSpeed*4, laserLen = spriteSize/2.4, alienLaserSpeed=(laserSpeed-enemySpeed)*0.75;\r\n\r\n\tvar enemyX = win.view.bounds.width.rand, enemyY=0, enemyRectArray;\r\n\r\n\tvar cannonWidth = spriteSize/12, cannonLength=0.6*spriteSize;\r\n\r\n\tvar livesView, levelView, scoreView;\r\n\r\n\tvar collision;\r\n\r\n\t\t\t//draw stars\r\n\tvar starArray = 500.collect({\r\n\t\tx = winW.rand;\r\n\t\tz = winH.rand;\r\n\t\tr = exprand(0.3,2.0);\r\n\t\t[[x,z,r],[x,(hudRect.top.neg+z),r]];\r\n\t}).flatten(1);\r\n\r\n\tvar starY = 0;\r\n\r\n\tvar board = UserView(win, Rect(0, 0, win.view.bounds.width, hudRect.top))\r\n\t.animate_(true)\r\n\t.frameRate_(15)\r\n\t.drawFunc_({\r\n\t\tstarY = (starY+1).wrap(0,hudRect.top);\r\n\t\tPen.translate(0, starY);\r\n\t\tPen.use({\r\n\t\t\tstarArray.do({\r\n\t\t\t\targ item;\r\n\t\t\t\tPen.addOval(Rect(\r\n\t\t\t\t\titem.at(0), item.at(1),\r\n\t\t\t\t\titem.at(2), item.at(2)\r\n\t\t\t\t)\r\n\t\t\t\t)\r\n\t\t\t\t.color_([Color.grey(exprand(0.8,1.0)), Color.white].wchoose([0.1,0.8]))\r\n\t\t\t\t.fill;\r\n\t\t\t});\r\n\t\t});\r\n\t});\r\n\r\n\tvar playerX=board.bounds.width/2-(spriteSize/2), playerY=board.bounds.height-(spriteSize*2), playerDir = Set(1), playerRect=Rect(playerX, playerY, spriteSize, spriteSize);\r\n\r\n\r\n\tif (~highScore == nil, {~highScore=score});\r\n\t~flashAlpha = 0.0;\r\n\t~flashSize = 0;\r\n\t~fireDelay = 0.25;\r\n\r\n\t~frameRate = 30;\r\n\r\n\t//sounds\r\n\r\n\t~lfoBus = Bus.control(s,1);\r\n\t~revIn = Bus.audio(s,1);\r\n\r\n\ts.sync;\r\n\r\n\r\n\tSynthDef(\\engine, {\r\n\t\targ freq=90, amp=0.5, gate=1, pan=0.5, filtFreq=1500, in=0, out=0;\r\n\t\tvar sig, env, detune, pitch, width, noise;\r\n\t\tdetune = 3.collect({0.5.rand2.midiratio});\r\n\t\twidth = LFNoise1.ar(LFNoise0.ar.range(1.0,4.0)).range(0.01,0.99);\r\n\t\tpitch = freq*detune;\r\n\t\tnoise = WhiteNoise.ar(0.18);\r\n\t\tnoise = RLPF.ar(noise, 2000, 0.8);\r\n\t\tsig = LFPulse.ar(pitch, 0, width, 1/6);\r\n\t\tenv = EnvGen.ar(Env.asr, gate, doneAction:2);\r\n\t\tsig = HPF.ar(sig, 500);\r\n\t\tsig = Mix.ar(sig);\r\n\t\tsig = Mix.ar([sig, noise]);\r\n\t\tsig = BPF.ar(sig, LFNoise1.ar(2).range(800,1000));\r\n\t\tsig = RLPF.ar(sig, 500, 0.5);\r\n\t\tsig = sig*amp*env;\r\n\t\t// sig = LeakDC.ar(sig);\r\n\t\tsig = Pan2.ar(sig, pan);\r\n\t\tOut.ar(out, sig);\r\n\t}).add;\r\n\r\n\tSynthDef(\\pow, {\r\n\t\targ freq1=2000, freq2=20, dur=0.3, pan=0.5, gate=1, amp = 0.5, out=0;\r\n\t\tvar sig, env, line;\r\n\t\tline = XLine.ar(freq1,freq2,dur);\r\n\t\tsig =\r\n\t\t4.collect({\r\n\t\t\targ i;\r\n\t\t\tLFPulse.ar((line*(1.rand2).midiratio), 0)/2\r\n\t\t});\r\n\t\tsig = Mix.ar(sig).fold(-1.0,1.0);\r\n\t\tenv = EnvGen.ar(Env.perc(0.01,dur*2), gate, doneAction:2);\r\n\t\tsig = BPF.ar(sig);\r\n\t\tsig = (sig * amp * env);\r\n\t\tsig = Pan2.ar(sig, pan);\r\n\t\tOut.ar(out, sig);\r\n\t}).add;\r\n\r\n\r\n\r\n\tSynthDef(\\explosion, {\r\n\t\targ amp=0.6, pan=0, freq=30, noiseAmp=0.16, noiseAmp2=0.5, lpfFreq=1748, hpfFreq=40, dur=3, out=0;\r\n\t\tvar sig, env, noise, fold;\r\n\t\tnoise = Mix.ar([ClipNoise.ar(noiseAmp), BrownNoise.ar(noiseAmp2)]);\r\n\t\tsig = 7.collect({\r\n\t\t\tLFPulse.ar(LFNoise1.ar.range(21.0,35.0), 1.0.rand, LFNoise1.ar(1).range(0.01,0.99));\r\n\t\t});\r\n\t\tfold = EnvGen.ar(Env([0.1,0.8],[0.4],-4.0.rand));\r\n\t\tsig = Splay.ar(sig);\r\n\t\tsig = Mix.ar([sig,noise]);\r\n\t\tsig = sig.fold(fold.neg,fold);\r\n\t\tsig = sig.round(2.pow(-4.rand));\r\n\t\tenv = EnvGen.ar(Env.perc(0.001,dur), doneAction:2);\r\n\t\tsig = sig.clip(-1,1);\r\n\t\tsig = CombL.ar(sig, 0.2, 0.2, 1.0);\r\n\t\tsig = sig*env*amp;\r\n\t\tsig = LPF.ar(sig, lpfFreq);\r\n\t\tsig = HPF.ar(sig, hpfFreq);\r\n\t\tsig = LeakDC.ar(sig);\r\n\t\tsig = Pan2.ar(sig, pan);\r\n\t\tOut.ar(out, sig);\r\n\t}).add;\r\n\r\n\tSynthDef(\\alien, {\r\n\t\targ amp=1, pan=0, freq=60, detun=0.5, fFreqLo=20, fFreqHi=1500, dur=5, depth=0, out=0;\r\n\t\tvar sig, env, filtMod, lfo;\r\n\t\tfiltMod = In.kr(~lfoBus).exprange(fFreqLo, fFreqHi);\r\n\r\n\t\tenv = EnvGen.ar(Env([0,1,0], [0,dur,0]), doneAction:2);\r\n\t\tsig = 7.collect({\r\n\t\t\tLFSaw.ar(freq*rand2(detun).midiratio, 4.0.rand);\r\n\t\t});\r\n\t\tsig = Mix.ar(sig/sig.size);\r\n\t\tsig = RLPF.ar(sig, filtMod, 0.3);\r\n\t\tsig = Pan2.ar(sig, pan);\r\n\t\tsig = sig * amp * env;\r\n\t\tOut.ar(out, sig);\r\n\t}).add;\r\n\r\n\r\n\t//borrowed from Designing Sound in SuperCollider\r\n\r\n\tSynthDef(\\red, {\r\n\r\n\t\targ amp = 0.05;\r\n\r\n\tvar env, redAlert, dfbe, aIn, bIn, cIn, aOut, bOut, cOut;\r\n\r\n\t# aIn, bIn, cIn = LocalIn.ar(7).clumps([5,1,1]);\r\n\r\n\tenv = [EnvGen.ar(Env.new([0,1,1,0], [0.9, 0.3, 0.0]), doneAction:2), EnvGen.ar(Env.new([0,1,1,0], [0.01, 0.88, 0.01]))];\r\n\tenv[0] = LFSaw.ar(env[0].sqrt * 487 + 360, 1, 0.5, 0.5);\r\n\tenv[0] = (env[0] - 0.5) + ((env[0] * 2 * 2pi).cos * 0.3);\r\n\tredAlert = (env[0] - OnePole.ar(env[0], exp(-2pi * (1 * SampleDur.ir)))) * env[1];\r\n\tredAlert = redAlert + (cIn * 0.006) * 0.2;\r\n\r\n\r\n\tdfbe = 0!6;\r\n\tredAlert = redAlert + (aIn * 0.7);\r\n\t5.do{|i| dfbe[i] = DelayN.ar(redAlert[i], 0.1, [0.015, 0.022, 0.035, 0.024, 0.011][i])};\r\n\taOut = dfbe[0..4];\r\n\r\n\tredAlert = redAlert[0..4].sum;\r\n\tredAlert = (redAlert - OnePole.ar(redAlert, exp(-2pi * (12 * SampleDur.ir))));\r\n\r\n\tdfbe[5] = redAlert + (bIn * 0.7);\r\n\tdfbe[5] = DelayN.ar(dfbe[5], 0.1, 0.061);\r\n\t# bOut, cOut = dfbe[5]!2;\r\n\tLocalOut.ar(aOut ++ bOut ++ cOut);\r\n\r\n\tredAlert = Clip.ar(redAlert * 4, -1, 1);\r\n\tredAlert = BPF.ar(redAlert, [740, 1400, 1500, 1600], (12!4).reciprocal) ++ (redAlert * 0.5);\r\n\tOut.ar(0, (redAlert.sum * amp)!2);\r\n\r\n}).add;\r\n\r\nSynthDef(\\laser2, {\r\n\t\targ freq1=4000, freq2=40, dur=0.5, pan=0, gate=1, amp = 0.2, out=0;\r\n\t\tvar sig, env, line;\r\n\t\tline = XLine.ar(freq1,freq2,dur);\r\n\t\tsig =\r\n\t\t10.collect({\r\n\t\t\targ i;\r\n\t\tLFSaw.ar((line*(5.rand2).midiratio), 0)/5\r\n\t\t});\r\n\t\tsig = Mix.ar(sig).fold(-1.0,1.0);\r\n\t\tenv = EnvGen.ar(Env.perc(0.01,dur*2), gate, doneAction:2);\r\n\t\tsig = BPF.ar(sig, line/2);\r\n\t\tsig = (sig * amp * env);\r\n\t\tsig = Pan2.ar(sig, pan);\r\n\t\tOut.ar(out, sig);\r\n\t}).add;\r\n\r\n\r\n\t// SynthDef(\\verb, {\r\n\t// \targ in=~revIn, out=0, mix=0.33, room=0.5, damp=0.5;\r\n\t// \tvar sig;\r\n\t// \tsig = In.ar(~revIn);\r\n\t// \tsig = FreeVerb.ar(sig, mix, room, damp);\r\n\t// \tOut.ar(out, sig);\r\n\t// }).add;\r\n\r\n\tSynthDef(\\lfo, {\r\n\t\targ cpm = 440, out=~lfoBus;\r\n\t\tvar freq = cpm/60, sig;\r\n\t\tsig = LFTri.kr(freq);\r\n\t\tOut.kr(~lfoBus, sig);\r\n\t}).add;\r\n\r\n\r\n\ts.sync;\r\n\r\n\tSynth(\\lfo);\r\n\r\n\t~alienSynth = {Synth(\\alien, [\\dur, 2, \\amp, 0.125, \\pan, x.linlin(radius, winW-radius, -1.0, 1.0)])};\r\n\r\n\t~explosionSynth = {Synth(\\explosion, [\\amp, 0.3])};\r\n\r\n\r\n\t//////////////////////////Sound Functions\r\n\r\n\r\n\t~engineSynth = Synth(\\engine);\r\n\r\n\t~laserSynth = {Synth(\\pow, [\\pan, playerX.linlin(0, win.view.bounds.width,-0.9,0.9)]);};\r\n\r\n\r\n\r\n\r\n\t//////////////////////////Drawing Functions\r\n\r\n\r\n\r\n\r\n\t~playerDraw = {\r\n\t\tvar cockpitH = spriteSize/3, cockpitW = spriteSize/7;\r\n\t\tvar numLines = 4;\r\n\t\tvar propulsionSize = rrand(15.0,20.0);\r\n\t\tvar delta=rrand(0.1, 0.3)*spriteSize/6, height = exprand(0.4,(1/4))*spriteSize, tip = radius+rand2(delta/2)@(spriteSize+height);\r\n\t\tplayerRect=Rect(playerX, playerY, spriteSize, spriteSize);\r\n\t\t//movement\r\n\t\tplayerDir.do({\r\n\t\t\targ item;\r\n\t\t\tcase\r\n\t\t\t{item == (\\left)} {playerX=playerX-playerSpeed}\r\n\t\t\t{item == (\\right)} {playerX=playerX+playerSpeed}\r\n\t\t\t{item == (\\down)} {playerY=playerY+playerSpeed}\r\n\t\t\t{item == (\\up)} {playerY=playerY-playerSpeed};\r\n\t\t});\r\n\t\tplayerY=playerY.clip(0, board.bounds.height-spriteSize);\r\n\t\tplayerX=playerX.clip(0, board.bounds.width-spriteSize);\r\n\t\tPen.translate(playerX, playerY);\r\n\r\n\t\t//draw\r\n\r\n\t\t//propulsion\r\n\t\tPen.use({\r\n\t\t\tPen\r\n\t\t\t.moveTo((radius)-(spriteSize/15) @ (spriteSize))\r\n\t\t\t.quadCurveTo((radius)+(spriteSize/15) @ (spriteSize), (tip.x) @ (tip.y*sqrtHalfPi))\r\n\t\t\t.lineTo((radius)-(spriteSize/15) @ (spriteSize))\r\n\t\t\t.fillAxialGradient((radius) @ (spriteSize), (spriteSize/2) @ (tip.y), Color.cyan(1,1.0), Color.cyan(1.0,0));\r\n\r\n\t\t\tPen\r\n\t\t\t.addOval(Rect.aboutPoint(radius @ (spriteSize), spriteSize/propulsionSize, spriteSize/propulsionSize)).color_(Color.cyan).fill;\r\n\t\t});\r\n\r\n\t\t2.do{\r\n\t\t\targ i;\r\n\t\t\tPen\r\n\t\t\t.moveTo(radius + [delta.neg, delta].at(i) @ spriteSize)\r\n\t\t\t.quadCurveTo(tip, radius + [delta.neg, delta].at(i) @ (spriteSize+delta.rand))\r\n\t\t\t.lineTo(radius + [delta, delta.neg].at(i)@spriteSize)\r\n\t\t\t.fillAxialGradient(tip, radius @ (spriteSize-delta), Color.blue, Color.cyan(1.5))\r\n\t\t};\r\n\t\tPen.addOval(Rect.aboutPoint(radius@spriteSize, delta, delta)).fillAxialGradient(tip, radius @ (spriteSize-delta), Color.cyan, Color.white);\r\n\t\tPen.use({\r\n\r\n\t\t\t//cannons\r\n\t\t\t2.do({\r\n\t\t\t\targ i;\r\n\t\t\t\tPen\r\n\t\t\t\t.line(((i*spriteSize)+[(cannonWidth/2),(cannonWidth/2).neg].at(i))  @ spriteSize, ((i*spriteSize)+[(cannonWidth/2),(cannonWidth/2).neg].at(i)) @ (cannonLength))\r\n\t\t\t\t.strokeColor_(Color.grey)\r\n\t\t\t\t.width_(cannonWidth)\r\n\t\t\t\t.stroke\r\n\t\t\t});\r\n\r\n\t\t\t//wings\r\n\r\n\t\t\tPen.use({\r\n\t\t\t\t2.do({\r\n\t\t\t\t\targ i;\r\n\t\t\t\t\tvar ratio = (5/8);\r\n\t\t\t\t\tPen\r\n\t\t\t\t\t.moveTo(spriteSize/2 @ (0.875*spriteSize))\r\n\t\t\t\t\t.lineTo(i*spriteSize @ spriteSize)\r\n\t\t\t\t\t.lineTo(i*spriteSize @ (15*spriteSize/16))\r\n\t\t\t\t\t.quadCurveTo(spriteSize/2 @ (spriteSize/4.neg), spriteSize/2 @ (spriteSize*ratio))\r\n\t\t\t\t\t.fillColor_(Color.grey(0.3))\r\n\t\t\t\t\t.fill\r\n\t\t\t\t});\r\n\r\n\t\t\t\t//decor\r\n\t\t\t\tnumLines.do({\r\n\t\t\t\t\targ i;\r\n\t\t\t\t\tPen\r\n\t\t\t\t\t.line(spriteSize/numLines*(i+0.5) @ spriteSize, spriteSize/numLines*(i+0.5) @ (7*spriteSize/10))\r\n\t\t\t\t\t.strokeColor_(Color.grey)\r\n\t\t\t\t\t.width_(spriteSize/18)\r\n\t\t\t\t\t.stroke\r\n\t\t\t\t});\r\n\t\t\t});\r\n\r\n\t\t\t~flashAlpha = ~flashAlpha - (0.1);\r\n\r\n\r\n\t\t\t//cannon flash\r\n\t\t\t2.do({\r\n\t\t\t\targ i;\r\n\t\t\t\t~flashSize = exprand(spriteSize/12.0, spriteSize/24.0);\r\n\t\t\t\tPen\r\n\t\t\t\t.addOval(~flashRect = Rect.aboutPoint(((i*spriteSize)+[(cannonWidth/2),(cannonWidth/2).neg].at(i))@((0.6*spriteSize)-(~flashSize)), ~flashSize, ~flashSize*1.5) )\r\n\t\t\t\t.color_(Color.cyan(1.8, ~flashAlpha))\r\n\t\t\t\t.fillAxialGradient(((i*spriteSize)+[(cannonWidth/2),(cannonWidth/2).neg].at(i))@(cannonLength), ((i*spriteSize)+[(cannonWidth/2),(cannonWidth/2).neg].at(i))@(cannonLength-(~flashSize*2)),Color.white.alpha_(~flashAlpha), Color.cyan(1,0.5*~flashAlpha));\r\n\t\t\t});\r\n\r\n\t\t\tPen.use({\r\n\r\n\t\t\t\t//body\r\n\t\t\t\t2.do({\r\n\t\t\t\t\targ i;\r\n\t\t\t\t\tPen\r\n\t\t\t\t\t.moveTo((spriteSize/2) @ 0)\r\n\t\t\t\t\t.quadCurveTo(spriteSize/2 @ (spriteSize), spriteSize/4+(i*spriteSize/2) @ (spriteSize/2))\r\n\t\t\t\t\t.width_(spriteSize/36)\r\n\t\t\t\t\t.fillAxialGradient(spriteSize/2 @ 0, spriteSize/2 @ spriteSize, Color.grey(0.6), Color.grey(0.3))\r\n\t\t\t\t});\r\n\r\n\t\t\t\t//jet\r\n\r\n\t\t\t\tPen\r\n\t\t\t\t.addRoundedRect(~jetRect = Rect.aboutPoint(spriteSize/2 @ (0.9*spriteSize), spriteSize/15, spriteSize/8), ~jetRect.width/2, ~jetRect.height/4)\r\n\t\t\t\t.fillAxialGradient(~jetRect.left@(~jetRect.height/2), ~jetRect.right@(~jetRect.height/2), Color.grey(0.7), Color.grey(0.5));\r\n\r\n\r\n\t\t\t\t//cockpit\r\n\t\t\t\tPen.addOval(Rect(spriteSize-cockpitW/2, (0.4*spriteSize), cockpitW, cockpitH))\r\n\t\t\t\t.fillAxialGradient(spriteSize-cockpitW/2 @ (4*spriteSize/10), spriteSize-(cockpitW/2+cockpitW) @ ((4*spriteSize/10)+cockpitH), Color.white, Color.cyan(0.5))\r\n\t\t\t\t.strokeColor_(Color.grey(0.7))\r\n\t\t\t\t.width_(2)\r\n\t\t\t\t.stroke;\r\n\t\t\t});\r\n\t\t});\r\n\t};\r\n\r\n\t~playerExplodeDraw = {\r\n\t\tplayerRect.do{\r\n\t\t\targ inval;\r\n\t\t\t50.do{\r\n\t\t\t\tvar delta = spriteSize.rand;\r\n\t\t\t\tvar rect = Rect.aboutPoint(inval.center, delta, delta);\r\n\t\t\t\tvar\r\n\t\t\t\ttopLeft = rrand(rect.left, rect.center.x) @ rrand(rect.top, rect.center.y),\r\n\t\t\t\ttopRight = rrand(rect.right, rect.center.x) @ rrand(rect.top, rect.center.y),\r\n\t\t\t\tbottomRight = rrand(rect.right, rect.center.x) @ rrand(rect.bottom, rect.center.y),\r\n\t\t\t\tbottomLeft = rrand(rect.left, rect.center.x) @ rrand(rect.bottom, rect.center.y);\r\n\t\t\t\tPen.moveTo(topLeft)\r\n\t\t\t\t.quadCurveTo(topRight, rect.center)\r\n\t\t\t\t.quadCurveTo(bottomRight, rect.center)\r\n\t\t\t\t.quadCurveTo(bottomLeft, rect.center)\r\n\t\t\t\t.quadCurveTo(topLeft, rect.center)\r\n\t\t\t\t.fillRadialGradient(rect.center, rect.center, 1, spriteSize/2, Color.red, Color.yellow);\r\n\t\t\t};\r\n\t\t};\r\n\t};\r\n\r\n\r\n/////////////////////////////Views\r\n\r\n\thud = UserView(win, hudRect)\r\n\t.background_(Color.grey(0.9))\r\n\t.drawFunc_{\r\n\t\tvar bounds = Rect(0,0,hudRect.width, hudRect.height);\r\n\t\tPen.addRect(bounds)\r\n\t\t.fillAxialGradient(\r\n\t\t\tbounds.center.x@(bounds.height*0.8),\r\n\t\t\tbounds.center.x@(bounds.bottom),\r\n\t\t\tColor.clear,\r\n\t\t\tColor.black\r\n\t\t)\r\n\t};\r\n\r\n\tscoreView = StaticText(hud, Rect(0,0,hud.bounds.width,hud.bounds.height))\r\n\t.string_(\"Score: \"++score).font_(Font(\"Futura\", 18)).stringColor_(Color.black).align_(\\center);\r\n\r\n\tlivesView = UserView(hud, Rect(hud.bounds.height/10, hud.bounds.height/10, 3.2*hud.bounds.height, 0.8*hud.bounds.height))\r\n\t.drawFunc_{\r\n\t\tnumLives.do{\r\n\t\t\targ i;\r\n\t\t\tvar rect = Rect(0, 0, 0.8*livesView.bounds.height, 0.8*livesView.bounds.height);\r\n\t\tvar cockpitH = rect.width/3, cockpitW = rect.width/7;\r\n\t\tvar numLines = 4;\r\n\r\n\t\t\tPen.translate(livesView.bounds.height, 0);\r\n\r\n\t\t//movement\r\n\r\n\t\t//draw\r\n\r\n\t\t\t//cannons\r\n\t\t\t2.do({\r\n\t\t\t\targ i;\r\n\t\t\t\tPen\r\n\t\t\t\t.line(((i*rect.width)+[(cannonWidth/2),(cannonWidth/2).neg].at(i))  @ rect.width, ((i*rect.width)+[(cannonWidth/2),(cannonWidth/2).neg].at(i)) @ (0.6*rect.height))\r\n\t\t\t\t.strokeColor_(Color.grey)\r\n\t\t\t\t.width_(cannonWidth)\r\n\t\t\t\t.stroke\r\n\t\t\t});\r\n\r\n\t\t\t//wings\r\n\r\n\t\t\tPen.use({\r\n\t\t\t\t2.do({\r\n\t\t\t\t\targ i;\r\n\t\t\t\t\tvar ratio = (5/8);\r\n\t\t\t\t\tPen\r\n\t\t\t\t\t.moveTo(rect.width/2 @ (0.875*rect.width))\r\n\t\t\t\t\t.lineTo(i*rect.width @ rect.width)\r\n\t\t\t\t\t.lineTo(i*rect.width @ (15*rect.width/16))\r\n\t\t\t\t\t.quadCurveTo(rect.width/2 @ (rect.width/4.neg), rect.width/2 @ (rect.width*ratio))\r\n\t\t\t\t\t.fillColor_(Color.grey(0.3))\r\n\t\t\t\t\t.fill\r\n\t\t\t\t});\r\n\r\n\t\t\t\t//decor\r\n\t\t\t\tnumLines.do({\r\n\t\t\t\t\targ i;\r\n\t\t\t\t\tPen\r\n\t\t\t\t\t.line(rect.width/numLines*(i+0.5) @ rect.width, rect.width/numLines*(i+0.5) @ (7*rect.width/10))\r\n\t\t\t\t\t.strokeColor_(Color.grey)\r\n\t\t\t\t\t.width_(rect.width/18)\r\n\t\t\t\t\t.stroke\r\n\t\t\t\t});\r\n\t\t\t});\r\n\r\n\t\t\tPen.use({\r\n\r\n\t\t\t\t//body\r\n\t\t\t\t2.do({\r\n\t\t\t\t\targ i;\r\n\t\t\t\t\tPen\r\n\t\t\t\t\t.moveTo((rect.width/2) @ 0)\r\n\t\t\t\t\t.quadCurveTo(rect.width/2 @ (rect.width), rect.width/4+(i*rect.width/2) @ (rect.width/2))\r\n\t\t\t\t\t.width_(rect.width/36)\r\n\t\t\t\t\t.fillAxialGradient(rect.width/2 @ 0, rect.width/2 @ rect.width, Color.grey(0.6), Color.grey(0.3))\r\n\t\t\t\t});\r\n\r\n\t\t\t\t//jet\r\n\r\n\t\t\t\tPen\r\n\t\t\t\t.addRoundedRect(~jetRect = Rect.aboutPoint(rect.width/2 @ (0.9*rect.width), rect.width/15, rect.width/8), ~jetRect.width/2, ~jetRect.height/4)\r\n\t\t\t\t.fillAxialGradient(~jetRect.left@(~jetRect.height/2), ~jetRect.right@(~jetRect.height/2), Color.grey(0.7), Color.grey(0.5));\r\n\r\n\r\n\t\t\t\t//cockpit\r\n\t\t\t\tPen.addOval(Rect(rect.width-cockpitW/2, (0.4*rect.width), cockpitW, cockpitH))\r\n\t\t\t\t.fillAxialGradient(rect.width-cockpitW/2 @ (4*rect.width/10), rect.width-(cockpitW/2+cockpitW) @ ((4*rect.width/10)+cockpitH), Color.white, Color.cyan(0.5))\r\n\t\t\t\t.strokeColor_(Color.grey(0.7))\r\n\t\t\t\t.width_(2)\r\n\t\t\t\t.stroke;\r\n\t\t\t});\r\n\t\t};\r\n\t\t\t};\r\n\r\n/*\tboostView = UserView(hud, Rect(50*hud.bounds.height/10, 2*hud.bounds.height/10, hud.bounds.height*6, 0.4*hud.bounds.height))\r\n\t.drawFunc_{\r\n\t\tvar width=2;\r\n\t\t//Outline\r\n\t\tPen\r\n\t\t.strokeColor_(Color.black)\r\n\t\t.fillColor_(Color.cyan)\r\n\t\t.fillRect(Rect(0,0,boostFuel*boostView.bounds.width, boostView.bounds.height).insetAll(width, width, width, width))\r\n\t\t.strokeRect(Rect(0,0,boostView.bounds.width, boostView.bounds.height).insetAll(width/2, width/2, width/2, width/2));\r\n\t}\r\n\t.background_(Color.grey(0.5));*/\r\n\r\n\tfork{loop{k = enemyArray.choose; alienLaserArray = alienLaserArray.add(k); Synth(\\laser2, [\\pan, k.left.linlin(radius, winW-spriteSize, -1, 1)]); rrand(1.0,0.2).wait;}};\r\n\r\n\r\n\t~laserView = UserView.new(board, win.view.bounds)\r\n\t.animate_(true)\r\n\t.drawFunc_({\r\n\t\tvar collisions;\r\n\t\talienLaserArray = alienLaserArray.select({\r\n\t\t\t\targ rect;\r\n\t\t\t\tboard.bounds.intersects(rect);\r\n\t\t\t});\r\n\t\tlaserArray = laserArray.select({\r\n\t\t\targ rect;\r\n\t\t\tboard.bounds.intersects(rect);\r\n\t\t});\r\n\t\tcollisions=laserArray.collect{\r\n\t\t\targ inval;\r\n\t\t\tenemyArray.select({\r\n\t\t\t\targ enemy;\r\n\t\t\t\tenemy.intersects(inval)\r\n\t\t\t});\r\n\t\t}.flat;\r\n\t\tif (collisions.isEmpty.not, {explosions = explosions.add(collisions).flat; score = score+25; scoreView.string_(\"Score: \"++score); scoreView.refresh; Synth(\\explosion); enemyArray.removeEvery(collisions);});\r\n\t\tlaserArray.do{\r\n\t\t\targ inval;\r\n\t\t\t2.do({\r\n\t\t\t\targ i;\r\n\t\t\t\tPen.line([inval.right-(cannonWidth/2) @ inval.center.y, inval.left+(cannonWidth/2) @ inval.center.y].at(i), [inval.right-(cannonWidth/2) @ (inval.center.y-laserLen), inval.left+(cannonWidth/2) @ (inval.center.y-laserLen)].at(i));\r\n\t\t\t});\r\n\t\t\tPen.width_(cannonWidth).capStyle_(1).color_(Color.cyan).stroke;\r\n\t\t};\r\n\t\tlaserArray.collectInPlace({\r\n\t\t\targ rect;\r\n\t\t\trect.moveBy(0, laserSpeed.neg)\r\n\t\t});\r\n\r\n\t\talienLaserArray.do{\r\n\t\t\t\targ inval;\r\n\t\t\t2.do({\r\n\t\t\t\targ i;\r\n\t\t\t\tPen.line([inval.right-(cannonWidth/2) @ inval.center.y, inval.left+(cannonWidth/2) @ inval.center.y].at(i), [inval.right-(cannonWidth/2) @ (inval.center.y-laserLen), inval.left+(cannonWidth/2) @ (inval.center.y-laserLen)].at(i));\r\n\t\t\t});\r\n\t\t\t\tPen.width_(cannonWidth).capStyle_(1).color_(Color.red).stroke;\r\n\t\t};\r\n\t\talienLaserArray=alienLaserArray.collect({\r\n\t\t\t\targ i;\r\n\t\t\t\ti.moveBy(0, alienLaserSpeed)\r\n\t\t\t\t\t});\r\n\t});\r\n\r\n\r\n\t~playerSprite = UserView(board, win.view.bounds)\r\n\t.animate_(true)\r\n\t.drawFunc_{~playerDraw.value;};\r\n\r\n\t~rot=0;\r\n\t~rotationSpeed = 30;\r\n\t~enemySpriteFx = {loop{~rot = ~rot + ~rotationSpeed; (1/30).wait;}}.fork;\r\n\r\n\t~enemySprites = UserView(board, win.view.bounds)\r\n\t.animate_(true)\r\n\t.drawFunc_({\r\n\r\n\t\tenemyArray = enemyArray.collectInPlace({\r\n\t\t\targ inval;\r\n\t\t\tinval.moveBy(0, enemySpeed);\r\n\t\t});\r\n\r\n\t\tenemyArray = enemyArray.select({\r\n\t\t\targ inval;\r\n\t\t\tboard.bounds.intersects(inval);\r\n\t\t});\r\n\r\n\t\tenemyArray.do{\r\n\t\t\targ inval;\r\n\t\t\tvar num = 12, cockpit = Rect.aboutPoint(inval.center, radius/2, radius/2);\r\n\t\t\tPen.color_(Color.grey);\r\n\t\t\tnum.do{\r\n\t\t\t\targ i;\r\n\t\t\t\tvar outer = rrand(radius, cockpit.height/2), inner = rrand(outer, cockpit.height/2);\r\n\t\t\t\tPen.addAnnularWedge(inval.center, inner, outer, ((360/num)*i+~rot).degrad, (360/num).degrad)\r\n\t\t\t\t.color_(Color.red).fill;\r\n\t\t\t};\r\n\t\t\tPen.addWedge_Deg(inval.center, radius, 315, 270).color_(Color.grey(0.5)).fill;\r\n\t\t\tPen.addOval(cockpit).fillRadialGradient(cockpit.rightTop, cockpit.center, cockpit.height/2, cockpit.height, Color.grey(0.9), Color.grey(0.1));\r\n\t\t};\r\n\t\texplosions.do{\r\n\t\t\targ inval;\r\n\t\t\t50.do{\r\n\t\t\t\tvar delta = spriteSize.rand;\r\n\t\t\t\tvar rect = Rect.aboutPoint(inval.center, delta, delta);\r\n\t\t\t\tvar\r\n\t\t\t\ttopLeft = rrand(rect.left, rect.center.x) @ rrand(rect.top, rect.center.y),\r\n\t\t\t\ttopRight = rrand(rect.right, rect.center.x) @ rrand(rect.top, rect.center.y),\r\n\t\t\t\tbottomRight = rrand(rect.right, rect.center.x) @ rrand(rect.bottom, rect.center.y),\r\n\t\t\t\tbottomLeft = rrand(rect.left, rect.center.x) @ rrand(rect.bottom, rect.center.y);\r\n\t\t\t\tPen.moveTo(topLeft)\r\n\t\t\t\t.quadCurveTo(topRight, rect.center)\r\n\t\t\t\t.quadCurveTo(bottomRight, rect.center)\r\n\t\t\t\t.quadCurveTo(bottomLeft, rect.center)\r\n\t\t\t\t.quadCurveTo(topLeft, rect.center)\r\n\t\t\t\t.fillRadialGradient(rect.center, rect.center, 1, spriteSize/2, Color.red, Color.yellow);\r\n\t\t\t};\r\n\t\t};\r\n\t});\r\n\r\n\r\n\t~fireFunc = {\r\n\t\t{canFire = false;\r\n\t\t\t~laserSynth.value;\r\n\t\t\tlaserArray = laserArray.add(Rect.fromPoints(playerX @ (playerY-laserLen+cannonLength), playerX+spriteSize @ (playerY+spriteSize)));\r\n\t\t\t~flashSize = (spriteSize/24.0);\r\n\t\t\t~flashAlpha = 1.0;\r\n\t\t\t0.2.wait;\r\n\t\t\tcanFire=true;\r\n\t\t}.fork(AppClock)\r\n\t};\r\n\r\n\tView.globalKeyDownAction_({\r\n\t\targ view, char, mod, uni, keycode;\r\n\t\tcase\r\n\t\t{keycode == keycodes[0]} {playerDir.add(\\left);}\r\n\t\t{keycode == keycodes[1]} {playerDir.add(\\right);}\r\n\t\t{keycode == keycodes[2]} {playerDir.add(\\down);}\r\n\t\t{keycode == keycodes[3]} {playerDir.add(\\up);}\r\n\t\t{keycode == keycodes[4] && canFire==true} {~fireFunc.value}\r\n\t\t// {mod.isShift} {playerSpeed = 16}\r\n\t\t{uni == 27} {win.close};\r\n\t});\r\n\tView.globalKeyUpAction_({\r\n\t\targ view, char, mod, uni, keycode;\r\n\t\tcase\r\n\t\t{keycode == keycodes[0]} {playerDir.remove(\\left);}\r\n\t\t{keycode == keycodes[1]} {playerDir.remove(\\right);}\r\n\t\t{keycode == keycodes[2]} {playerDir.remove(\\down);}\r\n\t\t{keycode == keycodes[3]} {playerDir.remove(\\up);}\r\n\t\t{keycode == keycodes[4]} {}\r\n\t});\r\n\r\n\t~enemySpawn = fork {\r\n\t\tloop { var x = rrand(winW-spriteSize, spriteSize);\r\n\t\t\tenemyArray = enemyArray.add(Rect.aboutPoint(x@0,radius, radius));\r\n\t\t\t~alienSynth.value;\r\n\t\t\trrand(2.0,0.5).wait;\r\n\t\t}\r\n\t};\r\n\r\n\t~explosionClear = {if (explosions.isEmpty.not, {0.2.wait; explosions.removeAt(0)})};\r\n\r\n\t~playerDeath =\r\n\t{\r\n\t\t~playerSprite.drawFunc_(~playerExplodeDraw);\r\n\t\tnumLives = numLives - 1;\r\n\t\t0.2.wait;\r\n\t\tlivesView.refresh;\r\n\r\n\r\n\t\tcase\r\n\t\t{numLives == 1.neg} {~playerSprite.remove;\r\n\t\t\tplayerRect = Rect(-1000,-1000,0,0);\r\n\t\t\tView.globalKeyDownAction_{arg view, char, mod, uni, keycode;\r\n\t\tcase {uni == 27} {win.close};};\r\n\t\t\tView.globalKeyUpAction_{nil};\r\n\t\t\tg = UserView(board, win.view.bounds)\r\n\t\t\t.background_(Color.red(1.0,0.2));\r\n\t\t\tStaticText(g, g.bounds).font_(Font(\"Futura\", 30)).align_(\\center).stringColor_(Color.white).string_(\"GAME OVER\");\r\n\t\t\tStaticText(g, g.bounds.moveBy(0, 30)).font_(Font(\"Futura\", 30)).align_(\\center).stringColor_(Color.white).string_(\"Highscore: \"++~highScore);\r\n\t\t}\r\n\r\n\t\t{numLives >= 0} {\r\n\t\t\tif (numLives == 0, {Synth(\\red)});\r\n\t\t\tplayerX=board.bounds.width/2-(spriteSize/2);\r\n\t\t\tplayerY=board.bounds.height-(spriteSize*2);\r\n\t\tplayerRect=Rect(playerX, playerY, spriteSize, spriteSize);\r\n\t\t~playerSprite.drawFunc_(~playerDraw);\r\n\t\t1.wait;\r\n\t\t\tplayerState=\\alive;}\r\n\t};\r\n\r\n\r\n\t~playerCollisionTest =\r\n\tfork{\r\n\t\tloop{\r\n\t\t\tc = (enemyArray++alienLaserArray).collect{\r\n\t\t\t\targ hazard;\r\n\t\t\t\thazard.intersects(playerRect);\r\n\t\t\t};\r\n\t\t\t~explosionClear.value;\r\n\t\t\tif (c.includesEqual(true) && playerState==\\alive, {playerState=\\dead; ~explosionSynth.value; ~playerDeath.fork(AppClock)});\r\n\t\t\t~highScore=score;\r\n\t\t\t(1/60).wait;\r\n\t\t}\r\n\t};\r\n\r\n\r\n\twin.refresh;\r\n});\r\n)",
   "is_private" : null,
   "id" : "1-5gm",
   "labels" : [
      "gui",
      "game",
      "arcade"
   ],
   "description" : "Top-down space shooter for SuperCollider. It is probably too easy but (I think) it is still fun.",
   "ancestor_list" : [],
   "name" : "Space Game",
   "author" : "mjsyts"
}
