2015-12-16 13 views
5

Tôi đang xây dựng một trò chơi động cơ nhỏ bằng gạch nhỏ. Tôi hiện đang làm việc trên thực hiện phát hiện va chạm dựa trên khối đơn giản, tuy nhiên tôi đang gặp vấn đề thực sự. Tôi đã googled này cho giờ nhìn vào triển khai khác nhau nhưng dường như không thể có được đầu của tôi xung quanh nó. Nỗ lực hiện tại của tôi (hiện tại chỉ phát hiện va chạm khi người chơi di chuyển ngay), chủ yếu là hoạt động nhưng cho phép người chơi vượt qua phần dưới cùng của chướng ngại vật. Vụ va chạm sử dụng mảng bản đồ thông thường để phát hiện va chạm, bất kỳ giá trị nào của 2 trong bản đồ là một đối tượng rắn.Trò chơi Canvas Javascript - Phát hiện va chạm

Tôi hiểu các khái niệm về những gì tôi cần làm - trước khi tôi di chuyển trình phát, tính toán ô nào mà trình phát sẽ kết thúc. Kiểm tra xem giá trị nào đã được gán cho ô đó. Nếu nó là 2, không cho phép người chơi di chuyển.

Vấn đề của tôi là tìm ra ô mà người chơi sẽ kết thúc bằng kỹ thuật, tại các điểm, người chơi có thể ở trong 4 ô cùng một lúc. Tôi đã cố gắng sử dụng nguồn gốc và phát hiện 4 góc để có được xung quanh này, nhưng tôi chỉ không thể làm cho nó hoạt động.

JS Fiddle ĐÂY - https://jsfiddle.net/j1xqxze8/

Mã My;

var Player = function() { 
     this.width = 16; 
     this.height = 16; 
     this.position = {}; 
     this.position.x = 32; 
     this.position.y = 32; 
     this.speed  = 8; 

     this.render = function() { 
      window.context.fillStyle = 'white'; 
      window.context.fillRect(this.position.x, this.position.y, this.width, this.height); 
     }; 

     var _self = this; 

     this.didCollide = function(dir) { 
      if(dir == 'right'){ 
       var newBlock = window.tileMap.getCell(Math.floor((_self.position.x + _self.width)/32), Math.floor((this.position.y + this.height/2)/32)); 

       if(newBlock == 2) 
        return true; 
      } 
     }; 

     window.addEventListener('keydown', function(e) { 
      if(e.keyCode == 38 || e.keyCode == 87){ 
       _self.position.y -= _self.speed; 
      } 

      if(e.keyCode == 40 || e.keyCode == 83){ 
       _self.position.y += _self.speed; 
      } 

      if(e.keyCode == 37 || e.keyCode == 65){ 
       _self.position.x -= _self.speed; 
      } 

      if(e.keyCode == 39 || e.keyCode == 68){ 
       if(!_self.didCollide('right')){ 
        _self.position.x += _self.speed; 
       } 
      } 
     }) 
    }; 

var TileMap = function() { 
    this.map = [ 
     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 
     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 
    ]; 

    this.tileSize = 32; 
    this.colors = ['black', 'red', 'green']; 

    this.getCell = function(x, y){ 
     return this.map[y][x]; 
    }; 

     this.render = function(){ 
      for(var x = 0; x < this.map.length; x++){ 
       for(var y = 0; y < this.map.length; y++){ 
        // SWAP Y AND X IN THE FILLSTYLE DUE TO BACKWARDS/MIRRORED JS ARRAY READING 
        window.context.fillStyle = this.colors[this.map[y][x]]; 
        window.context.fillRect((x * this.tileSize) - window.camera.position.x, (y * this.tileSize) - window.camera.position.y, this.tileSize, this.tileSize); 

        window.context.strokeStyle = 'yellow'; 
        window.context.strokeRect((x * this.tileSize) - window.camera.position.x, (y * this.tileSize) - window.camera.position.y, this.tileSize, this.tileSize); 
       } 
      } 
     } 
    }; 
+1

Vì bạn đang di chuyển trình phát 8 vị trí trên mỗi lần nhấn phím, khi bạn nhấn phím, bạn phải kiểm tra từng vị trí trong số 8 vị trí đó để xem có xảy ra va chạm hay không. – markE

+0

Tôi đã thử điều này với mức độ khác nhau về tốc độ, bao gồm 1 (để chỉ cập nhật vị trí một lần) và thậm chí ở cấp độ này, vấn đề vẫn xảy ra nơi bạn có thể nhấn sâu vào đối tượng - Cảm ơn, mặc dù :) – Lewis

+0

Tôi đã thêm một câu trả lời (thô, chưa được kiểm tra) cho biết cách kiểm tra từng vị trí tạm thời để xem có xảy ra va chạm hay không. – markE

