簡體   English   中英

Javascript 貪吃蛇游戲 - 遞歸錯誤太多

[英]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

現在您知道了所有不允許放置蘋果的索引,創建新蘋果時您需要做的就是:

  • 創建一個長度為0-N的索引數組:world.w * world.h
  • 循環蛇體索引並從索引數組中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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM