【问题标题】:Collision detection algorithm in JavascriptJavascript中的碰撞检测算法
【发布时间】:2019-09-21 04:38:31
【问题描述】:

我想创建一个函数,使用 JavaScript 对画布中的两个对象进行碰撞检测。我有硬币对象和存钱罐对象。我正在尝试创建一个函数,当硬币接触存钱罐时,硬币对象会消失。谁能帮我解释一下碰撞检测的算法吗?

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="https://unpkg.com/konva@4.0.5/konva.min.js"></script>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        body{
            margin:0;
            padding: 0;
            overflow: hidden;
            background-color: lightyellow; 
        }
        .konvajs-content{
            background-color: aliceblue;
            margin: 5%;
            border: solid 5px gray;
        }
        #stage-parent{
            width: 100%;
        }
     
    </style>
</head>
<body>
    <div id="stage-parent">
    <div id="container"></div>
</div>
<script>
 var stageWidth =  1200;
 var stageHeight = 1200;

    var stage = new Konva.Stage({
        width: stageWidth,
        height: stageHeight,
        container: 'container'
    });

    var layer = new Konva.Layer();
    stage.add(layer);

    //1yen
    var ichiYenImg = new Konva.Image({
        x:20,
        y:20,
        width:100,
        height: 100,
        draggable: true
            }); 
    layer.add(ichiYenImg);

    //5yen
    var goYenImg = new Konva.Image({
        x:200,
        y:20,
        width:100,
        height: 100,
        draggable: true
    });
layer.add(goYenImg);

    //10yen
    var jyuYenImg = new Konva.Image({
        x:200,
        y:50,
        width:100,
        height: 100,
        draggable: true
    });
layer.add(jyuYenImg);

    //50yen
    var gojyuYenImg = new Konva.Image({
        x:20,
        y:50,
        width:100,
        height: 100,
        draggable: true
    });
layer.add(gojyuYenImg);

    //500yen
    var gohyakuYenImg = new Konva.Image({
        x:100,
        y:20,
        width:100,
        height: 100,
        draggable: true
    });
layer.add(gohyakuYenImg);

    //100yen
    var hyakuYenImg = new Konva.Image({
        x:100,
        y:50,
        width:100,
        height: 100,
        draggable: true
    });
layer.add(hyakuYenImg);

  //piggy bank 1yen
  var ichiYenpiggyImg = new Konva.Image({
        x:100,
        y:500,
        width:100,
        height: 100,
        draggable: false
    });
layer.add(ichiYenpiggyImg);

//piggy bank 5yen
var goYenpiggyImg = new Konva.Image({
        x:450,
        y:500,
        width:100,
        height: 100,
        draggable: false
    });
layer.add(goYenpiggyImg);

//piggy bank 10yen
var jyuYenpiggyImg = new Konva.Image({
        x:800,
        y:500,
        width:100,
        height: 100,
        draggable: false
    });
layer.add(jyuYenpiggyImg);

//piggy bank 50yen
var gojyuYenpiggyImg = new Konva.Image({
        x:100,
        y:650,
        width:100,
        height: 100,
        draggable: false
    });
layer.add(gojyuYenpiggyImg);

//piggy bank 100yen
var hyakuYenpiggyImg = new Konva.Image({
        x:450,
        y:650,
        width:100,
        height: 100,
        draggable: false
    });
layer.add(hyakuYenpiggyImg);

//piggy bank 500yen
var gohyakuYenpiggyImg = new Konva.Image({
        x:800,
        y:650,
        width:100,
        height: 100,
        draggable: false
    });
layer.add(gohyakuYenpiggyImg);

//1yen
var imageObj1 = new Image();
imageObj1.onload = function(){
    ichiYenImg.image(imageObj1);
    layer.draw();
};
var sourceImg1 = "https://illustrain.com/img/work/2016/illustrain09-okane5.png";
drawImage(sourceImg1, ichiYenImg);
//5yen

var sourceImg2 = "https://illustrain.com/img/work/2016/illustrain09-okane7.png";
drawImage(sourceImg2, goYenImg);
//10yen

var sourceImg3 = "https://illustrain.com/img/work/2016/illustrain09-okane6.png";
drawImage(sourceImg3, jyuYenImg);
//50yen

var sourceImg4 = "https://illustrain.com/img/work/2016/illustrain02-money04.png";
drawImage(sourceImg4, gojyuYenImg);
//100yen

var sourceImg5 = "https://illustrain.com/img/work/2016/illustrain09-okane8.png";
drawImage(sourceImg5, hyakuYenImg);

//500yen
var sourceImg6 = "https://illustrain.com/img/work/2016/illustrain02-money06.png";
drawImage(sourceImg6, gohyakuYenImg);
//piggy1yen

var sourceImg7 = "https://user-images.githubusercontent.com/31402838/63416628-a322b080-c3b4-11e9-96e8-e709ace70ec1.png";
drawImage(sourceImg7, ichiYenpiggyImg);

//piggy5yen

var sourceImg8 = "https://user-images.githubusercontent.com/31402838/63416629-a322b080-c3b4-11e9-94a8-eb6c008d4584.png";
drawImage(sourceImg8, goYenpiggyImg);

