PONG Engine - Issue with bounce!?
BlitzMax Forums/BlitzMax Programming/PONG Engine - Issue with bounce!?
| ||
Hi, I have an issue with this pong game (full source). First i just want the bounching balls done, then i take it from there. But its bugging even now. This code is a port from this flash-actionshipt engine http://www.emanueleferonato.com/2007/08/19/managing-ball-vs-ball-collision-with-flash/ I think its very strange BlitzMax throws this unusual behaviour; After some time balls clutch together and drift to the upperleft corner. Try 30 balls for example. Const TableWidth = 64; Const TableHeight = 48; Const TabelPixel = 10; Graphics TableWidth * TabelPixel, TableHeight * TabelPixel Type Tball Field _x:Double Field _y:Double Field xspeed:Double Field yspeed:Double Field mass:Int Field collision:Int End Type Local number_of_balls = 5; Local speed_limit = 10; Local balls:Tball[number_of_balls] Local ball:Tball Local x:Int 'Create balls For x=0 To number_of_balls -1 ball:Tball = New Tball ball._x = Rand((TableWidth * TabelPixel)-50)+25 ball._y = Rand((TableHeight * TabelPixel)-50)+25 ball.collision = 0; ball.mass = 1; ball.xspeed = Rand(4.0) -2.0; ball.yspeed = Rand(4.0) -2.0; balls[x] = ball Next Function Bounce(ball:Tball, ball2:Tball) Local dx:Double = ball._x - ball2._x; Local dy:Double = ball._y - ball2._y; Local collisionision_angle:Double = ATan2(dy, dx); Local magnitude_1:Double = Sqr(ball.xspeed * ball.xspeed + ball.yspeed * ball.yspeed); Local magnitude_2:Double = Sqr(ball2.xspeed * ball2.xspeed + ball2.yspeed * ball2.yspeed); Local direction_1:Double = ATan2(ball.yspeed, ball.xspeed); Local direction_2:Double = ATan2(ball2.yspeed, ball2.xspeed); Local new_xspeed_1:Double = magnitude_1 * Cos(direction_1 -collisionision_angle); Local new_yspeed_1:Double = magnitude_1 * Sin(direction_1 -collisionision_angle); Local new_xspeed_2:Double = magnitude_2 * Cos(direction_2 -collisionision_angle); Local new_yspeed_2:Double = magnitude_2 * Sin(direction_2 -collisionision_angle); Local final_xspeed_1:Double = ((ball.mass -ball2.mass) * new_xspeed_1 + (ball2.mass + ball2.mass) * new_xspeed_2)/(ball.mass + ball2.mass); Local final_xspeed_2:Double = ((ball.mass + ball.mass) * new_xspeed_1 + (ball2.mass -ball.mass) * new_xspeed_2)/(ball.mass + ball2.mass); Local final_yspeed_1:Double = ((ball.mass -ball2.mass) * new_yspeed_1 + (ball2.mass + ball2.mass) * new_yspeed_2)/(ball.mass + ball2.mass); Local final_yspeed_2:Double = ((ball.mass + ball.mass) * new_yspeed_1 + (ball2.mass -ball.mass) * new_yspeed_2)/(ball.mass + ball2.mass); 'Local final_xspeed_1:Double = new_xspeed_1; 'Local final_xspeed_2:Double = new_xspeed_2; 'Local final_yspeed_1:Double = new_yspeed_1; 'Local final_yspeed_2:Double = new_yspeed_2; ball.xspeed = Cos(collisionision_angle) * final_xspeed_1 + Cos(collisionision_angle + Pi/2) * final_yspeed_1; ball.yspeed = Sin(collisionision_angle) * final_xspeed_1 + Sin(collisionision_angle + Pi/2) * final_yspeed_1; ball2.xspeed = Cos(collisionision_angle) * final_xspeed_2 + Cos(collisionision_angle + Pi/2) * final_yspeed_2; ball2.yspeed = Sin(collisionision_angle) * final_xspeed_2 + Sin(collisionision_angle + Pi/2) * final_yspeed_2; End Function Repeat 'left pad 'ball:Tball = balls[0] 'ball.xspeed = 1 'ball.yspeed = 0 'ball._x = 50 'ball._y = MouseY() 'right pad 'ball:Tball = balls[1] 'ball.xspeed = 0 'ball.yspeed = 0 'ball._x = (TableWidth * TabelPixel) - 50 'ball._y = MouseY() 'pong For x=0 To number_of_balls -1 ball:Tball = balls[x] If(ball._x<15) Then ball._x = 15; ball.xspeed = ball.xspeed *-1; Else If (ball._x>(TableWidth * TabelPixel) - 15) Then ball._x = (TableWidth * TabelPixel) - 15; ball.xspeed = ball.xspeed *-1; End If If (ball._y<15) Then ball._y = 15; ball.yspeed = ball.yspeed *-1; Else If (ball._y>(TableHeight * TabelPixel) - 15) Then ball._y = (TableHeight * TabelPixel) - 15 ball.yspeed = ball.yspeed *-1; End If If (ball.xspeed>speed_limit) Then ball.xspeed = speed_limit; End If If (ball.xspeed<speed_limit*-1) Then ball.xspeed = speed_limit*-1; End If If (ball.yspeed>speed_limit) Then ball.yspeed = speed_limit; End If If (ball.yspeed<speed_limit*-1) Then ball.yspeed = speed_limit*-1; End If ball._x = ball._x + ball.xspeed; ball._y = ball._y + ball.yspeed; Next For x=0 To number_of_balls -1 For y=x+1 To number_of_balls -1 Local distance_x:Double = Abs(balls[x]._x -balls[y]._x); Local distance_y:Double = Abs(balls[x]._y -balls[y]._y); Local distance:Double = Sqr(distance_x * distance_x + distance_y * distance_y); If (distance<=30 And (balls[x].collision = 0 Or balls[y].collision = 0)) Then balls[x].collision = 1; balls[y].collision = 1; Bounce(balls[x], balls[y]); Else If (distance>30) Then balls[x].collision = 0; balls[y].collision = 0; End If Next Next 'SetColor 0,200,0 'DrawOval balls[0]._x -15, balls[0]._y -15, 30, 30 'SetColor 255,255,255 'DrawOval balls[0]._x -13, balls[0]._y -13, 26, 26 'SetColor 0,0,200 'DrawOval balls[1]._x -15, balls[1]._y -15, 30, 30 'SetColor 255,255,255 'DrawOval balls[1]._x -13, balls[1]._y -13, 26, 26 For x=0 To number_of_balls -1 SetColor 200,0,0 DrawOval balls[x]._x -15, balls[x]._y -15, 30, 30 SetColor 255,255,255 DrawOval balls[x]._x -13, balls[x]._y -13, 26, 26 Next Flip Cls Until KeyHit(KEY_ESCAPE) 'ESC |
| ||
Ugh n.m. fixed it with re-calc the pos after the Bounce update'Fix distance Bug Local distance_x:Double = Abs(ball._x - ball2._x); Local distance_y:Double = Abs(ball._y - ball2._y); Local distance:Double = Sqr(distance_x * distance_x + distance_y * distance_y); ball2._x = ball2._x - Cos(collisionision_angle)*(30-distance); ball2._y = ball2._y - Sin(collisionision_angle)*(30-distance); |
| ||
Changing this:ball.xspeed = Cos(collisionision_angle) * final_xspeed_1 + Cos(collisionision_angle + Pi/2) * final_yspeed_1; ball.yspeed = Sin(collisionision_angle) * final_xspeed_1 + Sin(collisionision_angle + Pi/2) * final_yspeed_1; ball2.xspeed = Cos(collisionision_angle) * final_xspeed_2 + Cos(collisionision_angle + Pi/2) * final_yspeed_2; ball2.yspeed = Sin(collisionision_angle) * final_xspeed_2 + Sin(collisionision_angle + Pi/2) * final_yspeed_2; to this, seemed to fix it for me : ball.xspeed = Cos(collisionision_angle ) * final_xspeed_1 + Cos(collisionision_angle + 90 ) * final_yspeed_1; ball.yspeed = Sin(collisionision_angle ) * final_xspeed_1 + Sin(collisionision_angle + 90 ) * final_yspeed_1; ball2.xspeed = Cos(collisionision_angle ) * final_xspeed_2 + Cos(collisionision_angle + 90 ) * final_yspeed_2; ball2.yspeed = Sin(collisionision_angle ) * final_xspeed_2 + Sin(collisionision_angle + 90 ) * final_yspeed_2; Angles in BlitzMax are in degrees, not radians. |
| ||
Ah, cool! Yes, yours works. Got it. |
| ||
Alright, i have it setup to work like pong. However im not happy with the movement. What i would like is to increase the speed? But more importantly, that the pads dont glitch. I think its because im mis-using pads as balls :_) im terrible at math. Maybe someone would like to take a shot at it? I guess what needs to be done is work with the angle instead of the x,y velocity. That way you can change the angle instead of re-doing the velocity math. And then adjust the Bounce to work with the angle insead of the velocity. Full source below (cut & run) Const TableWidth = 14; Const TableHeight = 7; Const TabelPixel = 70; Graphics TableWidth * TabelPixel, TableHeight * TabelPixel Type Tball Field _x:Double Field _y:Double Field xspeed:Double Field yspeed:Double Field mass:Int Field collision:Int End Type Local number_of_balls = 3; Local speed_limit = 10; Local balls:Tball[number_of_balls] Local ball:Tball Local x:Int 'Create balls For x=0 To number_of_balls -1 ball:Tball = New Tball ball._x = Rand((TableWidth * TabelPixel)-50)+25 ball._y = Rand((TableHeight * TabelPixel)-50)+25 ball.collision = 0; ball.mass = 1; ball.xspeed = 4*((Rand(0,1)*2)-1) ball.yspeed = 2*((Rand(0,1)*2)-1) balls[x] = ball Next Function Bounce(ball:Tball, ball2:Tball) Local dx:Double = ball._x - ball2._x; Local dy:Double = ball._y - ball2._y; Local collisionision_angle:Double = ATan2(dy, dx); Local magnitude_1:Double = Sqr(ball.xspeed * ball.xspeed + ball.yspeed * ball.yspeed); Local magnitude_2:Double = Sqr(ball2.xspeed * ball2.xspeed + ball2.yspeed * ball2.yspeed); Local direction_1:Double = ATan2(ball.yspeed, ball.xspeed); Local direction_2:Double = ATan2(ball2.yspeed, ball2.xspeed); Local new_xspeed_1:Double = magnitude_1 * Cos(direction_1 -collisionision_angle); Local new_yspeed_1:Double = magnitude_1 * Sin(direction_1 -collisionision_angle); Local new_xspeed_2:Double = magnitude_2 * Cos(direction_2 -collisionision_angle); Local new_yspeed_2:Double = magnitude_2 * Sin(direction_2 -collisionision_angle); Local final_xspeed_1:Double = ((ball.mass -ball2.mass) * new_xspeed_1 + (ball2.mass + ball2.mass) * new_xspeed_2)/(ball.mass + ball2.mass); Local final_xspeed_2:Double = ((ball.mass + ball.mass) * new_xspeed_1 + (ball2.mass -ball.mass) * new_xspeed_2)/(ball.mass + ball2.mass); 'Local final_yspeed_1:Double = ((ball.mass -ball2.mass) * new_yspeed_1 + (ball2.mass + ball2.mass) * new_yspeed_2)/(ball.mass + ball2.mass); 'Local final_yspeed_2:Double = ((ball.mass + ball.mass) * new_yspeed_1 + (ball2.mass -ball.mass) * new_yspeed_2)/(ball.mass + ball2.mass); 'Local final_xspeed_1:Double = new_xspeed_1; 'Local final_xspeed_2:Double = new_xspeed_2; Local final_yspeed_1:Double = new_yspeed_1; Local final_yspeed_2:Double = new_yspeed_2; 'Radians 'ball.xspeed = Cos(collisionision_angle) * final_xspeed_1 + Cos(collisionision_angle + Pi/2) * final_yspeed_1; 'ball.yspeed = Sin(collisionision_angle) * final_xspeed_1 + Sin(collisionision_angle + Pi/2) * final_yspeed_1; 'ball2.xspeed = Cos(collisionision_angle) * final_xspeed_2 + Cos(collisionision_angle + Pi/2) * final_yspeed_2; 'ball2.yspeed = Sin(collisionision_angle) * final_xspeed_2 + Sin(collisionision_angle + Pi/2) * final_yspeed_2; 'Degrees ball.xspeed = Cos(collisionision_angle ) * final_xspeed_1 + Cos(collisionision_angle + 90 ) * final_yspeed_1; ball.yspeed = Sin(collisionision_angle ) * final_xspeed_1 + Sin(collisionision_angle + 90 ) * final_yspeed_1; ball2.xspeed = Cos(collisionision_angle ) * final_xspeed_2 + Cos(collisionision_angle + 90 ) * final_yspeed_2; ball2.yspeed = Sin(collisionision_angle ) * final_xspeed_2 + Sin(collisionision_angle + 90 ) * final_yspeed_2; End Function 'Ball index: 0 = Left pad, 1 = Right pad, 2 = ball Local ox,oy,nx,ny Repeat 'Detect Up or Down movement ox = nx oy = ny nx = MouseX() ny = MouseY() If ny>oy Then sy = 1 Else sy = -1 End If 'Pads are fixed balls. Advantage: Circular bounce radius (e.g. walls do just flat reflection) 'left pad ball:Tball = balls[0] ball.xspeed = Abs(balls[2].xspeed) ball.yspeed = Abs(balls[2].yspeed)*sy ball._x = 50 ball._y = MouseY() 'right pad ball:Tball = balls[1] ball.xspeed = Abs(balls[2].xspeed)*-1 ball.yspeed = Abs(balls[2].yspeed)*sy ball._x = (TableWidth * TabelPixel) - 50 ball._y = MouseY() 'pong For x=2 To number_of_balls -1 ball:Tball = balls[x] If(ball._x<15) Then ball._x = 15; ball.xspeed = ball.xspeed *-1; Else If (ball._x>(TableWidth * TabelPixel) - 15) Then ball._x = (TableWidth * TabelPixel) - 15; ball.xspeed = ball.xspeed *-1; End If If (ball._y<15) Then ball._y = 15; ball.yspeed = ball.yspeed *-1; Else If (ball._y>(TableHeight * TabelPixel) - 15) Then ball._y = (TableHeight * TabelPixel) - 15 ball.yspeed = ball.yspeed *-1; End If If (ball.xspeed>speed_limit) Then ball.xspeed = speed_limit; End If If (ball.xspeed<speed_limit*-1) Then ball.xspeed = speed_limit*-1; End If If (ball.yspeed>speed_limit) Then ball.yspeed = speed_limit; End If If (ball.yspeed<speed_limit*-1) Then ball.yspeed = speed_limit*-1; End If ball._x = ball._x + ball.xspeed; ball._y = ball._y + ball.yspeed; Next For x=0 To number_of_balls -2 'Pads check collision with.. 'For y=x+1 To number_of_balls -1 Int y=2 '..the ball Local distance_x:Double = Abs(balls[x]._x -balls[y]._x); Local distance_y:Double = Abs(balls[x]._y -balls[y]._y); Local distance:Double = Sqr(distance_x * distance_x + distance_y * distance_y); If (distance<=30 And (balls[x].collision = 0 Or balls[y].collision = 0)) Then balls[x].collision = 1; balls[y].collision = 1; 'Fix Position (prevent clutching) 'Not needed anymore? 'Local dx:Double = balls[x]._x - balls[y]._x; 'Local dy:Double = balls[x]._y - balls[y]._y; 'Local collisionision_angle:Double = ATan2(dy, dx); 'balls[y]._x = balls[y]._x - Cos(collisionision_angle)*(30-distance); 'balls[y]._y = balls[y]._y - Sin(collisionision_angle)*(30-distance); 'Do Bounce Bounce(balls[x], balls[y]); 'Boost Speed - Doesnt work well :( balls[y].xspeed = balls[y].xspeed * 1.1; Else If (distance>30) Then balls[x].collision = 0; balls[y].collision = 0; End If 'Next Next SetColor 0,200,0 DrawOval balls[0]._x -15, balls[0]._y -15, 30, 30 SetColor 255,255,255 DrawOval balls[0]._x -13, balls[0]._y -13, 26, 26 SetColor 0,0,200 DrawOval balls[1]._x -15, balls[1]._y -15, 30, 30 SetColor 255,255,255 DrawOval balls[1]._x -13, balls[1]._y -13, 26, 26 For x=2 To number_of_balls -1 SetColor 200,0,0 DrawOval balls[x]._x -15, balls[x]._y -15, 30, 30 SetColor 255,255,255 DrawOval balls[x]._x -13, balls[x]._y -13, 26, 26 Next Flip Cls Until KeyHit(KEY_ESCAPE) 'ESC |