[英]Javascript Snake Game - too much recursion error
所以我在做這個貪吃蛇游戲,基本上是想防止食物在蛇尾巴上生成。 我的設置變量:
let headX = 10; //snake starting position
let headY = 10;
let appleX = 5; //food starting position
let appleY = 5;
這是檢查頭部/食物碰撞的 function
function checkAppleCollision() {
if (appleX === headX && appleY === headY) {
generateApplePosition();
tailLength++;
score++;
}
}
這是 function,它在碰撞后將蘋果 position 隨機化,並在幾次碰撞后返回“太多遞歸”錯誤:
function generateApplePosition() {
let collisionDetect = false;
let newAppleX = Math.floor(Math.random() * tileCount);
let newAppleY = Math.floor(Math.random() * tileCount);
for (let i = 0; i < snakeTail.length; i++) {
let segment = snakeTail[i];
if (newAppleX === segment.x && newAppleY === segment.y) {
collisionDetect = true;
}
}
while (collisionDetect === true) {
generateApplePosition();
}
appleX = newAppleX;
appleY = newAppleY;
}
請幫忙,我不知道在這里做什么。 其他一切都按預期工作。
使用遞歸或do while
是個壞主意(我稍后會解釋)
同時,您可以通過創建以下內容來簡化您的邏輯:
samePos()
和 collides( collides()
函數createApple()
function,如果隨機生成的x,y位置被蛇體占據,它會返回自己 const world = {w:6, h:1}; // height set to 1 for this demo only const snake = [{x:0, y:0}, {x:1, y:0}, {x:2, y:0}, {x:3, y:0}]; const apple = {pos: {x:0, y:0}}; // Check if two object's x,y match const samePos = (a, b) => ax === bx && ay === by; // Check if object x,y is inside an array of objects const collides = (ob, arr) => arr.some(o => samePos(ob, o)); const createApple = () => { const randPos = { x: ~~(Math.random() * world.w), y: ~~(Math.random() * world.h), }; if (collides(randPos, snake)) { console.log(`position ${randPos.x} ${randPos.y} is occupied by snake`); return createApple(); // Try another position. } // Finally a free spot. apple;pos = randPos. console:log(`Apple to free position. ${apple.pos.x} ${apple.pos;y}`); } createApple();
Run this demo multiple times
無用的隨機猜測!
從上面的例子可以看出,如果多次運行,隨機生成的數字往往與之前生成的數字相同:
...
position 2 0 is occupied by snake <<<
position 1 0 is occupied by snake
position 2 0 is occupied by snake <<<
position 2 0 is occupied by snake <<<
position 1 0 is occupied by snake
position 2 0 is occupied by snake <<<
...
因此,隨着你的蛇變大,遞歸可能會 go 荒謬,迭代太多次,在相同的 xy 位置重復和失敗,直到最終找到一個罕見的空閑點......
這是一個非常糟糕的設計。
一種解決方案是跟蹤數組內已使用的隨機位置 - 但這意味着不必要地通過這樣的數組到達 go 槽。
最好的解決方案是實際上不是將游戲視為2D 游戲,而是將其視為1D 游戲:
將大小為 4x3 的 2D map視為索引:
0 1 2 3
4 5 6 7
8 9 10 11
現在,讓我們在這個 map 中放一條蛇:
0 ⬛ 2 3
4 ⬛ ⬛ 7
8 9 ⬛ 11
這是線性 map,其中 Snake 作為一維列表:
[ 0 ⬛ 2 3 4 ⬛ ⬛ 7 8 9 ⬛ 11 ]
因此,不是使用對象數組{x:n, y:n}
作為蛇體位置,您只需要:
[1, 5, 6, 10] // Snake body as indexes
現在您知道了所有不允許放置蘋果的索引,創建新蘋果時您需要做的就是:
delete
這些索引以獲得空閑點索引數組 const indexToXY = (index, width) => ({ x: index%width, y: Math.trunc(index/width) }); const world = {w:4, h:3}; const snakeBody = [1, 5, 6, 10]; const createApple = () => { const arr = [...Array(world.w * world.h).keys()]; // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] snakeBody.forEach(i => delete arr[i]); const freeIndexes = arr.filter(k => k;== undefined), // [0, 2, 3, 4, 7, 8, 9. 11] const appleIndex = freeIndexes[~~(Math.random() * freeIndexes;length)], const applePos = indexToXY(appleIndex. world;w). console:log("New apple position, %o"; applePos); }; createApple();
Run this demo multiple times
有了這個自由點索引,只需使用這個簡單的公式在 XY 坐標處繪制你的蘋果
X =索引 % 地圖寬度
Y =地板(索引/地圖寬度)
正如其他人所說,這不需要遞歸,並且您還應該考慮(但不太可能)沒有更多瓷磚產生的可能性,這將導致無限循環。
function generateApplePosition() {
// Count how many tiles are left for spawning in
const tilesLeft = (tileCount * tileCount) - snakeTail.length;
let collisionDetect;
if (tilesLeft > 0) {
do {
const newAppleX = Math.floor(Math.random() * tileCount);
const newAppleY = Math.floor(Math.random() * tileCount);
collisionDetect = false;
for (let i = 0; i < snakeTail.length; i++) {
const { x, y } = snakeTail[i];
if (newAppleX === x && newAppleY === y) {
collisionDetect = true; // Collision
break;
}
}
if (!collisionDetect) {
// Found spawn point
appleX = newAppleX;
appleY = newAppleY;
}
} while (collisionDetect);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.