将地下城算法从 java 转换为 javascript 不起作用

发布于 2024-12-02 04:39:18 字数 18113 浏览 0 评论 0原文

我正在尝试将这个地下城算法从java转换为javascript,但是,我的脚本在 70% 的时间内有效。当它工作时,问题是:房间一侧缺少墙壁,并且某些房间无法以任何方式进入。 当它不起作用时,它就会陷入无限循环。

房间缺少一侧

“房间缺少一侧”

房间缺少一侧

(抱歉,图像很小,我刚刚更新了我的 jfiddle 和输出较大http://jsfiddle.net/gUmH7/1/

我猜 makeRoom() 是问题所在,如果没有,那么肯定是 createDungeon() 的问题。 因此,当算法工作时,在第一次 makeRoom() 调用之后,我在 dungeon_map 数组中得到一些 1 和 2,其中 1 是棕色墙壁,2 是黄色地板。当算法不起作用时,dungeon_map数组中没有任何1或2,导致无限循环。

我很确定java代码可以工作,因为这里有一个在线输出。这是原文

我的代码与其他代码之间唯一不同的是 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

I am trying to convert this dungeon algorithm from java into javascript, however, my script works 70% of the time. When it works, the problems are: the rooms are missing a wall on one side and some of the rooms cannot be accessed in any way.
When it does not work, it is stuck in an infinite loop.

room is missing a side

room is missing a side

room is missing a side

(Sorry the images are small, I just updated my jfiddle and the output is larger http://jsfiddle.net/gUmH7/1/)

I am guessing the makeRoom() is the problem, and if not, its definitly createDungeon().
So when the algorithm works, after the first makeRoom() call, I get some 1 and 2, in my dungeon_map array, where 1 is the brown wall, and 2 is the yellow floor. When the algorithm does not work, there arent any 1 or 2 in the dungeon_map array, leading to an infinite loop.

I am pretty sure the java code works, because here is one with the output online. And here is the original.

The only thing that differs between my code and the others is the getRand() method, which I am pretty sure, just returns a number between the min and max that is passed in.

My entire code:

    //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();
}

and jfiddle.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

疧_╮線 2024-12-09 04:39:18

所以我找到了问题所在。所有变量都是 Java int,当我转换为 javascript 时,我忘记了这一点。因此,在除以一半的代码部分中,变量结果为小数。因此,为了解决这个问题,每当我除以一半时,我都会执行 Math.floor() ,然后我调整了一些 if 语句以匹配以修复墙壁。

So I figured out the problem. All of the variables were Java ints, and when I converted to javascript, I forgot about that. So in the parts of the code where you divide by half, the variable resulted with decimals. So to fix this, I just did Math.floor() whenever I divided by half, then I tweaked some of the if statements to match to fix the walls.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文