为什么我的蛇的链接会相互重叠?

Why the links of my snake getting place on top of each other?

重现步骤:

  1. 访问http://playclassicsnake.com/play
  2. 看到 3 个绿色方块和 1 个红色圆圈
  3. 将屏幕调整到足够小,使蛇所在的网格更小
  4. 红色圆圈会适当调整大小和替换,1个绿色方块也会,貌似
  5. console.log(SG.snake.links.length); 看到蛇上确实有3个链接。如果您分别查看 SG.snake.links[k].pos.xSG.snake.links[k].pos.yk=1,2,3 三个中的每一个的网格坐标,您会发现它们位于同一坐标上。

问题来源:

来源必须是我对处理板和板上元素大小调整的函数的实现。这是

this.rescale = function ( newWidth )
{
    // newWidth: new width of the div containing 

    this.board.setSize(newWidth, newWidth); // set the size of the board to be that of the containing div
    var blockWidth = this.board.getSize().width / this.numBlocks; // width in pixels of a block on the board  

    this.food.elem.remove(); // remove old food element   
    this.food.elem = this.board.circle(this.food.pos.x * blockWidth + blockWidth / 2, this.food.pos.y * blockWidth + blockWidth / 2, blockWidth / 2).attr('fill', '#cf6a4c');  // create food element to replace old one, in same grid location (see http://raphaeljs.com/reference.html#Paper.circle)

    for (var i in this.snake.links) 
    {
        var thisLink = this.snake.links[i];
        thisLink.elem.remove(); // remove old link element
        thisLink.elem = this.board.rect(thisLink.pos.x * blockWidth, thisLink.pos.y * blockWidth, blockWidth, blockWidth).attr('fill', '#19FF19'); // creata new link to replace old one http://raphaeljs.com/reference.html#Paper.circle
    }
}

代码转储:

如果您想查看代表游戏的对象的完整逻辑,请参见下方。

// define game object
function Game ( board, numBlocks ) {
    //     board: Raphael object that the snake will live on
    // numBlocks: Number of blocks both horizontally AND vertically -- the grid structure should be squares

    this.board = board;
    this.numBlocks = numBlocks;
    this.snake; // Snake object on the board
    this.coords = []; // map whose key-value pairs represent whether a coordinate is open or taken
    this.food = null; // food element on board

    this.getCoords = function ( )
    {
        // returns a nested list gridList of all grid coordinates on the canvas, 
        // acting like a map so that gridList[i,j]=true if the coordinate i,j is
        // occupied, and gridList[i,j]=false if the coordinate is not occupied
        var gridList = [];
        for (var i = 0; i < this.numBlocks; ++i)
        {
            var innerList = [];
            for (var j = 0; j < this.numBlocks; ++j) innerList.push(true);
            gridList.push(innerList);
        }
        return gridList;
    }

    this.elementOnGrid = function (elem, xpos, ypos) {
        //       elem: Rapael element (see: http://raphaeljs.com/reference.html#Element) 
        // xpos, ypos: x and y grid coordinates of the current position of the element 
        return { elem: elem, pos: { x: xpos, y: ypos } };
    }


    this.rescale = function ( newWidth )
    {
        // newWidth: new width of the div containing 

        this.board.setSize(newWidth, newWidth); // set the size of the board to be that of the containing div
        var blockWidth = this.board.getSize().width / this.numBlocks; // width in pixels of a block on the board  

        this.food.elem.remove(); // remove old food element   
        this.food.elem = this.board.circle(this.food.pos.x * blockWidth + blockWidth / 2, this.food.pos.y * blockWidth + blockWidth / 2, blockWidth / 2).attr('fill', '#cf6a4c');  // create food element to replace old one, in same grid location (see http://raphaeljs.com/reference.html#Paper.circle)

        for (var i in this.snake.links) 
        {
            var thisLink = this.snake.links[i];
            thisLink.elem.remove(); // remove old link element
            thisLink.elem = this.board.rect(thisLink.pos.x * blockWidth, thisLink.pos.y * blockWidth, blockWidth, blockWidth).attr('fill', '#19FF19'); // creata new link to replace old one http://raphaeljs.com/reference.html#Paper.circle
        }
    }

    this.Snake = function ( game )
    {
        // game: the Game function/object containing this function

        this.links; // list of 

        this.createNew = function ( )
        {

            this.links = [];  
            var blockWidth = game.board.getSize().width / game.numBlocks; // width in pixels of a block on the board
            var centerCoordXY = Math.round(game.numBlocks / 2); // x-y grid coordinate of center 
            for (var i = 0; i < 3; ++i) // start with 3 blocks in the center-ish
            {
                var newX = centerCoordXY + i;
                this.links.push(new game.elementOnGrid(
                                    game.board.rect(newX * blockWidth, centerCoordXY * blockWidth, blockWidth, blockWidth).attr('fill', '#19FF19'), // http://raphaeljs.com/reference.html#Paper.circle
                                    centerCoordXY,
                                    centerCoordXY
                                ) // add element of type elementOnGrid to the links
                );
                game.coords[newX][centerCoordXY] = false; // indicate that coordinates of element just added to snake is no longer open
            }

        }
    }

    this.placeFood = function ( )
    {
        do {
            var randXCoord = randInt(0, this.coords.length), randYCoord = randInt(0, this.coords.length);
        }
        while (this.coords[randXCoord][randYCoord] === false); // get random unused x-y coordinate

        var blockWidth = this.board.getSize().width / this.numBlocks; // width in pixels of a block on the board
        if (this.food == null) // if food element hasn't been initialized
        {
            // initialize the food element
            this.food = new this.elementOnGrid( 
                    this.board.circle(randXCoord * blockWidth + blockWidth / 2, randYCoord * blockWidth + blockWidth / 2, blockWidth / 2).attr('fill', '#cf6a4c'),  // place circle in random location on the board (see http://raphaeljs.com/reference.html#Paper.circle)
                    randXCoord,
                    randYCoord
            ); // set food to be new element of type elementOnGrid

        }
        else // food element has been initialized (game is in play)
        {
            // move the food element

            // ... 
        }

        this.coords[randXCoord][randYCoord] = false; // indicate that coordinates of the good element is not open

    }


    this.startNew = function ( ) {
        this.coords = this.getCoords();
        this.snake = new this.Snake(this);
        this.snake.createNew();
        this.placeFood();       
    }
}

