简体   繁体   English

如何检查两个图形(线)是否在Canvas中发生碰撞?

[英]How to check if two drawings (lines) are colliding in Canvas?

So I've been working on a running stick man game. 所以我一直在做一个正在运行的火柴人游戏。 Unfortunately I've come across this one problem I just can't seem to figure out. 不幸的是,我遇到了一个我似乎无法解决的问题。 I want an alert to appear and say "Game Over" if a drawing named obstacle passes through my stick man. 我希望出现警报,并且如果名为“障碍物”的图形通过我的火柴人通过,请说“游戏结束”。 However if my stickman kicks (which he turns red) and the obstacle touches the drawings right foot then it will say "You win". 但是,如果我的火柴人踢(他变成红色)并且障碍物右脚碰到图纸,那么它将说“您赢了”。 Any help would be well appreciated! 任何帮助将不胜感激!

The following is what I have so far: Btw I considered checking if a given pixel that the obstacle passes is red, then say "You win", but that seems not to work. 到目前为止,这是我的工作:顺便说一句,我考虑过检查障碍物通过的给定像素是否为红色,然后说“您赢了”,但这似乎行不通。

$(document).ready(function(e){

//get canvas from drawcanvas div
var canvas = document.getElementById("drawCanvas"),

//utilize 2D canvas
context = canvas.getContext('2d'),

//get width of canvas
width = canvas.width,

//get height of canvas
height = canvas.height,

//create stickman to keep track of body parts
stickman = {head: [200, 200, 10,0,  2*Math.PI ],
body: [195, 210, 178, 250],
rightArm: [192,215,200,230,210,230],
leftArm: [192,215,178 ,222,178,230],
rightLeg: [178, 250,190,260,185,275,192, 275],
leftLeg: [178, 250, 168, 260, 155, 262,153, 268]
} ;

//create obstacle 1
obstacle1  = { circle: [450,200, 8, 0, 2* Math.PI],
ob1_mv1:  [455, 200],
ob1_l1: [470, 200],
ob1_mv2:  [445, 200],
ob1_l2: [430, 200] };
var ob1Distance = 0;


var id = context.createImageData(1,1);
var d = id.data;
d[0] = 0;
d[1] = 0;
d[2] = 0;
d[3] = 0;

/function to render normal obstacle
function obstacle1_norm(ob1Distance) {
context.strokeStyle =  "rgb(0,0,0)";

context.beginPath();
//obstacle core
context.arc(obstacle1.circle[0] +ob1Distance,
obstacle1.circle[1],
obstacle1.circle[2],
obstacle1.circle[3],
obstacle1.circle[4],
obstacle1.circle[5]) ;
context.moveTo(obstacle1.ob1_mv1[0] + ob1Distance,obstacle1.ob1_mv1[1]);
context.lineTo(obstacle1.ob1_l1[0] + ob1Distance,obstacle1.ob1_l1[1]);
context.moveTo(obstacle1.ob1_mv2[0] +ob1Distance, obstacle1.ob1_mv2[1]);
context.lineTo(obstacle1.ob1_l2[0] +ob1Distance, obstacle1.ob1_l2[1]);
context.stroke();
}

//function render normal obstacle spin
function obstacle1_spin(ob1Distance){
context.strokeStyle =  "rgb(0,0,0)";

context.beginPath();
context.arc(obstacle1.circle[0] +ob1Distance,
obstacle1.circle[1],
obstacle1.circle[2],
obstacle1.circle[3],
obstacle1.circle[4],
obstacle1.circle[5]) ;
context.moveTo(obstacle1.ob1_mv1[0] - 5  + ob1Distance ,obstacle1.ob1_mv1[1]);
context.lineTo(obstacle1.ob1_l1[0] - 18 + ob1Distance ,obstacle1.ob1_l1[1]);
context.moveTo(obstacle1.ob1_mv2[0] - 5 + ob1Distance  ,obstacle1.ob1_mv2[1]);
context.lineTo(obstacle1.ob1_l2[0] - 20 + ob1Distance,obstacle1.ob1_l2[1]);
context.stroke();
}

function costume1(){
context.strokeStyle =  "rgb(0,0,0)";
context.beginPath();
//head
context.arc(stickman.head[0], stickman.head[1], stickman.head[2], stickman.head[3], stickman.head[4]);
//body
context.moveTo(stickman.body[0],stickman.body[1]);
context.lineTo(stickman.body[2],stickman.body[3]);

//right arm
context.moveTo(stickman.leftArm[0],stickman.leftArm[1]);
context.lineTo(stickman.leftArm[2] ,stickman.leftArm[3]);
context.lineTo(stickman.leftArm[4], stickman.leftArm[5]);

//left arm
context.moveTo(stickman.rightArm[0], stickman.rightArm[1]);
context.lineTo(stickman.rightArm[2], stickman.rightArm[3]);
context.lineTo(stickman.rightArm[4] , stickman.rightArm[5]);

//left leg
context.moveTo(stickman.rightLeg[0], stickman.rightLeg[1]);
context.lineTo(stickman.rightLeg[2],stickman.rightLeg[3]);
context.lineTo(stickman.rightLeg[4] , stickman.rightLeg[5]);
context.lineTo(stickman.rightLeg[6], stickman.rightLeg[7]);


//right leg
context.moveTo(stickman.leftLeg[0], stickman.leftLeg[1]);
context.lineTo(stickman.leftLeg[2], stickman.leftLeg[3]);
context.lineTo(stickman.leftLeg[4], stickman.leftLeg[5]);
context.lineTo(stickman.leftLeg[6] , stickman.leftLeg[7]);
context.stroke();
}

//stick figure costume 2
function costume2(){
context.strokeStyle =  "rgb(0,0,0)";

context.beginPath();
//head
context.arc(stickman.head[0], stickman.head[1], stickman.head[2], stickman.head[3], stickman.head[4]);
//body
context.moveTo(stickman.body[0],stickman.body[1]);
context.lineTo(stickman.body[2],stickman.body[3]);
//left arm
context.moveTo(stickman.leftArm[0],stickman.leftArm[1]);
context.lineTo(stickman.leftArm[2] +10 ,stickman.leftArm[3]+5);
context.lineTo(stickman.leftArm[4] +20, stickman.leftArm[5]-8);
//right arm
context.moveTo(stickman.rightArm[0]    ,  stickman.rightArm[1]);
context.lineTo(stickman.rightArm[2] -20 , stickman.rightArm[3] -5);
context.lineTo(stickman.rightArm[4] -20, stickman.rightArm[5]-5);
//right leg
context.moveTo(stickman.rightLeg[0], stickman.rightLeg[1]);
context.lineTo(stickman.rightLeg[2] - 8 ,stickman.rightLeg[3]);
context.lineTo(stickman.rightLeg[4] -20, stickman.rightLeg[5]);
context.lineTo(stickman.rightLeg[6] -20, stickman.rightLeg[7]);
//left leg
context.moveTo(stickman.leftLeg[0], stickman.leftLeg[1]);
context.lineTo(stickman.leftLeg[2] + 20 , stickman.leftLeg[3]);
context.lineTo(stickman.leftLeg[4] +8, stickman.leftLeg[5] + 8 );
context.lineTo(stickman.leftLeg[6] +15 , stickman.leftLeg[7] + 4);
context.stroke();
}

function fight_kick(){
context.strokeStyle =  "rgba(255,0,0,255)";

context.beginPath();
//head
context.arc(stickman.head[0] - 20, stickman.head[1], stickman.head[2], stickman.head[3], stickman.head[4]);
//body
context.moveTo(stickman.body[0] - 15,stickman.body[1]);
context.lineTo(stickman.body[2],stickman.body[3]);
//left arm
context.moveTo(stickman.leftArm[0] - 13,stickman.leftArm[1]);
context.lineTo(stickman.leftArm[2] - 15 ,stickman.leftArm[3]+5);
context.lineTo(stickman.leftArm[4] - 20, stickman.leftArm[5]-15);
//right arm
context.moveTo(stickman.rightArm[0] - 13    ,  stickman.rightArm[1]+1);
context.lineTo(stickman.rightArm[2]  , stickman.rightArm[3] - 22);
context.lineTo(stickman.rightArm[4] , stickman.rightArm[5] - 35);
//right leg
context.moveTo(stickman.rightLeg[0], stickman.rightLeg[1]);
context.lineTo(stickman.rightLeg[2] - 20 ,stickman.rightLeg[3]);
context.lineTo(stickman.rightLeg[4] -20, stickman.rightLeg[5]);
context.lineTo(stickman.rightLeg[6] -30, stickman.rightLeg[7]);
//left leg
context.moveTo(stickman.leftLeg[0], stickman.leftLeg[1]);
context.lineTo(stickman.leftLeg[2] + 25 , stickman.leftLeg[3]-18);
context.lineTo(stickman.leftLeg[4] + 55, stickman.leftLeg[5] -30 );
context.lineTo(stickman.leftLeg[6] +60, stickman.leftLeg[7] - 40);

context.stroke();
}

var ob1_flag = true ;
function ob1_spinning(){
 if (ob1_flag == true  ) {

   obstacle1_spin(ob1Distance);
   ob1_flag = false;
  }else  if (ob1_flag == false ) {

   obstacle1_norm(ob1Distance) ;
   ob1_flag = true;
  }
 ob1Distance -= 20;

}


//create board
function board(){
context.fillStyle="#FFF";
context.fill();
context.beginPath();
context.moveTo(0,276);
context.lineTo(width,276);
context.stroke();
context.strokeStyle="#000";
context.strokeRect(0,0,width,height);
//setInterval(function(){ob1_spinning();}, 100);

}


function collision() {

var dataPixel = context.getImageData(stickman.rightLeg[4] -20, stickman.rightLeg[5],
canvas.width, canvas.height).data;
if ( obstacle1.circle[0] + ob1Distance - 30  < stickman.head[0] + 10      )  {
}
 if (dataPixel[0] + dataPixel[1]  + dataPixel[2]  <  255 && dataPixel[0] + dataPixel[1]  + dataPixel[2] >= 241 ){
 alert("red") 
}
// context.putImageData(id,stickman.rightLeg[4] -20, stickman.rightLeg[5]);

 }




timer =  setInterval(function(){running();} , 200);
//function check  space key press if so kick
function check(e) {
    var code = e.keyCode;
    //Up arrow pressed
     if (code == 32 ) {
       context.clearRect(150,125.25, 70, 150);
       board();
       clearInterval(timer);
       setTimeout(fight_kick(), 250);
 }
 timer = setInterval(function() { running();}, 250);
}

//check for event keydown
window.addEventListener('keydown',check,false);

//flag for switching costumes
flag = true;

//running function to switch between all costumes
function running(){
if (flag == true) {
 context.clearRect(150,125.25, 70, 150);
 board();
 costume2();
 flag = false;
}else if(flag == false) {
 context.clearRect(150,125.25, 70, 150);
 board();
 costume1();
 flag = true;
}
 }
setInterval(function(){collision();}, 5);
setInterval(function(){
context.clearRect(400+ob1Distance,162, 90 , 50 );
ob1_spinning()
;} , 300);

});

