2013-07-19 105 views
0

正如標題所示,我遇到物體碰撞的麻煩... 我目前正在使用JavaScript的2d Html5帆布遊戲。我知道如何讓「玩家」對象遠離遊戲畫布的寬度/高度,並且我知道如何在玩家與對象發生碰撞時(例如力量或敵人或其他物體)做些事情,但我只是當玩家擊中立體物體時,不知道如何製作「固體」物體,玩家剛剛停止,並且不能穿過立體物體。2d html5帆布碰撞,howto

這是我現在有(不是所有的只是我的感覺代碼是相關的,對不起,如果這是太多/太少:

var canvasPlayer = document.getElementById('canvasPlayer'); 
var ctxPlayer = canvasPlayer.getContext('2d'); 
var canvasWalls = document.getElementById('canvasWalls'); 
var ctxWalls = canvasWalls.getContext('2d'); 

function checkKeyDown(e) { 
     var keyID = (e.keyCode) || e.which; 
     if (keyID === 38 || keyID === 87) { // up arrow OR W key 
     if (!player1.isDownKey && !player1.isLeftKey && !player1.isRightKey) { 
     player1.isUpKey = true; 
     e.preventDefault(); 
     } } 
     if (keyID === 39 || keyID === 68) { //right arrow OR D key 
     if (!player1.isDownKey && !player1.isLeftKey && !player1.isUpKey) { 
     player1.isRightKey = true; 
     e.preventDefault(); 
     } } 
     if (keyID === 40 || keyID === 83) {//down arrow OR S key 
     if (!player1.isUpKey && !player1.isLeftKey && !player1.isRightKey) { 
     player1.isDownKey = true; 
     e.preventDefault(); 
     } } 
     if (keyID === 37 || keyID === 65) {//left arrow OR A key 
     if (!player1.isDownKey && !player1.isUpKey && !player1.isRightKey) { 
     player1.isLeftKey = true; 
     e.preventDefault(); 
     } 
     } 
    } 

    Walls.prototype.draw = function(){ 
     ctxWalls.drawImage(imgSprite,this.srcX,this.srcY,this.width,this.height,this.drawX,this.drawY,this.width,this.height); 
     this.checkHitPlayer(); 
     }; 
    Walls.prototype.checkHitPlayer = function() { 
     if (this.drawX > player1.drawX && 
     this.drawX <= player1.drawX + player1.width && 
     this.drawY >= player1.drawY && 
     this.drawY < player1.drawY + player1.height) { 
     player1.isUpKey = false; 
     player1.isDownKey = false; 
     player1.isRightKey = false; 
     player1.isLeftKey = false; 
      } 
    }; 

這工作,試着上去時除外或左邊,玩家只能移動2-3個像素,所以需要3個向左或向上的箭頭向左或向上移動,同時玩家可以直接穿過牆壁,這不是我想要的。如果我包含了太多或者沒有足夠的代碼哦,我也忘了提及這款遊戲是一款益智遊戲,並且我已經設置好了,所以玩家一次只能移動一個方向,直到碰到牆壁。

回答

7

如果你只是想您的播放器停止時達到一堵牆,你可以應用一些數學:

例如:假設您的播放器是由10px的矩形和右牆的X位置10px的是200

矩形右側的X位置計算如下:

var playerRightSide = player.x + player.width; 

您可以測試玩家已經達到了這樣的牆:

if(playerRightSide >= 200) 

如果用戶試圖將他們的播放器推到牆壁之外,您可以使用播放器的X位置將播放器放在牆的左邊。

if(playerRightSide >= 200) { player.x = 190; } 

190是牆的X位置(200)減去玩家的寬度(10)。

如果您有興趣進行更高級的碰撞測試,請進一步閱讀。

許多基本遊戲衝突可分爲3種類型:

  • 圈與圈碰撞
  • 矩形與矩形碰撞
  • 矩形與圓形碰撞

這裏有一個圖如何檢測這些常見碰撞中的每一個。

假設你確定了一個圓是這樣的:

var circle1={ 
    x:30, 
    y:30, 
    r:10 
}; 

假設你定義一個矩形這樣的:

var rect1={ 
    x:20, 
    y:100, 
    w:20, 
    h:20 
}; 

您可以檢測圈VS圈的碰撞是這樣的...

enter image description here

...使用這個圈VS圈碰撞測試代碼:

// return true if the 2 circles are colliding 
    // c1 and c2 are circles as defined above 

    function CirclesColliding(c1,c2){ 
     var dx=c2.x-c1.x; 
     var dy=c2.y-c1.y; 
     var rSum=c1.r+c2.r; 
     return(dx*dx+dy*dy<=rSum*rSum); 
    } 

您可以檢測矩形VS矩形碰撞是這樣的...

enter image description here

...使用此矩形與矩形碰撞測試代碼:

// return true if the 2 rectangles are colliding 
    // r1 and r2 are rectangles as defined above 

    function RectsColliding(r1,r2){ 
     return !(r1.x>r2.x+r2.w || r1.x+r1.w<r2.x || r1.y>r2.y+r2.h || r1.y+r1.h<r2.y); 
    } 

您可以檢測矩形VS圈的碰撞是這樣的...

enter image description here

...使用這個矩形VS圈碰撞測試代碼:

// return true if the rectangle and circle are colliding 
    // rect and circle are a rectangle and a circle as defined above 

    function RectCircleColliding(rect,circle){ 
     var dx=Math.abs(circle.x-(rect.x+rect.w/2)); 
     var dy=Math.abs(circle.y-(rect.y+rect.y/2)); 

     if(dx > circle.r+rect.w2){ return(false); } 
     if(dy > circle.r+rect.h2){ return(false); } 

     if(dx <= rect.w){ return(true); } 
     if(dy <= rect.h){ return(true); } 

     var dx=dx-rect.w; 
     var dy=dy-rect.h 
     return(dx*dx+dy*dy<=circle.r*circle.r); 
    } 

例如,可以使用這些碰撞測試來響應玩家觸摸上電立方體:

// create a circular player object 
    // that's located at [30,30] and has a radius of 10px 

    var player={x:30,y:30,r:10}; 


    // create a rectangular power-up at position [200,30] 

    var powerup={x:200, y:30, w:20, h:20}; 


    // Let's say the user keys the player to coordinate [200,35] 
    // (touching the power-up) 

    player.x = 220; 
    player.y = 35; 


    // you can test if the circular player is touching the rectangular power-up 

    if(RectCircleColliding(powerup,player) ) { 

     // the player has collided with the power-up, give bonus power! 

     player.power += 100; 

    } 

這裏是代碼和一個小提琴:http://jsfiddle.net/m1erickson/u6t48/

<!doctype html> 
<html> 
<head> 
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css --> 
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script> 

<style> 
    body{ background-color: ivory; padding:20px; } 
    canvas{border:1px solid red;} 
</style> 

<script> 
    $(function(){ 

     var canvas=document.getElementById("canvas"); 
     var ctx=canvas.getContext("2d"); 

     window.requestAnimFrame = (function(callback) { 
      return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || 
      function(callback) { 
      window.setTimeout(callback, 1000/60); 
      }; 
     })(); 

     ctx.fillStyle="lightgray"; 
     ctx.strokeStyle="skyblue"; 

     // top collision circle vs circle 
     var circle1={x:30,y:30,r:10}; 
     var circle2={x:70,y:40,r:10}; 
     var circle3={x:100,y:30,r:10}; 
     var direction1=1; 

     // middle collision rect vs rect 
     var rect1={x:20,y:100,w:20,h:20}; 
     var rect2={x:50,y:110,w:20,h:20}; 
     var rect3={x:90,y:100,w:20,h:20}; 
     var direction2=1; 

     // bottom collision rect vs circle 
     var circle4={x:30,y:200,r:10}; 
     var rect4={x:50,y:205,w:20,h:20}; 
     var circle5={x:100,y:200,r:10}; 
     var direction3=1; 


     function drawAll(){ 
      ctx.clearRect(0,0,canvas.width,canvas.height); 
      drawCircle(circle1); 
      drawCircle(circle2); 
      drawCircle(circle3); 
      drawCircle(circle4); 
      drawCircle(circle5); 
      drawRect(rect1); 
      drawRect(rect2); 
      drawRect(rect3); 
      drawRect(rect4); 
     } 

     function drawCircle(c){ 
      ctx.beginPath(); 
      ctx.arc(c.x,c.y,c.r,0,Math.PI*2,false); 
      ctx.closePath(); 
      ctx.fill(); 
      ctx.stroke(); 
     } 

     function drawRect(r){ 
      ctx.beginPath(); 
      ctx.rect(r.x,r.y,r.w,r.h); 
      ctx.closePath(); 
      ctx.fill(); 
      ctx.stroke(); 
     } 

     // return true if the 2 circles are colliding 
     function CirclesColliding(c1,c2){ 
      var dx=c2.x-c1.x; 
      var dy=c2.y-c1.y; 
      var rSum=c1.r+c2.r; 
      return(dx*dx+dy*dy<=rSum*rSum); 
     } 

     // return true if the 2 rectangles are colliding 
     function RectsColliding(r1,r2){ 
      return !(r1.x>r2.x+r2.w || r1.x+r1.w<r2.x || r1.y>r2.y+r2.h || r1.y+r1.h<r2.y); 
     } 

     // return true if the rectangle and circle are colliding 
     function RectCircleColliding(rect,circle){ 
      var dx=Math.abs(circle.x-(rect.x+rect.w/2)); 
      var dy=Math.abs(circle.y-(rect.y+rect.h/2)); 

      if(dx > circle.r+rect.w/2){ return(false); } 
      if(dy > circle.r+rect.h/2){ return(false); } 

      if(dx <= rect.w){ return(true); } 
      if(dy <= rect.h){ return(true); } 

      var dx=dx-rect.w; 
      var dy=dy-rect.h 
      return(dx*dx+dy*dy<=circle.r*circle.r); 
     } 

     var fps = 15; 
     function animate() { 
      setTimeout(function() { 
       requestAnimFrame(animate); 

       // circle vs circle 
       circle2.x = circle2.x+direction1; 
       if(CirclesColliding(circle2,circle1) || CirclesColliding(circle2,circle3) ){ 
        direction1=-direction1; 
       } 

       // rect vs rect 
       rect2.x = rect2.x+direction2; 
       if(RectsColliding(rect2,rect1) || RectsColliding(rect2,rect3)){ 
        direction2=-direction2; 
       } 

       // rect vs circle 
       rect4.x = rect4.x+direction3; 
       if(RectCircleColliding(rect4,circle4) || RectCircleColliding(rect4,circle5)){ 
        direction3=-direction3; 
       } 

       drawAll(); 

      }, 1000/fps); 
     } 

     animate(); 

    }); // end $(function(){}); 
</script> 

</head> 

<body> 
    <canvas id="canvas" width=300 height=300></canvas> 
</body> 
</html> 
+0

嘿,我知道這個話題是舊的,但我又遇到問題時,我已經設置了塊之間的碰撞,其中如果「播放器」擊中「目標」, 「玩家」停在「對象」的左側。 但我希望「玩家」能夠從任何一邊(左,上,下,右)擊中相同的「對象」,並適當停止。任何指針爲newby? 哦,我忘了提及,謝​​謝你的迴應:) – user2582299

+0

我發佈的碰撞函數將處理來自各方的碰撞。看看這個小提琴:http://jsfiddle.net/m1erickson/EKCRJ/ – markE

+0

Thankyou爲您的快速回復!我正在閱讀你評論的鏈接,我可能是錯的,但我不確定這正是我想要做的。我有一個問題,從今天早些時候解釋自己更好,如果你不介意看一下? http://stackoverflow.com/questions/17932679/how-do-i-create-2d-object-collision-from-每-sidetop,左右下角,prope – user2582299