$(function () { // equivalent to $(document).ready(function() { 

    // div that holds the game area
    var snakeBoardHolder = $('#snake-board-holder');
    // make it have the same height as width
    snakeBoardHolder.height(snakeBoardHolder.width());

    // draw canvas for the snake to live on
    // http://raphaeljs.com/reference.html#Raphael
    if (!Raphael.svg) throw new Error("Your browser does not support SVG elements! Game won't work.");
    snakeBoard = Raphael("snake-board-holder", snakeBoardHolder.width(), snakeBoardHolder.height());

    // start new snake game
    SG = new Game(snakeBoard, 16);
    SG.startNew();

    // make the game area (div) have height always equal to width,
    // and make the Raphel object (canvas) inside it and all its elements
    // to be resized proportionally
    $(window).resize(function () {
        var w = snakeBoardHolder.width();
        snakeBoardHolder.height(w);
        SG.rescale(w);
    });

});

如果能帮助确定导致错误的逻辑部分,我们将不胜感激!

里面this.Snake,我相信createNew()应该是:

this.createNew = function ( )
{

    this.links = [];  
    var blockWidth = game.board.getSize().width / game.numBlocks; // width in pixels of a block on the board
    var centerCoordXY = Math.round(game.numBlocks / 2); // x-y grid coordinate of center 
    for (var i = 0; i < 3; ++i) // start with 3 blocks in the center-ish
    {
        var newX = centerCoordXY + i;
        this.links.push(new game.elementOnGrid(
                            game.board.rect(newX * blockWidth, centerCoordXY * blockWidth, blockWidth, blockWidth).attr('fill', '#19FF19'), // http://raphaeljs.com/reference.html#Paper.circle
                            newX,
                            centerCoordXY
                        ) // add element of type elementOnGrid to the links
        );
        game.coords[newX][centerCoordXY] = false; // indicate that coordinates of element just added to snake is no longer open
    }

}

在 this.links.push 中,我用 newX 替换了 centerCoordXY 的一个实例。

您有很多重复的数据(位置以两种不同的格式存储在 3 个不同的位置?),如果您未能使它们全部同步,则可能会导致此类问题。使用 Canvas 而不是 SVG 可能更好。如果您使用 SVG,我建议您使用更多辅助函数。例如,而不是

new game.elementOnGrid(
    game.board.rect(newX * blockWidth, centerCoordXY * blockWidth, blockWidth, blockWidth).attr('fill', '#19FF19'), // http://raphaeljs.com/reference.html#Paper.circle
    newX,
    centerCoordXY
)

考虑一个允许你做类似

的函数
newGridElement(newX, centerCoordXy, "#19FF19");

总之,祝你好运!