Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/470.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 碰撞检测:分离轴定理-圆与多边形_Javascript_Html_Canvas_Collision Detection_Separating Axis Theorem - Fatal编程技术网

Javascript 碰撞检测:分离轴定理-圆与多边形

Javascript 碰撞检测:分离轴定理-圆与多边形,javascript,html,canvas,collision-detection,separating-axis-theorem,Javascript,Html,Canvas,Collision Detection,Separating Axis Theorem,我一直在努力实现基于的圆和多边形之间的碰撞检测,非常仔细地遵循代码,但算法永远不会返回true 这是我的建议。(为了方便起见,主体使用HTML5画布API呈现) 代码片段(仅冲突检测): constcircpoly=(a,b)=>{ 让data={}, 中心=a.pos; data.contacts=[]; center=b.mat.clone().trans().mult(center.clone().sub(b.pos)); 设sep=-Number.MAX_值, faceNorm=0; 对

我一直在努力实现基于的圆和多边形之间的碰撞检测,非常仔细地遵循代码,但算法永远不会返回true

这是我的建议。(为了方便起见,主体使用HTML5画布API呈现)

代码片段(仅冲突检测):

constcircpoly=(a,b)=>{
让data={},
中心=a.pos;
data.contacts=[];
center=b.mat.clone().trans().mult(center.clone().sub(b.pos));
设sep=-Number.MAX_值,
faceNorm=0;
对于(设i=0;ia.radius)返回数据;
如果(sep2>sep){sep=sep2;faceNorm=i;}
}
设v1=b.verts2[faceNorm],
v2=b.verts2[faceNorm+1a.radius)返回数据;
norm=b.mat.clone().mult(norm);
data.norm=norm.clone().neg();
data.contacts[0]=data.norm.clone().vmult(a.pos.clone().sadd(a.radius));
}
返回数据;
};
请注意,
b.verts2
指的是真实世界坐标中多边形的顶点

我知道Vector类没有问题,但由于我对转换矩阵没有太多的经验,这个类可能是这些错误的根源,尽管它的代码几乎完全来自脉冲引擎,所以它应该可以工作。如前所述,即使确实发生了碰撞,算法也总是返回false。我做错了什么?我试着去掉早期的返回值,但那只是返回奇怪的结果,比如带有负坐标的接触点,这显然是不太正确的

编辑:修改了向量类的垂直函数,使其工作方式与脉冲引擎相同(两种方法都是正确的,但我认为一种是顺时针的,另一种是逆时针的——我还修改了顶点以反映逆时针方向)。不幸的是,它仍然没有通过测试


问题很多,我真的不明白你想做什么,因为它看起来太复杂了。例如,为什么矩阵有
trans
???为什么要使用Y向上屏幕作为变换的坐标系???(修辞)

