我正在尝试将此dungeon algorithm从java转换为javascript,但是,我的脚本在70%的时间都有效。当它工作时,问题是:房间一侧缺少墙壁,一些房间无法以任何方式访问。 当它不起作用时,它会陷入无限循环。
(抱歉图片很小,我刚刚更新了我的jfiddle,输出更大http://jsfiddle.net/gUmH7/1/)
我猜makeRoom()是问题,如果没有,它肯定是createDungeon()。 因此,当算法工作时,在第一次makeRoom()调用之后,我得到一些1和2,在我的dungeon_map数组中,其中1是棕色墙,2是黄色地板。当算法不起作用时,dungeon_map数组中没有任何1或2,导致无限循环。
我很确定java代码有效,因为here is one with the output online。这是original。
我的代码和其他代码之间唯一不同的是getRand()方法,我很确定,只返回传入的最小值和最大值之间的数字。
我的整个代码:
//size of the map
var xsize = 0;
var ysize = 0;
var TILESIZE = 8;
var objects = 0;
//define the %chance to generate either a room or a corridor on the map
//BTW, rooms are 1st priority so actually it's enough to just define the chance
//of generating a room
var chanceRoom = 75;
var chanceCorridor = 25;
//map
var dungeon_map = [];
//a list over tile types we're using
var tileUnused = 0;
var tileDirtWall = 1;
var tileDirtFloor = 2;
var tileStoneWall = 3;
var tileCorridor = 4;
var tileDoor = 5;
var tileUpStairs = 6;
var tileDownStairs = 7;
//setting a tile's type
function setCell(x, y, celltype)
{
dungeon_map[x + xsize * y] = celltype;
}
//returns the type of a tile
function getCell(x, y)
{
return dungeon_map[x + xsize * y];
}
function getRand(min, max)
{
return Math.floor(Math.random() * (max - min + 1) + min);
}
function makeCorridor(x, y, length, direction)
{
var len = getRand(2, length);
var floor = tileCorridor;
var dir = 0;
if (direction > 0 && direction < 4)
dir = direction;
var xtemp = 0;
var ytemp = 0;
if (x < 0 || x > xsize)
return false;
if (y < 0 || y > ysize)
return false;
if (dir == 0)
{
// north
xtemp = x;
//make sure its not out of bounds
for (ytemp = y; ytemp > (y - len); ytemp--)
{
if (ytemp < 0 || ytemp > ysize)
return false;
if (getCell(xtemp, ytemp) != tileUnused)
return false;
}
//start building
for (ytemp = y; ytemp > (y - len); ytemp--)
{
setCell(xtemp, ytemp, floor);
}
}
else if (dir == 1)
{
// east
ytemp = y;
for (xtemp = x; xtemp < (x + len); xtemp++)
{
if (xtemp < 0 || xtemp > xsize)
return false;
if (getCell(xtemp, ytemp) != tileUnused)
return false;
}
for (xtemp = x; xtemp < (x + len); xtemp++)
{
setCell(xtemp, ytemp, floor);
}
}
else if (dir == 2)
{
// south
xtemp = x;
//make sure its not out of bounds
for (ytemp = y; ytemp < (y + len); ytemp++)
{
if (ytemp < 0 || ytemp > ysize)
return false;
if (getCell(xtemp, ytemp) != tileUnused)
return false;
}
//start building
for (ytemp = y; ytemp < (y + len); ytemp++)
{
setCell(xtemp, ytemp, floor);
}
}
else if(dir == 3)
{
// west
ytemp = y;
for (xtemp = x; xtemp > (x - len); xtemp--)
{
if (xtemp < 0 || xtemp > xsize)
return false;
if (getCell(xtemp, ytemp) != tileUnused)
return false;
}
for (xtemp = x; xtemp > (x - len); xtemp--)
{
setCell(xtemp, ytemp, floor);
}
}
return true;
}
function makeRoom(x, y, xlength, ylength, direction)
{
console.log("DIRECTION: " + direction);
//define the dimensions of the room, it should be at least 4x4 tiles
//(2x2 for walking on, the rest is walls)
var xlen = getRand(4, xlength);
var ylen = getRand(4, ylength);
//tile type its going to be filled with
var floor = tileDirtFloor;
var wall = tileDirtWall;
var dir = 0;
if (direction > 0 && direction < 4)
dir = direction;
if (dir == 0)
{
//north
//check if there is enough space left for a room
for (var ytemp = y; ytemp > (y - ylen); ytemp--)
{
if (ytemp < 0 || ytemp > ysize)
return false;
for (var xtemp = (x - xlen / 2); xtemp < (x + (xlen + 1) / 2); xtemp++)
{
if (xtemp < 0 || xtemp > xsize)
return false;
if (getCell(xtemp, ytemp) != tileUnused)
return false;
}
}
//we're still here, build
for (var ytemp = y; ytemp > (y - ylen); ytemp--)
{
for (var xtemp = (x - xlen / 2); xtemp < (x + (xlen + 1) / 2); xtemp++)
{
//start with the walls
if (xtemp == (x - xlen / 2))
setCell(xtemp, ytemp, wall);
else if (xtemp == (x + (xlen - 1) / 2))
setCell(xtemp, ytemp, wall);
else if (ytemp == y)
setCell(xtemp, ytemp, wall);
else if (ytemp == (y - ylen + 1))
setCell(xtemp, ytemp, wall);
else
setCell(xtemp, ytemp, floor); //and then fill with the floor
}
}
}
else if (dir == 1)
{
//east
for (var ytemp = (y - ylen / 2); ytemp < (y + (ylen + 1) / 2); ytemp++)
{
if (ytemp < 0 || ytemp > ysize)
return false;
for (var xtemp = x; xtemp < (x + xlen); xtemp++)
{
if (xtemp < 0 || xtemp > xsize)
return false;
if (getCell(xtemp, ytemp) != tileUnused)
return false;
}
}
for (var ytemp = (y - ylen / 2); ytemp < (y + (ylen + 1) / 2); ytemp++)
{
for (var xtemp = x; xtemp < (x + xlen); xtemp++)
{
if (xtemp == x)
setCell(xtemp, ytemp, wall);
else if (xtemp == (x + xlen - 1))
setCell(xtemp, ytemp, wall);
else if (ytemp == (y - ylen / 2))
setCell(xtemp, ytemp, wall);
else if (ytemp == (y + (ylen - 1) / 2))
setCell(xtemp, ytemp, wall);
else
setCell(xtemp, ytemp, floor);
}
}
}
else if (dir == 2)
{
//south
for (var ytemp = y; ytemp < (y + ylen); ytemp++)
{
if (ytemp < 0 || ytemp > ysize)
return false;
for (var xtemp = (x - xlen / 2); xtemp < (x + (xlen + 1) / 2); xtemp++)
{
if (xtemp < 0 || xtemp > xsize)
return false;
if (getCell(xtemp, ytemp) != tileUnused)
return false;
}
}
for (var ytemp = y; ytemp < (y + ylen); ytemp++)
{
for (var xtemp = (x - xlen / 2); xtemp < (x + (xlen + 1) / 2); xtemp++)
{
if (xtemp == (x - xlen / 2))
setCell(xtemp, ytemp, wall);
else if (xtemp == (x + (xlen - 1) / 2))
setCell(xtemp, ytemp, wall);
else if (ytemp == y)
setCell(xtemp, ytemp, wall);
else if (ytemp == (y + ylen - 1))
setCell(xtemp, ytemp, wall);
else setCell(xtemp, ytemp, floor);
}
}
}
else if (dir == 3)
{
//west
for (var ytemp = (y - ylen / 2); ytemp < (y + (ylen + 1) / 2); ytemp++)
{
if (ytemp < 0 || ytemp > ysize)
return false;
for (var xtemp = x; xtemp > (x - xlen); xtemp--)
{
if (xtemp < 0 || xtemp > xsize)
return false;
if (getCell(xtemp, ytemp) != tileUnused)
return false;
}
}
for (var ytemp = (y - ylen / 2); ytemp < (y + (ylen + 1) / 2); ytemp++)
{
for (var xtemp = x; xtemp > (x - xlen); xtemp--)
{
if (xtemp == x)
setCell(xtemp, ytemp, wall);
else if (xtemp == (x - xlen + 1))
setCell(xtemp, ytemp, wall);
else if (ytemp == (y - ylen / 2))
setCell(xtemp, ytemp, wall);
else if (ytemp == (y + (ylen - 1) / 2))
setCell(xtemp, ytemp, wall);
else setCell(xtemp, ytemp, floor);
}
}
}
return true;
}
//print map to screen
function showDungeon()
{
for (var y = 0; y < ysize; y++)
{
for (var x = 0; x < xsize; x++)
{
var cell = getCell(x, y);
if (cell == tileUnused)
{
ctx.fillStyle = "#fff"; //white
}
else if (cell == tileDirtWall)
{
ctx.fillStyle = "#663300"; //brown
}
else if (cell == tileDirtFloor)
{
ctx.fillStyle = "#FFFFCC"; //yellow
}
else if (cell == tileStoneWall)
{
ctx.fillStyle = "#000"; //black
}
else if (cell == tileCorridor)
{
ctx.fillStyle = "#0033FF"; //dark blue
}
else if (cell == tileDoor)
{
ctx.fillStyle = "#00CCFF"; //lightblue
}
else if (cell == tileUpStairs)
{
ctx.fillStyle = "#00FF33"; //green
}
else if (cell == tileDownStairs)
{
ctx.fillStyle = "#FF0000"; //red
}
ctx.fillRect(x * TILESIZE, y * TILESIZE, TILESIZE, TILESIZE);
}
}
}
function createDungeon(inx, iny, inobj)
{
if (inobj < 1)
objects = 10;
else
objects = inobj;
//adjust the size of the map, if it's smaller or bigger than the limits
if (inx < 3)
xsize = 3;
else
xsize = inx;
if (iny < 3)
ysize = 3;
else
ysize = iny;
console.log("X size of dungeon: \t" + xsize);
console.log("Y size of dungeon: \t" + ysize);
console.log("max # of objects: \t" + objects);
//redefine the map var, so it's adjusted to our new map size
dungeon_map = new Array(xsize * ysize);
//start with making the "standard stuff" on the map
for (var y = 0; y < ysize; y++)
{
for (var x = 0; x < xsize; x++)
{
//ie, making the borders of unwalkable walls
if (y == 0)
setCell(x, y, tileStoneWall);
else if (y == ysize - 1)
setCell(x, y, tileStoneWall);
else if (x == 0)
setCell(x, y, tileStoneWall);
else if (x == xsize - 1)
setCell(x, y, tileStoneWall);
else
setCell(x, y, tileUnused);
}
}
/*******************************************************************************
And now the code of the random-map-generation-algorithm begins!
*******************************************************************************/
//start with making a room in the middle, which we can start building upon
makeRoom(xsize / 2, ysize / 2, 8, 6, getRand(0,3));
console.log("make room\n" + dungeon_map);
//keep count of the number of "objects" we've made
var currentFeatures = 1; //+1 for the first room we just made
for (var countingTries = 0; countingTries < 1000; countingTries++)
{
//check if we've reached our quota
if (currentFeatures == objects){
break;
}
//start with a random wall
var newx = 0;
var xmod = 0;
var newy = 0;
var ymod = 0;
var validTile = -1;
//1000 chances to find a suitable object (room or corridor)..
for (var testing = 0; testing < 1000; testing++)
{
newx = getRand(1, xsize - 1);
newy = getRand(1, ysize - 1);
validTile = -1;
if (getCell(newx, newy) == tileDirtWall || getCell(newx, newy) == tileCorridor)
{
//check if we can reach the place
if (getCell(newx, newy + 1) == tileDirtFloor || getCell(newx, newy + 1) == tileCorridor)
{
validTile = 0;
xmod = 0;
ymod = -1;
}
else if (getCell(newx - 1, newy) == tileDirtFloor || getCell(newx - 1, newy) == tileCorridor)
{
validTile = 1;
xmod = +1;
ymod = 0;
}
else if (getCell(newx, newy - 1) == tileDirtFloor || getCell(newx, newy - 1) == tileCorridor)
{
validTile = 2;
xmod = 0;
ymod = +1;
}
else if (getCell(newx + 1, newy) == tileDirtFloor || getCell(newx + 1, newy) == tileCorridor)
{
validTile = 3;
xmod = -1;
ymod = 0;
}
//check that we haven't got another door nearby, so we won't get alot of openings besides
//each other
if (validTile > -1)
{
if (getCell(newx, newy + 1) == tileDoor) //north
validTile = -1;
else if (getCell(newx - 1, newy) == tileDoor)//east
validTile = -1;
else if (getCell(newx, newy - 1) == tileDoor)//south
validTile = -1;
else if (getCell(newx + 1, newy) == tileDoor)//west
validTile = -1;
}
//if we can, jump out of the loop and continue with the rest
if (validTile > -1)
break;
}
}
if (validTile > -1)
{
//choose what to build now at our newly found place, and at what direction
var feature = getRand(0, 100);
if (feature <= chanceRoom)
{
if (makeRoom((newx + xmod), (newy + ymod), 8, 6, validTile))
{
//a new room
currentFeatures++; //add to our quota
//then we mark the wall opening with a door
setCell(newx, newy, tileDoor);
//clean up infront of the door so we can reach it
setCell((newx + xmod), (newy + ymod), tileDirtFloor);
}
}
else if (feature >= chanceRoom)
{ //new corridor
if (makeCorridor((newx + xmod), (newy + ymod), 6, validTile))
{
//same thing here, add to the quota and a door
currentFeatures++;
setCell(newx, newy, tileDoor);
}
}
}
}
console.log("\ndone making room\n" + dungeon_map);
/*******************************************************************************
All done with the building, let's finish this one off
*******************************************************************************/
//sprinkle out the bonusstuff (stairs, chests etc.) over the map
var newx = 0;
var newy = 0;
var ways = 0; //from how many directions we can reach the random spot from
var state = 0; //the state the loop is in, start with the stairs
while (state != 10)
{
for (var testing = 0; testing < 1000; testing++)
{
newx = getRand(1, xsize - 1);
newy = getRand(1, ysize - 2); //cheap bugfix, pulls down newy to 0<y<24, from 0<y<25
ways = 4; //the lower the better
//check if we can reach the spot
if (getCell(newx, newy + 1) == tileDirtFloor || getCell(newx, newy + 1) == tileCorridor)
{
//north
if (getCell(newx, newy + 1) != tileDoor)
ways--;
}
if (getCell(newx - 1, newy) == tileDirtFloor || getCell(newx - 1, newy) == tileCorridor)
{
//east
if (getCell(newx - 1, newy) != tileDoor)
ways--;
}
if (getCell(newx, newy - 1) == tileDirtFloor || getCell(newx, newy - 1) == tileCorridor)
{
//south
if (getCell(newx, newy - 1) != tileDoor)
ways--;
}
if (getCell(newx + 1, newy) == tileDirtFloor || getCell(newx + 1, newy) == tileCorridor)
{
//west
if (getCell(newx + 1, newy) != tileDoor)
ways--;
}
//console.log("ways: " + ways);
if (state == 0)
{
if (ways == 0)
{
console.log("upstairs");
//we're in state 0, let's place a "upstairs" thing
setCell(newx, newy, tileUpStairs);
state = 1;
break;
}
}
else if (state == 1)
{
if (ways == 0)
{
console.log("downstairs");
//state 1, place a "downstairs"
setCell(newx, newy, tileDownStairs);
state = 10;
break;
}
}
}
}
//all done with the map generation, tell the user about it and finish
console.log("# of objects made: \t" + currentFeatures);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
var x = 70;
var y = 70;
// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = x*TILESIZE;
canvas.height = y*TILESIZE;
document.body.appendChild(canvas);
var dungeon_objects = 40;
//then we create a new dungeon map
if (createDungeon(x, y, dungeon_objects))
{
//always good to be able to see the results..
showDungeon();
}
和jfiddle。
答案 0 :(得分:1)
所以我想出了问题所在。所有变量都是Java int,当我转换为javascript时,我忘了这一点。因此,在代码中除以一半的部分,变量由小数组成。所以为了解决这个问题,每当我除了一半时,我就做了Math.floor(),然后我调整了一些if语句以匹配修复墙壁。