2d ball to line collision
Monkey Forums/Monkey Code/2d ball to line collision
| ||
a simple example of a ball to line collision including gravity. [monkeycode] Strict Import mojo Function Main:Int() New Game Return 1 End Function Class Point Field x:Float Field y:Float Method New(x:Float,y:Float) Self.x = x Self.y = y End Method End Class Class Game Extends App Field velocity:Point Field gravity:Float = .05 Field damping:Float = 0.999 Field segments:Int = 30 Field ground:Ground[] Field peakHeights:Float[] Field vertices:Float[] Field ball:Ball Field width:float Field height:float Method OnCreate:Int() ground = New Ground[segments] peakHeights = New Float[segments+1] vertices = New Float[segments*2+2] ball = New Ball(50, 50, 10) velocity = New Point(.5, 0) width = DeviceWidth() height = DeviceHeight() ' Calculate ground peak heights For Local i:Int = 0 Until peakHeights.Length() peakHeights[i] = Rnd(height-50, height-100) Next #rem /* Float value required For segment width (segs) calculations so the ground spans the entire display window, regardless of segment number. */ #End rem Local segs:Float = segments ground[0] = New Ground(0,480,0,peakHeights[0]) For Local i:Int = 1 Until segments ground[i] = New Ground(width/segs*i, peakHeights[i], width/segs*(i+1), peakHeights[i+1]) Next ground[segments-1].x2 = 640 ground[segments-1].y2 = 480 SetUpdateRate 60 Return 1 End method Method OnUpdate:Int() ' Move ball ball.x += velocity.x velocity.y += gravity ball.y += velocity.y ' Collision detection checkWallCollision() For Local i:Int = 0 Until segments checkGroundCollision(ground[i]) Next Return 1 End Method Method OnRender:Int() Cls SetColor 0,105,255 DrawRect(0, 0, width, height) SetColor 255,0,255 For Local i:Int =0 Until segments vertices[i*2] = ground[i].x1 vertices[i*2+1] = ground[i].y1 Next vertices[segments*2] = ground[segments-1].x2 vertices[segments*2+1] = ground[segments-1].y2 DrawPoly(vertices) SetColor 255,100,50 DrawCircle(ball.x, ball.y, ball.r) Return 1 End Method Method checkWallCollision:Void() If (ball.x > width-ball.r) ball.x = width-ball.r velocity.x *= -1 velocity.x *= damping Else If (ball.x < ball.r) ball.x = ball.r velocity.x *= -1 velocity.x *= damping Endif End Method Method checkGroundCollision:Void(groundSegment:Ground) ' Get difference between ball and ground Local deltaX:Float = ball.x - groundSegment.x Local deltaY:Float = ball.y - groundSegment.y ' Precalculate trig values Local cosine:Float = Cos(groundSegment.rot) Local sine:Float = Sin(groundSegment.rot) #rem /* Rotate ground And velocity To allow orthogonal collision calculations */ #End rem Local groundXTemp:Float = cosine * deltaX + sine * deltaY Local groundYTemp:Float = cosine * deltaY - sine * deltaX Local velocityXTemp:Float = cosine * velocity.x + sine * velocity.y Local velocityYTemp:Float = cosine * velocity.y - sine * velocity.x #Rem /* Ground collision - check For surface collision And also that ball is within left/rights bounds of ground segment */ #End rem If (groundYTemp > -ball.r And ball.x > groundSegment.x1 And ball.x < groundSegment.x2 ) ' keep ball from going into ground groundYTemp = -ball.r ' bounce and slow down ball velocityYTemp *= -1.0 velocityYTemp *= damping End If ' Reset ground, velocity and ball deltaX = cosine * groundXTemp - sine * groundYTemp deltaY = cosine * groundYTemp + sine * groundXTemp velocity.x = cosine * velocityXTemp - sine * velocityYTemp velocity.y = cosine * velocityYTemp + sine * velocityXTemp ball.x = groundSegment.x + deltaX ball.y = groundSegment.y + deltaY End Method End Class Class Ground Field x1:Float Field y1:Float Field x2:Float Field y2:float Field x:Float Field y:Float Field len:Float Field rot:Float ' Constructor Method New(x1:Float, y1:Float, x2:Float, y2:Float) Self.x1 = x1 Self.y1 = y1 Self.x2 = x2 Self.y2 = y2 x = (x1+x2)/2 y = (y1+y2)/2 len = dist(x1, y1, x2, y2) rot = ATan2((y2-y1), (x2-x1)) End Method Method dist:float(x1:Float,y1:Float,x2:Float,y2:Float) Return Sqrt((x2-x1)*(x2-x1) +(y2-y1)*(y2-y1)) End Method End Class Class Ball Field x:Float Field y:Float Field r:Float Method New(x:Float, y:Float, r:Float) Self.x = x Self.y = y Self.r = r End Method End Class [/monkeycode] |
| ||
Really useful for me thanks Jesse :) |
| ||
Actually Jesse, maybe you can help. is this code able to check collisions against lines of all angles? For example, I added 4 additional Ground instances to form a square (I renamed the Ground class to Line) tL.lines2 = New Line[4] tL.lines2[0] = New Line(500.0, 200.0, 550.0, 200.0) tL.lines2[1] = New Line(550.0, 200.0, 550.0, 250.0) tL.lines2[2] = New Line(500.0, 250.0, 550.0, 250.0) tL.lines2[3] = New Line(500.0, 200.0, 500.0, 250.0) and when the left vertical line is hit (lines2[3]), the ball pops up on top of the square, however when lines2[0] is hit (horizontal line on top) the ball behaves as expected. Any tips? :) Thanks |
| ||
Algorithms with polygons usually make assumptions about orientation. Maybe that's the problem here. In the original code the line segments are oriented consistently. As you travel from (x1,y1) to (x2,y2) the sky is on the left, ground on the right. Your lines 0 and 1 have this property, but lines 2 and 3 are the reverse. As you define lines 1,2,3 the start point of each line should be the end point of the previous line. If that doesn't work then post your code so we can see what is happening. |
| ||
Hey Floyd, thanks for the reply. Yeah I thought this might be it, hence the dodgy order (originally it was in a more logical order for drawing a square) I know it's not pretty, but here is the code I've been messing with |
| ||
The idea seems to be to rotate everything (line, ball, velocity vector) around the center of line so the line becomes horizontal. The collision checking and bounce are calculated for this easier configuration and the results are rotated back to the original orientation. There's no obvious reason it wouldn't work for arbitrary angles, but something is going wrong. |
| ||
It almost looks like the repositioning code just handles vertical stuff, I'll have a play |
| ||
It almost looks like the repositioning code just handles vertical stuff yes it is. After the line and ball are rotated for movement calculations, the line is checked to see if the ball went below the line. If it did, the ball is moved above the line and then everything is rotated back to it's original orientations along with the correct bounce mechanism. I learned to do that while I was researching the vector math. I had it in my hard Drive so I decided to post it here. I have not had much use for it really. anyway I decided that I am going to create a vector object engine that works with a single ball and a line(s). I will post it as soon I am done with it. it shouldn't take me more than a day or two. it will have elastic and dynamic collision. stay tuned. |
| ||
Cheers Jesse :) I found what I believe to be your vector code examples on blitzbasic.com as well and I've been messing around converting them for Monkey. I think it's about time I learnt about trigonometry properly seeing as I will probably end up using it in one way or another in just about everything I create! |
| ||
Diddy has a 2D vector module if you want to take a look at it. |
| ||
@raz Just be careful if you go through the tutorials posted by toypa they are good but have steps that I guess he didn't either know how to do or decided not to share(?) so he did some work around that had me puzzled. he did something somewhat similar to this circle to line demo above. I had to do a lot more searching around vector tutorials before I figured it out. |
| ||
I'll have to have a look Samah, does it include reflection and point of intersection stuff? Jesse: By chance I had been looking at these tutorials myself and I wasn't able to get my head around them! With your blitzmax code though, from what I can tell, all angles worked fine :) |