Javascript html5画布弹性碰撞方块
我再次提出这个问题,因为我在上一个问题中没有明确说明我想要什么 有人知道如何使用矩形在画布上进行弹性碰撞或处理碰撞吗?或者你能给我指出正确的方向吗 我创建了一个有多个正方形的画布,希望每个正方形在接触时都发生偏转 这是一把我拼凑起来的快速小提琴,展示给黑色缓冲画布 第39行是我开始碰撞检测的地方,第59行是我尝试执行碰撞检测的地方。我将有3个以上的方块移动,如果它们彼此接触,我希望它们偏转Javascript html5画布弹性碰撞方块,javascript,html,canvas,html5-canvas,collision,Javascript,Html,Canvas,Html5 Canvas,Collision,我再次提出这个问题,因为我在上一个问题中没有明确说明我想要什么 有人知道如何使用矩形在画布上进行弹性碰撞或处理碰撞吗?或者你能给我指出正确的方向吗 我创建了一个有多个正方形的画布,希望每个正方形在接触时都发生偏转 这是一把我拼凑起来的快速小提琴,展示给黑色缓冲画布 第39行是我开始碰撞检测的地方,第59行是我尝试执行碰撞检测的地方。我将有3个以上的方块移动,如果它们彼此接触,我希望它们偏转 var canvas = document.getElementById("canvas"), c
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d");
context.fillStyle = "#FFA500";
context.fillRect(0, 0, canvas.width, canvas.height);
var renderToCanvas = function (width, height, renderFunction) {
var buffer = document.createElement('canvas');
buffer.width = width;
buffer.height = height;
renderFunction(buffer.getContext('2d'));
return buffer;
};
var drawing = renderToCanvas(100, 100, function (ctx) {
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, canvas.width, canvas.height);
});
var drawing2 = renderToCanvas(100, 100, function (ctx) {
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
});
var x = 0,
y = 0,
x2 = 200,
y2 = 10,
vx = .80,
vy = .80,
vx2 = .80,
vy2 = .80;
function collides(rectA, rectB) {
return !(rectA.x + rectA.width < rectB.x2 ||
rectB.x2 + rectB.width < rectA.x ||
rectA.y + rectA.height < rectB.y2 ||
rectB.y2 + rectB.height < rectA.y);
};
function executeFrame() {
x+=vx;
y+=vy;
x2+=vx2;
y2+=vy2;
if( x < 0 || x > 579) vx = -vx;
if( y < 0 || y > 265) vy = -vy;
if( x2 < 0 || x2 > 579) vx2 = - vx2;
if( y2 < 0 || y2 > 233) vy2 = - vy2;
if(collides(drawing, drawing2)){
//move in different direction
};
context.fillStyle = "#FFA500";
context.fillRect(0, 0, canvas.width, canvas.height);
context.drawImage(drawing, x, y);
context.drawImage(drawing2, x2, y2);
requestAnimationFrame(executeFrame);
}
//start animation
executeFrame();
var canvas=document.getElementById(“canvas”),
context=canvas.getContext(“2d”);
context.fillStyle=“#FFA500”;
context.fillRect(0,0,canvas.width,canvas.height);
var renderToCanvas=函数(宽度、高度、renderFunction){
var buffer=document.createElement('canvas');
buffer.width=宽度;
缓冲区高度=高度;
renderFunction(buffer.getContext('2d');
返回缓冲区;
};
变量绘图=渲染画布(100,100,函数(ctx){
ctx.fillStyle=“#000”;
ctx.fillRect(0,0,canvas.width,canvas.height);
});
var drawing2=renderToCanvas(100100,函数(ctx){
ctx.fillStyle=“蓝色”;
ctx.fillRect(0,0,canvas.width,canvas.height);
});
var x=0,
y=0,
x2=200,
y2=10,
vx=.80,
vy=.80,
vx2=0.80,
vy2=0.80;
函数冲突(rectA,rectB){
返回!(rectA.x+rectA.width579)vx=-vx;
如果(y<0 | | y>265)vy=-vy;
如果(x2<0 | | x2>579)vx2=-vx2;
如果(y2<0 | | y2>233)vy2=-vy2;
如果(碰撞(绘图、绘图2)){
//向不同的方向移动
};
context.fillStyle=“#FFA500”;
context.fillRect(0,0,canvas.width,canvas.height);
背景。绘图图像(绘图,x,y);
上下文。drawImage(drawing2,x2,y2);
requestAnimationFrame(ExecuteName);
}
//启动动画
executeFrame();
答案其实很简单:在碰撞时交换每个块的速度。就这样!此外,对于碰撞测试,请将RectA.x
更改为仅x
,因为它们是给定的正常变量:
function collides(rectA, rectB) {
return !(x + rectA.width < x2 ||
x2 + rectB.width < x ||
y + rectA.height < y2 ||
y2 + rectB.height < y);
};
在这些小的变化之后,我们有了弹性碰撞:矩形碰撞检测
进行矩形碰撞检测可能比看起来更复杂
这不仅仅是要弄清楚两个矩形是否相交或重叠,我们还需要知道它们碰撞的角度和移动的方向,以便使它们正确偏转,理想情况下相互传递“速度”(质量/能量)等等
我在这里介绍的此方法将执行以下步骤:
- 首先做一个简单的相交检测,看看它们是否发生碰撞
- 如果相交:计算两个矩形之间的角度
- 将设置的主矩形划分为圆形的四个区域,其中区域1为右侧,区域2为底部,依此类推
- 根据区域,检查矩形的移动方向,如果朝向另一个矩形,则根据检测到的区域使其偏转
r1
和r2
是具有属性x
、y
、w
和h
的对象
function collides(r1, r2) {
/// classic intersection test
var hit = !(r1.x + r1.w < r2.x ||
r2.x + r2.w < r1.x ||
r1.y + r1.h < r2.y ||
r2.y + r2.h < r1.y);
/// if intersects, get angle between the two rects to determine hit zone
if (hit) {
/// calc angle
var dx = r2.x - r1.x;
var dy = r2.y - r1.y;
/// for simplicity convert radians to degree
var angle = Math.atan2(dy, dx) * 180 / Math.PI;
if (angle < 0) angle += 360;
return angle;
} else
return null;
}
差不多就是这样
使用命中
标志,这样当我们命中时,我们会将“情况”标记为命中情况,这样我们就不会发生内部偏转(例如,在高速时可能发生)。只要我们在命中后得到一个角度设置为真,我们仍然处于相同的命中情况(理论上无论如何)。当我们收到空值时,我们重置并准备好迎接新的命中情况
同样值得一提的是,这里的主矩形(我们检查其一侧)是第一个(本例中为黑色)
两个以上的矩形
如果你想加入两个以上的矩形,那么我建议使用一种不同于这里使用的方法来处理矩形本身。我建议创建一个位置、大小、颜色都是独立的,并且还嵌入了更新速度、方向和绘制的方法。矩形对象可以由执行清除并调用对象的更新方法的主机对象来维护
要检测冲突,您可以使用这些对象迭代数组,以找出哪个矩形与正在测试的当前矩形冲突。这里很重要的一点是,您“标记”(使用标志)一个已经测试过的矩形,因为在碰撞中始终至少会有两个矩形,如果您测试a和B,则最终将反转速度变化的效果,而不使用标志跳过每帧碰撞“伙伴”对象的测试
总之
注意:此处未涉及特殊情况,例如精确角上的碰撞,或矩形被困在边和其他矩形之间(您也可以使用上面提到的命中标志进行边测试)
我没有优化任何代码,但我试图保持它尽可能简单,使它更容易理解
希望这有帮助 如果你在你贴的(,ref)小提琴上看到第二次碰撞,你可以看到它们在角度上没有正确偏转。除此之外,这是一种很好且简单的检测方法。这是因为该公式是基于一维的解决方案,如果将碰撞视为跨越一维线,则碰撞是正确的。能量
function collides(r1, r2) {
/// classic intersection test
var hit = !(r1.x + r1.w < r2.x ||
r2.x + r2.w < r1.x ||
r1.y + r1.h < r2.y ||
r2.y + r2.h < r1.y);
/// if intersects, get angle between the two rects to determine hit zone
if (hit) {
/// calc angle
var dx = r2.x - r1.x;
var dy = r2.y - r1.y;
/// for simplicity convert radians to degree
var angle = Math.atan2(dy, dx) * 180 / Math.PI;
if (angle < 0) angle += 360;
return angle;
} else
return null;
}
var angle = collides({x: x, y: y, w: 100, h: 100}, /// rect 1
{x: x2, y: y2, w: 100, h: 100}); /// rect 2
/// did we have an intersection?
if (angle !== null) {
/// if we're not already in a hit situation, create one
if (!hit) {
hit = true;
/// zone 1 - right
if ((angle >= 0 && angle < 45) || (angle > 315 && angle < 360)) {
/// if moving in + direction deflect rect 1 in x direction etc.
if (vx > 0) vx = -vx;
if (vx2 < 0) vx2 = -vx2;
} else if (angle >= 45 && angle < 135) { /// zone 2 - bottom
if (vy > 0) vy = -vy;
if (vy2 < 0) vy2 = -vy2;
} else if (angle >= 135 && angle < 225) { /// zone 3 - left
if (vx < 0) vx = -vx;
if (vx2 > 0) vx2 = -vx2;
} else { /// zone 4 - top
if (vy < 0) vy = -vy;
if (vy2 > 0) vy2 = -vy2;
}
}
} else
hit = false; /// reset hit when this hit is done (angle = null)