_='Q=150;S=T=C=N=7]=9]=0;r=Math.random;X=21;DStyle="#"+d;Rect(LRDOP122dc2c3ccccc".subst@3*((s-1)Z3GG24GQDO2c4"U,132,231,3^H`+"jjj00P1"[iXiZP7iTextOx"+s+" Score: "+S,8,145{)qk+9$kQ U* ,3,9JqHY)|0]D(+q9]?"fP":"333"U*$k9<.t++)}}LW!dzJdz=eLVv=d+d.w>=ed<=e+e.wLsetIntervalO1<T||2E3<STJ1>NW(GA1|38Yy:0|-5Yg:@).toString(2)}N=(7-s)/2+5Y)|0++,21<,S-=s)N--}TX-=7]-9],X=1>X?1:37<X?37:X2]1>CW(1,AX+1,y:20}C=7 ||!iJ --,0> )J k=Q;kKXB: 3},B)|vKAP7B: 9},6})|vJi?(=,.t=G, ,S+=2*s):(,S-=H*s)}^6`S<[5G1H,333UH,1E3,1E9][i]s=1+iT=++T%3;C--;R()",HFdown1LFup0}=function(d,{c[i+^Q`2z]DOfff"U*c[i]=[]._/5|03,3 Q]A6*fo@--;)+3*(c[k]&&if(;break}a[d.which]=);,w:a.fill),10.x.ya[3(e,f,g,h)k=;k+$kZ6Yr(A{x:B15}Fb.onkeyG0,H25J){KV(!i?L};O("P11U,6Y*@Z%5^i=`;ij00q.g[z*Q]';for(Y=0;$='zqj`^ZYUPOLKJHGFBA@$ '[Y++];)with(_.split($))_=join(pop());eval(_)
//Set up some vars
//We use some of the given vars to host arrays too.
Q = 150;
S = T = C = N = a[37] = a[39] = 0;
r = Math.random;
X = 21;
//Draw function
//Combines setting the colour and drawing a rectangle
D = function (d, e, f, g, h) {
a.fillStyle = "#" + d;
a.fillRect(e, f, g, h)
};
//Render function
R = function (d, e, f, g, h) {
D("11122dc2c3ccccc".substr(3 * ((s - 1) % 5), 3), 0, 0, 240, Q); //Draw the BG
D("2c4", 6, 132, 231, 3); //Green ground line
//The below line draws the player's tank.
//The binary string isn't long enough to benefit from bit shifting, I think. Unlike in my Pipe Dream demo.
for (i = 25; i--;) + "0010001010001000111010101"[i] && D("fff", 6 * X + 3 * (i % 5), 117 + 3 * (i / 5 | 0), 3, 3);
a.fillText("x" + s + " Score: " + S, 8, 145); //Draws level and score
for (i = Q; i--;) { //As our asteroids, laser shots and explosions are in the same array, we only need one array iteration loop
//Draw the asteroids - Only draw a rect if its binary string at the current point is equal to one.
if (c[i]) for (k = 10; k--;) + c[i].g[k + 9] && D("fff", 6 * c[i].x + 3 * (k % 5), 6 * c[i].y + 3 * (k / 5 | 0), 3, 3);
c[i + Q] && D("fff", 6 * c[i + Q].x, 6 * c[i + Q].y, 3, 9); //Lasers
if (c[i + 2 * Q]) { //Draw explosions
//Similar to the asteroid drawing code. A random number is used per point for visibility and if the binary string equals one at [9] then it's drawn as red instead of grey
for (k = 10; k--;) + c[i + 2 * Q].g[25 * r() | 0] && D(+c[i + 2 * Q].g[9] ? "f11" : "333", 6 * c[i + 2 * Q].x + 3 * (k % 5), 6 * c[i + 2 * Q].y + 3 * (k / 5 | 0), 3, 3);
9 < c[i + 2 * Q].t++ && (c[i + 2 * Q] = []._) //Counter used to kill explosion after a few frames
}
}
};
//Used when creating a new block, laser shot or explosion, so find the next empty array space
W = function (d, e, f, g, h) {
for (i = Q; i--;) if (!c[i + d * Q]) {
c[i + d * Q] = e;
break
}
};
//Collision detection
//We only do 1D detection as it crushes better this way
V = function (d, e, f, g, h) {
v = d.x + d.w >= e.x && d.x <= e.x + e.w
};
//Game logic
setInterval("
if (1 < T || 2E3 < S && T) { //On the second tick, or first if the score is over 2000...
1 > N && (W(0, { //If the new asteroid tick is 0, add a new asteroid
x: 1 | 38 * r(),
y: 0 | -5 * r(),
g: r().toString(2) //This binary string is for its appearance
}), N = (7 - s) / 2 + 5 * r() | 0); //Set the new asteroid tick to a value based on the level
for (i = Q; i--;) c[i] && (c[i].y++, 21 < c[i].y && (c[i] = []._, S -= s)); //If an asteroid has hit the ground, destroy it and decrease the score
N-- //Decrease the new asteroid tick.
}
T && (X -= a[37] - a[39], X = 1 > X ? 1 : 37 < X ? 37 : X); //If the player can move on this tick, do so and make sure the tanks says in the area
a[32] && 1 > C && (W(1, { //If the player is firing and there is a free projectile to shoot, fire it from the tanks position.
x: X + 1,
y: 20
}), C = 7); //No free projectile for 7 frames
for (i = Q; i--;) if (c[i + Q] || !i) { //Loop through the array, as long as the laser shot is active or the player
if (c[i + Q] && (c[i + Q].y--, 0 > c[i + Q].y)) { //Move the laser up
c[i + Q] = []._; //And destroy it if goes off the top of the screen
break
}
for (k = Q; k--;) if (c[k] && V(!i ? { //This visual mess is the collision detection check
x: 6 * X, //If i is currently 0, then check the asteroid (k) against the player
w: 15
} : {
x: 6 * c[i + Q].x, //If it's not 0 then check against the laser shot
w: 3
}, {
x: 6 * c[k].x, //This is the astroid we're checking against
w: 15
}) | v && V(!i ? { //And to help crushing we have to call V twice
x: 117,
w: 15
} : {
x: 6 * c[i + Q].y,
w: 9
}, {
x: 6 * c[k].y,
w: 6
}) | v) {
//If there is a collision destroy things, change the score and maybe make an explosion
i ? (c[i + 2 * Q] = c[k], c[i + 2 * Q].t = 0, c[k] = []._, c[i + Q] = []._, S += 2 * s) : (c[k] = []._, S -= 25 * s);
break
}
}
for (i = 6; i--;) S < [50, 125, 333, 625, 1E3, 1E9][i] && (s = 1 + i); //Use the score to find the correct level
T = ++T % 3; //Game logic tick
C--; //Decrease laser tick
R() //Render!
", 25);
//Handle key presses
//As you may have noticed all the function take the same amount of parameters to help crushing
b.onkeydown = function (d, e, f, g, h) {
a[d.which] = 1
};
b.onkeyup = function (d, e, f, g, h) {
a[d.which] = 0
}
/*Things that help with minification:
https://github.com/jed/140bytes/wiki/Byte-saving-techniques
Picking apart other peoples demos!
Time, experience and sleeping
P.S. Sorry if anyone preferred my Pipe Dream demo over this one.*/