You can use a line intersection algorithm. 您可以使用直线相交算法。 Feed the two lines you want to check, if non-null result they intersect. 喂入要检查的两行,如果非空结果相交。 Then determine based on which lines you fed or the position on the line in the result, which part was hit and provide action accordingly. 然后根据您喂入的行或结果中该行的位置确定命中了哪个部分,并采取相应的措施。

To optimize you could first check against a bounding box, then if bounding box is hit check each line part of the shapes. 为了进行优化,您可以首先检查边界框,然后如果边界框被选中,请检查形状的每条线。

Here is one line intersection function ( source ): 这是一个线的交点函数( source ):

Line 1 is given as p0x, p0y, p1x, p1y, line 2 as p2x, p2y, p3x, p3y. 第1行给出为p0x,p0y,p1x,p1y,第2行给出为p2x,p2y,p3x,p3y。 If intersect an object is returned with properties x and y . 如果相交,则返回具有属性xy的对象。

var intPoint = intersection( .... );
if (intPoint) {
  ... some action here...
}

function intersection(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) {

    var d1x = p1x - p0x,
        d1y = p1y - p0y,
        d2x = p3x - p2x,
        d2y = p3y - p2y,

        // determinator
        d = d1x * d2y - d2x * d1y,
        px, py, s, t;

    // continue if intersecting/is not parallel
    if (d) {

      px = p0x - p2x;
      py = p0y - p2y;

      s = (d1x * py - d1y * px) / d;
      if (s >= 0 && s <= 1) {

        // if s was in range, calc t
        t = (d2x * py - d2y * px) / d;
        if (t >= 0 && t <= 1) {
          return {x: p0x + (t * d1x),
                  y: p0y + (t * d1y)}
        }
      }
    }
    return null
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM