旋转图像&像素碰撞检测 [英] Rotating Images & Pixel Collision Detection

查看:215
本文介绍了旋转图像&像素碰撞检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在这个 plunker 中有这个游戏。



当剑不旋转时,它一切正常(您可以通过取消注释行221和注释222-223检查)。当他们像上面的plunker一样旋转时,碰撞不能很好地工作。



我想这是因为getImageData记住旧的图像,但我收集一个昂贵的东西重新计算一遍又一遍。



有更好的方法来旋转我的图片,使这项工作吗?

罪魁祸首的代码:

 <$> c $ c> for(var i = 0; i  var monster = monsters [i]; 
if(monster.ready){
if(imageCompletelyOutsideCanvas(monster,monster.monsterImage)){
monster.remove = true;
}
// else {
//ctx.drawImage(monster.monsterImage,monster.x,monster.y);
drawRotatedImage(monster.monsterImage,monster.x,monster.y,monster);
monster.rotateCounter + = 0.05;
//}
}
}


解决方案

几何解决方案



通过更快速的几何解决方案来实现。



最简单的解决方案是具有圆交点算法的线段。


$ b


$ b

线段

多种方式。在这种情况下,我们将使用开始和结束坐标。

  var line = {
x1:?,
y1:?,
x2:?,
y2:?,
}


b $ b

圈子



圈子由其位置和半径描述

  var circle = {
x:?,
y:?,
r:?,
}

圆线段相交



我如何测试圆线段的碰撞。我不知道是否有一个更好的方式(很可能有),但这已经给我很好,是可靠的警告,线段必须有长度和圈子必须有面积。如果你不能保证这一点,那么你必须在代码中添加检查,以确保你不会被零除。



因此,为了测试一条线是否拦截了圆首先找出线上最近点的距离(注意,线是无限大,而线段具有长度,开始和结束)

  //快速转换vars,使其更容易阅读。 
var x1 = line.x1;
var y1 = line.y1;
var x2 = line.x2;
var y2 = line.y2;

var cx = circle.x;
var cy = circle.y;
var r = circle.r;

测试结果如果存在冲突则为真。

  var result; //测试结果

将行转换为向量。

  var vx = x2  -  x1; // convert line to vector 
var vy = y2 - y1;
var d2 =(vx * vx + vy * vy); //获取长度平方

获取线上近点圆周的单位距离。单位距离是从0到1(包括)的数字,表示沿点的矢量的距离。如果值小于0,那么点在向量之前,如果大于1,点就会越过结束。



我知道这是由内存和忘记的概念。它是线向量的点积和从线段的开始到圆心的向量除以线向量长度平方。

  //两个向量的点积是v1.x * v2.x + v1.y * v2.y对v1长度平方
u =((cx-x1)* vx +(cy- y1) * vy)/ d2;

现在使用单位位置来获得最接近圆的线的实际坐标

  //获取最接近的点
var xx = x1 + vx * u;
var yy = y1 + vy * u;

现在我们有一个点在线上,我们使用pythagoras平方根

  //获取与圆心的距离
var d = Math。 hypot(xx - cx,yy - cy);

现在如果线(不是线段)与圆相交,距离将等于或小于圆半径。

  if(d> r){//是大于半径的距离
result = false; // no intercept
} else {//否则我们需要更多的计算

如果线段已经截取了圆,我们需要找到线已经穿过的圆的圆周上的两个点。我们有半径和圆与线的距离。由于距离线的距离总是成直角,我们有一个直角三角形,其中hypot是半径,一边是找到的距离。



找出三角形缺失的长度。 UPDATE 查看改进版本的代码,从这里开始,在更新底部使用单位长度,而不是规范化行向量。

  // ld线距离是hyp减法平方的平方根
var ld = Math.sqrt(r * r - d * d)

现在将该距离添加到我们在 xx yy 通过将行向量除以其长度来对行向量进行归一化(使行向量为一个单位长),然后乘以上面的距离

  var len = Math.sqrt(d2) //得到行向量长度
var nx =(vx / len)* ld;
var ny =(vy / len)* ld;有些人可能看到我可以使用单位长度,并跳过了几个计算。是的,但我可以打扰重写的演示,所以将离开它是



现在通过添加和减去新的向量到最接近圆的线上

  ix1 = xx + nx; //最远的点
iy1 = xx + ny;
ix2 = xx - nx; //在另一个方向的点
iy2 = xx - ny;

现在我们有了这两个点,我们可以计算出它们是否在线段,单位距离,它们在原始线矢量上,使用点积除以平方距离。

  var u1 =((ix1-x1)* vx +(iy1-y1)* vy)/ d2; 
var u2 =((ix2-x1)* vx +(iy1-y1)* vy)/ d2;

现在进行一些简单的测试,看看这些点的单位位置是否在线段上

  if(u1 <0){//是线段开始的前向截距
result = false; //没有拦截
} else
if(u2> 1){//是行结束后的后截断
result = false; //没有拦截
} else {
//虽然线段可能没有拦截圆圈
//圆周如果我们有到这里它必须满足条件
/ /接触圆的一部分。
result = true;
}
}

演示 >

一如既往,这里是一个演示逻辑的演示。圆圈以鼠标为中心。有几条测试线,如果圆圈接触他们会变红。它还将显示圆周与圆的交点。该点将是红色的,如果在线段或绿色如果外面。这些点可以用来添加效果或什么不是



我今天很懒,所以这是直接从我的图书馆。

$ b $

b

我已经通过使用单位长度来计算圆周长相交来改进了算法,消除了大量的代码。我已将它添加到演示中。



从距离直线的距离小于圆半径的点

  //获取截距的单位距离
var ld = Math.sqrt(r * r - d * d)/ Math.sqrt(d2)

