Elemental Master: juego en menos de 1K de Javascript
Tenía algunas horas libres y decidí codificar un juego
agradable para la nueva edición del
concurso JS1K, para el año
2016 el tema fue Elementos. Así que codifiqué
Elemental Master.
La versión corregida puede jugarse aquí (post-concurso):
Elemental Master.
El objetivo del juego es atrapar los átomos amarillos y
evitar los rojos mientras se mueve en una pista rápida parecida a un tunel,
inspirado por juegos vectoriales antiguos.
Como siempre, trabajé duro en este juego, desafortunadamente
metí un error en el último paso de optimización haciendo que no fuera posible
jugarlo en teléfonos móviles (olvidé cambiar width a W). Es muy probable que
esto me impidiera entrar en el top 10. (más reciente descubrí que sólo
funciona bien en iPhones y que es muy lento en Android)
La forma de uso es sencilla: utilice las flechas para
moverse a la izquierda y derecha, y en teléfonos móviles oprima sobre la mitad
izq. de la pantalla para ir a la izquierda, y sobre la mitad der. para ir a la
derecha.
Código fuente
Note que el JS1K "provee" de algunas variables cargadas
con datos importantes, similar a esto:
<canvas id="c">
</canvas><script>
var c=document.getElementById("c");
var a=c.getContext("2d");
</script>
<script src="elemental-master.js">
</script>
Aquí está mi código fuente original (y corregido). Note
que el código fuente está comprimido para el JS1K usando el compresor JS de
@aivopass disponible en
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);