UNPKG

voxel-maze

Version:

Creates mazes and translates in voxels

529 lines (408 loc) 17.1 kB
/*------------------------------------------------------------------------------------------------------------------- ADD-ON EXPORT --------------------------------------------------------------------------------------------------------------------*/ module.exports = function(game, opts) { // TODO add some code :D this.game = game this.width = his.opts.width || 5 this.height = this.opts.height || 5 return new Labyrinthe(this.width, this.height) } module.exports.Labyrinthe = Labyrinthe function Labyrinthe(game, opts) { // protect against people who forget 'new' if (!(this instanceof Labyrinthe)) return new Labyrinthe(game, opts) // we need to store the passed in variables on 'this' // so that they are available to the .prototype methods this.game = game this.opts = opts || {} this.width = his.opts.width || 5 this.height = this.opts.height || 5 } /*------------------------------------------------------------------------------------------------------------------- CELLULE --------------------------------------------------------------------------------------------------------------------*/ var Cellule = function(){ /* différent mur, 1 = mur et 0 = pas de mur*/ this.nord = 1; // mur nord this.ouest = 1; // mur ouest this.sud = 1; // mur sud this.est = 1; // mur est this.visited = 0; // indique si la case a déjà été visitée ou non (1 = visitée, 0 = pas visitée) } /*------------------------------------------------------------------------------------------------------------------- LABYRINTHE --------------------------------------------------------------------------------------------------------------------*/ var Labyrinthe = function(width, height){ this.tabLaby = new Array(); // tableau Labyrinthe contenant les celulles this.pileLaby = new Array(); // tableau pile contenant les coordonnées this.width = width; // largeur du tableau this.height = height; //hauteur du tableau } /* fonction principale : génére un labyrinthe aléatoirement */ Labyrinthe.prototype.generationAlea = function(){ this.init(); // initialisation du labyrinthe this.caseDepart(); // choix de la case départ /* tant qu'on ne revient pas à la cellule de départ et qu'il n'y a pas de vosin de libre*/ do{ if( this.aVoisinLibre() ){ var newVoisin = this.choixVoisin(); //on choisit un nouveau voisin aléatoirement this.casserMur(newVoisin.newPosX, newVoisin.newPosY); // on casse les murs en fonction this.tabLaby[newVoisin.newPosY][newVoisin.newPosX].visited = 1; // la nouvelle cellule est considéré comme visitée /*stockage de la nouvelle cellule dans la pile*/ this.pileLaby[this.pileLaby.length] = [newVoisin.newPosX, newVoisin.newPosY]; } else{ this.pileLaby.pop(); } }while( this.pileLaby.length > 0) } /* initialisation du labyrinthe */ Labyrinthe.prototype.init = function(){ for(var i = 0; i < this.height; i++){ this.tabLaby[i] = new Array(); for(var j = 0; j < this.width; j++){ this.tabLaby[i][j] = new Cellule(); } } } /* case départ du labyrinthe */ Labyrinthe.prototype.caseDepart = function(){ var randX = parseInt(Math.random()*this.width); // choix aléatoire d'une position X var randY = parseInt(Math.random()*this.height); // choix aléatoire d'une position Y this.tabLaby[randY][randX].visited = 1; // la case départ est visitée /* placement de cette cellule dans la pile*/ this.pileLaby[0] = new Array(); this.pileLaby[0][0] = randX; this.pileLaby[0][1] = randY; } /* vérification si cellule en cours a un voisin */ Labyrinthe.prototype.aVoisinLibre = function(){ posX = this.pileLaby[this.pileLaby.length-1][0]; // la position X de la cellule en cours posY = this.pileLaby[this.pileLaby.length-1][1]; // la position Y de la cellule en cours /* on vérifie la case de gauche */ if(posX > 0 && this.tabLaby[posY][posX-1].visited == 0){ return true; } /* on vérifie la case de droite */ if(posX != this.width-1 && this.tabLaby[posY][posX+1].visited == 0){ return true; } /* on vérifie la case du haut*/ if(posY > 0 && this.tabLaby[posY-1][posX].visited == 0){ return true; } /* on vérifie la case du bas*/ if(posY != this.height-1 && this.tabLaby[posY+1][posX].visited == 0){ return true; } /*si pas de voisin de libre*/ return false; } /* choix aléatoire du voisin */ Labyrinthe.prototype.choixVoisin = function(){ var randVoisin; //nombre aléatoire pour choisir le nouveau voisin var stockage = this.stockVoisin(); //stockage des voisins randVoisin = parseInt(Math.random()*(stockage.length)); //choix d'un voisin return {newPosX : stockage[randVoisin][0], newPosY : stockage[randVoisin][1]}; } /* stocke tous les voisins possibles de la cellules en cours */ Labyrinthe.prototype.stockVoisin = function(){ posX = this.pileLaby[this.pileLaby.length -1][0]; // la position X de la cellule en cours posY = this.pileLaby[this.pileLaby.length -1][1]; // la position Y de la cellule en cours var tab = new Array(); var i = 0; /* stock la case de gauche si libre */ if(posX != 0 && this.tabLaby[posY][posX-1].visited == 0){ tab[i] = new Array(); tab[i][0] = posX-1; tab[i][1] = posY; i++; } /* stock la case de droite si libre*/ if(posX != this.width-1 && this.tabLaby[posY][posX+1].visited == 0){ tab[i] = new Array(); tab[i][0] = posX+1; tab[i][1] = posY; i++; } /* stock la case du haut si libre*/ if(posY != 0 && this.tabLaby[posY-1][posX].visited == 0){ tab[i] = new Array(); tab[i][0] = posX; tab[i][1] = posY-1; i++; } /* stock la case du bas si libre*/ if(posY != this.height-1 && this.tabLaby[posY+1][posX].visited == 0){ tab[i] = new Array(); tab[i][0] = posX; tab[i][1] = posY+1; } return tab; } /* détruit le mur de la cellule en courss ainsi que du nouveau voisin */ Labyrinthe.prototype.casserMur = function(newVoisinX, newVoisinY){ posX = this.pileLaby[this.pileLaby.length -1][0]; // la position X de la cellule en cours posY = this.pileLaby[this.pileLaby.length -1][1]; // la position Y de la cellule en cours newPosX = newVoisinX; // la position X du voisin choisi newPosY = newVoisinY; // la position Y du voisin choisi /* si nouveau voisin correspond à la cellule gauche de la cellule en cours*/ if (newPosX == posX-1 && newPosY == posY){ this.tabLaby[posY][posX].ouest = 0; //on casse le mur ouest de la cellule en cours this.tabLaby[newPosY][newPosX].est = 0; //on casse le mur est de la nouvelle cellule } /* si nouveau voisin correspond à la cellule droite de la cellule en cours*/ if (newPosX == posX+1 && newPosY == posY){ this.tabLaby[posY][posX].est = 0; //on casse le mur est de la cellule en cours this.tabLaby[newPosY][newPosX].ouest = 0; //on casse le mur ouest de la nouvelle cellule } /* si nouveau voisin correspond à la cellule haute de la cellule en cours*/ if ( newPosX == posX && newPosY == posY-1){ this.tabLaby[posY][posX].nord = 0; //on casse le mur nord de la cellule en cours this.tabLaby[newPosY][newPosX].sud = 0; //on casse le mur sud de la nouvelle cellule } /* si nouveau voisin correspond à la cellule basse de la cellule en cours*/ if (newPosX == posX && newPosY == posY+1){ this.tabLaby[posY][posX].sud = 0; //on casse le mur sud de la cellule en cours this.tabLaby[newPosY][newPosX].nord = 0; //on casse le mur nord de la nouvelle cellule } } /* résolution automatique du Labyrinthe */ Labyrinthe.prototype.reso = function(departX, departY, finX, finY){ var posX = departX; var posY = departY; //initialisation des cellules visitées dans le Labyrinthe for(var i = 0; i < this.height; i++){ for(var j = 0; j < this.width; j++){ this.tabLaby[i][j].visited = 0; } } this.pileLaby[0] = [posX, posY]; // on initialise la pile avec la case de départ this.tabLaby[posY][posX].visited = 1; // le départ est déjà visitée do{ //on vérifie la case de gauche if(posX > 0 && this.tabLaby[posY][posX-1].visited == 0 && this.tabLaby[posY][posX].ouest == 0){ posX = posX-1; // la position change this.tabLaby[posY][posX].visited = 1; // la case devient visitée this.pileLaby[this.pileLaby.length] = [posX, posY]; //on met à jour la pile } /* on vérifie la case de droite */ else if(posX != this.width-1 && this.tabLaby[posY][posX+1].visited == 0 && this.tabLaby[posY][posX].est == 0){ posX = posX+1; // la position change this.tabLaby[posY][posX].visited = 1; // la case devient visitée this.pileLaby[this.pileLaby.length] = [posX, posY]; //on met à jour la pile } /* on vérifie la case du haut*/ else if(posY > 0 && this.tabLaby[posY-1][posX].visited == 0 && this.tabLaby[posY][posX].nord == 0){ posY = posY-1; // la position change this.tabLaby[posY][posX].visited = 1; // la case devient visitée this.pileLaby[this.pileLaby.length] = [posX, posY]; //on met à jour la pile } /* on vérifie la case du bas*/ else if(posY != this.height-1 && this.tabLaby[posY+1][posX].visited == 0 && this.tabLaby[posY][posX].sud == 0){ posY = posY+1; // la position change this.tabLaby[posY][posX].visited = 1; // la case devient visitée this.pileLaby[this.pileLaby.length] = [posX, posY]; //on met à jour la pile } /* si aucun voisin possible on retourne en arriere*/ else{ /* on ne ne soustrait que lorsqu'elle ne sera pas vide */ if(this.pileLaby.length>1){ this.pileLaby.pop(); // retour dans la pile /* mise à jour des nouvelles coordonnées en cours */ posX = this.pileLaby[this.pileLaby.length-1][0]; posY = this.pileLaby[this.pileLaby.length-1][1]; } } }while(posX != finX || posY != finY) // la boucle s'effectue tant qu'on est pas arrivé à la case départ return this.pileLaby; } /* Pour passer de la 2D à la 3D, il faut changer l'échelle du labyrinthe. On compte les lignes ( murs Horizontaux) composant le labyrinthe pour faire une map binaire. */ Labyrinthe.prototype.compterMursHorizontaux = function() { // 0 = pas de block, 1 = block; // 1 mur = une case; var murHorizontal = [0,1,1,1,1,1,1,0]; var murCasse = [0,0,0,0,0,0,0,0]; this.mursHorizontaux = new Array(); for ( var ligne = 0; ligne <= this.tabLaby.length; ligne++){ this.mursHorizontaux[ligne] = new Array(); for (var index = 0; index < this.tabLaby[0].length; index++){ if ( ligne < this.tabLaby.length){ if ( this.tabLaby[ligne][index].nord == 1 ) { this.mursHorizontaux[ligne].push(1,1,1,1,1,1,1,1); } else if ( this.tabLaby[ligne][index].nord == 0) { this.mursHorizontaux[ligne].push(0,0,0,0,0,0,0,0); } } else { if ( this.tabLaby[ligne-1][index].sud == 1 ) { this.mursHorizontaux[ligne].push(1,1,1,1,1,1,1,1); } else if ( this.tabLaby[ligne-1][index].sud == 0) { this.mursHorizontaux[ligne].push(0,0,0,0,0,0,0,0); } } } } } /* Puis on compte les colonnes / murs verticaux */ Labyrinthe.prototype.compterMursVerticaux = function() { var murVertical = [0,1,1,1,1,1,1,0]; var murCasse = [0,0,0,0,0,0,0,0]; this.mursVerticaux = new Array(); for ( var colonne = 0; colonne <= this.tabLaby[0].length; colonne++){ this.mursVerticaux[colonne] = new Array(); for (var index = 0; index < this.tabLaby[0].length; index++){ if ( colonne < this.tabLaby[0].length ){ if ( this.tabLaby[index][colonne].ouest == 1 ) { this.mursVerticaux[colonne].push(1,1,1,1,1,1,1,1); } else if ( this.tabLaby[index][colonne].ouest == 0) { this.mursVerticaux[colonne].push(0,0,0,0,0,0,0,0); } } else { if ( this.tabLaby[index][colonne-1].est == 1 ) { this.mursVerticaux[colonne].push(1,1,1,1,1,1,1,1); } else if ( this.tabLaby[index][colonne-1].est == 0) { this.mursVerticaux[colonne].push(0,0,0,0,0,0,0,0); } } } } } /* Dessine une portion du labyrinthe en 3D game = sert à passer le canvas 3D entre les fonctions chunkedHz = où commence la portion à tracer horizontalement chunkedVt = où commence la portion à tracer verticalement */ Labyrinthe.prototype.draw3D = function(chunkedHz, chunkedVt) { var chunkedHzMax = chunkedHz*4 + 4; var chunkedVtMax = chunkedVt*4 + 4; for (var colonne = chunkedVt*4; colonne <= chunkedVtMax; colonne++){ for (var index = chunkedHz * 8; index <= chunkedHzMax * 8; index++){ if ( colonne < this.mursVerticaux.length){ if ( this.mursVerticaux[colonne][index] == 1 ){ this.game.createBlock([colonne*8, 2, index], 'brick' ); this.game.createBlock([colonne*8, 3, index], 'grass' ); this.game.createBlock([colonne*8, 4, index], 'grass' ); this.game.createBlock([colonne*8, 5, index], 'brick' ); } } } } for ( var ligne = chunkedHz * 4; ligne <= chunkedHzMax ; ligne++){ for ( index = chunkedVt * 8; index <= chunkedVtMax *8; index++){ if ( ligne < this.mursHorizontaux.length) { if ( this.mursHorizontaux[ligne][index] == 1 ){ this.game.createBlock([index, 2, ligne*8], 'brick' ); this.game.createBlock([index, 3, ligne*8], 'grass' ); this.game.createBlock([index, 4, ligne*8], 'grass' ); this.game.createBlock([index, 5, ligne*8], 'brick' ); } } } } } /*---------------------------------------------------------------------------------------------------------------------- crée un chemin entre le joueur et la sortie du labyrinthe -----------------------------------------------------------------------------------------------------------------------*/ Labyrinthe.prototype.resoudre = function(game) { var reso = this.reso(unconvert(departX), unconvert(departZ), finX, finZ) for (var i = 0; i < reso.length; i++){ this.game.createBlock([convert(reso[i][0]), 8, convert(reso[i][1])], 'brick'); } } /*---------------------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------------------*/ document.getElementById("new_game").addEventListener('click', newGame); document.getElementById("continuer").addEventListener('click', continuer); document.getElementById("quitter").addEventListener('click', quitter); window.addEventListener('keydown', keyDown, true); /*---------------------------------------------------------------------------------------------------------------------- crée une minimap en 2D, à partir de divs -----------------------------------------------------------------------------------------------------------------------*/ Labyrinthe.prototype.minimap = function () { var marg = 0; var div = document.createElement('div'); for( var i = 0; i < this.height; i++){ for (var j = 0; j < this.width; j++){ var cellId = "cell"+cpt; var inner = document.createElement('div'); inner.setAttribute('id', cellId); inner.setAttribute('class', 'cellule'); inner.style.marginLeft = marg+"px"; inner.style.marginTop = i*10+"px"; if(this.tabLaby[i][j].nord == 1){ inner.style.borderTop = "1px solid"; } if(this.tabLaby[i][j].sud == 1){ inner.style.borderBottom = "1px solid"; } if(this.tabLaby[i][j].ouest == 1){ inner.style.borderLeft = "1px solid"; } if(this.tabLaby[i][j].est == 1){ inner.style.borderRight = "1px solid"; } div.appendChild(inner); marg = marg + 10; cpt++; } marg = 0; } document.body.appendChild(div); } // convertit unité cellule en unité voxel convert = function(pos){ return pos*8+4; } //convertit unité voxel en unité cellule unconvert = function(pos){ return parseInt(pos/8); } function keyDown(evt) { if ( evt.keyCode == 76) { quitter(); console.log('key down'); } } /*---------------------------------------------------------------------------------------------------------------------- Création d'un labyrinthe, définition de variables globales -----------------------------------------------------------------------------------------------------------------------*/ var departX = 0; var departZ = 0; var finX = Maze.width-1; var finZ = Maze.height-1; var cpt = 0; var marg = 0; var tilemap3D = new Array(); /*---------------------------------------------------------------------------------------------------------------------- Fonctions relatives à la partie et à l'initialisation 3D -----------------------------------------------------------------------------------------------------------------------*/ function newGame(aMaze) { var containerLaby = document.getElementById("scene"); aMaze.generationAlea(); document.getElementById("menu").style.display = 'none'; document.getElementById("quitter").style.display = 'block'; jouer(); } function continuer(aMaze) { document.getElementById("menu").style.display = 'none'; document.getElementById("quitter").style.display = 'block'; jouer(); } function quitter() { document.getElementById("scene").removeChild(document.getElementById("scene").firstChild); document.getElementById("quitter").style.display = 'none'; document.getElementById("menu").style.display = 'block'; }