如果 2 个对象相互碰撞,Javascript 如何停止动画

JavasScript How to stop animation if 2 object hits each other

我制作了一个关于移动矩形的脚本。 我想在两个对象相互碰撞时停止动画,并将矩形 bot 的 javasript 输出制作到左上角。 我该怎么做?

这是我的实际代码:

<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>
window.onload=function(){
    var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

// define a rect using a javascript object
var rect1={
  x:25,
  y:150,
  width:180,
  height:50,
  directionX:1
}

// define another rect using a javascript object
var rect2={
  x:800,
  y:150,
  width:200,
  height:80,
  directionX:-1
}

// put each rect in a rects[] array
var rects=[rect1,rect2];

// start the animation loop
requestAnimationFrame(animate);

function animate(time){

  // move each rect in the rects[] array by its 
  // own directionx
  for(var i=0;i<rects.length;i++){
    rects[i].x+=rects[i].directionX;
  }

  // draw all the rects in their new positions
  draw();

  // request another frame in the animation loop
  requestAnimationFrame(animate);
}

function draw(){
  ctx.clearRect(0,0,cw,ch);
  for(var i=0;i<rects.length;i++){
    var r=rects[i]
    ctx.strokeRect(r.x,r.y,r.width,r.height);  
  }

}


}
</script>
</head>
<body>
  <canvas id="canvas" width="1000px" height="600"
    style="border: 1px solid #000000;"></canvas>
</body>
</html>

我会给你几个选项来停止你的动画。所有这些都使用基本的轴对齐矩形碰撞检测算法。

  1. 取消动画本身。这使用 cancelAnimationFrame()

window.onload=function(){
    var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

// define a rect using a javascript object
var rect1={
  x:25,
  y:150,
  width:180,
  height:50,
  directionX:1
}

// define another rect using a javascript object
var rect2={
  x:800,
  y:150,
  width:200,
  height:80,
  directionX:-1
}

// put each rect in a rects[] array
var rects=[rect1,rect2];
  
function collision(obj1, obj2) {
  if (obj1.x + obj1.width <= obj2.x ||
      obj1.y + obj1.height <= obj2.y ||
      obj1.x >= obj2.x + obj2.width ||
      obj1.y >= obj2.y + obj2.height) {
    return true
  }
 return false
}

function animate(time){
  // move each rect in the rects[] array by its 
  // own directionx
  for(var i=0;i<rects.length;i++){
    rects[i].x+=rects[i].directionX;
  }
  // draw all the rects in their new positions
  draw();
 
  // request another frame in the animation loop
  let anim = requestAnimationFrame(animate);
  //cancel is they collide
  if (!collision(rect1, rect2)) {
    cancelAnimationFrame(anim)
  }
}
animate();
  
function draw(){
  ctx.clearRect(0,0,cw,ch);
  for(var i=0;i<rects.length;i++){
    var r=rects[i]
    ctx.strokeRect(r.x,r.y,r.width,r.height);  
  }
}
}
<canvas id="canvas" width="1000px" height="600"
    style="border: 1px solid #000000;"></canvas>

  1. 此示例将对象的 directionX 更改为 0,但允许动画循环继续到 运行。如果您打算为其他事物制作动画,您可能需要它。

window.onload=function(){
    var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

// define a rect using a javascript object
var rect1={
  x:25,
  y:150,
  width:180,
  height:50,
  directionX:1
}

// define another rect using a javascript object
var rect2={
  x:800,
  y:150,
  width:200,
  height:80,
  directionX:-1
}

// put each rect in a rects[] array
var rects=[rect1,rect2];
  
function collision(obj1, obj2) {
  if (obj1.x + obj1.width <= obj2.x ||
      obj1.y + obj1.height <= obj2.y ||
      obj1.x >= obj2.x + obj2.width ||
      obj1.y >= obj2.y + obj2.height) {
    return
  }
  obj1.directionX = 0;
  obj2.directionX = 0;
}

function animate(time){
  // move each rect in the rects[] array by its 
  // own directionx
  for(var i=0;i<rects.length;i++){
    rects[i].x+=rects[i].directionX;
  }
  // draw all the rects in their new positions
  draw();
  collision(rect1, rect2)
  // request another frame in the animation loop
  requestAnimationFrame(animate);
}
animate();
  
function draw(){
  ctx.clearRect(0,0,cw,ch);
  for(var i=0;i<rects.length;i++){
    var r=rects[i]
    ctx.strokeRect(r.x,r.y,r.width,r.height);  
  }
}
}
 <canvas id="canvas" width="1000px" height="600"
    style="border: 1px solid #000000;"></canvas>

  1. 此选项使用 switch/trigger 暂停动画循环中的 for 循环函数

