Elemental Master game in less than 1K of Javascript
I had some hours free and I wanted to code a nice game for
the newest edition of the JS1K contest, for
2016 the theme was Elemental. So I went and code
Elemental Master.
The corrected version can be played here (post-contest):
Elemental Master.
The purpose of this game is to catch yellow atoms and avoid
red ones while moving in a fast lane tunnel-like, inspired by old vectorial
games.
As always I worked hard in this one, unfortunately I
introduced a bug in the last optimization pass making it non-playable
in mobile phones (I forgot to change width to W). Probably this alone prevented
me getting into the top 10. (more recently I discovered it only works well
in iPhone and it's slow in Android phones)
The usage is easy: use arrows to move left and right and in
mobile phones press over half-left of screen to move left, and press over
half-right to move right.
Source code
Note that the JS1K "provides" some variables loaded with important data, similar to this:
<canvas id="c">
</canvas><script>
var c=document.getElementById("c");
var a=c.getContext("2d");
</script>
<script src="elemental-master.js">
</script>
Here is my original (and fixed) commented source code,
note the source code is compressed for JS1K using
@aivopass JS compressor
available at
http://www.iteral.com/jscrush/
// Elemental master (Mar/13/2016) by Oscar Toledo G. http://nanochess.org/
// Catch the yellow atoms, don't touch the red ones.
// Use keyboard or touch your screen.
// Size
W = a.width / 2,
H = a.height / 2,
Z = W > H ? H : W,
// Coming elements, lifes / difficulty
O = [{t:2,d:L=R=1}],
// Time for next one
Q = new Date().valueOf() + 1e3,
// Score
S = 0,
// Start angle
G = 4,
// Keys
K = [];
// Compression of <canvas> function names
for(M in c)c[M[0]+(M[6]||M[2])]=c[M];
onkeydown = function(w){K[w.which-37] = 1};
a.addEventListener("touchstart", function(w){K[w.touches[0].clientX<W?0:2]=1}, 0);
setInterval(function(w){
with (Math) {
P = PI / 18;
with(c){
sv(),
// Clear canvas
fc(0, 0, W*2, H*2),
// Show score
strokeStyle = shadowColor = "#0f0",
shadowBlur = 5,
lineCap = "round",
sT("Score: " + S, 16, 16),
// Prepare rotated canvas
ta(W, H),
rt(G * P - P * 4.5),
sa(Z, Z * .8),
// Draw border
U = new Date().valueOf(),
strokeStyle = "#" + (999 - U / 250 % 900 | 0),
i = .3 + U / 2e3 % .1;
while (i < 1)
lineWidth = 4 * i / Z,
ba(),
ac(0, 0, i, 0, P * 36),
sr(),
i += i / 4;
// Draw perspective lines
ba(),
lineWidth = 2 / Z,
i = P * 27;
while (i < P * 46)
mv(0, 0),
ln(sin(i), cos(i)),
i += P * 2;
sr(),
// Move player
K[0] && G && --G,
K[2] && G < 9 && ++G,
K[0] = K[2] = 0,
// Draw atoms
O[0].x = G,
j = O.length;
while (j-- > (L > 3))
fillStyle = "#f00#ff0#08f".substr(O[j].t * 4, 4),
i = O[j].x * P * 2 + P * 27,
ba(),
ac(sin(i) / O[j].d, cos(i) / O[j].d, 25 / Z / (j ? O[j].d : L), 0, P * 36),
fl(),
j && (O[j].d -= (U - T) / 60) < 1 && (
O[j].x == G & L < 3.5 ? O[j].t ? S++ : (L += .5) : 0, O.splice(j, 1));
re(),
T = U,
// Add new atoms
Q < T &&
(Q = T + random() * (L < 3.5 ? 1e3 / R : 100),
O[O.length] = {x: random() * 10 | 0, d: 25, t: random() > .7 | 0},
R += 1e-4);
}}
}, 15);