我正在为物理学做一点测试。我用画布和上下文画了一个圆圈:
function drawAngles () {
var d = 50; //start line at (10, 20), move 50px away at angle of 30 degrees
var angle = 80 * Math.PI/180;
ctx.beginPath();
ctx.moveTo(300,0);
ctx.lineTo(300,600); //x, y
ctx.moveTo(0,300);
ctx.lineTo(600,300);
ctx.arc(300,300,300,0,2*Math.PI);
ctx.stroke();
}
我想以某种方式获得圆圈的弯曲边界,以便我可以判断球元素是否已经碰撞。
如果我在典型div
上测试边界,我可以这样做:
var divCoords= $(".boundingBoxDiv").position();
var top = divCoords.top;
etc...
如何使用上下文行执行此操作?
这是一张图片......球应该从圆圈中反弹。
答案 0 :(得分:1)
你有没有看过光线投射?碰撞检测的一个巧妙技巧是创建一个仅用于碰撞检测的新隐藏画布。然后,您可以仅使用黑色和白色绘制圆圈。如果画布上填充黑色并带有白色圆圈,则可以通过检查x点处特定像素的颜色来测试碰撞。如果点x是黑色,则对象发生碰撞,如果不是,则碰撞。
答案 1 :(得分:1)
这很容易实现,在基于半径的碰撞中,如果距离比物体碰撞的半径更近,则只需检查距离。在这种情况下,我们需要做相反的事情,如果物体距离大于而不是边界半径,我们需要改变角度以保持物体进入。
首先,我们需要确定边界中心点和边界半径
var boundaryRadius = 300,
boundaryX = 300,
boundaryY = 300;
稍后在ball.update
方法中,我会检查这些值。
var dx = boundaryX - this.x,
dy = boundaryY - this.y
我们需要距离球和边界中心点的距离。
dist = Math.sqrt(dx * dx + dy * dy);
现在我们需要根据当前角度获得速度
this.radians = this.angle * Math.PI/ 180;
this.velX = Math.cos(this.radians) * this.speed;
this.velY = Math.sin(this.radians) * this.speed;
接下来我们检查一下我们是否还在边界内。在这种情况下,如果我们的距离小于300 - 我们自己的半径(即10)那么290,那么继续移动。
if (dist < boundaryRadius-this.radius) {
this.x += this.velX;
this.y += this.velY;
否则,如果我们的距离大于大于290,我们需要首先向后移动一点,这样我们才不会碰撞,然后我们只需改变我们的航向角。你可以用更多更好的方式来实际计算你应该反弹到哪里,在这个例子中,我只是让它与一点点随机性相反。
} else {
this.x -= this.velX;
this.y -= this.velY;
this.angle += 180+Math.random()*45;
}
完整的代码。
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 600,
height = 600;
canvas.width = width;
canvas.height = height;
var boundaryRadius = 300,
boundaryX = 300,
boundaryY = 300;
var Ball = function (x, y, speed) {
this.x = x || 0;
this.y = y || 0;
this.radius = 10;
this.speed = speed || 10;
this.color = "rgb(255,0,0)";
this.angle = Math.random() * 360;
this.radians = this.angle * Math.PI/ 180;
this.velX = 0;
this.velY = 0;
}
Ball.prototype.update = function () {
var dx = boundaryX - this.x,
dy = boundaryY - this.y,
dist = Math.sqrt(dx * dx + dy * dy);
this.radians = this.angle * Math.PI/ 180;
this.velX = Math.cos(this.radians) * this.speed;
this.velY = Math.sin(this.radians) * this.speed;
// check if we are still inside of our boundary.
if (dist < boundaryRadius-this.radius) {
this.x += this.velX;
this.y += this.velY;
} else {
// collision, step back and choose an opposite angle with a bit of randomness.
this.x -= this.velX;
this.y -= this.velY;
this.angle += 180+Math.random()*45;
}
};
Ball.prototype.render = function () {
ctx.fillStyle = this.color;
ctx.beginPath();
// draw our circle with x and y being the center
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(this.x, this.y);
ctx.lineTo(this.px, this.py);
ctx.closePath();
};
var balls = [],
ballNum = 10;
for(var i = 0; i < ballNum; i++){
balls.push(new Ball(boundaryX + Math.random()*30, boundaryY + Math.random() * 30, 5 + Math.random()*15));
}
function drawAngles() {
var d = 50; //start line at (10, 20), move 50px away at angle of 30 degrees
var angle = 80 * Math.PI / 180;
ctx.beginPath();
ctx.moveTo(300, 0);
ctx.lineTo(300, 600); //x, y
ctx.moveTo(0, 300);
ctx.lineTo(600, 300);
ctx.arc(boundaryX, boundaryY, boundaryRadius, 0, 2 * Math.PI);
ctx.strokeStyle = "#000";
ctx.stroke();
}
function render() {
ctx.clearRect(0, 0, width, height);
drawAngles();
balls.forEach(function(e){
e.update();
e.render();
});
requestAnimationFrame(render);
}
render();