我遇到两个球之间碰撞检测的问题。 只有偶尔球会合并,它们通常表现得如此。 我在画布的边框上遇到了同样的问题但能够修复它。 我似乎无法弄清楚如何应用圈子的逻辑。
非常感谢任何帮助。
请参阅下面的相关代码块。也是完整的片段。
//Intersect function takes a ball as a perameter
//ball will be the the object used to test if the two are touching.
function intersect(ball,ball1) {
//the x and y cordinates of the first ball are subtracted from the test ball and stored
//in productX and productY
dx = ball1.x - ball.x;
dy = ball1.y - ball.y;
//pythagoras theorem is used to get the distance between both center points of each circle.
distance = Math.sqrt(dx * dx + dy * dy);
//A condition is used to check if the distance between both bencer point of each circle
//is less than or equal to the sum of both radii the circles are touching.
//the result is p[rinted out to the console
if (distance < ball1.r + ball.r) {
collision_angle = Math.atan2(dy,dx);
magnitude_1 = Math.sqrt(ball.xvel*ball.xvel+ball.yvel*ball.yvel);
magnitude_2 = Math.sqrt(ball1.xvel*ball1.xvel+ball1.yvel*ball1.yvel);
direction_1 = Math.atan2(ball.yvel, ball.xvel);
direction_2 = Math.atan2(ball1.yvel, ball1.xvel);
new_xvel_1 = magnitude_1 * Math.cos(direction_1-collision_angle);
new_yvel_1 = magnitude_1 * Math.sin(direction_1-collision_angle);
new_xvel_2 = magnitude_2 * Math.cos(direction_2-collision_angle);
new_yvel_2 = magnitude_1 * Math.sin(direction_2-collision_angle);
final_xvel_1 = ((ball.mass-ball1.mass)*new_xvel_1+(ball1.mass+ball1.mass)*new_xvel_2)/(ball.mass+ball1.mass);
final_xvel_2 = ((ball.mass+ball.mass)*new_xvel_1+(ball1.mass-ball.mass)*new_xvel_2)/(ball.mass+ball1.mass);
final_yvel_1 = new_yvel_1;
final_yvel_2 = new_yvel_2;
ball.xvel = Math.cos(collision_angle)*final_xvel_1+Math.cos(collision_angle+Math.PI/2)*final_yvel_1;
ball.yvel = Math.sin(collision_angle)*final_xvel_1+Math.sin(collision_angle+Math.PI/2)*final_yvel_1;
ball1.xvel = Math.cos(collision_angle)*final_xvel_2+Math.cos(collision_angle+Math.PI/2)*final_yvel_2;
ball1.yvel = Math.sin(collision_angle)*final_xvel_2+Math.sin(collision_angle+Math.PI/2)*final_yvel_2;
}
}
<!DOCTYPE html>
<html>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<head>
<meta charset="UTF-8">
<title>Canvas</title>
<style type="text/css">
canvas {
border: 1px solid grey;
}
</style>
</head>
<body>
<canvas id="canvas-for-ball"></canvas>
<script type="text/javascript">
// Gets a handle to the element with id canvasOne.
var canvas = document.getElementById("canvas-for-ball");
// Get a 2D context for the canvas.
var ctx = canvas.getContext("2d");
function init(){
canvas.width = 500;
canvas.height = 500;
}
init();
//ball object
class Ball {
constructor(x,y,r,xvel,yvel,mass){
this.x =x;
this.y = y;
this.r =r;
this.xvel = xvel;
this.yvel = yvel;
this.mass = mass;
//angle defining spin and sections of ball
this.theta = 0;
//for the sections of the ball
this.theta2 = 0;
//for he amount of sections needed
this.seventh = (Math.PI*2)/7
//to control the amount of spin the ball has
this.thetaInc = 0.0129;
//For gravity
this.gravity = 1;
this.friction = .01;
}
drop(){
//Gravity
this.yvel += this.gravity*1.9;
//friction
this.xvel = this.xvel - (this.xvel*this.friction);
}
draw(){
// Update the y location.
this.x += this.xvel;
this.y += this.yvel;
//draw circle
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
ctx.stroke();
//fill the circle
ctx.fillStyle = this.color ;
ctx.fill();
//draw inner circle of ball
ctx.beginPath();
ctx.arc(this.x,this.y,this.r*.9,0,Math.PI*2,false);
ctx.stroke();
//spin control
this.theta += this.thetaInc;
//loop for adding sections to pie
for( var n = 0; n < 7; ++n) { // add loop to draw radii
this.theta2 = this.theta + n * this.seventh;
ctx.moveTo( this.x, this.y);
ctx.lineTo( this.x + this.r*Math.cos(this.theta2), this.y + this.r*Math.sin(this.theta2));
}
ctx.lineWidth = "2";
ctx.lineCap = "round";
ctx.strokeStyle = "black";
ctx.stroke();
}
move(){
if(this.y >= canvas.height - this.r){
this.y = canvas.height - this.r;
this.yvel =-this.yvel;
}else if(this.y<=0+this.r){
this.y = this.r;
this.yvel = -this.yvel;
}
//to reverse the direction of the ball when hitting walls
if((this.xvel<0 && this.yvel >0) && this.thetaInc <0){
this.thetaInc = -1*this.thetaInc;
}
else if((this.xvel <0 && this.yvel>0) && this.thetaInc >0){
this.thetaInc = -1*this.thetaInc
}
else if((this.xvel >0 && this.yvel >0) && this.thetaInc >0){
this.thetaInc = -1 * this.thetaInc;
}
else if((this.xvel > 0 && this.yvel < 0)&& this.thetaInc <0){
this.thetaInc = -1 * this.thetaInc;
}
if(this.x>=canvas.width-this.r){
this.x = canvas.width - this.r;
this.xvel = -this.xvel;
}else if(this.x<=this.r){
this.x = this.r;
this.xvel = -this.xvel;
}
}
resize(){
var that = this;
that.up = true;
that.r = 20;
that.increment = 1;
that.ceiling = 50;
function PerformCalc() {
if (that.up == true && that.r <= that.ceiling) {
that.r += that.increment
if (that.r == that.ceiling) {
that.up = false;
}
} else {
that.up = false
that.r -= that.increment;
if (that.r == 20) {
that.up = true;
}
}
}
setInterval(PerformCalc, 800);
}
setColour(){
this.o = Math.round, this.rd = Math.random, this.s = 255;
this.color = 'rgb(' + this.o(this.rd()*this.s) + ',' + this.o(this.rd()*this.s) + ',' + this.o(this.rd()*this.s) +')';
}
}
//Intersect function takes a ball as a perameter
//ball will be the the object used to test if the two are touching.
function intersect(ball,ball1) {
//the x and y cordinates of the first ball are subtracted from the test ball and stored
//in productX and productY
dx = ball1.x - ball.x;
dy = ball1.y - ball.y;
//pythagoras theorem is used to get the distance between both center points of each circle.
distance = Math.sqrt(dx * dx + dy * dy);
//A condition is used to check if the distance between both bencer point of each circle
//is less than or equal to the sum of both radii the circles are touching.
//the result is p[rinted out to the console
if (distance < ball1.r + ball.r) {
collision_angle = Math.atan2(dy,dx);
magnitude_1 = Math.sqrt(ball.xvel*ball.xvel+ball.yvel*ball.yvel);
magnitude_2 = Math.sqrt(ball1.xvel*ball1.xvel+ball1.yvel*ball1.yvel);
direction_1 = Math.atan2(ball.yvel, ball.xvel);
direction_2 = Math.atan2(ball1.yvel, ball1.xvel);
new_xvel_1 = magnitude_1 * Math.cos(direction_1-collision_angle);
new_yvel_1 = magnitude_1 * Math.sin(direction_1-collision_angle);
new_xvel_2 = magnitude_2 * Math.cos(direction_2-collision_angle);
new_yvel_2 = magnitude_1 * Math.sin(direction_2-collision_angle);
final_xvel_1 = ((ball.mass-ball1.mass)*new_xvel_1+(ball1.mass+ball1.mass)*new_xvel_2)/(ball.mass+ball1.mass);
final_xvel_2 = ((ball.mass+ball.mass)*new_xvel_1+(ball1.mass-ball.mass)*new_xvel_2)/(ball.mass+ball1.mass);
final_yvel_1 = new_yvel_1;
final_yvel_2 = new_yvel_2;
ball.xvel = Math.cos(collision_angle)*final_xvel_1+Math.cos(collision_angle+Math.PI/2)*final_yvel_1;
ball.yvel = Math.sin(collision_angle)*final_xvel_1+Math.sin(collision_angle+Math.PI/2)*final_yvel_1;
ball1.xvel = Math.cos(collision_angle)*final_xvel_2+Math.cos(collision_angle+Math.PI/2)*final_yvel_2;
ball1.yvel = Math.sin(collision_angle)*final_xvel_2+Math.sin(collision_angle+Math.PI/2)*final_yvel_2;
}
}
canvas.addEventListener("click", function(event) {
var clickX = event.clientX - canvas.offsetLeft;
var clickY = event.clientY- canvas.offsetTop;
b1.x = clickX;
b1.y = clickY;
});
// Add a Javascript event listener to the keypress event.
window.addEventListener("keypress", function(event) {
// Just log the event to the console.
console.log(event);
});
//keypresses with jQuery
$(document.body).on('keydown', function(e) {
console.log(e.which);
switch (e.which) {
// key code for left arrow
case 37:
console.log('left arrow key pressed!');
b1.xvel --;
break;
//keycode for up
case 38:
console.log('up key pressed');
b1.yvel++;
break;
//key code for right
case 39:
console.log('right arrow key pressed!');
b1.xvel++;
break;
//key code for down
case 40:
console.log('down arrow key pressed!');
b1.yvel--;
break;
//key code for + key to increase spin
case 107:
console.log('down arrow key pressed!');
b1.thetaInc += .001;
break;
//key code for - key to decrease spin
case 109:
console.log('down arrow key pressed!');
b1.thetaInc -= .001;
break;
}
});
b1 = new Ball(200,200,40,10,10,5);
b2 = new Ball(100,100,40,2,2,5);
b1.resize();
b2.resize();
// A function to repeat every time the animation loops.
function repeatme() {
//clear canvas for each frame of the animation.
ctx.clearRect(0,0,500,500);
// Draw the ball (stroked, not filled).
b1.draw();
b2.draw();
b1.move();
b1.drop();
b1.setColour();
b2.move();
intersect(b1,b2);
//put repeatme function into the animation frame and store it in animate
animate = window.requestAnimationFrame(repeatme);
}
// Get the animation going.
repeatme();
</script>
</body>
</html>
您可以单击屏幕更改其中一个球的位置以更快地查看问题。
答案 0 :(得分:0)
我无法添加评论,所以在此处添加= /
我注意到的是,一旦问题发生,其中一个球的质量设置不正确,因为它会反弹,然后在空间中的移动速度比另一个慢得多。有时这会发生,但它们不会粘住,但看起来它们几乎总是在下一次碰撞发生后坚持。
仍然试图围绕为什么正在发生,但我认为这可能是相关的。