javascript - 解决两个二维元素的碰撞

标签 javascript canvas collision-detection move

我试图让我的播放器围绕另一个播放器 move ,在 X 轴上它似乎没问题,但 Y 轴不工作。就像我想让它像检测方 block 一样检测“边界”,我想防止玩家与敌人重叠......

if ((87 in keysDown) && player.y > 0) {
  if ((player.x < player2.x -50 || player.x > player2.x+50))
    if( player.y < player2.y+50){
      player.y -= player.speed;
    }
}

最佳答案

2D 无转义

防止元素 move 到 map /舞台之外

 // After new x and y are set:
 this.x = Math.min(Math.max(0,this.x), Stage.w-this.w);
 this.y = Math.min(Math.max(0,this.y), Stage.h-this.h);
 // Where `this` is the moving element and `Stage` is the game area.

二维碰撞检测

function collision(A, B) {
  return !(((A.y+A.h)<(B.y))||(A.y>(B.y+B.h))||((A.x+A.w)<B.x)||(A.x>(B.x+B.w)));
}

像这样使用:

if( collision(Player,Enemy) ) {
   // explodePlayer(); // or whatever, they collided!
}

2D 解决碰撞

相反,如果您不想要被动碰撞检测,而是要解决 move 玩家的碰撞:

function resolveCollision(A, B) {
    // get the vectors to check against
    var vX = (A.x + (A.w / 2))  - (B.x + (B.w / 2)),
        vY = (A.y + (A.h / 2)) - (B.y + (B.h / 2)),
        // Half widths and half heights of the objects
        ww2 = (A.w / 2) + (B.w / 2),
        hh2 = (A.h / 2) + (B.h / 2),
        colDir = "";

    // if the x and y vector are less than the half width or half height,
    // they we must be inside the object, causing a collision
    if (Math.abs(vX) < ww2 && Math.abs(vY) < hh2) {
        // figures out on which side we are colliding (top, bottom, left, or right)
        var oX = ww2 - Math.abs(vX),
            oY = hh2 - Math.abs(vY);
        if (oX >= oY) {
            if (vY > 0) {
                colDir = "TOP";
                A.y += oY;
            } else {
                colDir = "BOTTOM";
                A.y -= oY;
            }
        } else {
            if (vX > 0) {
                colDir = "LEFT";
                A.x += oX;
            } else {
                colDir = "RIGHT";
                A.x -= oX;
            }
        }
    }
    return colDir; // If you need info of the side that collided
}

像这样使用:

resolveCollision(Player, Enemy);

或:

var res = resolveCollision(Player, Enemy);
console.log( res ); // "TOP", "BOTTOM"... (the side that collided uppercase)

实例:

// Collision boolean (useful for passive collision detection)
function collision(A, B) {
  return !(((A.y+A.h)<(B.y))||(A.y>(B.y+B.h))||((A.x+A.w)<B.x)||(A.x>(B.x+B.w)));
}

// Resolve collision
function resolveCollision(A, B) {
  // get the vectors to check against
  var vX = (A.x + (A.w / 2))  - (B.x + (B.w / 2)),
      vY = (A.y + (A.h / 2)) - (B.y + (B.h / 2)),
      // Half widths and half heights of the objects
      ww2 = (A.w / 2) + (B.w / 2),
      hh2 = (A.h / 2) + (B.h / 2),
      colDir = "";

  // if the x and y vector are less than the half width or half height,
  // they we must be inside the object, causing a collision
  if (Math.abs(vX) < ww2 && Math.abs(vY) < hh2) {
    // figures out on which side we are colliding (top, bottom, left, or right)
    var oX = ww2 - Math.abs(vX),
        oY = hh2 - Math.abs(vY);
    if (oX >= oY) {
      if (vY > 0) {
        colDir = "TOP";
        A.y += oY;
      } else {
        colDir = "BOTTOM";
        A.y -= oY;
      }
    } else {
      if (vX > 0) {
        colDir = "LEFT";
        A.x += oX;
      } else {
        colDir = "RIGHT";
        A.x -= oX;
      }
    }
  }
  return colDir;
}


// Elements
var cvs= document.createElement("canvas"),
    ctx= cvs.getContext("2d"),
    EL_collisionInfo = document.getElementById("collisionInfo");


// Game variables
var Stage = {
  w: 300,
  h: 200
},
    Keys = {},
    Player = {
      x: 0,
      y: 0,
      w: 30,
      h: 30,
      color: "blue",
      velocity: 4,
      move: function() {
        if(Keys[65]) { // A
          this.x -= this.velocity;
        } 
        if(Keys[87]) { // W
          this.y -= this.velocity; 
        }
        if(Keys[68]) { // D
          this.x += this.velocity;
        } 
        if(Keys[83]) { // S
          this.y += this.velocity; 
        }

        // General Collision / Touching
        var orgColor = "";
        if(collision(this, Enemy)) {
          this.color = "red";
        } else { // not colliding
          this.color = "blue";
        }

        // Resolve collision
        var coll = resolveCollision(this, Enemy);
        // And write info on screen
        EL_collisionInfo.innerHTML = coll;

        // Prevent go out of Stage
        this.x = Math.min(Math.max(0,this.x), Stage.w-this.w);
        this.y = Math.min(Math.max(0,this.y), Stage.h-this.h);
      }
    },
    Enemy = {
      x: 130,
      y: 80,
      w: 50,
      h: 50,
      color: "red"
    };


// INIT canvas and size
document.body.appendChild(cvs);
cvs.width = Stage.w;
cvs.height = Stage.h;


function canvasDraw( el ) {
  ctx.beginPath();
  ctx.fillStyle = el.color;
  ctx.fillRect(el.x, el.y, el.w, el.h);
}

// /////
// KEYBOARD LISTENERS
document.addEventListener("keydown", function(e){
  Keys[e.which] = 1;
}, false);
document.addEventListener("keyup", function(e){
  delete Keys[e.which];
}, false);


// /////
// ENGINE
(function engine() {

  Player.move();
  // Clear canvas and draw
  ctx.clearRect(0, 0, cvs.width, cvs.height);
  canvasDraw( Player );
  canvasDraw( Enemy );

  window.requestAnimationFrame( engine );
}());
*{box-sizing:border-box; -webkit-box-sizing:border-box;}
html, body{height:100%; margin:0; font:16px/20px sans-serif;}
canvas{background: #eee;}
#collisionInfo{position:absolute;}
WASD to move<br>
<p id="collisionInfo"></p>

关于javascript - 解决两个二维元素的碰撞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38648693/

相关文章:

JavaScript 日期时间字符串转换为秒?

javascript - 使用三 Angular 学为 HTML5 Canvas 制作动画,但如何定位这个正方形?

javascript - twitter bootstrap 侧面导航菜单 onclick 折叠

JavaScript 关闭 onclick

javascript - 当乒乓 Racket 移动时, Canvas 球会朝错误的方向弹跳

javascript - HTML5 Canvas 轮盘赌

hash - 使用哈希跟踪文件的唯一版本

java - 如何获取线与缓冲图像或矩形碰撞的点?

c++ - SFML2 与每个对象的碰撞

javascript - 在 Sonar 中显示 jsHint 和 cssLint 结果