window.onload=function(){
    var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var collided = false;
// define a rect using a javascript object
var rect1={
  x:25,
  y:150,
  width:180,
  height:50,
  directionX:1
}

// define another rect using a javascript object
var rect2={
  x:800,
  y:150,
  width:200,
  height:80,
  directionX:-1
}

// put each rect in a rects[] array
var rects=[rect1,rect2];
  
function collision(obj1, obj2) {
  if (obj1.x + obj1.width <= obj2.x ||
      obj1.y + obj1.height <= obj2.y ||
      obj1.x >= obj2.x + obj2.width ||
      obj1.y >= obj2.y + obj2.height) {
    return
  }
  collided = true
}

function animate(time){
  // move each rect in the rects[] array by its 
  // own directionx
  if (!collided) {
    for(var i=0;i<rects.length;i++){
      rects[i].x+=rects[i].directionX;
    }
  }
  // draw all the rects in their new positions
  draw();
  collision(rect1, rect2)
  // request another frame in the animation loop
  requestAnimationFrame(animate);
}
animate();
  
function draw(){
  ctx.clearRect(0,0,cw,ch);
  for(var i=0;i<rects.length;i++){
    var r=rects[i]
    ctx.strokeRect(r.x,r.y,r.width,r.height);  
  }
}
}
<canvas id="canvas" width="1000px" height="600"
    style="border: 1px solid #000000;"></canvas>

至于你问题的另一部分,我不明白你在问什么。请更清楚地说明“将矩形机器人的 javasript 输出到左上角”是什么意思。

你运行调用动画requestAnimationFrame(animate)

所以如果你想停止动画,可以很简单,只需 stop 调用它! :)

如何?

您可以使用 if 语句 :

if(collision){
    // Not requesting a new frame
    // Do the actions on collision
} else {
    // Requesting a new frame
    requestAnimationFrame(animate);
}

碰撞函数如下所示:

function collision(){
    let collision = false;
    if(rect1.x > rect2.x + rect2.width ||
       rect1.x + rect1.width < rect2.x ||
       rect1.y > rect2.y + rect2.height ||
       rect1.y + rect1.height < rect2.y){
        // console.log(`No collision between rect1 and rect2`);
    } else {
        // console.log(`Collision !! between rect1 and rect2`);
        collision = true;
    }
    return collision;
}

无碰撞条件的解释:

关于输出是什么,可以用fillText()来记录 canvas.

上你想要的矩形位置
for(let i = 0; i < rects.length; i++){
    ctx.font = `20px Arial`;
    ctx.fillStyle = "black";
    ctx.textAlign = "left";
    ctx.textBaseline = "top";
    ctx.fillText(`Rect ${i + 1}: x = ${rects[i].x}, y = ${rects[i].y}`, 10, 10 + 20 * i);
}

对于多个矩形:

window.onload = function(){
  const canvas = document.getElementById("canvas");
  const ctx = canvas.getContext("2d");
  const cw = canvas.width;
  const ch = canvas.height;
  
  const rect1 = {
    x: 25,
    y: 30,
    width: 180,
    height: 50,
    directionX: 1
  }
  
  const rect2 = {
    x: 800,
    y: 30,
    width: 200,
    height: 80,
    directionX: -1
  }
  
  const rect3 = {
    x: -215,
    y: 90,
    width: 500,
    height: 90,
    directionX: 1
  }
  
  const rects = [rect1, rect2, rect3];
  
  function collision(){
    let collision = false;
    for(let i = 0; i < rects.length - 1; i++){
      for(let j = i + 1; j < rects.length; j++){
        if( rects[i].x > rects[j].x + rects[j].width ||
            rects[i].x + rects[i].width < rects[j].x ||
            rects[i].y > rects[j].y + rects[j].height ||
            rects[i].y + rects[i].height < rects[j].y){
          // console.log(`No collision between rect${i+1} and rect${j+1}`);
        } else {
          // console.log(`Collision !! between rect${i+1} and rect${j+1}`);
          collision = true;
        }
      }
    }
    return collision;
  }
  
  function logPosition(){
    for(let i = 0; i < rects.length; i++){
      ctx.font = `14px Arial`;
      ctx.fillStyle = "black";
      ctx.textAlign = "left";
      ctx.textBaseline = "top";
      ctx.fillText(`Rect ${i + 1}: x = ${rects[i].x}, y = ${rects[i].y}`, 10, 10 + 14 * i);
    }
  }
  
  function update(){
    for(let i = 0; i < rects.length; i++){
      rects[i].x += rects[i].directionX;
    }
  }

  function draw(){
    ctx.clearRect(0, 0, cw, ch);
    for(let i = 0; i < rects.length; i++){
      // ------ Draw the rectangle --------------
      ctx.strokeRect(rects[i].x, rects[i].y, rects[i].width, rects[i].height);
      
      // ------ Show name on the rectangle ------
      ctx.font = `20px Arial`;
      ctx.textAlign = "center";
      ctx.textBaseline = "middle";
      ctx.fillStyle = "black";
      ctx.fillText(`Rect ${i + 1}`, rects[i].x + rects[i].width / 2, rects[i].y + rects[i].height / 2);
      // ----------------------------------------
    }
  }

  function animate(time){
  
    // Update rectangles position
    update();
    
    // Draw updated rectangles
    draw();
    
    // Outpout (top-left) the position of the rectangles if collision otherwise, request a new frame
    if(collision()){
      logPosition();
      console.log("COLLISION");
    } else {
      requestAnimationFrame(animate);
    }
  }

  // Start the animation
  requestAnimationFrame(animate);
}
<!DOCTYPE html>
<html>
<head>

