2011-09-01 10 views
-1

J'essaye de convertir ce dungeon algorithm de java en javascript, cependant, mon script fonctionne 70% du temps. Quand cela fonctionne, les problèmes sont: les murs manquent d'un côté et certaines chambres ne sont pas accessibles. Lorsque cela ne fonctionne pas, il est bloqué dans une boucle infinie.Convertir un algorithme de donjon de java en javascript ne fonctionne pas

room is missing a side

room is missing a side

room is missing a side

(Désolé les images sont petites, je viens de mettre à jour mon jfiddle et la sortie est plus grande http://jsfiddle.net/gUmH7/1/)

Je devine que la makeRoom() est le problème, et sinon, c'est definitly createDungeon(). Donc, quand l'algorithme fonctionne, après le premier appel makeRoom(), j'obtiens quelques 1 et 2, dans mon tableau dungeon_map, où 1 est le mur marron, et 2 est le sol jaune. Lorsque l'algorithme ne fonctionne pas, il n'y a pas 1 ou 2 dans le tableau dungeon_map, conduisant à une boucle infinie.

Je suis assez sûr que le code java fonctionne, car here is one with the output online. Et voici le original.

La seule chose qui diffère entre mon code et les autres est la méthode getRand(), que je suis assez sûr, juste retourne un nombre entre min et max qui est passé dans

Mon code entier.:

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

et jfiddle.

+3

Est-il possible de réduire ce problème à un petit cas de test? – templatetypedef

+5

_ "Je devine que makeRoom() est le problème, et sinon, c'est definitly createDungeon()." _ - Donc vous dites que vous l'avez réduit à une fonction de 150 lignes ou une autre fonction de 150 lignes? Eh bien, tant que je sais où chercher ... – nnnnnn

+0

Le getRandom semble fonctionner http://jsfiddle.net/mplungjan/Z522m/ – mplungjan

Répondre

1

J'ai donc résolu le problème. Toutes les variables étaient Java int, et quand j'ai converti en javascript, j'ai oublié à ce sujet. Ainsi, dans les parties du code où vous divisez par deux, la variable se traduit par des décimales. Donc, pour résoudre ce problème, j'ai juste fait Math.floor() chaque fois que je l'ai divisé de moitié, puis j'ai modifié quelques-unes des instructions if pour faire correspondre les murs.

+0

au lieu de Math.floor(), essayez le décalage vers la droite (x >> 1). – Ron

+0

@Ron Cela divisera le résultat par 2. Je pense que vous vouliez dire 'x >> 0' ou' x << 0'. – Phrogz

+0

@Phrogz Je voulais dire au lieu de Math.floor (x/2), essayez (x >> 1). – Ron