//得到沿线的点单位距离
var u1 = u + ld;
var u2 = u - ld;
if(u1< 0){//是行的前向截距
result = false; // no intercept
} else
if(u2> 1){//是超过行末尾的反向截断
result = false; // no intercept
} else {
result = true;
}
}

  var demo = function ){//在答案中描述的函数中有额外的东西为演示//在底部你会发现用于测试圆截取的函数。 / ** GeomDependancies.js begin ** / //用于加速计算。 //用法可能与描述不同。 var data = {x:0,// coordinate y:0,x1:0,//如果需要第二个坐标y1:0,u:0,//单位长度i:0,索引d:0,//距离d2:0,//距离平方l:0,//长度nx:0,//法向量ny:0,结果:false,//布尔结果} //确保hypot suported if(typeof Math.hypot!==function){Math.hypot = function(x,y){return Math.sqrt(x * x + y * y);}; } / ** GeomDependancies.js end ** / / ** LineSegCircleIntercept.js begin ** / //使用数据属性// result //拦截bool用于拦截// x,y //行上的拦截点** / / x1,y1 //行上的逆向截取点// u //截距中点的单位距离// d2 //线段长度平方// // //圆上最近点的距离// i //位0开启对于段上的正向截取// //位1 on用于向后截取// ** x = null id截取点不存在var lineSegCircleIntercept = function(ret,x1,y1,x2,y2,cx,cy,r) {var vx,vy,u,u1,u2,d,ld,len,xx,yy; vx = x2-x1; //将行转换为向量vy = y2  -  y1; ret.d2 =(vx * vx + vy * vy); //得到线上近点的单位距离ret.u = u =((cx-x1)* vx +(cy-y1)* vy)/ ret.d2; xx = x1 + vx * u; //得到最近点yy = y1 + vy * u; //得到离圆心的距离ret.d = d = Math.hypot(xx  -  cx,yy  -  cy); if(d <= r){//线在圆内//获得到两个截取点的距离ld = Math.sqrt(r * r-d * d)/ Math.sqrt(ret.d2); //得到点沿u1的单元距离u1 = u + ld; if(u1 <0){//是行的前向截距ret.result = false; // no intercept return ret; } u2 = u-ld; if(u2> 1){//是超过行结束的反向截距ret.result = false; // no intercept return ret; } ret.i = 0; if(u1 <= 1){ret.i + = 1; //得到前进点线截取圆ret.x = x1 + vx * u1; ret.y = y1 + vy * u1; } else {ret.x = x2; ret.y = y2; } if(u2> = 0){ret.x1 = x1 + vx * u2; ret.y1 = y1 + vy * u2; ret.i + = 2; } else {ret.x1 = x1; ret.y1 = y1; } //艰难的截距点可能不在线上seg //最近的点必须在线段上ret.result = true; return ret; } ret.x = null; //标志,没有截获; ret.result = false; // no intercept return ret; } / ** LineSegCircleIntercept.js end ** / //此示例的鼠标和画布函数。 / ** fullScreenCanvas.js begin ** / var canvas =(function(){var canvas = document.getElementById(canv); if(canvas!== null){document.body.removeChild(canvas);} /使用2D上下文创建空白图像canvas = document.createElement(canvas); canvas.id =canv; canvas.width = window.innerWidth; canvas.height = window.innerHeight; canvas.style.position = absolute; canvas.style.top =0px; canvas.style.left =0px; canvas.style.zIndex = 1000; canvas.ctx = canvas.getContext(2d); document.body.appendChild canvas); return canvas;})(); var ctx = canvas.ctx; / ** fullScreenCanvas.js end ** / / ** MouseFull.js begin ** / var canvasMouseCallBack = undefined; //如果需要var mouse =(function(){var mouse = {x:0,y:0,w:0,alt:false,shift:false,ctrl:false,interfaceId:0,buttonLastRaw:0,buttonRaw: 0,over:false,//鼠标在元素bm:[1,2,4,6,5,3],//设置和清除按钮原始位的掩码; getInterfaceId:function(){return this.interfaceId ++ ;},// For UI functions startMouse:undefined,}; function mouseMove(e){var t = e.type,m = mouse; mx = e.offsetX; my = e.offsetY; if(mx === undefined ){mx = e.clientX; my = e.clientY;} m.alt = e.altKey; m.shift = e.shiftKey; m.ctrl = e.ctrlKey; if(t ===mousedown){ m.buttonRaw | = m.bm [e.which-1];} else if(t ===mouseup){m.buttonRaw& = m.bm [e.which + 2];} else if t ===mouseout){m.buttonRaw = 0; m.over = false;} else if(t ===mouseover){m.over = true; } else if(t ===mousewheel){m.w = e.wheelDelta; } else if(t ===DOMMouseScroll){m.w = -e.detail;} if(canvasMouseCallBack){canvasMouseCallBack(m.x,m.y); } e.preventDefault(); } function startMouse(element){if(element === undefined){element = document; }mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll.split(,)forEach(function(n){element.addEventListener(n,mouseMove);}); element.addEventListener(contextmenu,function(e){e.preventDefault();},false); } mouse.mouseStart = startMouse;返回鼠标})(); if(typeof canvas ===undefined){mouse.mouseStart(canvas); } else {mouse.mouseStart(); } / ** MouseFull.js end ** / //帮助函数function drawCircle(ctx,x,y,r,col,col1,lWidth){if(col1){ctx.lineWidth = lWidth; ctx.strokeStyle = col1; } if(col){ctx.fillStyle = col; } ctx.beginPath(); ctx.arc(x,y,r,0,Math.PI * 2); if(col){ctx.fill(); } if(col1){ctx.stroke(); }} // helper function function drawLine(ctx,x1,y1,x2,y2,col,lWidth){ctx.lineWidth = lWidth; ctx.strokeStyle = col ctx.beginPath(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke(); } var h = canvas.height; var w = canvas.width; var unit = Math.ceil(Math.sqrt(Math.hypot(w,h))/ 32); const U80 = unit * 80; const U60 = unit * 60; const U40 = unit * 40; const U10 = unit * 10; var lines = [{x1:U80,y1:U80,x2:w / 2,y2:h-U80},{x1:w-U80,y1:U80,x2:w / {x1:w / 2-U10,y1:h / 2-U40,x2:w / 2,y2:h / 2 + U10 * 2},{x1:w / 2 + U10,y1:h / ,x2:w / 2,y2:h / 2 + U10 * 2} function update(){var i,l; ctx.clearRect(0,0,w,h); drawCircle(ctx,mouse.x,mouse.y,U60,undefined,black,unit * 3); drawCircle(ctx,mouse.x,mouse.y,U60,undefined,yellow,unit * 2); for(i = 0; i  

>


I've got this game in this plunker.

When the swords are not rotating, it all works fine (you can check by uncommenting lines 221 and commenting out 222-223). When they are rotating like in the plunker above, the collision doesn't work well.

I guess that's because the "getImageData" remembers the old images, but I gather it's an expensive thing to recalculate over and over again.

Is there a better way to rotate my images and make this work? Or do I have to recalculate their pixel map?

Code of the culprit:

for (var i = 0; i < monsters.length; i++) {
    var monster = monsters[i];
    if (monster.ready) {
        if (imageCompletelyOutsideCanvas(monster, monster.monsterImage)) {
            monster.remove = true;
        }
        //else {
        //ctx.drawImage(monster.monsterImage, monster.x, monster.y);
        drawRotatedImage(monster.monsterImage, monster.x, monster.y, monster);
        monster.rotateCounter += 0.05;
        //}
    }
}

解决方案

Geometric solution

To do this via a quicker geometry solution.

The simplest solution is a line segment with circle intersection algorithm.

Line segment.

A line has a start and end described in a variety of ways. In this case we will use the start and end coordinates.

var line = {
    x1 : ?,
    y1 : ?,
    x2 : ?,
    y2 : ?,
}

Circle

The circle is described by its location and radius

var circle = {
   x : ?,
   y : ?,
   r : ?,
}

Circle line segment Intersect

The following describes how I test for the circle line segment collision. I don't know if there is a better way (most likely there is) but this has served me well and is reliable with the caveat that line segments must have length and circles must have area. If you can not guarantee this then you must add checks in the code to ensure you don't get divide by zeros.

Thus to test if a line intercepts the circle we first find out how far the closest point on the line (Note a line is infinite in size while a line segment has a length, start and end)

// a quick convertion of vars to make it easier to read.
var x1 = line.x1;
var y1 = line.y1;
var x2 = line.x2;
var y2 = line.y2;

var cx = circle.x;
var cy = circle.y;
var r = circle.r;

The result of the test, will be true if there is a collision.

var result; // the result of the test

Convert the line to a vector.

var vx = x2 - x1;  // convert line to vector
var vy = y2 - y1;
var d2 = (vx * vx + vy * vy);  // get the length squared

Get the unit distance from the circle of the near point on the line. The unit distance is a number from 0, to 1 (inclusive) and represents the distance along the vector of a point. if the value is less than 0 then the point is before the vector, if greater then 1 the point is past the end.

I know this by memory and forget the concept. Its the dot product of the line vector and the vector from the start of the line segment to the circle center divided by the line vectors length squared.

// dot product of two vectors is v1.x * v2.x + v1.y * v2.y over v1 length squared 
u =  ((cx - x1) * vx + (cy - y1) * vy) / d2;

Now use the unit position to get the actual coordinate of the point on the line closest to the circle by adding to the line segment start position the line vector times the unit distance.

 // get the closest point
var  xx = x1 + vx * u;
var  yy = y1 + vy * u;

Now we have a point on the line, we calculate the distance from the circle using pythagoras square root of the sum of the two sides squared.

// get the distance from the circle center
var d =  Math.hypot(xx - cx, yy - cy);    

Now if the line (not line segment) intersects the circle the distance will be equal or less than the circle radius. Otherwise the is no intercept.

if(d > r){ //is the distance greater than the radius
    result = false;  // no intercept
} else { // else we need some more calculations

To determine if the line segment has intercepted the circle we need to find the two points on the circle's circumference that the line has crossed. We have the radius and the distance the circle is from the line. As the distance from the line is always at right angles we have a right triangle with the hypot being the radius and one side being the distance found.

Work out the missing length of the triangle. UPDATE see improved version of the code from here at bottom of answer under "update" it uses unit lengths rather than normalise the line vector.

// ld for line distance is the square root of the hyp subtract side squared
var ld = Math.sqrt(r * r - d * d);

Now add that distance to the point we found on the line xx, yy to do that normalise the line vector (makes the line vector one unit long) by dividing the line vector by its length, and then to multiply it by the distance found above

var len = Math.sqrt(d2); // get the line vector length
var nx = (vx / len) * ld;      
var ny = (vy / len) * ld;      

Some people may see that I could have used the Unit length and skipped a few calculations. Yes but I can be bothered rewriting the demo so will leave it as is

Now to get the to intercept points by adding and subtracting the new vector to the point on the line that is closest to the circle

ix1 = xx + nx; // the point furthest alone the line 
iy1 = xx + ny;
ix2 = xx - nx; // the point in the other direction
iy2 = xx - ny;

Now that we have these two points we can work out if they are in the line segment but calculating the unit distance they are on the original line vector, using the dot product divide the squared distance.

    var u1 =  ((ix1 - x1) * vx + (iy1 - y1) * vy) / d2;
    var u2 =  ((ix2 - x1) * vx + (iy1 - y1) * vy) / d2; 

Now some simple tests to see if the unit postion of these points are on the line segment

    if(u1 < 0){  // is the forward intercept befor the line segment start
        result = false;  // no intercept            
    }else
    if(u2 > 1){ // is the rear intercept after the line end
        result = false;  // no intercept            
    } else {
        // though the line segment may not have intercepted the circle
        // circumference if we have got to here it must meet the conditions
        // of touching some part of the circle.
        result = true;
    }
}

Demo

As always here is a demo showing the logic in action. The circle is centered on the mouse. There are a few test lines that will go red if the circle touches them. It will also show the point where the circle circumference does cross the line. The point will be red if in the line segment or green if outside. These points can be use to add effects or what not

I am lazy today so this is straight from my library. Note I will post the improved math when I get a chance.

Update

I have improved the algorithm by using unit length to calculate the circle circumference intersects, eliminating a lot of code. I have added it to the demo as well.

From the Point where the distance from the line is less than the circle radius

            // get the unit distance to the intercepts
            var ld = Math.sqrt(r * r - d * d) / Math.sqrt(d2);

            // get that points unit distance along the line
            var u1 =  u + ld; 
            var u2 =  u - ld; 
            if(u1 < 0){  // is the forward intercept befor the line
                result = false;  // no intercept
            }else
            if(u2 > 1){  // is the backward intercept past the end of the line
                result = false;  // no intercept
            }else{
                result = true;
            }
        }