在第一个循环中

  • 第一个是测试法向量的距离 对于每个垂直,应测试垂直位置
  • 此外,您还可以使用所需的
    vec.dot
    函数查找距离 返回距离的平方。但是你要测试半径,你 应测试
    if(sep2
  • 你的比较方法是错误的 小于半径平方(不大于)时的测试
  • 然后,当检测到半径范围内的顶点时,返回数据 对象,但忘记将在圆内找到的顶点放在
    data.contacts
    数组
  • 我不确定保留最新索引的意图是什么 距离向量为,但函数的其余部分对 我???:(我试着去理解它
你需要做的就是

检查多边形上的任何顶点是否比半径更近,如果是,则有一个截距(或完全在内部)

然后需要检查每条线段的距离

如果您不需要截距(或低于截距,如果您需要截距),则可以使用以下方法对每个线段执行操作,仅使用其中一个

// circle is a point {x:?,y:?}
// radius = is the you know what
// p1,p2 are the start and end points of a line
        checkLineCircle = function(circle,radius,p1,p2){
            var v1 = {};
            var v2 = {};
            var v3 = {};
            var u;
            // get dist to end of line
            v2.x = circle.x - p1.x;
            v2.y = circle.y - p1.y;
            // check if end points are inside the circle
            if( Math.min(
                    Math.hypot(p2.x - circle.x, p2.y - circle.y),
                    Math.hypot(v2.x, v2.y)
                ) <= radius){
                return true;
            }
            // get the line as a vector
            v1.x = p2.x - p1.x;
            v1.y = p2.y - p1.y;
            // get the unit distance of the closest point on the line
            u = (v2.x * v1.x + v2.y * v1.y)/(v1.y * v1.y + v1.x * v1.x);
            // is this on the line segment
            if(u >= 0 && u <= 1){
                v3.x = v1.x * u;  // get the point on the line segment
                v3.y = v1.y * u;
                // get the distance to that point and return true or false depending on the 
                // it being inside the circle
                return (Math.hypot(v3.y - v2.y, v3.x - v2.x) <= radius);
            }
            return false; // no intercept
      }
//圆是点{x:?,y:?}
//半径=你知道吗
//p1、p2是直线的起点和终点
checkLineCircle=函数(圆、半径、p1、p2){
var v1={};
var v2={};
var v3={};
var u;
//把距离移到行尾
v2.x=圆.x-p1.x;
v2.y=圆.y-p1.y;
//检查端点是否在圆内
如果(Math.min)(
数学形下(p2.x-circle.x,p2.y-circle.y),
数学形下(v2.x,v2.y)

)=0&&u问题很多,我真的不明白你想做什么,因为它看起来太复杂了。例如,为什么矩阵有
trans
??为什么你要用Y向上屏幕作为变换的坐标系??(修辞)

在第一个循环中

  • 第一个是测试法向量的距离 对于每个垂直,应测试垂直位置
  • 此外,您还可以使用所需的
    vec.dot
    函数查找距离 返回距离的平方。但如果测试半径,则 应测试
    if(sep2
  • 你的比较方法是错误的 小于半径平方(不大于)时的测试
  • 然后,当检测到半径范围内的顶点时,返回数据 奥布耶
    // circle is a point {x:?,y:?}
    // radius = is the you know what
    // p1,p2 are the start and end points of a line
            checkLineCircle = function(circle,radius,p1,p2){
                var v1 = {};
                var v2 = {};
                var v3 = {};
                var u;
                // get dist to end of line
                v2.x = circle.x - p1.x;
                v2.y = circle.y - p1.y;
                // check if end points are inside the circle
                if( Math.min(
                        Math.hypot(p2.x - circle.x, p2.y - circle.y),
                        Math.hypot(v2.x, v2.y)
                    ) <= radius){
                    return true;
                }
                // get the line as a vector
                v1.x = p2.x - p1.x;
                v1.y = p2.y - p1.y;
                // get the unit distance of the closest point on the line
                u = (v2.x * v1.x + v2.y * v1.y)/(v1.y * v1.y + v1.x * v1.x);
                // is this on the line segment
                if(u >= 0 && u <= 1){
                    v3.x = v1.x * u;  // get the point on the line segment
                    v3.y = v1.y * u;
                    // get the distance to that point and return true or false depending on the 
                    // it being inside the circle
                    return (Math.hypot(v3.y - v2.y, v3.x - v2.x) <= radius);
                }
                return false; // no intercept
          }
    
    // p1,p2 are the start and end points of a line
     // returns an array empty if no points found or one or two points depending on the number of intercepts found
     // If two points found the first point in the array is the point closest to the line start (p1)
     function circleLineIntercept(circle,radius,p1,p2){
            var v1 = {};
            var v2 = {};
            var ret = [];
            var u1,u2,b,c,d;
            // line as vector
            v1.x = p2.x - p1.x;
            v1.y = p2.y - p1.y;
            // vector to circle center
            v2.x = p1.x - circle.x;
            v2.y = p1.y - circle.y;
            // dot of line and circle
            b = (v1.x * v2.x + v1.y * v2.y) * -2;
            // length of line squared * 2
            c = 2 * (v1.x * v1.x + v1.y * v1.y);
            // some math to solve the two triangles made by the intercept points, the circle center and the perpendicular line to the line.
            d = Math.sqrt(b * b - 2 * c * (v2.x * v2.x + v2.y * v2.y - radius * radius));
            // will give a NaN if no solution
            if(isNaN(d)){ // no intercept
                return ret;
            }
            // get the unit distance of each intercept to the line
            u1 = (b - d) / c;
            u2 = (b + d) / c;
    
            // check the intercept is on the line segment
            if(u1 <= 1 && u1 >= 0){  
                ret.push({x:line.p1.x + v1.x * u1, y : line.p1.y + v1.y * u1 });
            }
            // check the intercept is on the line segment
            if(u2 <= 1 && u2 >= 0){  
                ret.push({x:line.p1.x + v1.x * u2, y : line.p1.y + v1.y * u2});
            }
            return ret;
        }