//piggy10yen

var sourceImg9 = "https://user-images.githubusercontent.com/31402838/63416630-a322b080-c3b4-11e9-95ef-a04228fc3c0d.png";
drawImage(sourceImg9, jyuYenpiggyImg);
//piggy50yen
var sourceImg10 = "https://user-images.githubusercontent.com/31402838/63416631-a322b080-c3b4-11e9-9e99-43061e2eaf2c.png";
drawImage(sourceImg10, gojyuYenpiggyImg);

//piggy100yen
var sourceImg11 = "https://user-images.githubusercontent.com/31402838/63416626-a322b080-c3b4-11e9-9ff6-00b3babf3fe9.png";
drawImage(sourceImg11, hyakuYenpiggyImg);

//piggy500yen
var sourceImg12 = "https://user-images.githubusercontent.com/31402838/63416627-a322b080-c3b4-11e9-86c4-4edf13a57063.png";
drawImage(sourceImg12, gohyakuYenpiggyImg);

// This will draw the image on the canvas.
function drawImage(source, konvaImage) {
    var image = new Image();
    image.src = source;
    image.onload = function() {
        konvaImage.image(image);
        layer.draw();
    }
}

//use event delegation to update pointer style
layer.on('mouseover', function(evt){
    var shape = evt.target;
    document.body.style.cursor = 'pointer';
    shape.strokeEnabled(false);
    layer.draw();
});

layer.on('mouseout', function(evt){
    var shape = evt.target;
    document.body.style.cursor = 'default';
    shape.strokeEnabled(false);
    layer.draw();
});

function fitStageIntoParentContainer(){
    var container = document.querySelector('#stage-parent');
    

    var containerWidth = container.offsetWidth;
    var scale = containerWidth / stageWidth;

    stage.width(stageWidth * scale);
    stage.height(stageHeight * scale);
    stage.scale({x:scale, y: scale});
    stage.draw(); 
}
fitStageIntoParentContainer();
window.addEventListener('resize', fitStageIntoParentContainer);


</script>
</body>
</html>

【问题讨论】:

标签: javascript html canvas


【解决方案1】:

调试这些问题的第一件事是将代码缩减为一个小示例。
一旦你有了它,你就可以做更复杂的事情了。

以下是您的工作冲突代码:

var stage = new Konva.Stage({
  width: 400,
  height: 200,
  container: 'container'
});
var layer = new Konva.Layer();
stage.add(layer);

layer.on('dragmove', function(e) {
  var target = e.target;
  var targetRect = e.target.getClientRect();
  layer.children.each(function(obj) {
    if (obj === target) {
      return;
    }
    if (haveIntersection(obj.getClientRect(), targetRect)) {
      alert("Intersection")
    }    
  });
});

function haveIntersection(r1, r2) {
  return !(
    r2.x > r1.x + r1.width/2 ||
    r2.x + r2.width/2 < r1.x ||
    r2.y > r1.y + r1.height/2 ||
    r2.y + r2.height/2 < r1.y
  );
}

// This will draw the image on the canvas.
function drawImage(source, konvaImage) {
  layer.add(konvaImage);
  var image = new Image();
  image.src = source;
  image.onload = function() {
    konvaImage.image(image);
    layer.draw();
  }
}


//1yen
var ichiYenImg = new Konva.Image({
  x: 20,
  y: 20,
  width: 100,
  height: 100,
  draggable: true
});
var sourceImg1 = "https://illustrain.com/img/work/2016/illustrain09-okane5.png";
drawImage(sourceImg1, ichiYenImg);

//piggy bank 1yen
var ichiYenpiggyImg = new Konva.Image({
  x: 300,
  y: 100,
  width: 100,
  height: 100,
  draggable: false
});
var sourceImg7 = "https://user-images.githubusercontent.com/31402838/63416628-a322b080-c3b4-11e9-96e8-e709ace70ec1.png";
drawImage(sourceImg7, ichiYenpiggyImg);
<!DOCTYPE html>
<html lang="en">

<head>
  <script src="https://unpkg.com/konva@4.0.5/konva.min.js"></script>
</head>

<body>
  <div id="stage-parent">
    <div id="container"></div>
  </div>
</body>

</html>

这里的关键是function haveIntersection,我们假设碰撞框是对象的宽度和高度的 1/2 的正方形。

该函数内部的条件是:

  • r1 的右边缘是否位于 r2 左边缘的右边缘?或
  • r1 的左边缘是否位于 r2 的右边缘的左边缘?或
  • r1 的底部边缘是否低于 r2 的顶部边缘?或
  • r1 的顶部边缘是否高于 r2 的底部边缘?

这里有更多详细信息:
http://jeffreythompson.org/collision-detection/rect-rect.php

【讨论】:

  • 非常感谢您的解释!能否请您更详细地解释一下函数 haveIntersection 内部的计算?
  • @Kijimu7 我添加了更多细节...但是haveIntersection 中的计算很少它们周围的白色填充物……那里到底有什么不清楚的地方?
  • 我现在了解函数 haveIntersection。非常感谢您的帮助:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2015-02-02
  • 2010-11-07
  • 1970-01-01
相关资源
最近更新 更多