var demo = function(){
    
    // the function described in the answer with extra stuff for the demo
    // at the bottom you will find the function being used to test circle intercepts.
    
    
    /** GeomDependancies.js begin **/
        
    // for speeding up calculations.
    // usage may vary from descriptions. See function for any special usage notes
    var data = {
        x:0,   // coordinate
        y:0,
        x1:0,   // 2nd coordinate if needed
        y1:0,
        u:0,   // unit length
        i:0,   // index
        d:0,   // distance
        d2:0,  // distance squared
        l:0,   // length
        nx:0,  // normal vector
        ny:0,
        result:false, // boolean result
    }
    // make sure hypot is suported
    if(typeof Math.hypot !== "function"){
        Math.hypot = function(x, y){ return Math.sqrt(x * x + y * y);};
    }
    /** GeomDependancies.js end **/
    
    /** LineSegCircleIntercept.js begin **/
    // use data properties
    // result  // intercept bool for intercept
    // x, y    // forward intercept point on line ** 
    // x1, y1  // backward intercept point on line
    // u       // unit distance of intercept mid point
    // d2      // line seg length squared
    // d       // distance of closest point on line from circle
    // i       // bit 0 on for forward intercept on segment 
    //         // bit 1 on for backward intercept
    // ** x = null id intercept points dont exist
    var lineSegCircleIntercept = function(ret, x1, y1, x2, y2, cx, cy, r){
    var vx, vy, u, u1, u2, d, ld, len, xx, yy;
        vx = x2 - x1;  // convert line to vector
        vy = y2 - y1;
        ret.d2 = (vx * vx + vy * vy);
        
        // get the unit distance of the near point on the line
        ret.u = u =  ((cx - x1) * vx + (cy - y1) * vy) / ret.d2;
        xx = x1 + vx * u; // get the closest point
        yy = y1 + vy * u;
        
        // get the distance from the circle center
        ret.d = d =  Math.hypot(xx - cx, yy - cy);    
        if(d <= r){ // line is inside circle
            // get the distance to the two intercept points
            ld = Math.sqrt(r * r - d * d) / Math.sqrt(ret.d2);

            // get that points unit distance along the line
            u1 =  u + ld; 
            if(u1 < 0){  // is the forward intercept befor the line
                ret.result = false;  // no intercept
                return ret;
            }
            u2 =  u - ld; 
            if(u2 > 1){  // is the backward intercept past the end of the line
                ret.result = false;  // no intercept
                return ret;
            }
            ret.i = 0;
            if(u1 <= 1){
                ret.i += 1;
                // get the forward point line intercepts the circle
                ret.x = x1 + vx * u1;  
                ret.y = y1 + vy * u1;
            }else{
                ret.x = x2;
                ret.y = y2;
                
            }
            if(u2 >= 0){
                ret.x1 = x1 + vx * u2;  
                ret.y1 = y1 + vy * u2;
                ret.i += 2;
            }else{
                ret.x1 = x1;
                ret.y1 = y1;
            }
            
            // tough the points of intercept may not be on the line seg
            // the closest point to the must be on the line segment
            ret.result = true;
            return ret;
            
        }
        ret.x = null; // flag that no intercept found at all;
        ret.result = false;  // no intercept
        return ret;
            
    }
    /** LineSegCircleIntercept.js end **/
    

    // mouse and canvas functions for this demo.

    /** fullScreenCanvas.js begin **/
    var canvas = (function(){
        var canvas = document.getElementById("canv");
        if(canvas !== null){
            document.body.removeChild(canvas);
        }
        // creates a blank image with 2d context
        canvas = document.createElement("canvas"); 
        canvas.id = "canv";    
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight; 
        canvas.style.position = "absolute";
        canvas.style.top = "0px";
        canvas.style.left = "0px";
        canvas.style.zIndex = 1000;
        canvas.ctx = canvas.getContext("2d"); 
        document.body.appendChild(canvas);
        return canvas;
    })();
    var ctx = canvas.ctx;
    
    /** fullScreenCanvas.js end **/
    /** MouseFull.js begin **/
    
    var canvasMouseCallBack = undefined;  // if needed
    var mouse = (function(){
        var mouse = {
            x : 0, y : 0, w : 0, alt : false, shift : false, ctrl : false,
            interfaceId : 0, buttonLastRaw : 0,  buttonRaw : 0,
            over : false,  // mouse is over the element
            bm : [1, 2, 4, 6, 5, 3], // masks for setting and clearing button raw bits;
            getInterfaceId : function () { return this.interfaceId++; }, // For UI functions
            startMouse:undefined,
        };
        function mouseMove(e) {
            var t = e.type, m = mouse;
            m.x = e.offsetX; m.y = e.offsetY;
            if (m.x === undefined) { m.x = e.clientX; m.y = e.clientY; }
            m.alt = e.altKey;m.shift = e.shiftKey;m.ctrl = e.ctrlKey;
            if (t === "mousedown") { m.buttonRaw |= m.bm[e.which-1];
            } else if (t === "mouseup") { m.buttonRaw &= m.bm[e.which + 2];
            } else if (t === "mouseout") { m.buttonRaw = 0; m.over = false;
            } else if (t === "mouseover") { m.over = true;
            } else if (t === "mousewheel") { m.w = e.wheelDelta;
            } else if (t === "DOMMouseScroll") { m.w = -e.detail;}
            if (canvasMouseCallBack) { canvasMouseCallBack(m.x, m.y); }
            e.preventDefault();
        }
        function startMouse(element){
            if(element === undefined){
                element = document;
            }
            "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",").forEach(
            function(n){element.addEventListener(n, mouseMove);});
            element.addEventListener("contextmenu", function (e) {e.preventDefault();}, false);
        }
        mouse.mouseStart = startMouse;
        return mouse;
    })();
    if(typeof canvas === "undefined"){
        mouse.mouseStart(canvas);
    }else{
        mouse.mouseStart();
    }
    /** MouseFull.js end **/
    
    // helper function
    function drawCircle(ctx,x,y,r,col,col1,lWidth){
        if(col1){
            ctx.lineWidth = lWidth;
            ctx.strokeStyle = col1;
        }
        if(col){
            ctx.fillStyle = col;
        }
        
        ctx.beginPath();
        ctx.arc( x, y, r, 0, Math.PI*2);
        if(col){
            ctx.fill();
        }
        if(col1){
            ctx.stroke();
        }
    }
    
    // helper function
    function drawLine(ctx,x1,y1,x2,y2,col,lWidth){
        ctx.lineWidth = lWidth;
        ctx.strokeStyle = col;
        ctx.beginPath();
        ctx.moveTo(x1,y1);
        ctx.lineTo(x2,y2);
        ctx.stroke();
    }
    var h = canvas.height;
    var w = canvas.width;
    var unit = Math.ceil(Math.sqrt(Math.hypot(w, h)) / 32);
    const U80 = unit * 80;
    const U60 = unit * 60;
    const U40 = unit * 40;
    const U10 = unit * 10;
    var lines = [
        {x1 : U80, y1 : U80, x2 : w /2, y2 : h - U80},
        {x1 : w - U80, y1 : U80, x2 : w /2, y2 : h - U80},
        {x1 : w / 2 - U10, y1 : h / 2 - U40, x2 : w /2, y2 : h/2 + U10 * 2},
        {x1 : w / 2 + U10, y1 : h / 2 - U40, x2 : w /2, y2 : h/2 + U10 * 2},
    ];
    
    function update(){
        var i, l;
        ctx.clearRect(0, 0, w, h);
        
        drawCircle(ctx, mouse.x, mouse.y, U60, undefined, "black", unit * 3);
        drawCircle(ctx, mouse.x, mouse.y, U60, undefined, "yellow", unit * 2);
        for(i = 0; i < lines.length; i ++){
            l = lines[i]
            drawLine(ctx, l.x1, l.y1, l.x2, l.y2, "black" , unit * 3)
            drawLine(ctx, l.x1, l.y1, l.x2, l.y2, "yellow" , unit * 2)
            
            // test the lineSegment circle
            data = lineSegCircleIntercept(data,  l.x1, l.y1, l.x2, l.y2, mouse.x, mouse.y, U60);
            // if there is a result display the result
            if(data.result){
                drawLine(ctx, l.x1, l.y1, l.x2, l.y2, "red" , unit * 2)
                if((data.i & 1) === 1){
                    drawCircle(ctx, data.x, data.y, unit * 4, "white", "red", unit );
                }else{
                    drawCircle(ctx, data.x, data.y, unit * 2, "white", "green", unit );
                }
                if((data.i & 2) === 2){
                    drawCircle(ctx, data.x1, data.y1, unit * 4, "white", "red", unit );
                }else{
                    drawCircle(ctx, data.x1, data.y1, unit * 2, "white", "green", unit );
                }
            }
        }
        requestAnimationFrame(update);
    }
    
    update();
}
// resize if needed by just starting again
window.addEventListener("resize",demo);

// start the demo
demo();

这篇关于旋转图像&amp;像素碰撞检测的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