Estoy tratando de hacer un juego de combinar 3 (como candy crush). Tengo un objeto level que tiene la propiedad tiles que es una matriz 2d. Después de hacer algunas manipulaciones, quiero cambiar el tipo de un elemento específico a -1 usando esta línea simple (usaré for, pero por ahora lo he hecho simple con fines demostrativos)

level.tiles[1][0].type = -1;

Aquí está el código

var level = {
    x: 250,         // X position
    y: 113,         // Y position
    columns: 8,     // Number of tile columns
    rows: 8,        // Number of tile rows
    tilewidth: 40,  // Visual width of a tile
    tileheight: 40, // Visual height of a tile
    tiles: [],      // The two-dimensional tile array
    selectedtile: {selected: false, column: 0, row: 0}
};

var tileTypes = [
    {
        type: "red",
        colors: [255, 128, 128]
    },
    {
        type: "green",
        colors: [128, 255, 128]
    },
    {
        type: "darkBlue",
        colors: [128, 128, 255]
    },
    {
        type: "yellow",
        colors: [255, 255, 128]
    }
];
function createLevel() {
    for (var i = 0; i < level.columns; i++) {
        level.tiles[i] = [];
    }

    for (var i = 0; i < level.columns; i++) {
        for (var j = 0; j < level.rows; j++) {
            level.tiles[i][j] = getRandomTile();
        }
    }
}

function getRandomTile() {
    return tileTypes[Math.floor(Math.random() * tileTypes.length)];
}

createLevel();
level.tiles[1][0].type = -1;

Desafortunadamente, no solo tiles[1][0] se modifica, sino que se usan varias celdas. Lo interesante es que cada vez que las células aleatorias se ven afectadas

0
Reath 31 oct. 2017 a las 11:09

3 respuestas

La mejor respuesta

Esto ocurre porque getRandomTile() devuelve una referencia a un tipo de mosaico, no una copia del mismo.

Es decir. para simplificar este caso:

var a = {x: 1};
var b = [a, a, a, a];
b[0].x = 2;
console.log(a, b);

Saldrá

{x: 2} [{x: 2}, {x: 2}, {x: 2}, {x: 2}]

Si desea que los mosaicos sean modificables, haga que getRandomTile devuelva una copia, una copia superficial en este caso, por lo que colors sigue siendo una referencia, no una copia, del tipo de mosaico elegido al azar.

function getRandomTile() {
    const tileType = tileTypes[Math.floor(Math.random() * tileTypes.length)];
    // Idiom for shallow copy, i.e. assign all properties of tileType
    // into a new, unique object.
    return Object.assign({}, tileType);
}
1
AKX 31 oct. 2017 a las 08:14

Esto es causado por getRandomTile que devuelve la misma referencia de object definida en tileTypes si el índice pasado es el mismo. Puede imprimir tileTypes para ayudarlo a comprender lo que sucede.

0
Lancelod Liu 31 oct. 2017 a las 08:17

El problema es que modifica el objeto de tipo, en lugar de vincularlo a otro tipo. Una solución sería clonarlo al crear los mosaicos:

function getRandomTile() {
    var srcType = tileTypes[Math.floor(Math.random() * tileTypes.length)];
    return {type:srcType.type, colors:srcType.color};
}

Otro (dependiendo de su objetivo) sería tener objetos Tile, cada uno con una referencia a un objeto Type (no solo un entero). En este punto, algunas clases pueden ser útiles:

class TileType {
   constructor(colors){
       this.colors = colors;
   }
}
let tileTypes = [...]

class Tile {
    constructor(){
        this.type = tileTypes[Math.random()*tileTypes.length|0];
    }
    setNewType(type){
        this.type = type;
    }
}

Etcetera.

1
Denys Séguret 31 oct. 2017 a las 08:13