如何检查两个绘图(线)是否在 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):
第 1 行给出为 p0x, p0y, p1x, p1y,第 2 行给出为 p2x, p2y, p3x, p3y.如果相交,则返回具有属性 x
和 y
的对象.
Line 1 is given as p0x, p0y, p1x, p1y, line 2 as p2x, p2y, p3x, p3y. If intersect an object is returned with properties x
and y
.
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
}
相关文章