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

时间:2015-07-27 03:28:50

标签: javascript algorithm svg game-physics

Repro步骤:

  1. 访问manual page
  2. 参见3个绿色方块和1个红色圆圈
  3. 调整屏幕大小,使蛇生活的网格更小
  4. 红色圆圈将调整大小并适当更换,因此1绿色正方形,看似
  5. console.log(SG.snake.links.length);看到蛇上确实有3个链接。如果您使用SG.snake.links[k].pos.xSG.snake.links[k].pos.y k=1,2,3单独查看三者中每一个的网格坐标,您将看到它们位于相同的坐标上。
  6. 问题的根源:

    源必须是我的函数实现,它处理电路板的大小调整和电路板上的元素。它是

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

    非常感谢任何有助于确定导致错误的逻辑的帮助!

1 个答案:

答案 0 :(得分:1)

在这个内部。我认为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");

无论如何,祝你好运!