碰撞画布时,球碰撞卡在一起5

时间:2017-11-03 16:59:41

标签: javascript html5 canvas

我遇到两个球之间碰撞检测的问题。 只有偶尔球会合并,它们通常表现得如此。 我在画布的边框上遇到了同样的问题但能够修复它。 我似乎无法弄清楚如何应用圈子的逻辑。

非常感谢任何帮助。

请参阅下面的相关代码块。也是完整的片段。

//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>

您可以单击屏幕更改其中一个球的位置以更快地查看问题。

1 个答案:

答案 0 :(得分:0)

我无法添加评论,所以在此处添加= /

我注意到的是,一旦问题发生,其中一个球的质量设置不正确,因为它会反弹,然后在空间中的移动速度比另一个慢得多。有时这会发生,但它们不会粘住,但看起来它们几乎总是在下一次碰撞发生后坚持。

仍然试图围绕为什么正在发生,但我认为这可能是相关的。