2017-03-22 63 views
0

我想寫一個蛇的變體,蛇從牆壁「反彈」。JS蛇遊戲中的碰撞檢測錯誤

它大部分時間都在使用,但偶爾蛇會「逃脫」,我不知道爲什麼。起初,我將碰撞檢測功能中的不等式設置爲嚴格爲<>,我認爲這是問題的原因,但我已將它們更改爲<=>=,問題依然存在。

任何人都可以解釋爲什麼發生這種情況嗎? (你通常需要一分鐘左右的蛇逃脫前玩...)

<canvas id="canvas" width=500 height=500 style="display: block; border: 1px solid green; margin: auto;"></canvas> 
<script> 
var ctx = document.getElementById('canvas').getContext('2d'); 
ctx.font = '30px Arial'; 

var HEIGHT = 500; 
var WIDTH = 500; 
var SEGMENT_WIDTH = 30; 

var snakeVelocity = { 
    i: 1, 
    j: 0 
}; 
var snakeArray = createSnake(); 

function createSnake() { 
    var snakeArray = []; 
    var length = 5; // Initial length of snake 
    for (var i = 0; i < length; i++) { 
     snakeArray.push({ 
      x: i + 1, 
      y: 1 
     }); 
    } 
    return snakeArray; 
} 

function moveSnake(arr) { 
    var head = arr.slice(-1)[0]; 
    var tail = arr[0]; 
    var newHead = arr.shift(); 

    // check for wall collision, which also updates velocity if needed 
    snakeWallCollision(head); 

    newHead.x = head.x + snakeVelocity.i; 
    newHead.y = head.y + + snakeVelocity.j; 

    arr.push(newHead); 
    return arr; 
} 

function snakeWallCollision(obj) { 
    var collision = false; 
    if (obj.x >= WIDTH/SEGMENT_WIDTH || obj.x <= 0) { 
     snakeVelocity.i *= -1; 
     collision = true; 
    } 
    if (obj.y >= HEIGHT/SEGMENT_WIDTH || obj.y <= 0) { 
     snakeVelocity.j *= -1; 
     collision = true; 
    } 
    return collision; 
} 

function drawSnake() { 
    console.log(snakeArray[0]); 
    for (var i = 0; i < snakeArray.length; i++) { 
     var segment = snakeArray[i]; 
     ctx.fillText('S', segment.x * SEGMENT_WIDTH, segment.y * SEGMENT_WIDTH + 30); 
    } 
} 

function update() { 
    ctx.clearRect(0, 0, WIDTH, HEIGHT); 
    moveSnake(snakeArray); 
    drawSnake(); 
} 

function checkKey(e) { 

    e = e || window.event; 

    if ([38, 40, 37, 39].includes(e.keyCode)) { 
     e.preventDefault(); 
    } 

    if (e.keyCode == '38') { 
     snakeVelocity = { 
      i: 0, 
      j: -1 
     }; 
    } else if (e.keyCode == '40') { 
     snakeVelocity = { 
      i: 0, 
      j: 1 
     }; 
    } else if (e.keyCode == '37') { 
     snakeVelocity = { 
      i: -1, 
      j: 0 
     }; 
    } else if (e.keyCode == '39') { 
     snakeVelocity = { 
      i: 1, 
      j: 0 
     }; 
    } 
} 
document.onkeydown = checkKey; 
setInterval(update, 1000/20); 
drawSnake(); 
</script> 

回答

1

如果出現該問題在你撞牆之前改變方向遠離牆壁。

舉例來說,蛇的頭剛剛移動到x = 0並向左移動,用戶在下一個更新幀之前鍵入右箭頭。現在snakeVelocity.i設置爲遠離牆壁1。

你再測試牆

if (obj.x >= WIDTH/SEGMENT_WIDTH || obj.x <= 0) { 
    snakeVelocity.i *= -1; // negate the direction 
          // but the direction is already away from the 
          // wall due to user input. This will turn it back 
          // onto the wall 
} 

同樣的情況,爲上下。

您需要讓碰撞測試知道蛇的方向,然後根據該測試確定該移動是否會導致碰撞。

更改測試功能,找到蛇的頭部將允許隨其當前狀態移動的下一個位置。只有當這一舉動導致頭部超出遊戲界限時,你纔會改變方向。

