Présentation
Snake, de l’anglais signifiant « serpent », est un jeu vidéo populaire créé au milieu des années 1970, disponible de par sa simplicité sur l’ensemble des plate-formes de jeu existantes sous des noms de clone. Il s’est de nouveau fait connaître dans les années 1990 avec l’émergence du nouveau support de jeu qu’est le téléphone portable. Aujourd’hui, il est toujours aussi populaire et est devenu un classique dans les jeux vidéo.
Le joueur contrôle une longue et fine créature semblable à un serpent, qui doit slalomer entre les bords de l’écran et les obstacles qui parsèment le niveau. Pour gagner chacun des niveaux, le joueur doit faire manger à son serpent un certain nombre de pastilles ou de fruits (de la nourriture en général), allongeant à chaque fois la taille de la bestiole. Alors que le serpent avance inexorablement, le joueur ne peut que lui indiquer une direction à suivre (en haut, en bas, à gauche, à droite) afin d’éviter que la tête du serpent ne touche les murs ou son propre corps, dans ce cas il risque de mourir.
Le niveau de difficulté est contrôlé par l’aspect du niveau (simple ou labyrinthique), le nombre de pastilles à manger, l’allongement du serpent et sa vitesse.
Le code Javascript
// variables var canvas, ctx, longueur, angle, compteur, ajouteAnneaux, victoire, vitesse, droite, gauche, snake, pomme, posx, posy, stockAnneaux, timer; var W = 480; var H = 480; // charger les images du jeu var snakeImg = new Image(); var head = new Image(); var pommeImg = new Image(); var fond = new Image(); fond.src = "assets/fond.jpg"; pommeImg.src = "assets/pomme.png"; head.src = "assets/head.png"; snakeImg.src = "assets/anneau.png"; // préparation du jeu window.onload = function() { canvas = document.getElementById('canvas'); ctx = canvas.getContext('2d'); canvas.width = W; canvas.height = H; init(); } // initialisation du jeu function init() { snake = {}; pomme = {}; posx = []; posy = []; stockAnneaux = []; longueur = 5; angle = 0; compteur = 0; ajouteAnneaux = 4; victoire = 140; vitesse = 10; droite = 0; gauche = 0; for (var i=0; i<longueur; i++) { stockAnneaux.push({x:0,y:0,width:snakeImg.width,height:snakeImg.height}) } snake.x = W*.5; snake.y = H*.5; snake.width = head.width; snake.height = head.height; pomme.x = 30+Math.random()*(W-60); pomme.y = 30+Math.random()*(H-60); pomme.width = pommeImg.width; pomme.height = pommeImg.height; canvas.setAttribute('tabindex','1'); canvas.focus(); timer = setInterval(main,60); canvas.addEventListener("keydown", appuie, false); canvas.addEventListener("keyup", relache, false); } // gestion clavier function appuie(e){ if (e.keyCode == 39) droite = 1; if (e.keyCode == 37) gauche = 1; } // gestion clavier function relache(e){ if (e.keyCode == 39) droite = 0; if (e.keyCode == 37) gauche = 0; } // boucle principale function main(){ var i; var j; // Direction angle += (parseInt(droite)-parseInt(gauche))*20; // Enregistre la position de la tête posx[0] = snake.x; posy[0] = snake.y // Deplace la tête snake.x += Math.cos(angle*Math.PI/180)*vitesse; snake.y += Math.sin(angle*Math.PI/180)*vitesse; // Envoye le dernier anneau en premier var dernier = longueur-1-compteur++; if (dernier == 0) compteur = 0; stockAnneaux[dernier].x = posx[0]; stockAnneaux[dernier].y = posy[0]; // Déplace les anneaux for (i=longueur-1; i>0; i--) { posx[i] = posx[i-1]; posy[i] = posy[i-1]; } // si la tête touche de la nourriture if (collisions(snake,pomme)) { // ajoute des anneaux for (i=0; i<ajouteAnneaux; i++) { posx[longueur] = posx[longueur-1]; posy[longueur] = posy[longueur-1]; longueur++; stockAnneaux.push({x:0,y:0,width:snakeImg.width,height:snakeImg.height}); } // place la pomme ailleurs pomme.x = 30+Math.random()*(W-60); pomme.y = 30+Math.random()*(H-60); // Repositionne le Snake complet (assure la cohésion) for (i=0; i<longueur; i++) { stockAnneaux[i].x = posx[i]; stockAnneaux[i].y = posy[i]; } compteur = 0; } // Vérifie si la tête touche un bord if (snake.x<0 || snake.x>W || snake.y<0 || snake.y>H) finPartie(); // Vérifie si la tête touche un anneau var point = {x:snake.x+Math.cos(angle*Math.PI/180)*4, y:snake.y+Math.sin(angle*Math.PI/180)*4, width:1, height:1}; for (i =0; i<stockAnneaux.length; i++){ if(collisions(point,stockAnneaux[i])) finPartie(); } // vérifie si le joueur gagne if (longueur>=victoire) gagnePartie(); // dessin final render(); } // collisions function collisions(A,B) { if (A.y+A.height < B.y || A.y > B.y+B.height || A.x > B.x+B.width || A.x+A.width < B.x) return false; return true; } function finPartie(){ alert("Perdu, cliquez pour rejouer."); clearInterval(timer); init(); } function gagnePartie(){ alert("Bravo, cliquez pour rejouer."); clearInterval(timer); init(); } // Dessine le jeu function render() { ctx.drawImage(fond,0,0); ctx.save(); ctx.translate(snake.x + snake.width / 4, snake.y + snake.height / 2); ctx.rotate(angle*Math.PI/180); ctx.drawImage(head,-snake.width/4,-snake.height/2); ctx.translate(-(snake.x + snake.width / 4), -(snake.y + snake.height / 2)); ctx.restore(); for(var i =0; i<stockAnneaux.length;i++){ ctx.drawImage(snakeImg,posx[i],posy[i]); } ctx.drawImage(pommeImg,pomme.x,pomme.y); }
A retenir
L’autre petite chose utile ici c’est la trigonométrie. Pour ceux qui n’en auraient aucune notion, on joue avec des angles et on utilise le sinus et le cosinus de l’angle pour déterminer une direction sur les deux axes (x et y). Il suffit ensuite de multiplier cette direction sur chaque axe par une vitesse donnée et l’objet avance. Attention, dans la plupart des langages de programmation les angles sont exprimés en radians, il nous faut donc opérer une conversion entre les degrés et les radians pour faire nos calculs.
Enfin, dernière petite astuce concernant les graphismes, chaque objet possède un point d’origine ou de pivot, c’est lui qu’on utilise pour placer l’objet, or ce point est la plupart du temps le point situé aux coordonnées 0,0 de l’objet soit son point haut gauche. Afin d’afficher correctement nos objets à l’écran il va nous falloir appliquer une petite correction pour replacer virtuellement ce point au centre de l’objet avant de l’afficher.
test de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lontest de blabla un peu lon
oui ok bla bla oui ok bla bla oui ok bla bla oui ok bla bla oui ok bla bla oui ok bla bla oui ok bla bla oui ok bla bla oui ok bla bla oui ok bla bla oui ok bla bla oui ok bla bla oui ok bla bla oui ok bla bla