Help with Physics: Momentum!
BlitzMax Forums/BlitzMax Programming/Help with Physics: Momentum!
| ||
It is so close, but it just won't work (that last bit). Something is wrong with the reflection. Because somehow I need to apply it to both of the object who collide, but when I do they act crazy. This shouldn't be that hard to solve so I ask anyone, please help me! I pasted all code into one file, to run this just copy and paste. |
| ||
Can anyone try it? |
| ||
run this vesion and you can REALLY see the problem. And it doesn't look good: I'll see what I can do for ya EDIT_____________________________________________________ Not that far now - they just dont move in the right direction tho: EDIT:________________________________________________ It wont let me have another code box :( |
| ||
Try this then wave - Its a bit rough around the edges but it kida works: |
| ||
When I run it the bounces are reversed, it doesn't seem to work. I tried to tweak it some more. I think there is a problem in that each ball is checked against each other, but when a collision occur both ball's velocities is altered, instead of just one of them. And the amount we change velocity with need to be based on the mass of both objects and on the elasticity of the objects. Or perhaps the best solution would be to separate the two cases. No bounce vs Perfect Bounce. Anyhow I still can't get it to work.. |
| ||
try playing with this version. I made the collision into a method and update in drawall. I think i added a collision field but you can get rid of that: EDIT: as i said I have no Idea about physics but i'm just trying to get it to a point when it looks right. and also keeping it at the top till someone else with a better idear of what todo repliys :D |
| ||
Thanks, yet the collisions are chaotic ;) I think my collision idea is flawed. I need to do it another way, though the momentum is easy in theory, so I don't understand why it should be so hard to code. I'll try some more. I think this problem can be solved, hm.. |
| ||
And if you didn't know: Momentum Momentum is a measurement of an objects ability to resist change in velocity. The greater the speed and the larger the mass, the greater will the object’s momentum be. Momentum is a vector quantity and always has the same direction as the objects velocity vector. There will be times where objects of different mass and different speeds collide. Some times you might even have an object that increases or decreases its mass. That could for example be a helicopter landing on a train, where as the trains mass gets a little bigger, and therefore the train’s velocity will decreases slightly. Momentum = Velocity*Mass If a collision involving two objects the total momentum all conserved! So the total momentum before and after collision is always the same. Example: Our bounce balls, each have different masses and velocities. When a big ball collide with a smaller one, and they both have the same speed, the larger ball will not change it's velocity very much, while the small ball will bounce away with a larger speed. Example2: Think about a pool table, if you fire a ball against a not moving ball, the moving ball will transfer its momentum to the stationary ball and that ball will fly off with the same speed the first ball had before collision. Also consider that at the moment of collision we have some energy loss (friction) so in the real world the second ball would have a slightly slower velocity than the first. This is what I call friction in my ApplyResponse( Velocity:Vector2D Var, SurfaceNormal:Vector2D, Friction!, Elasticity! ) method. |
| ||
Still not solved.. |
| ||
I think this is the last time I try this :D. The balls don't stick together too much any more and momentum is kida accounted for now. However somtimes the larger balls get effect a bit to much by the smaller ones. Also acounts for friction between the balls now: I mate of mine was vgood at physics at school (A* at a level) and hes also good at coding, I'll see if I can get him to help - He is extreamly lazy tho :D |
| ||
Thanks, I really appriciate your effort, however when the balls collide they sometimes switch direction and bounce away in a reversed direction. Also I don't think the momentum works. On the other hand, I think the solution is very easy. If someone knows how to apply momentum. Because without momentum the collisions are perfect. In the collide method, rem everything except the loop and this: If Reflection <> Null Then ApplyResponse( _otherBall.Velocity, Reflection, 0.2, 1.998 ) Endif Momentum and speed needs to be applied on both colliding objects. But not 50-50.. I don't know.. I mate of mine was vgood at physics at school (A* at a level) and hes also good at coding, I'll see if I can get him to help - He is extreamly lazy tho :D I will wish for the best :) |
| ||
Here is how to do this, afaik (haven't done it before, just looked it up online) You need to know the line between the balls centers, lets call it the Line of Sight (LOS) Each ball has a different velocity and mass, and so a different momentum. Ignore the x and y components and instead calculate the magnitude of the momentum vectors, and then resolve that relative to the line of sight - so that for each ball you have the momentum parallel to the LOS, and the momentum perpendicular to the LOS. Then do 1D collision involving the LOS. You then solve a system of equations, the conservation of LOS parallel momentum equation and a LOS parallel kinetic energy equation to find the LOS parallel new velocities. Perpendicular to the LOS, no change will have been made. This is hard to understand as I have written it, here is the page that I am using as a reference: http://www.mcasco.com/p1lmc.html |
| ||
Will! Fantastic! Just what I needed. I have written down the formulas and the theory, tomorrow I'll test if it works. What I'm going to do is project both objects velocities on the reflecting vector and then apply the change in velocity acording to the equation give on that page. Ignore the x and y components and instead calculate the magnitude of the momentum vectors That is a paradox, because the vector consists of x and y values, and if I ignore them I can't calculate the magnitude. Na, just kidding, I know what you mean.Thanks again! I think this solves it! |
| ||
Great! Post your code again when it works plz - BTW: is it ok to copy your code? |
| ||
It works, but something is still worng. I don't know what. At least this should be sufficient, but where does the extra energy come from, and elasticity doesn't work. Global Gravity:Vector2D = CreateVector( 0, 0.05 ) Type TBall Global list:TList = New TList Field Color Field Position:Vector2D Field Velocity:Vector2D = CreateVector() Field Circle:Circle2D Field LastCollide:TBall ' Method New() List.Addlast( Self ) color = Rand(1,5) EndMethod Function Create:TBall( Circle:Circle2D ) Local Ball:TBall = New TBall Ball.Circle = Circle Ball.Position = Circle.Position Return Ball EndFunction Method Draw() Circle.Draw() EndMethod Method SetBallColor() Select Color Case 1 SetColor 255,0,0 Case 2 SetColor 0,255,0 Case 3 SetColor 0,0,255 Case 4 SetColor 0,255,255 Case 5 SetColor 255,255,0 EndSelect EndMethod Function DrawAll() For Local Ball:TBall = EachIn List Ball.SetBallColor() Ball.Draw() Ball.Velocity.Add( Gravity ) Ball.Position.Add( Ball.Velocity ) If Ball.Position.Y > GraphicsHeight() And Ball.Velocity.Y > 0 Then Ball.Velocity.Y:*-1 If Ball.Position.X < 0 And Ball.Velocity.X < 0 Then Ball.Velocity.X:*-1 If Ball.Position.X > GraphicsWidth() And Ball.Velocity.X > 0 Then Ball.Velocity.X:*-1 Next EndFunction Function Collision() For Local BallA:TBall = EachIn List For Local BallB:TBall = EachIn List If BallA <> BallB Local Reflection:Vector2D = BallA.Circle.CollideCircleReflect( BallB.Circle ) 'If BallA and BallB does not collide Reflection = null 'If they do collide then Reflection is a vector From BallA to BallB 'The Length of Reflection is the amount BallA has passed into/over BallB If Reflection ' A Dynamic object against another Dynamic object DrawText "COLLISION DETECTED!!! ",150,150 'Get us out of collision (Hopefully) BallA.Position.Subtract( Reflection ) 'Add Elasticy 'ApplyResponse( BallA.Velocity, Reflection, 0.0, 0.5 )'Bounce or Slide 'ApplyResponse( BallB.Velocity, Reflection, 0.0, 0.5 )'Bounce or Slide ' With the setting 0,1 the above should do Nothin' ' Initial Velocity Local iVelocityA:Vector2D = CreateProjection( BallA.Velocity, Reflection ) Local iVelocityB:Vector2D = CreateProjection( BallB.Velocity, Reflection ) ' SetColor 255,255,255 ' DrawText "iVel Vector A ",20,50 ' iVelocityA.DrawModify( BallA.Position, 20 ,0) ' Flip ' WaitKey() ' SetColor 255,55,255 ' DrawText "iVel Vector B ",20,50 ' iVelocityB.DrawModify( BallB.Position, 20 ,0) ' Flip ' WaitKey() ' Make it a one dimentional problem, simpler N easier to solve Local InitialA! = iVelocityA.Magnitude() Local InitialB! = iVelocityB.Magnitude() ' Print "InitialA : "+InitialA ' Print "InitialB : "+InitialB Local MassA! = BallA.Circle.Radius*0.01 Local MassB! = BallB.Circle.Radius*0.01 If MassA = 0 And MassB = 0 Then Exit'Exit Current loop ' The Velocity we seek; the Velocity after the collision Local AfterVelocityA!,AfterVelocityB! ' This is carfully calculated math ' It is the momentum equation combined with the energy equations ' No Energy is lost. *cough* AfterVelocityA! = ( InitialA*(MassA - MassB)/(MassA + MassB) ) + ( InitialB*(2*MassB) / (MassA + MassB) ) AfterVelocityB! = ( InitialA*(2*MassA)/(MassA + MassB) ) + ( InitialB*( MassB - MassA ) / (MassB + MassA) ) ' Print "AfterVelocityA : "+AfterVelocityA 'Should be B's inital if both have same Mass ' Print "AfterVelocityB : "+AfterVelocityB 'Should be A's inital if both have same Mass ' Now we create the Vector which represents the change in Velocity Local VelChangeB:Vector2D = Vector2D.CreateField( AfterVelocityB, Reflection.Angle() ) Reflection.Reverse()' Now Reflection is Vector From B to A (Reversed) Local VelChangeA:Vector2D = Vector2D.CreateField( AfterVelocityA, Reflection.Angle() ) ' Print "ChangeVelocityA : "+VelChangeA.Length() ' Print "ChangeVelocityB : "+VelChangeB.Length() ' Add change in Velocity to Current Velocity BallA.Velocity.Add( VelChangeA ) BallB.Velocity.Add( VelChangeB ) EndIf EndIf Next Next EndFunction EndType Local A:TBall = TBall.Create( Circle2D.Create( 20 , 90, 100 ) ) Local B:TBall = TBall.Create( Circle2D.Create( 300, 70, 10 ) ) A.Velocity.Set( 2 , 0 ) B.Velocity.Set( 0 , 0 ) Graphics 640 , 480 , 0 While Not KeyDown(Key_Escape) DrawText "Use the Mouse, Left-Click to Create Balls",10,10 If MouseHit(1) TBall.Create( Circle2D.Create( MouseX(), MouseY(), Rand(2,20) ) ) TBall.DrawAll() TBall.Collision() Flip;Cls Wend'REST of THIS FILE IS VECTOR2D.bmx and CIRCLE2D.bmx Rem File: "Vector2D.bmx" 2D Vector Module The Vector Module which is a part of the Public MaxPhysics PROJECT VERSION HISTORY: ADDITIONS: Added Mirror Method! Added Reflection and Projection methods! Added some more function commands (these should be in a aseparate file..) Added a DrawPoint Function Added methods for converting and creating perpendicular vectors (normals) ' \__ Commands see: CreateLeftNormal() Added a method: Plus( value!) - increases a vectors leangth with a scalar FIXES: Fixed: CreateField, it was using ints and not doubles - choppy movement as result Fixed: Now using the real cartesian coordinate system Fixed: Replaced floats with doubles. TO DO: Add methods and functions from the PollyCode Vector Each method should have a equivalent function only 3-4 are done. EndRem ' / / / / / / / / / / / / / / / / ' T V E C T O R '------------------------------------------------------------------------ Type Vector2D Field X!,Y! '=============== ' BASIC COMMANDS '=============== ' C R E A T E V E C T O R '----------------------------------------------- Function Create:Vector2D( X!, Y! ) Local Vector:Vector2D Vector = New Vector2D Vector.X! = X! Vector.Y! = Y! Return Vector End Function ' C R E A T E V E C T O R F R O M '---------------------------------------------- Function CreateFrom:Vector2D( Position1:Vector2D , Position2:Vector2D ) Local Vector:Vector2D = Create(0,0) Vector.VectorFrom( Position1, Position2 ) Return Vector EndFunction ' C R E A T E /w D I E C T I O N '---------------------------------------------- ' I don't know any good name for this method Function CreateField:Vector2D( Length! , Direction! ) Local Vector:Vector2D = Create(1,0) Vector.SetLength( Length ) Vector.SetDirection( Direction ) Return Vector EndFunction ' C O P Y V E C T O R '---------------------------------------------- Method Copy:Vector2D()' Return Create( X , Y ) End Method ' S E T V E C T O R '---------------------------------------------- Method Set( newX! , newY! )' X! = newX! Y! = newY! End Method ' S E T D I R E C T I O N '---------------------------------------------- Method SetDirection( Angle! )' Local Length! = Length() X = Cos( Angle! )*Length Y = -Sin( Angle! )*Length End Method Method SetDir( Angle! ) SetDirection( Angle ) EndMethod ' S E T L E N G T H '---------------------------------------------- Method SetLength( Length! ) 'If we want to set vector to zero If Length = 0 Set(0,0);Return 'If the new length is negative assume we want to If Length < 0 Turn180() 'Reverse Local Angle! = Angle()'Of this Vector X = Cos(Angle) * Length Y = -Sin(Angle) * Length EndMethod Method SetMagnitude( Length! ) SetLength( Length ) EndMethod ' G E T L E N G T H '---------------------------------------------- Method Length!() Return Sqr( X*X + Y*Y )' EndMethod 'Alternative Names - Use whatever you like Method Magnitude!() Return Length() EndMethod Method GetLength!() Return Length() EndMethod Method GetMagnitude!() Return Length() EndMethod ' G E T L E N G T H S Q U A R E D '---------------------------------------------- Method LengthSquared() Return ( X*X + Y*Y )' EndMethod ' G E T D I R E C T I O N '---------------------------------------------- Method Direction!() Return ATan2(-y , x) End Method 'Also Alternative Names - Use whatever you like Method GetDirection!() Return Direction() EndMethod Method Dir!() Return Direction() EndMethod Method GetAngle!() Return Direction() EndMethod Method Angle!() Return Direction() EndMethod 'And alternative to get 0<= Angle <360 Method Dir360!() Local Angle! = Direction!() If Angle < 0 Then Angle:+360 Return Angle End Method ' G E T A N G L E B E T W E E N '---------------------------------------------- Method AngleBetween( Vector:Vector2D ) Local DT! = Self.Dot( Vector ) Local DB! = Length()*Vector.Length() If DB = 0 Return Return ACos( DT / DB ) EndMethod ' C R E A T E L E F T N O R M A L '---------------------------------------------- ' This is a a Perpendicular Vector! 'As if you would rotate it 90 degrees Method CreateLeftNormal:Vector2D( ) Return Create( Y, -X ) EndMethod ' C R E A T E R I G H T N O R M A L '---------------------------------------------- ' This is a a Perpendicular Vector! Method CreateRightNormal:Vector2D( ) Return Create( -Y, X ) EndMethod ' M A K E L E F T N O R M A L '---------------------------------------------- Method MakeLeftNormal( ) Return Set( Y, -X ) EndMethod ' M A K E R I G H T N O R M A L '---------------------------------------------- Method MakeRightNormal() Return Set( -Y, X ) EndMethod ' M A K E L E F T N O R M A L F R O M '---------------------------------------------- Method MakeLeftNormalFrom( Vector:Vector2D ) Return Set( Vector.Y, -Vector.X ) EndMethod ' M A K E R I G H T N O R M A L F R O M '---------------------------------------------- Method MakeRightNormalFrom( Vector:Vector2D ) Return Set( -Vector.Y, Vector.X ) EndMethod ' R E V E R S E V E C T O R '---------------------------------------------- Method Reverse() 'or Turn 180 Degrees X = -X Y = -Y End Method Method Turn180() Reverse() EndMethod ' V E C T O R F R O M '---------------------------------------------- Method VectorFrom( Position1:Vector2D , Position2:Vector2D) X = ( Position2.X - Position1.X ) Y = ( Position2.Y - Position1.Y ) 'Change the vector into a vector from Position1 to Position2 EndMethod '=============== ' MATH COMMANDS '=============== ' A D D '---------------------------------------------- Method Add( Vector:Vector2D ) X:+ Vector.X Y:+ Vector.Y EndMethod ' A D D C O P Y '---------------------------------------------- ' Add two Vectors and return the result as a ' third vector. Method AddCopy:Vector2D( Vector:Vector2D ) Local NewVector:Vector2D NewVector = Self.Copy() NewVector.Add( Vector ) Return NewVector EndMethod ' I N C R E A S E '---------------------------------------------- Method Increase( Value! )'Add a value to the vectors length Local Angle# = GetAngle() X:+ Cos( Angle ) * Value Y:- Sin( Angle ) * Value End Method Method Plus( Value! ) Increase( Value ) EndMethod ' P R O J E C T I O N '---------------------------------------------- ' ' Returns: Self vector projected on the Input Vector ' Method ProjectOn( Vector:Vector2D ) 'Self = A 'Vector = B Local DotAB! = Dot( Vector)'A*B Local DotBB! = Vector.Dot( Vector)'B*B X = ( DotAB / DotBB )*Vector.X 'Ab.x = ( A*B / B*B ) B.x Y = ( DotAB / DotBB )*Vector.Y 'Ab = A projected on B EndMethod Method ProjectionOf( VectorA:Vector2D, VectorB:Vector2D ) X = VectorA.X 'Copy Y = VectorA.Y Self.ProjectOn( VectorB ) EndMethod Function CreateProjection:Vector2D( VectorA:Vector2D, VectorB:Vector2D ) Local ProjectVector:Vector2D = VectorA.Copy() ProjectVector.ProjectOn( VectorB ) Return ProjectVector EndFunction ' R E F L E C T I O N - AGAINST SURFACE '---------------------------------------------------------- ' ' Mainly used for Velocity vectors that collide against surfaces ' Self = Incoming Vector to be reflected (or vector you want to reflect at surface) ' Surface = Surface normal ( any vector perpendicular to the surface ) ' ' This would be the same as reversing and then mirroring the vector in the ' surface normal! Method Reflect:Vector2D( SurfaceNormal:Vector2D ) Local Reflect:Vector2D = Create(0,0) SurfaceNormal.Normalize()'Make its length = 1 Reflect.Mirror( SurfaceNormal ) Return Reflect EndMethod ' M I R R O R 'Surface must be a unit vector! Method Mirror( Normal:Vector2D ) Local Dotprod# = -X * Normal.X - Y * Normal.Y X=X+2 * Normal.X * dotprod Y=Y+2 * Normal.Y * dotprod ' Self.Reverse() ' Local Angle! = AngleBetween( Surface ) ' Self.SetDirection( Angle*2 ) 'X = Surface.X* Surface.DOT( Self ) - X 'Y = Surface.Y* Surface.DOT( Self ) - Y EndMethod ' R O T A T E '---------------------------------------------- Method Rotate( Angle! ) Local CurrentAngle! = Direction() Local Length! = Length() X = Cos( CurrentAngle + Angle ) * Length Y = -Sin( CurrentAngle + Angle ) * Length EndMethod Method AddAngle( Angle! ) Rotate( Angle ) EndMethod ' S U B T R A C T '---------------------------------------------- Method Subtract( Vector:Vector2D ) X:- Vector.X Y:- Vector.Y 'This would also work 'Self.Add( Vector.Copy().Reverse() ) EndMethod ' D O T P R O D U C T '---------------------------------------------- Method DOT!( Vector:Vector2D ) Return ( X * Vector.X + Y * Vector.Y) EndMethod 'Alternative Name Method DotProduct!( Vector:Vector2D ) Return Self.DOT( Vector ) EndMethod ' M U L T I P L Y V E C T O R '---------------------------------------------- Method Multiply( Value! ) X:*Value Y:*Value EndMethod ' N O R M A L I Z E '---------------------------------------------- Method Normalize() Local Length! = Length() If Length = 0 Return'Don't divide by zero Set( (X / Length), ( Y / Length) ) 'Make length = 1 End Method ' U N I T V E C T O R '---------------------------------------------- Method Unit:Vector2D() Local Vector:Vector2D Vector = Self.Copy() Vector.Normalize() Return Vector'Returns a New vector with length = 1 End Method ' D I S T A N C E '---------------------------------------------- 'The Distance between the end points of two vectors Method DistanceTo!( Other:Vector2D ) Local dx! = Other.X - X Local dy! = Other.Y - Y Return Sqr( dx*dx + dy*dy ) EndMethod 'Calculates the perpendicular distance from a point to a line (or vector) 'If the vector returned is smaller than the radius of your round object (circle) 'then you have collided and if you then add this vector to your position you 'will move out of collision, then you are free to change velocity: (bounce or slide) Method ToLine:Vector2D( LineStart:Vector2D, LineEnd:Vector2D ) Return PointToLineVector( X, Y, LineStart.X, LineStart.Y, LineEnd.X, LineEnd.Y ) EndMethod Function PointToLineVector:Vector2D( px!, py!, x1!, y1!, x2!, y2! ) If x1 = x2 And y1 = y2 Then Return Vector2D.Create( x1-px, y1-py ) Local sx! = x2-x1 Local sy! = y2-y1 If sx = 0 And sy = 0 Then Return Local q! = ((px-x1) * (x2-x1) + (py - y1) * (y2-y1)) / (sx*sx + sy*sy) If q < 0.0 Then q = 0.0 If q > 1.0 Then q = 1.0 Local Xx! = (1-q)*x1 + q*x2 Local Xy! = (1-q)*y1 + q*y2 Return Vector2D.Create(Xx - Px, Xy - Py ) End Function '=============== ' DEBUG COMMANDS '=============== ' D R A W V E C T O R '-------------------------------------------------- Method DrawModify( From:Vector2D , Multiply! , Xtra ) 'DrawLine From.X + Xtra, From.Y, From.X + Xtra + X* Multiply , From.Y + Y* Multiply DrawArrow From.X + Xtra, From.Y, From.X + Xtra + X* Multiply , From.Y + Y* Multiply EndMethod Method DrawXY( FromX, FromY, Multiply! , Xtra ) DrawModify( Point(FromX, FromY) , Multiply! , Xtra ) End Method ' D R A W R E A L V E C T O R '-------------------------------------------------- Method Draw( Origin:Vector2D =Null ) If Origin = Null Origin = Create( 0, 0 ) DrawModify( Origin , 1 , 0 ) EndMethod ' D R A W V E C T O R D A T A '----------------------------------------------- Method DrawData( sLen, sDir, X, Y ) Local Row = 0 If sLen DrawText "Length : "+Length(),X,Y +Row*15; Row:+1 If sDir DrawText "Dir : " +Dir360(),X,Y +Row*15; Row:+1 End Method Function DrawArrow(x1%, y1%, x2%, y2%, _arrowHeadLength% = 10, _arrowHeadWidth% = 5) Local dx = x1 - x2 Local dy = y1 - y2 If Sqr( dX*dX + dY*dY ) = 0 Then Return DrawLine x1, y1, x2, y2 Local lineAngle% = ATan2( dx , dy ) lineAngle:+ 180 DrawLine x2, y2, (x2 + (Sin(lineAngle * -1) * _arrowHeadLength%)) + (Cos(lineAngle) * _arrowHeadWidth%), (y2 - (Cos(lineAngle * -1) * _arrowHeadLength%)) - (Sin(lineAngle) * _arrowHeadWidth%) DrawLine x2, y2, (x2 + (Sin(lineAngle * -1) * _arrowHeadLength%)) - (Cos(lineAngle) * _arrowHeadWidth%), (y2 - (Cos(lineAngle * -1) * _arrowHeadLength%)) + (Sin(lineAngle) * _arrowHeadWidth%) End Function EndType ' / / / / / / / / / / / / / / / / '------------------------------------------------------------------------ ' C R E A T E V E C T O R '----------------------------------------------- 'Purpose: Creates a New Vector 'Parameters: X = Vectors X value ' Same For Y 'Returns: New Vector Type '----------------------------------------------- Function CreateVector:Vector2D( X!=0, Y!=0 ) Return Vector2D.Create( X, Y ) EndFunction ' C O P Y V E C T O R '---------------------------------------------- 'Purpose: Copies a Vector into a New vector 'Parameters: VECTOR 'Returns: a VECTOR, exact copy of first VECTOR '----------------------------------------------- Function CopyVector:Vector2D( Vector:Vector2D ) Return Vector.Copy() EndFunction ' V E C T O R D I R E C T I O N '---------------------------------------------------- 'Purpose: Calculates the direction of a vector 'Parameters: VECTOR 'Returns: Degrees 'Note on Angel: 0 is Left, 90 is down (BlitzStyle) 'Note LastDir: If Length = 0 this Function returns LastDir '--------------------------------------------------------- Function VectorDirection!( Vector:Vector2D ) If Vector = Null Return Return Vector.Direction() EndFunction ' S E T V E C T O R '---------------------------------------------- Function SetVector( Vector:Vector2D, X!=0, Y!=0 ) If Vector = Null Return Vector.Set( X, Y ) EndFunction ' M A K E L E F T N O R M A L '---------------------------------------------- ' Creates Vector that is perpendicular to the first ' Fast way to rotate it 90 degrees. ' Function CreateLeftNormal:Vector2D( Vector:Vector2D ) Return Vector.CreateLeftNormal() EndFunction ' P R O J E C T I O N '---------------------------------------------- ' Project A-Vector on the B-Vector and return the ' resulting Vector Function CreateProjection:Vector2D( VectorA:Vector2D, VectorB:Vector2D ) Return Vector2D.CreateProjection( VectorA, VectorB ) EndFunction ' D O T P R O D U C T '--------------------------------------------------- 'Purpose: Calculated the Dot-Product of Two Vectors 'Parameters: Two vectors you want to "Dot" 'Returns: The result '--------------------------------------------------- Function Dot!(Vector:Vector2D,Vector2:Vector2D) If Vector = Null Return Return Vector.DOT( Vector2 ) End Function 'Alternative Naming (Both these works the same) Function DotProduct!(Vector:Vector2D,Vector2:Vector2D) If Vector = Null Return Return Vector.DOT( Vector2 ) End Function ' N O R M A L I Z E '---------------------------------------------- 'Purpose: Sets Vector length To ONE but keeps ' it's direction 'Parameters: VECTOR to normalize '----------------------------------------------- Function NormalizeVector( Vector:Vector2D ) If Vector = Null Return Vector.Normalize() EndFunction ' R O T A T E '---------------------------------------------- ' Rotates the Vector by this much. ' Possitive numbers for clockwise movement ' Negative for Anit-Clockwise =) ' 'Note: Don't confuse this command with SetVectorDirection() Function RotateVector( Vector:Vector2D, Angle! ) If Vector = Null Return Vector.Rotate( Angle! ) EndFunction ' U N I T V E C T O R '---------------------------------------------- 'Note: This is same as Normalizing a vector ' except that this function does not alter the ' original vector. Instead it return a new vector Function CreateUnitVector:Vector2D( Vector:Vector2D ) If Vector Return Vector.Unit() EndIf EndFunction ' D R A W V E C T O R '__________________________________________________ 'Purpose: Draws the vector from the specifed point 'Parameters: X,Y location '-------------------------------------------------- Function DrawVector( Vector:Vector2D, From:Vector2D , Multiply!=1 , Xtra=0 ) Vector.DrawModify( From , Multiply! , Xtra ) EndFunction ' D R A W V E C T O R D A T A '----------------------------------------------- 'Purpose: Prints the data of a vector 'Parameters: sLen=ShowLength, SDir=ShowDirection ' X and Y = Where to start draw the data (text) '----------------------------------------------- Function DrawVectorData( Vector:Vector2D, X=10, Y=20, sLen=True, sDir=False ) Vector.DrawData( sLen, sDir, X, Y ) EndFunction Function DrawVectorInfo( Vector:Vector2D, X=10, Y=20, sLen=True, sDir=False) Vector.DrawData( sLen, sDir, X, Y ) EndFunction Rem If you ever need a function to check something of a point you can use the vector to check against (position vector for example) Ex drawline( Point(50,100), ShipPosition:Vector ) EndRem Function Point:Vector2D( X! , Y! ) Local Vector:Vector2D= New Vector2D Vector.X = X Vector.Y = Y Return Vector EndFunction Function DrawPoint( Point:Vector2D, Radius) DrawOval Point.X-Radius, Point.Y-Radius, Radius*2, Radius*2' Center Point! EndFunction Function DrawLineToPointFromOrigin( Start:Vector2D, Origin:Vector2D ) DrawLine Start.X, Start.Y, Start.X + Origin.X , Start.Y + Origin.Y EndFunction 'Import "vector2D.bmx" Type Shape2D Abstract Field Position:Vector2D = Point(0,0)'Center position! Method ShapesOverlap( Shape:Shape2D ) EndMethod Method ShapesCollide:Vector2D( Shape:Shape2D ) 'A Shape Collides Against another Shape EndMethod EndType Type Circle2D Extends Shape2D Field Radius! = 1 Function Create:Circle2D( X, Y, Radius! ) Local Circle:Circle2D = New Circle2D Circle.Position.Set(X,Y) Circle.Radius = Radius Return Circle End Function 'Circle vs another Shape 'Returns the projected vector required to push us out of collision Method ShapesCollide:Vector2D( Shape:Shape2D ) Select Shape Case Circle2D( Shape ) Return CollideCircleReflect( Circle2D( Shape) ) 'Case Line2D( Shape ) ' Return CollideLineReflect( Line2D( Shape ) ) 'Case Polygon2D( Shape ) ' Return CollidePolygonReflect( Polygon2D( Shape ) ) EndSelect EndMethod 'Circle vs another Shape Method ShapesOverlap( Shape:Shape2D ) Select Shape Case Circle2D( Shape ) Return CollideCircle( Circle2D( Shape) ) 'Case Line2D( Shape ) ' Return CollideLine( Line2D( Shape ) ) 'Case Polygon2D( Shape ) ' Return CollidePolygon( Polygon2D( Shape ) ) EndSelect EndMethod 'Just check collision - Quick version Method CollideCircle( Circle:Circle2D) Local Distance! = Distance( Position, Circle.Position ) Local Amount! = ( Radius + Circle.Radius ) - Distance If Amount > 0 Then Return Amount Else Return False EndMethod Method GetAngleToCircle!( Circle:Circle2D ) Local Reflect:Vector2D = Vector2D.CreateFrom( Position, Circle.Position ) Return Reflect.Dir360() 'Or Angle() - depends on the form you want EndMethod '------------------------------------------------------------------------ 'Check for collisions, if collision detecte it return a reflection vector 'The reflection vector has the same length and direction required to push 'the circle out-of collision with the other circle '------------------------------------------------------------------------ Method CollideCircleReflect:Vector2D( Circle:Circle2D ) Local Magnitude! = CollideCircle( Circle ) If Magnitude = False Then Return Null Local ReflectAngle = GetAngleToCircle!( Circle ) Return Vector2D.CreateField( Magnitude!, ReflectAngle ) EndMethod Rem UNDER CONTRUCTION Method CollideLineReflect:Vector2D( Circle:Circle2D ) Local FromPointToLine:Vector2D = See solution in File: "CircleTesting5.bmx" VectorToLine.Reverse() Local Dist = VectorToLine.Length() VectorToLine.Normalize() VectorToLine.Multiply( Ball.Radius - Dist ) Ball.Position.Add( VectorToLine ) EndRem Method Draw() DrawOval Position.X - Radius, Position.Y - Radius, Radius*2, Radius*2 EndMethod EndType Function Distance!( Position1:Vector2D, Position2:Vector2D ) Local DX! = Position2.X - Position1.X Local DY! = Position2.Y - Position1.Y Return Sqr(DX*DX + DY*DY) EndFunction Rem Local CircleA:Circle2D = Circle2D.Create(100 , 100 , 100) Local CircleB:Circle2D = Circle2D.Create(320 , 240 , 50) Local CircleB_Mobile = False 'Can we move B? Graphics 640 , 480 , 0 While Not KeyDown(Key_Escape) DrawText "Move around, Press SPACE to make the RED circle MOBILE.",10,10 SetColor 0 , 200 , 0 'Green CircleA.Draw SetColor 200 , 0 , 0' Red CircleB.Draw If KeyHit( Key_Space ) If CircleB_Mobile = True Then CircleB_Mobile = False Else CircleB_Mobile = True EndIf SetColor 0 , 0 , 255' Blue 'Local OverlapDist = CircleA.CollideCircle( CircleB ) 'Local OverlapAng = CircleA.GetAngleToCircle( CircleB ) 'If OverlapDist 'DrawText "COLLIDING! by : "+OverlapDist+", Angle: "+OverlapAng ,50,50 Local Reflection:Vector2D = CircleA.CollideCircleReflect( CircleB ) If Reflection Reflection.Draw( CircleA.Position ) If CircleB_Mobile = True CircleB.Position.Add( Reflection ) EndIf ApplyResponse( BallVelocity, SurfaceNormal, 0.00, 0.2 ) 'EndIf CircleA.Position.Set( MouseX(), MouseY() ) Flip;Cls Wend EndRem Rem Friction! from 0 to 1 ; 1 = Total Friction (get stuck), 0 = No Friction Elasticy! from 0 to 1 ; 1 = Perfect Bounce, 0 = No Bounce USE: If CollideSurface( SurfaceNormal,....) ApplyResponse( Tank.Velocity, SurfaceNormal, 0, 0.5 ) Endif EndRem Function ApplyResponse( Velocity:Vector2D Var, SurfaceNormal:Vector2D, Friction!, Elasticity! ) SurfaceNormal.Normalize() Velocity.Mirror( SurfaceNormal ) If Elasticity < 0 Then Elasticity = 0'Slide If Elasticity > 1 Then Elasticity = 1'Perfect Bounce Local Bounce:Vector2D = CreateVector(0,0) Bounce.ProjectionOf( Velocity, SurfaceNormal ) Bounce.Multiply( Elasticity ) ' Apply Elasticy, to the perpendicular part of velocity If Friction < 0 Then Friction = 0 If Friction > 1 Then Friction = 1 Friction = 1 - Friction'' Case 1, now: 0, Case 0, now: 1 Local Slide:Vector2D = CreateVector() SurfaceNormal.MakeLeftNormal()'Convert the normal to the surface! Slide.ProjectionOf( Velocity, SurfaceNormal )' Project to surface Slide.Multiply( Friction ) ' Apply Friction, to the parallel part of velocity Velocity.Set(0,0) Velocity.Add( Slide ) Velocity.Add( Bounce ) 'FOR DEBUGGING ONLY ' SetColor 0,0,255'GREEN ' Slide.Draw ( Ball.Position ) ' SetColor 255,255,0'YELLOW ' Bounce.Draw ( Ball.Position ) EndFunction The code is open source, see the MaxPhysics Community Project Page. You can take it and do whatever you want with it, though I would appriciate, if you manage to improve this, that you share your advancements :) |