function snakeWallCollision(head) { 
    var x = head.x + snakeVelocity.i; // find out where the head will be 
    var y = head.y + snakeVelocity.j; // next frame 
    if (x > WIDTH/SEGMENT_WIDTH || x < 0) { 
     snakeVelocity.i *= -1; 
     return true; 
    } 
    if (y > HEIGHT/SEGMENT_WIDTH || y < 0) { 
     snakeVelocity.j *= -1; 
     return true; 
    } 
    return false; 
} 
+0

這似乎很好地解決它。謝謝。 – Robin

0

如果你身邊掉這些行會發生什麼:

newHead.x = head.x + snakeVelocity.i; 
newHead.y = head.y + + snakeVelocity.j; 

// check for wall collision, which also updates velocity if needed 
snakeWallCollision(head); 
+0

這就像如果你使用它應該工作'snakeWallCollision(newHead);',但我覺得,因爲'newHead'值致力於蛇仍然逃脫...... – Robin

0

的問題似乎是,如果用戶按下與您的collision check同步的鑰匙,方向改變兩次,蛇越過牆壁。

也許這一個可以幫助你(我加了一個測試變量USER_ACTION檢查,如果用戶按下按鍵,如果是這樣,不做collision check):

var ctx = document.getElementById('canvas').getContext('2d'); 
ctx.font = '30px Arial'; 

var HEIGHT = 500; 
var WIDTH = 500; 
var SEGMENT_WIDTH = 30; 
var USER_ACTION = false; 

var snakeVelocity = { 
    i: 1, 
    j: 0 
}; 
var snakeArray = createSnake(); 

function createSnake() { 
    var snakeArray = []; 
    var length = 5; // Initial length of snake 
    for (var i = 0; i < length; i++) { 
     snakeArray.push({ 
      x: i + 1, 
      y: 1 
     }); 
    } 
    return snakeArray; 
} 

function moveSnake(arr) { 
    var head = arr.slice(-1)[0]; 
    var tail = arr[0]; 
    var newHead = arr.shift(); 

    // check for wall collision, which also updates velocity if needed 
    snakeWallCollision(head); 

    newHead.x = head.x + snakeVelocity.i; 
    newHead.y = head.y + +snakeVelocity.j; 

    arr.push(newHead); 
    return arr; 
} 

function snakeWallCollision(obj) { 
    if (!USER_ACTION) { 
     var collision = false; 
     if (obj.x >= WIDTH/SEGMENT_WIDTH || obj.x <= 0) { 
      snakeVelocity.i *= -1; 
      collision = true; 
     } 
     if (obj.y >= HEIGHT/SEGMENT_WIDTH || obj.y <= 0) { 
      snakeVelocity.j *= -1; 
      collision = true; 
     } 
    } else { 
     USER_ACTION = false; 
    } 
    return collision; 
} 

function drawSnake() { 
    console.log(snakeArray[0]); 
    for (var i = 0; i < snakeArray.length; i++) { 
     var segment = snakeArray[i]; 
     ctx.fillText('S', segment.x * SEGMENT_WIDTH, segment.y * SEGMENT_WIDTH + 30); 
    } 
} 

function update() { 
    ctx.clearRect(0, 0, WIDTH, HEIGHT); 
    moveSnake(snakeArray); 
    drawSnake(); 
} 

function checkKey(e) { 
    USER_ACTION = true; 
    e = e || window.event; 

    if ([38, 40, 37, 39].includes(e.keyCode)) { 
     e.preventDefault(); 
    } 

    if (e.keyCode == '38') { 
     snakeVelocity = { 
      i: 0, 
      j: -1 
     }; 
    } else if (e.keyCode == '40') { 
     snakeVelocity = { 
      i: 0, 
      j: 1 
     }; 
    } else if (e.keyCode == '37') { 
     snakeVelocity = { 
      i: -1, 
      j: 0 
     }; 
    } else if (e.keyCode == '39') { 
     snakeVelocity = { 
      i: 1, 
      j: 0 
     }; 
    } 
} 
document.onkeydown = checkKey; 
setInterval(update, 1000/20); 
drawSnake(); 
+0

可悲的是這個問題與此版本仍然存在。不管怎麼說,還是要謝謝你。 – Robin