为什么我的蛇的链接会相互重叠?
Why the links of my snake getting place on top of each other?
重现步骤:
- 访问http://playclassicsnake.com/play
- 看到 3 个绿色方块和 1 个红色圆圈
- 将屏幕调整到足够小,使蛇所在的网格更小
- 红色圆圈会适当调整大小和替换,1个绿色方块也会,貌似
console.log(SG.snake.links.length);
看到蛇上确实有3个链接。如果您分别查看 SG.snake.links[k].pos.x
、SG.snake.links[k].pos.y
和 k=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");
总之,祝你好运!
重现步骤:
- 访问http://playclassicsnake.com/play
- 看到 3 个绿色方块和 1 个红色圆圈
- 将屏幕调整到足够小,使蛇所在的网格更小
- 红色圆圈会适当调整大小和替换,1个绿色方块也会,貌似
console.log(SG.snake.links.length);
看到蛇上确实有3个链接。如果您分别查看SG.snake.links[k].pos.x
、SG.snake.links[k].pos.y
和k=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");
总之,祝你好运!