篮球物理碰撞检测和反弹物理
Posted
技术标签:
【中文标题】篮球物理碰撞检测和反弹物理【英文标题】:Basketball Physics Collision Detection and Bounce Physics 【发布时间】:2018-01-28 06:40:46 【问题描述】:我正在制作一个篮球物理模拟器。我正在使用参数方程来计算球的路径。我很难检测与篮筐前部、篮板、杆和球场地板(帆布底部)的碰撞。另外,我想让球在击中这些物体时反弹,但我很难。任何人都可以为这个问题提供一些帮助吗?
这里是sn-p的代码:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.transform(1, 0, 0, -1, 0, canvas.height)
ctx.translate(canvas.width / 2, canvas.height / 2);
var speed = 5;
var gravity = 16;
var bounce = 10;
var mouseX = 0;
var mouseY = 0;
var stage = 1;
var x = 0;
var y = 0;
var xOrgn = 0;
var yOrgn = 0;
var xClk = 175;
var yClk = 100;
var mag = 0;
var ang = 0;
var xVel = 0;
var yVel = 0;
var time = 0;
function drawBall()
ctx.beginPath();
ctx.arc(x, y, 12, 0, Math.PI * 2);
ctx.fillStyle = "#FF8C00";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x, y + 12);
ctx.lineTo(x, y - 12);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x - 12, y);
ctx.lineTo(x + 12, y);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x - 8, y - 8);
ctx.bezierCurveTo(x - 2, y - 4, x - 2, y + 4, x - 8, y + 8);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x + 8, y - 8);
ctx.bezierCurveTo(x + 2, y - 4, x + 2, y + 4, x + 8, y + 8);
ctx.strokeStyle = 'black';
ctx.stroke();
function drawHoop()
ctx.beginPath();
ctx.rect(228, -160, 12, 172);
ctx.fillStyle = "#191919";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.rect(222, -12, 6, 80);
ctx.fillStyle = "#666666";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.rect(171, -6, 51, 6);
ctx.fillStyle = "#e50000";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.arc(171, -3, 3, 0, Math.PI * 2);
ctx.fillStyle = "#e50000";
ctx.fill();
ctx.closePath();
function drawCursor()
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(mouseX - 12, mouseY);
ctx.lineTo(mouseX + 12, mouseY);
ctx.strokeStyle = '#00cd00';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(mouseX, mouseY - 12);
ctx.lineTo(mouseX, mouseY + 12);
ctx.strokeStyle = '#00cd00';
ctx.stroke();
ctx.closePath();
function calcVel()
mag = Math.sqrt((Math.pow(xClk - xOrgn, 2) + Math.pow(yClk - yOrgn, 2)) / 4);
ang = Math.atan((yClk - yOrgn) / (xClk - xOrgn));
xVel = mag * Math.cos(ang);
yVel = mag * Math.sin(ang);
function draw()
ctx.clearRect(-(canvas.width / 2), -(canvas.height / 2), canvas.width, canvas.height);
ctx.canvas.addEventListener('mousemove', function(event)
mouseX = event.clientX - ctx.canvas.offsetLeft - canvas.width / 2;
mouseY = -event.clientY + ctx.canvas.offsetTop + canvas.height / 2;
);
drawBall();
drawHoop();
if (stage === 1)
x = mouseX;
y = mouseY;
ctx.canvas.addEventListener('click', function(event)
xOrgn = x;
yOrgn = y;
stage = 2;
);
else if (stage === 2)
drawCursor();
ctx.canvas.addEventListener('click', function(event)
xClk = mouseX;
yclk = mouseY;
calcVel();
time = 0;
stage = 3;
);
else if (stage === 3)
x = xVel * time + xOrgn;
y = -gravity * Math.pow(time, 2) + yVel * time + yOrgn;
time = time + speed * 0.01;
setInterval(draw, 10);
canvas
background: white;
<canvas id="myCanvas" width="480" height="320"></canvas>
这是 jsfiddle 中的代码:JSfiddle
【问题讨论】:
可能的帮助:跟踪新旧 x,y 值,然后查看球是否“穿过”篮筐或篮板。因为您将 x,y 值增加超过1,你不能检查是否相等:球可能在一次平局中高于篮筐,在下一次平局中低于篮筐。 【参考方案1】:您只需要在“阶段 3”中添加碰撞检测。由于所有内容的位置和大小都是硬编码的,因此逐项添加碰撞检测非常简单。 (但如果你把这变得更复杂,我会添加一些变量或对象,以便更容易地将事物的位置作为变量等)。
当球击中篮板时,我添加了水平弹跳,以及从地板上垂直弹跳。其他都类似。
(请注意,使这些成为可能的是迭代地更新 x 和 y(以及 xVel、yVel)而不是从确定的方程。结果是相同的,但计算和动态行为更容易)。
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.transform(1, 0, 0, -1, 0, canvas.height)
ctx.translate(canvas.width / 2, canvas.height / 2);
var speed = 5;
var gravity = 16;
var bounce = 10;
var mouseX = 0;
var mouseY = 0;
var stage = 1;
var x = 0;
var y = 0;
var xOrgn = 0;
var yOrgn = 0;
var xClk = 175;
var yClk = 100;
var mag = 0;
var ang = 0;
var xVel = 0;
var yVel = 0;
var time = 0;
function drawBall()
ctx.beginPath();
ctx.arc(x, y, 12, 0, Math.PI * 2);
ctx.fillStyle = "#FF8C00";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x, y + 12);
ctx.lineTo(x, y - 12);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x - 12, y);
ctx.lineTo(x + 12, y);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x - 8, y - 8);
ctx.bezierCurveTo(x - 2, y - 4, x - 2, y + 4, x - 8, y + 8);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x + 8, y - 8);
ctx.bezierCurveTo(x + 2, y - 4, x + 2, y + 4, x + 8, y + 8);
ctx.strokeStyle = 'black';
ctx.stroke();
function drawHoop()
ctx.beginPath();
ctx.rect(228, -160, 12, 172);
ctx.fillStyle = "#191919";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.rect(222, -12, 6, 80);
ctx.fillStyle = "#666666";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.rect(171, -6, 51, 6);
ctx.fillStyle = "#e50000";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.arc(171, -3, 3, 0, Math.PI * 2);
ctx.fillStyle = "#e50000";
ctx.fill();
ctx.closePath();
function drawCursor()
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(mouseX - 12, mouseY);
ctx.lineTo(mouseX + 12, mouseY);
ctx.strokeStyle = '#00cd00';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(mouseX, mouseY - 12);
ctx.lineTo(mouseX, mouseY + 12);
ctx.strokeStyle = '#00cd00';
ctx.stroke();
ctx.closePath();
function calcVel()
mag = Math.sqrt((Math.pow(xClk - xOrgn, 2) + Math.pow(yClk - yOrgn, 2)) / 4);
ang = Math.atan((yClk - yOrgn) / (xClk - xOrgn));
xVel = mag * Math.cos(ang);
yVel = mag * Math.sin(ang);
function draw()
ctx.clearRect(-(canvas.width / 2), -(canvas.height / 2), canvas.width, canvas.height);
ctx.canvas.addEventListener('mousemove', function(event)
mouseX = event.clientX - ctx.canvas.offsetLeft - canvas.width / 2;
mouseY = -event.clientY + ctx.canvas.offsetTop + canvas.height / 2;
);
drawBall();
drawHoop();
if (stage === 1)
x = mouseX;
y = mouseY;
ctx.canvas.addEventListener('click', function(event)
xOrgn = x;
yOrgn = y;
stage = 2;
);
else if (stage === 2)
drawCursor();
ctx.canvas.addEventListener('click', function(event)
xClk = mouseX;
yclk = mouseY;
calcVel();
time = 0;
stage = 3;
);
else if (stage === 3)
//x = xVel * time + xOrgn;
// update x from it's own value so we can vary the xVel.
x += xVel * speed * 0.01;
//y = -gravity * Math.pow(time, 2) + yVel * time + yOrgn;
// update yVel and y iteratively instead of this determined calculation
//y = -gravity * Math.pow(time, 2) + yVel * time + yOrgn;
yVel -= gravity * 0.1;
y += yVel * speed * 0.01;
// do a collision check: the backboard.
if (x > 222 - 12 && y > -12 && y < 62)
xVel *= -1;
// with floor
if(y <= -142)
y = -142;
yVel *= -1;
time = time + speed * 0.01;
setInterval(draw, 10);
canvas
background: white;
<canvas id="myCanvas" width="480" height="320"></canvas>
您可以类似地处理您想要的任何其他碰撞
【讨论】:
感谢您的帮助。我将使用变量来表示对象的位置。这对我很有用! 很高兴它的工作!我所说的变量的意思是,如果您可以输入类似if (x > backboard.x)
或更好的if (backboard.intersects(x,y))
之类的内容,那就太好了。您可以像以前一样使用变量(这是一个很好的第一步!),但如果您可以这样做,它将更具可读性并且“幻数”更少。以上是关于篮球物理碰撞检测和反弹物理的主要内容,如果未能解决你的问题,请参考以下文章