精华内容
下载资源
问答
  • 物体碰撞检测方法

    千次阅读 2012-07-23 15:07:05
    物体碰撞检测方法 在屏幕上有只有两物体时, 判断它们之间的碰撞是非常简单的。但是如果物体很时,我们就需要了解一些碰撞检测的策略,以便不遗漏任何可能发生的碰撞。当要检测的物体越来越时,如果进行有效...
    多物体碰撞检测方法 在屏幕上有只有两个物体时, 判断它们之间的碰撞是非常简单的。但是如果物体很多时,我们就需要了解一些碰撞检测的策略,以便不遗漏任何可能发生的碰撞。当要检测的物体越来越多时,如果进行有效的判断就显得至关重要。 基本的多物体碰撞检测 当只有两个物体时,碰撞只可能在 A - B 物体间发生。如果有三个物体,就有三种可能:A – B, B – C, C – A。如果是四个物体就有六种可能,五个物体就有十种可能。 如果物体多达 20 个,就需要分别进行判断 190 次。这就意味着在我们的 enterFrame
     函数中,需要调用 190 次 hitTest 方法或距离计算。 如果使用这种方法,那么就会多用出必要判断的两倍!比如说 20 个物体就执行了 380 次 if 语句(20 个影片每个判断 19 次,20 * 19 = 380)。大家现在知道学习本节内容的重要性了吧。 看一下问题,审视一下平常的做法。假设我们有六个影片,分别为 sprite0, sprite1, sprite2, sprite3, sprite4, sprite5。让它们运动并执行反弹,我们想要知道它们之间何时会发生碰撞。思考一下,依次获得每个影片的引用,然后再执行循环,再去和其它的影片进行比较。下面是一段伪代码:
     numSprites = 6; for (i = 0; i < numSprites; i++) { spriteA = sprites[i]; for (j = 0; j < numSprites; j++) { spriteB = sprites[j]; if (spriteA.hitTestObject(spriteB)) { // 执行代码 } } } 六个影片执行了 36 次判断。看上去很合理,对吗?其实,这段代码存在着两大问题。首先,来看第一次循环,变量 i 和 j 都等于 0。因此 spriteA
     所持的引用是 sprite0,而 spriteB 的引用也是一样。嗨,我们原来是在判断这个影片是否和自己发生碰撞!无语了。所以要在 hitTest 之前确认一下 spriteA != sprieB,或者可以简单地写成 i != j。代码就应该是这样: numSprites = 6; for (i = 0; i < numSprites; i++) { spriteA = sprites[i]; for (j = 0; j < numSprites; j++) { spriteB = sprites[j];
     if (i != j && spriteA.hitTestObject(spriteB)) { // do whatever } } } OK,现在已经排除了六次判断,判断次数降到了 30 次,但还是太多。下面列出每次比较的过程: sprite0 与 sprite1, sprite2, sprite3, sprite4, sprite5 进行比较 sprite1 与 sprite0, sprite2, sprite3, sprite4, sprite5 进行比较 sprite2 与 sprite0, sprite1,
     sprite3, sprite4, sprite5 进行比较 sprite3 与 sprite0, sprite1, sprite2, sprite4, sprite5 进行比较 sprite4 与 sprite0, sprite1, sprite2, sprite3, sprite5 进行比较 sprite5 与 sprite0, sprite1, sprite2, sprite3, sprite4 进行比较 请看第一次判断: 用 sprite0 与 sprite1 进行比较。再看第二行: sprite1
     与 sprite0 进行比较。它俩是一回事,对吧?如果 sprite0 没有与 sprite1 碰撞,那么 sprite1 也肯定不会与 sprite0 碰撞。或者说,如果一个物体与另一个碰撞,那么另一个也肯定与这个物体发生碰撞。所以可以排除两次重复判断。如果删掉重复判断,列表内容应该是这样的: sprite0 与 sprite1, sprite2, sprite3, sprite4, sprite5 进行比较 sprite1 与 sprite2, sprite3, sprite4, sprite5 进行比较
     sprite2 与 sprite3, sprite4, sprite5 进行比较 sprite3 与 sprite4, sprite5 进行比较 sprite4 与 sprite5 进行比较 sprite5 没有可比较的对象! 我们看到第一轮判断,用 sprite0 与每个影片进行比较。随后,再没有其它影片与 sprite0 进行比较。把 sprite0 放下不管,再用 sprite1 与剩下的影片进行比较。当执行到最后一个影片 sprite5 时,所有的影片都已经和它进行过比较了,因此 sprite5 不需要再与任何影片进行比较了。结果,比较次数降到了
     15 次,现在大家明白我为什么说初始方案通常执行了实际需要的两倍了吧。 那么接下来如果写代码呢?仍然需要双重嵌套循环,代码如下: numSprites = 6; for (i = 0; i < numSprites - 1; i++) { spriteA = sprites[i]; for (j = i + 1; j < numSprites; j++) { spriteB = sprites[j]; if (spriteA.hitTestObject(spriteB)) { // do whatever
     } } } 请注意,外层循环执次数比影片总数少一次。就像我们在最后的列表中看到的,不需要让最后一个影片与其它影片比较,因为它已经被所有影片比较过了。 内层循环的索引以外循环索引加一作为起始。这是因为上一层的内容已经比较过了,而且不需要和相同的索引进行比较。这样一来执行的效率达到了 100%。
    
    展开全文
  • 碰撞检测

    2018-02-23 08:38:00
    心血来潮,就想写写碰撞检测,废话不说,直接怼。 矩形和矩形的碰撞检测 现有rect1 = {x:0,y:0,w:5,h:5};rect2 = {x:10,y:10,w:5,h:5};。矩形我们一般拥有的都是左上角点的XY以及他的宽高WH。碰撞当然就是我中有...
        

    碰撞检测

    刚才回答了一个H5游戏的问答。心血来潮,就想写写碰撞检测,废话不多说,直接怼。

    矩形和矩形的碰撞检测

    现有rect1 = {x:0,y:0,w:5,h:5};rect2 = {x:10,y:10,w:5,h:5};
    矩形我们一般拥有的都是左上角点的XY以及他的宽高WH。碰撞当然就是我中有你,你中有我咯,那么就是判断四条边,在我左边的右边,右边的左边,上边的下边,下边的上边。说起来有点绕口,那就直接上代码吧,下面四个条件如果都成立那么就是有交集,他们碰撞了。

    rect1.x < rect2.x + rect2.w // rect1.x 代表左边界
    rect1.x + rect1.w > rect2.x // rect1.x + rect1.w 代表右边界
    rect1.y < rect2.y + rect2.h // rect1.y 代表上边界
    rect1.y + rect1.h > rect2.y // rect1.y + rect1.h 代表下边界
    //x和y可以看做起始点,x+w和y+h可以看做终止点。
    
    

    圆形和圆形的碰撞检测

    现有circle1={x:5,y:5,r:1};circle2={x:8,y:8,r:1}
    圆形我们一般拥有的是圆心点的XY以及他的半径r。圆的碰撞怎么判断呢?计算两个圆心点的距离,如果距离大于他们的半径相加就可以了。那好,我们怼代码了。坐标相减算出来的是坐标点之间的距离,这样我们是不是一个直角三角形?勾股定理可以求出第三条边,这样我们就可以比较了

    Math.sqrt((circle2.x - circle1.x)**2+(circle2.y - circle1.y)**2)>circle2.r + circle1.r
    

    clipboard.png

    圆形和矩形的碰撞检测

    现有circle={x:5,y:5,r:1};rect={x:10,y:10,w:5,h:5};
    这个就有点难度了不是想象中的那么简单,要检查圆形和矩形碰撞,矩形上找到离圆心最近的点,比较两点距离对于半径。

    //我们先找x轴,比较圆心点和矩形左边界,如果不是比对右边界。如果不存在左右就是存在中间呗。
    if(circle.x<rect.x){return x}
    else if(circle.x>rect.x+rect.w){return rect.x+rect.w}
    else{return circle.x}
    //我们再去找y轴,同样的道理.
    if(circle.y<rect.y){return y}
    else if(circle.y>rect.y+rect.h){return rect.y+rect.h}
    else{return circle.y}
    //有上面我们获得到的量,去计算就可以了,这就很简单了。
    
    

    圆形与旋转矩形碰撞检测

    可以看我下面的那个链接,我在这里先大体说一下原理,旋转部分是把矩形复原,把圆形通过矩形的中心点旋转,也可以理解为旋转画布,然后找圆形中心点,之后基本原理同上。

    椭圆与椭圆碰撞检测

    其他的检测手段

    不管什么东西,老夫就是正面刚
    1.canvascontext.globalCompositeOperation="source-in";
    destination-in 在源图像中显示目标图像。只有源图像之内的目标图像部分会被显示,源图像是透明的。
    source-in 在目标图像中显示源图像。只有目标图像之内的源图像部分会显示,目标图像是透明的。
    clipboard.png

    资料

    1. 圆形与矩形碰撞检测
    2. 圆形与旋转矩形碰撞检测
    3. HTML canvas globalCompositeOperation 属性
    4. 椭圆碰撞检测
    展开全文
  • 通过两球心的距离和半径的关系来实现碰撞检测。 需要注意的一点是两球在碰撞时需要根据碰撞点的位置和角度调整球的位置,如果不调整位置会导致出现两球粘在一起的情况。 两球碰撞后速度改变是基于假设球体质量相同...
  • 简单的碰撞检测的常见方法有:1.外接矩形判断2.外接圆判断一,外接矩形判断判断两矩形是否发生碰撞,只需要判断:两矩形左上角的坐标所处的范围,如果两矩形的左上角的坐标满足一定的条件,两矩形就发生碰撞...

    简单的碰撞检测的常见方法有:

    1.外接矩形判断

    2.外接圆判断


    一,外接矩形判断

    判断两个矩形是否发生碰撞,只需要判断:两个矩形左上角的坐标所处的范围,如果两个矩形的左上角的坐标满足一定的条件,两个矩形就发生碰撞

    语法:

    window.tools.checkRect=function(rectA,rectB){

         return (

            rectA.x+rectA.width<rectB.x||
            rectA.y+rectA.height<rectB.y||

             rectB.x+rectB.width<rectA.x||
            rectB.y+rectB.height<rectA.y

        );

    };

    代码在tools.js里面

    在线demo:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    
    <body>
        <p id="msg"></p>
        <canvas id="canvas" width="800" height="800"></canvas>
    
        <script src="../assit/arrow.js"></script>
        <script src="../assit/tools.js"></script>
         <script src="../assit/ball.js"></script>
        <script>
        function $$(id) {
            return document.getElementById(id);
        }
        window.onload = function() {
            var cnv = $$("canvas");
            var cxt = cnv.getContext("2d");
            var msg=document.getElementById("msg");
            //定义一个位置固定的小球
            var ballA=new Ball(cnv.width/2,cnv.height/2,30);
            //获取ballA的外接矩形
            var rectA=ballA.getRect();
            var mouse=tools.getMouse(cnv);
    
            ;(function frame(){
                window.requestAnimationFrame(frame);
                cxt.clearRect(0,0,cnv.width,cnv.height);
                ballA.fill(cxt);
                //绘制ballA以及他的外接矩形
                cxt.strokeRect(rectA.x,rectA.y,rectA.width,rectA.height);
    
                //定义一个位置不固定的小球,小球追随鼠标
                var ballB=new Ball(mouse.x,mouse.y,30);
                //获取ballB的外接圆
                var rectB=ballB.getRect();
                //绘制ballB以及他的外接矩形
                cxt.strokeRect(rectB.x,rectB.y,rectB.width,rectB.height);
                  ballB.fill(cxt);
                //碰撞检测
    
                if(tools.checkRect(rectA,rectB)){
                    msg.innerHTML="碰到了";
                }
                else{
                    msg.innerHTML="没碰到";
                }
    
    
    
            })();
        }
        </script>
    </body>
    
    </html>

    外接矩形的应用(简单俄罗斯方块)在线demo

    这里新增了一个Box.js文件来生成随机宽高和随机颜色的方块

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    
    <body>
        <canvas id="canvas" width="300" height="400"></canvas>
        <script src="../assit/arrow.js"></script>
        <script src="../assit/tools.js"></script>
        <script src="../assit/ball.js"></script>
        <script src="../assit/Box.js"></script>
        <script>
        function $$(id) {
            return document.getElementById(id);
        }
        window.onload = function() {
            var cnv = $$("canvas");
            var cxt = cnv.getContext("2d");
    
            //定义一个用来存放方块的数组
            var boxes = [];
            //定义一个当前的方块
            var activeBox = createBox();
            //定于y轴方向速度
            var vy = 1;
            //定义一个函数createBox,用户创建新的方块
            function createBox() {
                var x = Math.random() * cnv.width;
                var y = 0;
                var width = Math.random() * 40 + 10;
                var height = Math.random() * 40 + 10;
                var color = window.tools.getRandomColor();
                console.log(color)
                var box = new Box(x, y, width, height, color);
                //添加到数组
                boxes.push(box);
                return box;
            };
            //获取键盘
            //获取按键方向
            var key = tools.getKey();
            window.addEventListener("keydown", function() {
                cxt.clearRect(0, 0, cnv.width, cnv.height);
                console.log("这里只执行一次")
                //根据key.direction的值,判断物体的移动方向、
                switch (key.direction) {
                    case "down":
                        activeBox.y += 5;
    
                        break;
                    case "left":
                        activeBox.x -= 5;
    
                        break;
                    case "right":
                        activeBox.x += 5;
    
                        break;
    
                }
            }, false);
    
    
            (function frame() {
                window.requestAnimationFrame(frame);
                cxt.clearRect(0, 0, cnv.width, cnv.height);
                activeBox.y += vy;
                //边界检测,如果到底底部,则创建一个新的box
                if (activeBox.y > cnv.height - activeBox.height) {
                    activeBox.y = cnv.height - activeBox.height;
                    activeBox = createBox();
                }
                //遍历数组boxes,一遍单独处理每一个BOX
                boxes.forEach(function(box) {
                    //如果单钱遍历的box不是活动(activeBox),并且单钱遍历的方块与“活动方块(activeBox)”碰上,则创建新的方块
                    //console.log(activeBox,"box",box)
                    if (activeBox !== box && tools.checkRect(activeBox, box)) {
                        activeBox.y = box.y - activeBox.height;
                        activeBox = null;
                        activeBox = createBox();
                    }
                    box.fill(cxt);
                })
            })();
    
    
    
        }
        </script>
    </body>
    
    </html>


    二,外接圆判断方法

    如果一个物体是一个圆或者接近圆,我们可以把这个物体抽象为一个圆,然后用两个圆来进行碰撞检测

    在实际开发中,什么时候用外接矩形,什么时候用圆取决于物体的形状,那个方法误差大,就用那个

    外接圆碰撞检测只需要判断两个圆的圆心距

    语法:

    window.tools.checkCircle=function(circleB,circleA){
            var dx=circleB.x-cirlceA.x;
            var dy=circleB.y-circleA.y;
            var distance=Math.sqrt()dx*dx+dy*dy;
    
            if(distance<(circleA.radius+circleB.radius)){
                return true;
            }    
    
         else{
            return false;       
       }
    }

    外接圆碰撞检测,在线demo:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    
    <body>
        <div id="txt"></div>
        <canvas id="canvas" width="800" height="800"></canvas>
        <script src="../assit/arrow.js"></script>
        <script src="../assit/tools.js"></script>
        <script src="../assit/ball.js"></script>
        <script>
        function $$(id) {
            return document.getElementById(id);
        }
        window.onload = function() {
            var cnv = $$("canvas");
            var cxt = cnv.getContext("2d");
            //定义一个位置固定的小球
            var ballA = new Ball(10, cnv.height / 2, 20, "#FF6699");
            var ballB = new Ball(cnv.width - 10, cnv.height / 2, 20, "#000000");
            
            var vx=2;//定义小球的X轴速度
            ;
            (function frame() {
                window.requestAnimationFrame(frame);
                cxt.clearRect(0, 0, cnv.width, cnv.height);
               
               ballA.x+=vx;
               ballB.x-=vx;
    
    
               //如果发生碰撞,速度都取反,tools.checkCircle(ballB,ballA) 
               if(tools.checkCircle(ballB,ballA)  ||(ballB.x>cnv.width - 10&&ballA.x<10)){
                    vx=-vx;
               }
               
                ballA.fill(cxt);
                ballB.fill(cxt);
            })();
        }
        </script>
    </body>
    
    </html>


    三,多个物体两两比较碰撞检测

     两两比较有个公式是:

    n*(n-1)/2,这个公式是我四年级时候学的,现在还很印象深刻。

    意思是N个物体两两比较的时候需要对比n*(n-1)/2次

    下面在回顾下N年前的知识,同时用代码展示一次

    案例,现有小球5个,分别是b0,b1,b2,b3,b4,两两比较分别有一下几种情况

    b0与 b0,b1,b2,b3,b4,

    b1与 b0,b1,b2,b3,b4,

    b2与 b0,b1,b2,b3,b4,

    b3与 b0,b1,b2,b3,b4,

    b4与 b0,b1,b2,b3,b4,

    对应代码,balls=[ b0,b1,b2,b3,b4];

    balls.forEach(ballA,i){
    for(var j=0;balls.length;j++){
      var ballB=balls[j];
      if(tools.checkCircle(ballA,ballB)){
       //******
      }
    }
    }

    弊端:

    1.每个求都和自己对比了

    2.b0和b1对比后,b1还会和b0对比


    解决方法:

    b0与b1,b2,b3,b4

    b1与b2,b3,b4

    b2与b3,b4

    b3与b4

    b4与没有任何物体对比

    代码:

     balls.forEach(function(ballA,i){
            for(var j=0;balls.length;j++){
                var ballB=balls[i];
                if(i!j&&tools.checkCircle(ballA,ballB)){
                    //*****
                }
            }
        })


    多个外接圆碰撞(有bug)在线demo:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    
    <body>
        <div id="txt"></div>
        <canvas id="canvas" width="800" height="800"></canvas>
        <script src="../assit/arrow.js"></script>
        <script src="../assit/tools.js"></script>
        <script src="../assit/ball.js"></script>
        <script>
        function $$(id) {
            return document.getElementById(id);
        }
        window.onload = function() {
            var cnv = $$("canvas");
            var cxt = cnv.getContext("2d");
         
            var n = 10;
            var balls = [];
    
            //生成N个小球,小球的x、y、color、vx,vy素质取得都是随机值
            for (var i = 0; i < n; i++) {
                ball = new Ball();
                ball.x = Math.random() * cnv.width;
                ball.y = 10;
                console.log(ball.x,ball.y)
                ball.radius = 10;
                ball.color = tools.getRandomColor();
                ball.vx = Math.random() * 6 - 3;
                ball.vy = Math.random() * 6 - 3;
                //添加到数组
                balls.push(ball);
            }
    
            //碰撞检测(小球和小球)
            function checkCollision(ballA, i) {
                for (var j = i + 1; j < balls.length; j++) {
                    var ballB = balls[j];
                    //如果两个小球碰撞后,则碰撞的vx,vy都取反
                    if (tools.checkCircle(ballB, ballA)) {
                        ballA.vx = -ballA.vx;
                        ballA.vy = -ballB.vy;
                        ballB.vx = -ballB.vx;
                        ballB.vy = -ballB.vy;
                    }
                }
            };
            //边界检测(小球和边界)
            function checkBorder(ball) {
                //碰撞到最左边
                if (ball.x < ball.radius) {
                    ball.x = ball.radius;
                    ball.vx = -ball.vx;
    
                } else if (ball.x > cnv.width - ball.radius) {
                    ball.x = cnv.width - ball.radius;
                    ball.vx = -ball.vx;
                }
                //碰到最顶上
                if (ball.y < ball.radius) {
                    ball.y = ball.radius;
                    ball.vy = -ball.vy;
                    console.log("yxiaoyu")
                } else if (ball.y > cnv.height - ball.radius) {
                    console.log("y大于")
                    ball.y = cnv.height - ball.radius;
                    ball.vy = -ball.vy;
                }
            }
            //绘制小球
            function drawBall(ball){
                ball.fill(cxt);
                ball.x+=ball.vx;
                ball.y+=ball.vy;
            }
    
    
    
    
    
    
            ;
            (function frame() {
                window.requestAnimationFrame(frame);
                cxt.clearRect(0, 0, cnv.width, cnv.height);
                //碰撞检测
                balls.forEach(checkCollision);
                //边界检测
                balls.forEach(checkBorder);
               balls.forEach(drawBall);
    
    
            })();
        }
        </script>
    </body>
    
    </html>

    会有小球重叠的问题,解决方案是碰撞的同事把小球加上一个偏移量(重叠问题,可能是物体的速度问题),但是如果物品再多一点,还是有这个问题

    改良的添加偏移量的在线demo:

    这里我故意吧个数调多了,如果想看正常的可以把个数改小一点

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    
    <body>
        <div id="txt"></div>
        <canvas id="canvas" width="800" height="800"></canvas>
        <script src="../assit/arrow.js"></script>
        <script src="../assit/tools.js"></script>
        <script src="../assit/ball.js"></script>
        <script>
        function $$(id) {
            return document.getElementById(id);
        }
        window.onload = function() {
            var cnv = $$("canvas");
            var cxt = cnv.getContext("2d");
    
            var n = 20;
            var balls = [];
    
            //生成N个小球,小球的x、y、color、vx,vy素质取得都是随机值
            for (var i = 0; i < n; i++) {
                ball = new Ball();
                ball.x = Math.random() * cnv.width;
                ball.y = 10;
                console.log(ball.x, ball.y)
                ball.radius = Math.random()*10+10;
                ball.color = tools.getRandomColor();
                ball.vx = Math.random() * 6 - 3;
                ball.vy = Math.random() * 6 - 3;
                //添加到数组
                balls.push(ball);
            }
    
            //碰撞检测(小球和小球)
            function checkCollision(ballA, i) {
                for (var j = i + 1; j < balls.length; j++) {
                    var ballB = balls[j];
                    //如果两个小球碰撞后,则碰撞的vx,vy都取反
                    if (tools.checkCircle(ballB, ballA)) {
                        ballA.vx = -ballA.vx;
                        ballA.vy = -ballB.vy;
                        ballB.vx = -ballB.vx;
                        ballB.vy = -ballB.vy;
    
    
                        //每次碰撞,小球的,x,y都添加一个半径偏移量,避免相互重叠,只是一定程度减少重叠,不能根治
                        if (ballA.vx > 0) {
                            ballA.x += 10;
                        } else {
                            ballA.x -= 10;
                        }
                        if (ballA.y > 0) {
                            ballA.y += 10;
                        } else {
                            ballA.y -= 10;
                        }
    
    
                        if (ballB.vx > 0) {
                            ballB.x += 10;
                        } else {
                            ballB.x -= 10;
                        }
                        if (ballB.y > 0) {
                            ballB.y += 5;
                        } else {
                            ballB.y -= 5;
                        }
    
                    }
                }
            };
            //边界检测(小球和边界)
            function checkBorder(ball) {
                //碰撞到最左边
                if (ball.x < ball.radius) {
                    ball.x = ball.radius;
                    ball.vx = -ball.vx;
    
                } else if (ball.x > cnv.width - ball.radius) {
                    ball.x = cnv.width - ball.radius;
                    ball.vx = -ball.vx;
                }
                //碰到最顶上
                if (ball.y < ball.radius) {
                    ball.y = ball.radius;
                    ball.vy = -ball.vy;
                    console.log("yxiaoyu")
                } else if (ball.y > cnv.height - ball.radius) {
                    console.log("y大于")
                    ball.y = cnv.height - ball.radius;
                    ball.vy = -ball.vy;
                }
            }
            //绘制小球
            function drawBall(ball) {
                ball.fill(cxt);
                ball.x += ball.vx;
                ball.y += ball.vy;
            }
    
    
    
    
    
    
            ;
            (function frame() {
                window.requestAnimationFrame(frame);
                cxt.clearRect(0, 0, cnv.width, cnv.height);
                //碰撞检测
                balls.forEach(checkCollision);
                //边界检测
                balls.forEach(checkBorder);
                balls.forEach(drawBall);
    
    
            })();
        }
        </script>
    </body>
    
    </html>


    展开全文
  • 多矩形碰撞 原理:设置多个矩形碰撞检测区域 检测碰撞矩形数组 与另一碰撞矩形数组之间的位置关系. 矩形碰撞 代码: public class MySurfaceView extends SurfaceView implements Callback, Runnable { private ...
  • 物体碰撞检测策略

    千次阅读 2014-07-08 19:04:19
    当只有两物体时,碰撞只可能在 A - B 物体间发生。如果有三物体,就有三种可能:A – B,B – C,C – A。如果是四物体就有六种可能,五物体就有十种可能。 如果物体多达 20 ,就需要分别进行判断 190 次...

    当只有两个物体时,碰撞只可能在 A - B 物体间发生。如果有三个物体,就有三种可能:A – B,B – C,C – A。如果是四个物体就有六种可能,五个物体就有十种可能。

    如果物体多达 20 个,就需要分别进行判断 190 次。这就意味着在我们的 enterFrame 函数中,需要调用 190 次 hitTest 方法或距离计算。

    如果使用这种方法,那么就会多用出必要判断的两倍!比如说 20 个物体就执行了 380次 if 语句(20 个影片每个判断 19 次,20 * 19 = 380)。大家现在知道学习本节内容的重要性了吧。

    看一下问题,审视一下平常的做法。假设我们有六个Sprite,分别为 sprite0,sprite1,sprite2,sprite3,sprite4,sprite5。让它们运动并执行反弹,我们想要知道它们之间何时会发生碰撞。思考一下,依次获得每个Sprite的引用,然后再执行循环,再去和其它的Sprite进行比较。下面是一段伪代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    numSprites = 6;
    for (i = 0; i < numSprites; i++)
    {
        spriteA = sprites[i]; 
        for (j = 0; j < numSprites; j++)
        {
            spriteB = sprites[j]; 
            if (spriteA.hitTestObject(spriteB))
            {
                // 执行代码
            }
        }
    }

    六个Sprite执行了 36 次判断。看上去很合理,对吗?其实,这段代码存在着两大问题。首先,来看第一次循环,变量 i 和 j 都等于 0。因此 spriteA 所持的引用是 sprite0,而 spriteB 的引用也是一样。嗨,我们原来是在判断这个影片是否和自己发生碰撞!无语了。所以要在 hitTest 之前确认一下 spriteA != sprieB,或者可以简单地写成 i != j。代码就应该是这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    numSprites = 6;
    for (i = 0; i < numSprites; i++)
    {
        spriteA = sprites[i];
        for (j = 0; j < numSprites; j++)
        {
            spriteB = sprites[j];
            if (i != j && spriteA.hitTestObject(spriteB))
            {
                // do whatever
            }
        }
    }

    OK,现在已经排除了六次判断,判断次数降到了 30 次,但还是太多。下面列出每次比较的过程:

    • sprite0 与 sprite1, sprite2, sprite3, sprite4, sprite5 进行比较
    • sprite1 与 sprite0, sprite2, sprite3, sprite4, sprite5 进行比较
    • sprite2 与 sprite0, sprite1, sprite3, sprite4, sprite5 进行比较
    • sprite3 与 sprite0, sprite1, sprite2, sprite4, sprite5 进行比较
    • sprite4 与 sprite0, sprite1, sprite2, sprite3, sprite5 进行比较
    • sprite5 与 sprite0, sprite1, sprite2, sprite3, sprite4 进行比较

    请看第一次判断: 用 sprite0 与 sprite1 进行比较。再看第二行: sprite1 与 sprite0 进行比较。它俩是一回事,对吧?如果 sprite0 没有与 sprite1 碰撞,那么 sprite1 也肯定不会与 sprite0 碰撞。或者说,如果一个物体与另一个碰撞,那么另一个也肯定与这个物体发生碰撞。所以可以排除两次重复判断。如果删掉重复判断,列表内容应该是这样的:

    • sprite0 与 sprite1, sprite2, sprite3, sprite4, sprite5 进行比较
    • sprite1 与 sprite2, sprite3, sprite4, sprite5 进行比较
    • sprite2 与 sprite3, sprite4, sprite5 进行比较
    • sprite3 与 sprite4, sprite5 进行比较
    • sprite4 与 sprite5 进行比较
    • sprite5 没有可比较的对象!

    我们看到第一轮判断,用 sprite0 与每个影片进行比较。随后,再没有其它影片与 sprite0 进行比较。把 sprite0 放下不管,再用 sprite1 与剩下的影片进行比较。当执行到最后一个影片 sprite5 时,所有的Sprite都已经和它进行过比较了,因此 sprite5 不需要再与任何影片进行比较了。结果,比较次数降到了 15 次,现在大家明白我为什么说初始方案通常执行了实际需要的两倍了吧。

    那么接下来如果写代码呢?仍然需要双重嵌套循环,代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    numSprites = 6
    for (i = 0; i < numSprites - 1; i++) 
    {
        spriteA = sprites[i];
        for (j = i + 1; j < numSprites; j++)
        {
            spriteB = sprites[j];
            if (spriteA.hitTestObject(spriteB)) 
            
                // do whatever
            }
        }
    }

    请注意,外层循环执次数比Sprite总数少一次。就像我们在最后的列表中看到的,不需要让最后一个Sprite与其它Sprite比较,因为它已经被所有Sprite比较过了。内层循环的索引以外循环索引加一作为起始。这是因为上一层的内容已经比较过了,而且不需要和相同的索引进行比较。这样一来执行的效率达到了 100%。

    展开全文
  • 小球碰撞检测

    2012-12-31 14:51:38
    java小球碰撞检测,使用图形界面实现多个小球的碰撞效果!
  • 关于碰撞检测

    2021-02-18 17:37:24
    1.系统默认会给每个对象添加一个碰撞组件,一些背景对象则可以取消该组件。 2.在Unity3D中,能检测碰撞发生的方式有两种,一种是利用碰撞器,另一种则是利用触发器。这两种方式的应用非常广泛。为了完整的了解这两种...
  • 碰撞检测算法

    2015-08-29 23:19:31
    目前正在用j2me开发一3D手游,所有的东西都做好了,但是由于积累不深,对于碰撞检测算法这块了解不
  •  多矩形的原理是:将一个物体A分解成多个矩形组成A组,将另外一个物体B分解成多个矩形组成B组,然后通过A组中的矩形和B组中的矩形是否发生了碰撞就可得知物体A与物体B是否发生了碰撞。 /** *...
  • 游戏之碰撞检测

    2019-05-09 22:22:35
    碰撞检测(Collision Detection):返回两个或多个物体是否发生碰撞的布尔判断。 碰撞确定(Collision Determination):找到物体之间实际相交位置。 碰撞响应(Collision Response):针对两个物体之间的碰撞决定采取何种...
  • 组合体碰撞检测

    2020-01-04 22:27:33
    Unity3D学习之组合体碰撞检测 本文将就组合体的碰撞检测进行测试、记录。碰撞的发生至少需要满足以下2条件:(1)碰撞对象都具有碰撞器(Collider),(2)至少有一对象具有刚体组件(rigidbody)。组合体一般是...
  • 1. 检测矩形是否重叠
  • lua 碰撞检测

    千次阅读 2016-10-06 17:54:30
    不规则图形碰撞检测 对于矩形碰撞,很多人都知道。但面对多边形图形,大多数采用矩形覆盖的方式。 但是我不是很喜欢这种方式,我所采用的是利用一经典算法: SAT 一种可以快速检测不规则的凸多边形是否碰撞...
  • android 游戏 碰撞检测

    千次阅读 2016-05-27 12:03:55
    矩形碰撞 原理: 两个矩形位置 的四种情况 不是这四中情况 则碰撞圆形碰撞 ...像素碰撞 :不适用 遍历所有像素 检测 太多了多矩形碰撞: 设置多个矩形碰撞检测区域 检测碰撞矩形数组 与另一碰撞矩形数组之间的位置关系.
  • 文中回顾了碰撞检测算法的发展历史并从多个角度对目前现有的算法进行了分类归纳;介绍了十余种代表性的基于 CPU 和 GPU 并行化碰撞检测算法,并从算法的可扩展性和存储空间消耗以及任务量均衡化等方面分析了这些算法...
  • 碰撞检测,故名思议,两元素在运动的过程中是否有接触。接下来,我们从简单到复杂的碰撞一一解析其中的算法。编码使用JavaScript。ps:下列图形均指实心图形点与点的碰撞这太简单了,不说,就是当坐标一致的...
  • 这几天放寒假了,时间也了...他虽然是搞C++的,但听了我代码解释中有检测圆形碰撞时,他立刻就发现了问题,他告诉我,敌人可以看作是方块,而攻击范围是圆的,如果把敌人弄成圆形进行碰撞检测那必然不准,应该检测
  • 有一影片实例是要对另一影片实例进行碰撞检测,但是这两影片实例都是用attachMovie语句或者用duplicateMovieClip语句复制到场景中的,并且两影片实例的复制数都大于一。如果觉得我这样说不够清楚的话,...
  •  碰撞检测是指在页面中有多个元素时,拖拽一个元素会出现碰撞问题,碰撞检测是以模拟拖拽和磁性吸附中的范围限定为基础的  效果:碰撞检测 ▓▓▓▓▓▓ 碰撞检测  先来看看碰撞检测的原理  我们想要移动...
  • 42. 碰撞检测

    2019-10-06 13:01:19
    如果世界是由多个动态物体构成的,充满了成万或成千万的三角形,那么如何用一种快速有效的方式检测和避免可能发生的碰撞?要解决这个问题其实并不简单。使用数学运算检查两个三角形之间是否存在碰撞,非常消耗CPU,...
  • cocos creator 碰撞检测系统collider

    千次阅读 2019-06-04 00:31:51
    cocos creator 内置了简单的碰撞检测系统,会根据当前节点下添加的碰撞组件进行碰撞检测。它可以应用在很多场景,比如可以用来判断子弹是否...如果节点下挂有多个碰撞组件时,可以根据标签来区分各个碰撞组件 Off...
  • “多点接入”表示许多计算机以多点接入的方式连接在一根总线上。...“碰撞检测”就是计算机边发送数据边检测信道上的信号电压大小。当几站同时在总线上发送数据时,总线上的信号电压摆动值将会增大(互相叠加)。...
  • Java之碰撞检测

    2015-05-30 09:31:00
    1.简介: 碰撞检测是计算机图形学和虚拟现实中最基本且非常重要的组成部分。...碰撞检测(Collision Detection):返回两个或多个物体是否发生碰撞的布尔判断。 碰撞确定(Collision Determination):找到物体...
  • 碰撞检测原理

    2017-08-24 09:39:00
    一切的碰撞都是通过网页中x,y坐标来计算的,判断两矩形是否发生碰撞,就是判断它们是否有重合部分。理论上是这样,但是实际上我们应该考虑什么时候不重合,因为这种逆向思维会简单很,如果一味考虑什么时候重合...
  • 碰撞检测入门

    2011-03-01 20:45:00
    在3D游戏开发、虚拟现实应用开发中,碰撞检测问题是最常见,也是最基本的。很傻很天真的办法就是遍历场景中所有的物体,每两物体之间做相交测试,相交即发生碰撞,然后对碰撞的问题做出相应的反应,比如用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,076
精华内容 430
关键字:

多个碰撞检测