Trả lời

1

Kể từ khi bạn đang di chuyển người chơi 8 vị trí mỗi KeyDown, trong KeyDown bạn phải kiểm tra mỗi người 8 vị trí tạm thời để xem nếu một vụ va chạm xảy ra.

Cảnh báo: - (! Lẽ) mã chưa được kiểm tra một số tinh chỉnh cần thiết

window.addEventListener('keydown', function(e) { 
    // save x,y before the move 
    var beginningX=_self.position.x; 
    var beginningY=_self.position.y; 

    // test each interim positon between the beginning & 
    // current position for collisions 
    // if a collision occurs, stop at the collision position 
    if(e.keyCode == 38 || e.keyCode == 87){ 
     _self.position.y -= _self.speed; 
     _self.position.y = testInterimVerticalCollisions(
      beginningY, _self.position.y, _self.position.x); 
    } 

    if(e.keyCode == 40 || e.keyCode == 83){ 
     _self.position.y += _self.speed; 
     _self.position.y = testInterimVerticalCollisions(
      beginningY, _self.position.y, _self.position.x); 
    } 

    if(e.keyCode == 37 || e.keyCode == 65){ 
     _self.position.x -= _self.speed; 
     _self.position.x = testInterimHorizontalCollisions(
      beginningX, _self.position.x, _self.position.y); 
    } 

    if(e.keyCode == 39 || e.keyCode == 68){ 
     _self.position.x += _self.speed; 
     _self.position.x = testInterimHorizontalCollisions(
      beginningX, _self.position.x, _self.position.y); 
     } 
    } 
}) 

// test if any interim movement caused a collision 
// if yes, return the x that caused the collision 
// if no, return the ending x 
function testInterimHorizontalCollisions(beginningX,endingX,y){ 
    for(var x=beginningX;x<=endingX;x++){ 
     // TODO: adjust for camera position offset 
     var cellX = parseInt(x/cellWidth); 
     var cellY = parseInt(y/cellHeight); 
     if(getCell(cellX,cellY)==2){return(x);} 
    } 
    return(endingX); 
} 

// test if any interim movement caused a collision 
// if yes, return the y that caused the collision 
// if no, return the ending y 
function testInterimVerticalCollisions(beginningY,endingY,x){ 
    for(var y=beginningY;y<=endingY;y++){ 
     // TODO: adjust for camera position offset 
     var cellX = parseInt(x/cellWidth); 
     var cellY = parseInt(y/cellHeight); 
     if(getCell(cellX,cellY)==2){return(y);} 
    } 
    return(endingY); 
} 
+1

Xin cảm ơn! Tôi đã kết thúc với một giải pháp dựa trên câu trả lời này. Điều này tất cả sẽ dễ dàng đến với tôi một ngày, nhưng chưa được;) – Lewis

2

Bạn cần phải tính toán vị trí mới của người chơi bằng cách thêm/trừ tốc độ đến/từ hiện tại x/y vị trí. Sau đó, bạn cần tính toán phạm vi pixel được trình phát ở vị trí mới bao phủ. Sau đó, bạn cần tính toán phạm vi ô tương ứng với phạm vi pixel. Sau đó, bạn cần phải lặp qua phạm vi ô để xem có bất kỳ va chạm nào không. Lưu ý rằng khi tính toán đúng/pixel đáy bao phủ bởi người chơi, bạn cần phải thêm x/y và chiều rộng/chiều cao và sau đó trừ đi 1.

Change ...

this.didCollide = function(dir) { 
    if(dir == 'right'){ 
     var newBlock = window.tileMap.getCell(Math.floor((_self.position.x + _self.width)/32), Math.floor((this.position.y + this.height/2)/32)); 
     if(newBlock == 2) 
      return true; 
    } 
}; 

để ...

this.didCollide = function(dir) { 
    if(dir == 'right'){ 
     var col1 = Math.floor((_self.position.x + _self.speed)/32); 
     var col2 = Math.floor((_self.position.x + _self.speed + _self.width - 1)/32); 
     var row1 = Math.floor((_self.position.y)/32); 
     var row2 = Math.floor((_self.position.y + _self.height - 1)/32); 
     document.getElementById("player").textContent = "player: " + _self.position.x + " " + _self.position.y + " " + _self.width + " " + _self.height; 
     document.getElementById("cells").textContent = "cells: " + col1 + " " + col2 + " " + row1 + " " + row2; 
     for (var c = col1; c <= col2; c++) { 
      for (var r = row1; r <= row2; r++) { 
       var newBlock = window.tileMap.getCell(c, r); 
       if(newBlock == 2) { 
        return true; 
       } 
      } 
     } 
    } 
    return false; 
}; 
Các vấn đề liên quan