/* This was a simulation I made to see what procedural room generation would look like if we just kept adding a wall with a door, prependicular to existing walls. Since we're adding a door to each new wall, all of the rooms will always be accessible, but it's kind of an architectural nightmare. Down the road it'd probably help to have some predefined hallway layouts, and then use this to fill in the areas separated by hallways. */ var canvas = document.getElementById("myCanvas"); var ctx = canvas.getContext("2d"); ctx.lineWidth = 1; var hTiles = 64; var vTiles = 64; var tileSize = 16; ctx.fillStyle = "#FFFFFF"; ctx.fillRect(0,0,1040,1040); var doorX = []; var doorY = []; var wallArray = new Array(65); for (var i=0; i < 65; i++) wallArray[i]=new Array(65); /* Wall nodes can only project a wall segment Down or Right: o-- | Wall node data is stored as such: 00 = no walls 10 = wall projected Down only 01 = wall projected Right only 11 = walls projected both Down and Right This array is designed to wrap around a 64x64 grid of cells, so your room contents can exists in those cells. */ function drawLine(ctc,xs,ys,xe,ye) { ctx.fillStyle = "#000000"; ctx.beginPath(); ctx.moveTo(xs,ys); ctx.lineTo(xe,ye); ctx.stroke(); } function drawRedLine(ctc,xs,ys,xe,ye) { ctx.fillStyle = "#FF0000"; ctx.beginPath(); ctx.moveTo(xs,ys); ctx.lineTo(xe,ye); ctx.stroke(); } function getRandInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } function getRandInt2(max) { return Math.floor((Math.random() * max)); } //find a suitable wall node function findWallStart() { //fixed: //It shouldn't start walls at the end of the array length... reducing 65 to 64 var optionsX = []; var optionsY = []; //we could pass paremeters to only wall up a subsection for(var i = 0; i < 64; i++) { for(var j = 0; j < 64; j++) { var temp = wallArray[i][j]; if(temp == 10 || temp == 1) { optionsX.push(i); optionsY.push(j); } } } //var option = getRandInt(0,optionsX.length-1); var option = getRandInt2(optionsX.length-1); //var option = Math.floor(Math.random() * optionsX.length); var result = [optionsX[option],optionsY[option]]; return result; } function generateWall(node) { console.log(" generate wall received "+node); var x = node[0]; var y = node[1]; var start = wallArray[x][y]; var doorOptionsX = []; var doorOptionsY = []; var shift = 1; var tempX; var tempY; if(start == 1) { //have to go down console.log("starting down wall at "+node[0]+" "+node[1]); if(wallArray[x][y+shift] == 0) wallArray[x][y] = 11; while(wallArray[x][y+shift] == 0) { console.log(" incrementing wall..."); wallArray[x][y+shift] = 10; tempX = x*tileSize; tempY = ((y+shift)*tileSize)-8; doorOptionsX.push(tempX); doorOptionsY.push(tempY); console.log(" storing door option "+tempX+" "+tempY); shift++; } //var option = getRandInt(0,doorOptionsX.length-1); if(shift > 1) { var option = getRandInt2(doorOptionsX.length-1); doorX.push(doorOptionsX[option]); doorY.push(doorOptionsY[option]); console.log("pushing door "+doorOptionsX[option]+" "+doorOptionsY[option]); } } else if (start == 10) { //have to go right console.log("starting right wall at "+node[0]+" "+node[1]); if(wallArray[x+shift][y] == 0) wallArray[x][y] = 11; while(wallArray[x+shift][y] == 0) { console.log(" incrementing wall..."); wallArray[x+shift][y] = 01; tempX = ((x+shift)*tileSize)-8; tempY = y*tileSize; doorOptionsX.push(tempX); doorOptionsY.push(tempY); console.log(" storing door option "+tempX+" "+tempY); shift++; } //var option = getRandInt(0,doorOptionsX.length-1); if(shift > 1) { var option = getRandInt2(doorOptionsX.length-1); doorX.push(doorOptionsX[option]); doorY.push(doorOptionsY[option]); console.log("pushing door "+doorOptionsX[option]+" "+doorOptionsY[option]); } } else { console.log("invalid wall start "+node[0]+" "+node[1]); } } //generate checkered background for(var i = 0; i < 64; i++) { for(var j = 0; j < 64; j++) { if((j+i)%2 == 0) ctx.fillStyle = "#FFFFFF"; else ctx.fillStyle = "#D3D3D3"; ctx.fillRect(i*tileSize,j*tileSize,(i*tileSize)+16,(j*tileSize)+16); } } //draw walls on the outer edge for(var i = 0; i < 65; i++) { for(var j = 0; j < 65; j++) { if(i == 0 && j == 64) wallArray[i][j] = 1; else if(i == 64 && j == 0) wallArray[i][j] = 10; else if(i == 0 && j == 0) wallArray[i][j] = 11; else if(i==0 && i < 64) wallArray[i][j] = 10; else if(j==0 && j < 64) wallArray[i][j] = 1; else if(i==64) wallArray[i][j] = 10; else if(j==64) wallArray[i][j] = 1; else wallArray[i][j] = 0; } } //slice rooms out for(var i = 0; i < 25; i++) { var result = findWallStart(); try { console.log("option: "+result[0]+" "+result[1]); generateWall(result); } catch(err) { console.log("something went wrong: "+err); } } //draw walls for(var i = 0; i < 65; i++) { for(var j = 0; j < 65; j++) { var temp = wallArray[i][j]; var xOffset = i*16; var yOffset = j*16; if(temp == 01 || temp == 11) drawLine(ctx,xOffset,yOffset,xOffset+16,yOffset); if(temp == 10 || temp == 11) drawLine(ctx,xOffset,yOffset,xOffset,yOffset+16); } } //draw doors for(var i = 0; i < doorX.length; i++) { var xd = doorX[i]; var yd = doorY[i]; ctx.fillStyle = "#FF0000"; ctx.fillRect(xd-4,yd-4,8,8); }
<canvas id="myCanvas" width="1024" height="1024"></canvas>