</head>
<body>
  <canvas id="canvas" width="1000px" height="600"
    style="border: 1px solid #000000;"></canvas>
</body>
</html>

Why multiple rectangles ?

因为您只对 2 个矩形使用了长袜数组(矩形)和 for 循环,所以我认为将来可能会有更多矩形,所以我选择了更一般的情况。但如果它真的只适用于 2 个矩形,我会放弃放养阵列和 for 循环。

只有 2 个矩形:

window.onload = function(){
  const canvas = document.getElementById("canvas");
  const ctx = canvas.getContext("2d");
  const cw = canvas.width;
  const ch = canvas.height;
  
  const rect1 = {
    x: 25,
    y: 50,
    width: 180,
    height: 50,
    directionX: 1
  }
  
  const rect2 = {
    x: 800,
    y: 50,
    width: 200,
    height: 80,
    directionX: -1
  }
  
  function collision(){
    let collision = false;
    if( rect1.x > rect2.x + rect2.width ||
        rect1.x + rect1.width < rect2.x ||
        rect1.y > rect2.y + rect2.height ||
        rect1.y + rect1.height < rect2.y){
      // console.log(`No collision between rect1 and rect2`);
    } else {
      // console.log(`Collision !! between rect1 and rect2`);
      collision = true;
    }
    return collision;
  }
  
  function logPosition(){
    ctx.font = `14px Arial`;
    ctx.fillStyle = "black";
    ctx.textAlign = "left";
    ctx.textBaseline = "top";
    ctx.fillText(`Rect 1: x = ${rect1.x}, y = ${rect1.y}`, 10, 10);
    ctx.fillText(`Rect 2: x = ${rect2.x}, y = ${rect2.y}`, 10, 24);
  }
  
  function update(){
    rect1.x += rect1.directionX;
    rect2.x += rect2.directionX;
  }

  function draw(){
    ctx.clearRect(0, 0, cw, ch);
    
    // ------ Draw the rectangles ---------------
    ctx.strokeRect(rect1.x, rect1.y, rect1.width, rect1.height);
    ctx.strokeRect(rect2.x, rect2.y, rect2.width, rect2.height);
      
    // ------ Show name on the rectangles ------
    ctx.font = `20px Arial`;
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.fillStyle = "black";
    ctx.fillText(`Rect 1`, rect1.x + rect1.width / 2, rect1.y + rect1.height / 2);
    ctx.fillText(`Rect 2`, rect2.x + rect2.width / 2, rect2.y + rect2.height / 2);
    // -----------------------------------------
  }

  function animate(time){
  
    // Update rectangles position
    update();
    
    // Draw updated rectangles
    draw();
    
    // Outpout (top-left) the position of the rectangles if collision otherwise, request a new frame
    if(collision()){
      logPosition();
      console.log("COLLISION");
    } else {
      requestAnimationFrame(animate);
    }
  }

  // Start the animation
  requestAnimationFrame(animate);
}
<!DOCTYPE html>
<html>
<head>

</head>
<body>
  <canvas id="canvas" width="1000px" height="600"
    style="border: 1px solid #000000;"></canvas>
</body>
</html>

就是这样!

但是如果您有其他动作并且需要动画循环保持 运行ning,那么,另一个选择是停止更新逻辑(矩形的位置)。它可以通过使用 if 语句 :

来实现
function animate(time){

    // Update rectangles position
    if(!collision()){
        update();
    } else {
        logPosition();
        console.log("COLLISION");
    }
    
    // Draw updated rectangles
        draw();
    
    // Outpout (top-left) the position of the rectangles if collision otherwise, request a new frame
    requestAnimationFrame(animate);

}