Building a mini snake game in JS is one of these things every webcoder should be able to do. Since I hadn't tackled that "challenge" yet (and mostly because I was bored like hell and wanted to code something without using jQuery for a change), I decided to give it a shot. This is very basic, but it taught me a two interesting things I was unaware of:
Anyway, you can find the result of that one-hour experiment at the following URL:
http://www.manuthommes.be/toolbox/snakejs/
Note: Left/Right arrows to turn.
Quick review of the code now:
function move(){
- it seems that a DIV cannot natively receives the focus, but a simple workaround to cope with this is to give the DIV a tabIndex value
- if you duplicate an array (Array.splice(0)), references are maintained (so as far as I understand, if you modify the original array, the copy will be modified in sync...sounds pretty weird, but I must admit that there was something fishy with the values returned during my initial attempts to clone an array)
Anyway, you can find the result of that one-hour experiment at the following URL:
http://www.manuthommes.be/toolbox/snakejs/
Note: Left/Right arrows to turn.
/* let's define a few variables: the orientation of the snake (0-3), two 2D arrays to store the position of each part of the body (x and y coordinates) and the score */
dir=0;
snake=new Array(new Array());
oldsnake=new Array(new Array());
snake[0][0]=160;
snake[0][1]=120;
score=0;
dir=0;
snake=new Array(new Array());
oldsnake=new Array(new Array());
snake[0][0]=160;
snake[0][1]=120;
score=0;
// main function -> create the board dynamically + the head of the snake
function new_game(){
b=document.createElement("div");
b.id="board";
b.tabIndex="1";
document.getElementsByTagName("body")[0].appendChild(b);
s=document.createElement("div");
s.id="sn_head";
document.getElementById("board").appendChild(s);
addBonus();
function new_game(){
b=document.createElement("div");
b.id="board";
b.tabIndex="1";
document.getElementsByTagName("body")[0].appendChild(b);
s=document.createElement("div");
s.id="sn_head";
document.getElementById("board").appendChild(s);
addBonus();
// here add an event listener on the board
b.addEventListener("keydown",turn ,false);
var tmr=setInterval(function(){
b.addEventListener("keydown",turn ,false);
var tmr=setInterval(function(){
// every 150ms, move the snake
move();
}, 150);
move();
}, 150);
// focus on the board to make sure the user can start playing right away!
b.focus();
}
b.focus();
}
// function invoked when the head of the snake collided with the bonus
// we get random X and Y positions and then create dynamically the object (div)
function addBonus(){
xpos=Math.floor((Math.random()*32))*10;
ypos=Math.floor((Math.random()*24))*10;
s=document.createElement("div");
s.id="bonus";
document.getElementById("board").appendChild(s);
document.getElementById("bonus").style.left=xpos+"px";
document.getElementById("bonus").style.top=ypos+"px";
}
function addBonus(){
xpos=Math.floor((Math.random()*32))*10;
ypos=Math.floor((Math.random()*24))*10;
s=document.createElement("div");
s.id="bonus";
document.getElementById("board").appendChild(s);
document.getElementById("bonus").style.left=xpos+"px";
document.getElementById("bonus").style.top=ypos+"px";
}
function move(){
// in the array oldsnake, we get the position of the head and other body parts BEFORE their position is updated
oldsnake[0][0]=parseInt(document.getElementById("sn_head").style.left);
oldsnake[0][1]=parseInt(document.getElementById("sn_head").style.top);
var allParts=document.getElementsByClassName("snake");
for (var i=1; i<allParts.length; i++) {
oldsnake[i][0]=parseInt(allParts[i-1].style.left);
oldsnake[i][1]=parseInt(allParts[i-1].style.top);
}
oldsnake[0][0]=parseInt(document.getElementById("sn_head").style.left);
oldsnake[0][1]=parseInt(document.getElementById("sn_head").style.top);
var allParts=document.getElementsByClassName("snake");
for (var i=1; i<allParts.length; i++) {
oldsnake[i][0]=parseInt(allParts[i-1].style.left);
oldsnake[i][1]=parseInt(allParts[i-1].style.top);
}
// move the snake either to the left, to the right, up or down depending on the value of variable dir
switch(dir){
case 0: snake[0][0]=snake[0][0]-10;break;
case 1: snake[0][1]=snake[0][1]-10;break;
case 2: snake[0][0]=snake[0][0]+10;break;
case 3: snake[0][1]=snake[0][1]+10;break;
}
switch(dir){
case 0: snake[0][0]=snake[0][0]-10;break;
case 1: snake[0][1]=snake[0][1]-10;break;
case 2: snake[0][0]=snake[0][0]+10;break;
case 3: snake[0][1]=snake[0][1]+10;break;
}
// if the snake hits a border, move it the other side
if(snake[0][0]<0)snake[0][0]=310; if(snake[0][0]>310)snake[0][0]=0;
if(snake[0][1]<0)snake[0][1]=230; if(snake[0][1]>230)snake[0][1]=0;
if(snake[0][0]<0)snake[0][0]=310; if(snake[0][0]>310)snake[0][0]=0;
if(snake[0][1]<0)snake[0][1]=230; if(snake[0][1]>230)snake[0][1]=0;
// update the position of the head
document.getElementById("sn_head").style.left=snake[0][0]+"px";
document.getElementById("sn_head").style.top=snake[0][1]+"px";
document.getElementById("sn_head").style.left=snake[0][0]+"px";
document.getElementById("sn_head").style.top=snake[0][1]+"px";
// collision with the bonus?
testCollision();
testCollision();
// position the body parts:
// body part 1 goes at the position of the OLD head (before it was updated)
// body part 2 goes at the position of the OLD body part 1 (before it was updated)
// ...and so on and so forth until we've moved the whole snake
var allParts=document.getElementsByClassName("snake");
for(var i=1;i<snake.length;i++){
snake[i][0]=oldsnake[i-1][0];
snake[i][1]=oldsnake[i-1][1];
allParts[i-1].style.left=snake[i][0]+"px";
allParts[i-1].style.top=snake[i][1]+"px";
}
}
var allParts=document.getElementsByClassName("snake");
for(var i=1;i<snake.length;i++){
snake[i][0]=oldsnake[i-1][0];
snake[i][1]=oldsnake[i-1][1];
allParts[i-1].style.left=snake[i][0]+"px";
allParts[i-1].style.top=snake[i][1]+"px";
}
}
/* if X/Y of snake head equals X/Y of bonus, the latter is removed, the score is increased, the snake gets bigger and we update the score board */
function testCollision(){
if(snake[0][0]==xpos && snake[0][1]==ypos){
document.getElementById("board").removeChild(document.getElementById("bonus"));
addBonus(); score=score+10;
growBody();
document.getElementById("scoreboard").innerHTML="Score: "+score;
}
}
function testCollision(){
if(snake[0][0]==xpos && snake[0][1]==ypos){
document.getElementById("board").removeChild(document.getElementById("bonus"));
addBonus(); score=score+10;
growBody();
document.getElementById("scoreboard").innerHTML="Score: "+score;
}
}
// add a new body part and update the arrays (initialize a new item at the end of the arrays)
function growBody(){
s=document.createElement("div");
s.className="snake";
document.getElementById("board").appendChild(s);
snake[snake.length]=[];
oldsnake[oldsnake.length]=[];
}
function growBody(){
s=document.createElement("div");
s.className="snake";
document.getElementById("board").appendChild(s);
snake[snake.length]=[];
oldsnake[oldsnake.length]=[];
}
// the function called by the event listener
// if key pressed = 37 (left arrow), direction is decreased by 1 (reset to 3 if it's below 0, which would be a value non processed)
// if key pressed = 38 (rightarrow), direction is increased by 1 (reset to 0 if it's greater than 3, which would be a value non processed)
function turn(ev){
if(ev.keyCode==37){
dir-=1;
if(dir<0)dir=3;
}
if(ev.keyCode==39){
dir+=1;
if(dir>3)dir=0;
}
}
if(ev.keyCode==37){
dir-=1;
if(dir<0)dir=3;
}
if(ev.keyCode==39){
dir+=1;
if(dir>3)dir=0;
}
}
To be implemented: collision of the head with the body (basically going through the array of body parts and testing their X/Y coordinates with the ones of the head), potentially decreasing the timer interval when the score gets bigger, fancy stuff...hf :)
Commentaires
Enregistrer un commentaire