{ Deutsch | English }

Snake − LX

Source Code

For this game a little XSS is used. It uses background colors of table cells, so if some values are changed here they also have to be changed in the code.
In the CSS part the background color of the snake's container and the size of one table cell is defined:
<STYLE type="text/css"> td { height:15px; width:15px; background-color:#87AC3B; } </STYLE>
So one cell ist 15×15 pixels. Now to the actual script. At first the usual global variable declarations. A counter variable
<SCRIPT type="text/javascript"> var i;
the direction the snake is heading
Richtung = '+1';
a variable to block further key presses
var block = 0;
if the game is over or not
var zuEnde = 0;
the cell currently worked on
var Zelle;
var Countdown = 3;
for a fruit
var Leckerli;
current level
var Level = 0;
amount of fruits that still have to be eaten
var Fruechte;
additional variables
var blah, fnord = false;
the snake
var Snake = new Array();
head of the snake
var Kopf;
The following function is called when a key is pressed. It changes the Richtung variable if a certain cursor key is pressed.
function Tastendruck(Druck) { if (document.all) k = window.event.keyCode; else k = Druck.which; if (k == 37 && !block && Richtung != '+1') { Richtung = '-1'; block = 1; } if (k == 38 && !block && Richtung != '+20') { Richtung = '-20'; block = 1; } if (k == 39 && !block && Richtung != '-1') { Richtung = '+1'; block = 1; } if (k == 40 && !block && Richtung != '-20') { Richtung = '+20'; block = 1; } }
Following are some arrays containing images that are shown on screen at certain times. Among them are the countdown numbers (C1 to C3), the smiley when you beat a level, a sad smiley when you lost the game and 2 more smileys which create an animated cheering smiley if you beat the whole game. I leave out the values for those arrays here, they can be found in the source code of the game itself or you can create your own images.
var C3 = [...]; var C2 = [...]; var C1 = [...]; var Smiley = [...]; var Frowny = [...]; var Jubel1 = [...]; var Jubel2 = [...];
Afterwards the arrays for the different levels.
var Wall0 = []; var noFruit0 = []; var Wall1 = [...]; var noFruit1 = [...]; var Wall2 = [...]; var noFruit2 = [...]; . . . var Wall13 = [...]; var noFruit13 = [...]; var Wall14 = [...]; var noFruit14 = [...];
The following function is called when a game is started.
function Start() {
At first the New Game button is hidden and the number of the current level is printed out. Also block is set to 1 to block key presses.
document.getElementById('nG').style.visibility = 'hidden'; document.getElementById('Level').firstChild.nodeValue = 'Level ' + (Level + 1); block = 1;
If the Countdown variable contains a value and at the same time fnord==0 (i.e. if the game is not paused) the the countdown decrements. The screen is cleared (call of reset()), the current value of Countdown is displayed and the variable decremented by 1. Afterwards Start() is called again after 1 second.
if (Countdown && !fnord) { reset(); for (i = 0; i < eval('C' + Countdown).length; i++) { Zelle = 'Zelle' + eval('C' + Countdown)[i]; document.getElementById(Zelle).style.backgroundColor = 'black'; } Countdown--; setTimeout("Start()", 1000); }
Is the countdown however at 0 the actual level is started. The screen is also cleared and the number of fruits to collect is set to 10
else if (!fnord) { reset(); Fruechte = 10; document.getElementById('frucht').value = Fruechte;
The Snake[] array is cleared and the position of the snake and its head on the field is written in the corresponding variables.
while (Snake[0]) Snake.pop(); Snake.push(198, 199, 200, 201, 202, 203, 204, 205, 206); Kopf = 206;
The key lock is revoked, the direction of the snake's movement after the beginning is set, a new fruit is generated (with Happen()), the obstacles of the current level are drawn (with Hindernisse()), the Pause button is hidden and the game flow function is called.
block = 0; zuEnde = 0; Richtung = '+1'; Happen(); Hindernisse(); document.getElementById('pause').style.visibility = 'hidden'; Verlauf(); } }
Function Pause() is used to stop the game between levels. It uses the variable fnord which is checked as seen in the Start() function. Is this variable 1 the game is paused, otherwise it continues. Also the Pause button is labelled correspondingly. After every click on the Pause button Countdown is reset to 3.
function Pause() { fnord = !fnord; if (fnord) document.getElementById('pause').value = "Weiter"; else document.getElementById('pause').value = "Pause"; Countdown = 3; Start(); }
Happen() creates a fruit. Since the playing field has 220 cells a random number between 0 and 219 is generated. Afterwards it's checked if the cell with that number is blocked by a part of the snake's body, by a wall or by an area in which no fruit is allowed because the snake couldn't reach it. If one of those cases is met the function is called again, if not the cell of the fruit is colored red.
function Happen() { Leckerli = Math.floor((Math.random() * 1000) % 220); for (i = 0; i < Snake.length; i++) { if (Leckerli == Snake[i]) Happen(); } for (i = 0; i < eval('Wall' + Level).length; i++) { if (Leckerli == eval('Wall' + Level)[i]) Happen(); } for (i = 0; i < eval('noFruit' + Level).length; i++) { if (Leckerli == eval('noFruit' + Level)[i]) Happen(); } document.getElementById('Zelle' + Leckerli).style.backgroundColor = 'red'; }
Hindernisse() colors the cells of the Wall[] array grey.
function Hindernisse() { for (i = 0; i < eval('Wall' + Level).length; i++) { document.getElementById('Zelle' + eval('Wall' + Level)[i]).style.backgroundColor = '#444444'; } }
Now we come to the heart of the game: the game flow function. It is responsible for the cycles of the game. The snake should always be in motion and the most important events are checked.
function Verlauf() {
At first the position of the snake's head after the next movement is calculated by adding the value of Richtung to Kopf. Afterwards it's checked whether the head is still in the container or if it hit a wall. It's also checked if the snake bit its own tail and finally if it hit an obstacle.
Kopf = eval(Kopf + Richtung); if (Kopf < 0 || Kopf > 219 || (!(Kopf%20) && Richtung == '+1') || (!((Kopf+1)%20) && Richtung == '-1')) zuEnde = 1; for (i = 1; i < Snake.length; i++) { if (Kopf == Snake[i]) zuEnde = 1; } for (i = 0; i < eval('Wall' + Level).length; i++) { if (Kopf == eval('Wall' + Level)[i]) zuEnde = 1; }
If none of those cases is met it's checked if the snake just ate a fruit. If not, the first element of Snake[] is removed and the head is added as the last element (the snake practically moved one cell). If the fruit was eaten the number of fruits to collect is decremented and the head is added to Snake[] without cutting its tail (the snake grows by one cell with each eaten fruit). Finally a new fruit is created.
if (!zuEnde) { if (Kopf != Leckerli) { blah = Snake.shift(); Snake.push(Kopf); } else { Fruechte--; document.getElementById('frucht').value = Fruechte; Snake.push(Kopf); Happen(); }
Of course the snake has to be drawn...
Now it's checked if there are more fruits to collect. If so the key lock is revoked for the next move and the function is called again after 300 milliseconds (so the snake makes a little more than 3 movements per second).
if (Fruechte) { block = 0; setTimeout("Verlauf()",300); }
However if all needed fruits were already eaten the smiley image is drawn, the key lock set and the level number incremented. If the 15th level is beaten the cheering animation is started, if not the Countdown is set to 3 and the Start() function is called.
else { Smiley_malen(); block = 1; Level++; if (Level == 15) setTimeout("Jubel(1)",500); else { Countdown = 3; if (!fnord) setTimeout("Start()",2000); } } }
This branch is executed if the snake bit a wall, an obstacle or itself. In this case the sad smiley is drawn and the Countdown is reset for another game.
else { setTimeout("Frowny_malen()",500); Countdown = 3; } }
The following function animates the cheering smiley. It consists of 2 Frames which are swapped every 120 milliseconds.
function Jubel(x) { document.getElementById('nG').style.visibility = 'visible'; reset(); if (x) { for (i = 0; i < Jubel1.length; i++) { Zelle = 'Zelle' + Jubel1[i]; document.getElementById(Zelle).style.backgroundColor = 'black'; } } else { for (i = 0; i < Jubel2.length; i++) { Zelle = 'Zelle' + Jubel2[i]; document.getElementById(Zelle).style.backgroundColor = 'black'; } } x++; x %= 2; setTimeout("Jubel("+x+")",150); }
This function draws the smiley. Additionally zuEnde is set to 0 since the current level is finished.
function Smiley_malen() { reset(); document.getElementById('pause').style.visibility = 'visible'; for (i = 0; i < Smiley.length; i++) { Zelle = 'Zelle' + Smiley[i]; document.getElementById(Zelle).style.backgroundColor = 'black'; } zuEnde = 0; }
Here the sad smiley is printed out.
function Frowny_malen() { reset(); document.getElementById('nG').style.visibility = 'visible'; for (i = 0; i < Frowny.length; i++) { Zelle = 'Zelle' + Frowny[i]; document.getElementById(Zelle).style.backgroundColor = 'black'; } }
The following function draws the snake. The cell of the first element of the Snake() array is colored green and the rest of the array is colored black.
function Schlange_malen() { Zelle = 'Zelle' + Snake[0]; document.getElementById(Zelle).style.backgroundColor = '#87AC3B'; for (i = 1; i < Snake.length; i++) { Zelle = 'Zelle' + Snake[i]; document.getElementById(Zelle).style.backgroundColor = 'black'; } }
reset() clears the screen by coloring the cells with the green background color.
function reset() { for (i = 0; i < 220; i++) { Zelle = 'Zelle' + i; document.getElementById(Zelle).style.backgroundColor = '#87AC3B'; } } </SCRIPT>
Now the HTML part of the game. At first we need a text element in which the current level number is written. It doesn't matter much which kind of an element is used here, what matters is the attribute id="Level" by which it is referred to by the functions. I chose the H2 tag because its default formatting fits the purpose of this element.
<H2 id="Level">Level 1</H2>
Also in the BODY you need the check if a key is pressed...
<SCRIPT type="text/javascript"> document.onkeydown = Tastendruck;
... and the playing field is created. This part could be hardcoded but I think this method is more elegant. Therefor counter variables for rows and columns are created and the HTML code is generated. Again the id="" is important here because every cell has to have a unique value, which consists of the word "Zelle" and a consecutive number.
var Zeilen, Spalten; var Index = 0; document.write('<TABLE cellspacing="0" cellpadding="0">'); for (Zeilen = 0; Zeilen &lt; 11; Zeilen++) { document.write('<TR>'); for (Spalten = 0; Spalten &lt; 20; Spalten++) { document.write('<TD id="Zelle' + Index + '"><\/TD>'); Index++; } document.write('<\/TR>'); } document.write('<\/TABLE>'); </SCRIPT>
Also an input field is needed to show the amount of fruits to eat.
<INPUT type="text" id="frucht" value="0" size="3">
Finally 2 buttons: one to start the game and another one to pause between levels. this.blur() in the event handler causes to remove focus from the button after it is pressed. Therefore it can't be hit again by using the space bar after it is hidden via CSS.
<INPUT type="button" id="nG" value="New Game" onClick="this.blur(); Level=0; Start(); "> <INPUT type="button" id="pause" value="Pause" onClick="this.blur(); Pause(); ">