@@ -24,6 +24,13 @@ bool checkCollide(BOX, BOX);
2424void doCollision (uint, uint);
2525BOX boxMaker (LOC);
2626/* *********************************************************************************************************************************************************************/
27+ enum Collisions { // The method of the collision (I just wanted to play around with some options.
28+ CollideElastic = 0 , // This is the normal way things collide, they hit and bounce off, no energy is lost
29+ CollideInelastic, // balls collide and bounce off of each other losing some energy.
30+ CollidePerfectInelastic, // In this method the balls collide and then stick together
31+ CollideNone // No collisions
32+ };
33+ /* *********************************************************************************************************************************************************************/
2734namespace Global {
2835#ifdef DEFINED_BUILD_MODE_PRIVATE
2936 const bool blnDebugMode = true ;
@@ -38,14 +45,13 @@ namespace Global {
3845 const float fDensityAir = 1.2754 ; // Density of air
3946 const float fRecoil = -0.56 ;
4047 const float fVelocityScalar = 1 ; // Changing this effects the fire velocity
41- const float fMinVelocity = 0.005 ; // If a ball has less velocity than the it will "die"
42- const float fMomentumLoss = 1 ; // How much total momentum stays after a collisions
48+ const float fMinVelocity = 0.5 ; // If a ball has less velocity than the it will "die"
49+ const float fMomentumLoss = 0.76 ; // How much total momentum stays after a collisions
50+ const uchar CollisionMethod = CollideElastic;
4351 }
4452}
4553/* *********************************************************************************************************************************************************************/
46- /* TODO (GamerMan7799#1#): Figure out how to detect the edges of the images */
47- /* TODO (GamerMan7799#1#): Get Highest height and Distance from fire at end of run. */
48- /* *********************************************************************************************************************************************************************/
54+ // This is the maximum number of cannonballs which can be "alive" at a time
4955#define DEFINED_CANNONBALL_LIMIT 10
5056/* *********************************************************************************************************************************************************************/
5157clsCannonball Cannonballs[DEFINED_CANNONBALL_LIMIT];
@@ -69,7 +75,8 @@ int main(int argc, char *argv[]) {
6975 LOC OldMouse, CurrentMouse;
7076 SDL_Event event;
7177 do {
72- CannonWindow.clearscreen ();
78+ CannonWindow.clearscreen (); // Clear the screen so new stuff can be drawn
79+
7380 // poll events
7481 if (SDL_PollEvent ( &event ) != 0 ) {
7582 if ( event.type == SDL_QUIT ) {quit = true ;}
@@ -91,13 +98,16 @@ int main(int argc, char *argv[]) {
9198 if (holding) {CannonWindow.drawline (CurrentMouse, OldMouse);}
9299 // Update every ball
93100 tempdeltat = Tick.getTimeDifference ();
94- for (uint i = 0 ; i < DEFINED_CANNONBALL_LIMIT; i++) {
95- if (Cannonballs[i].blnstarted ) {
101+
102+ for (uint i = 0 ; i < DEFINED_CANNONBALL_LIMIT; i++) { // Loop through each cannonball
103+ if (Cannonballs[i].blnstarted ) { // only update cannonball if it is "alive"
96104 Cannonballs[i].update (tempdeltat);
97- checkForCollisons (i);
105+ // Check for collisions if no collide is not on
106+ if (Global::Physics::CollisionMethod != CollideNone) {checkForCollisons (i);}
98107 } // end if started
99108 } // end for loop
100- CannonWindow.update ();
109+
110+ CannonWindow.update (); // Update the screen
101111 } while (!quit);
102112 return 0 ;
103113}
@@ -107,20 +117,23 @@ void addNewCannonball(LOC mouseC, LOC mouseO ) {
107117 double fire_v;
108118 double angle;
109119
120+ // Because y increasing is going down according to SDL we first negative the velocity
110121 fire_v = -1 * sqrt ( pow (mouseC.x - mouseO.x , 2 ) + pow (mouseC.y - mouseO.y , 2 ) );
111122 fire_v /= (double ) Global::Physics::fVelocityScalar ;
112123
124+ // if the mouse if pointing straight up or straight down make the angle 90
125+ // Other calculate the angle with atan.
113126 if (mouseC.x == mouseO.x ) {
114127 if (mouseC.y > mouseO.y ) {angle = -90.0 ;}
115128 else if (mouseC.y < mouseO.y ) {angle = 90.0 ;}
116129 else {angle = 0 ;}
117130 } else {
118131 angle = (double )-1.0 * atan ( (mouseC.y - mouseO.y ) / (mouseC.x - mouseO.x ) );
119- angle * = (double )( 180 / 3.1415926535 );
120- if (mouseC. x < mouseO. x ) { angle *= (double )- 1.0 ;}
132+ if (mouseC. x < mouseO. x ) { angle + = (double )PI;}
133+ angle *= (double )( 180 /PI);
121134 } // end if x = x
122135
123- // mod mouse start
136+ // mod mouse start, once again because the top left is 0,0 to SDL
124137 mouseO.y = tempwin.height - mouseO.y ;
125138
126139 // loop through array to find next available cannonball slot
@@ -159,32 +172,110 @@ bool checkCollide(BOX A, BOX B) { //checks if two objects (made with the BOXES c
159172/* *********************************************************************************************************************************************************************/
160173void doCollision (uint numA, uint numB) {
161174 dblXY Avel, Bvel, NewVel;
162- double Amass, Bmass;
175+ PP Aprops, Bprops;
176+
163177 Avel = Cannonballs[numA].getVelocity ();
164178 Bvel = Cannonballs[numB].getVelocity ();
165- Amass = Cannonballs[numA].getmass ();
166- Bmass = Cannonballs[numB].getmass ();
179+ Aprops = Cannonballs[numA].getPhysicalProps ();
180+ Bprops = Cannonballs[numB].getPhysicalProps ();
181+
182+ double Aangle, Bangle, ContactAngle;
183+ double Atotal_v, Btotal_v;
167184
168- double totalMomX = Amass * Avel.x - Bmass * Bvel.x ;
169- double totalMomY = Amass * Avel.y - Bmass * Bvel.y ;
170- totalMomX *= (double )Global::Physics::fMomentumLoss ;
171- totalMomY *= (double )Global::Physics::fMomentumLoss ;
185+ dblXY TotalAMomentum, TotalBMomentum;
172186
173- // I know that this is not a true Momentum equation
174- // I'm just trying to get something up to test things out.
175- NewVel.x = totalMomX / (Amass + Bmass);
176- NewVel.y = totalMomY / (Amass + Bmass);
187+ if ( Global::Physics::CollisionMethod != CollidePerfectInelastic ) {
188+ // The equations for Perfect Inelastic is much simpler than if not
189+ // so I am handling those a bit differently to speed up that method.
190+
191+ // Equations used can be found and explained here: https://en.wikipedia.org/wiki/Elastic_collision
192+ Atotal_v = sqrt ( pow (Avel.x ,2 ) + pow (Avel.y ,2 ) );
193+ Btotal_v = sqrt ( pow (Bvel.x ,2 ) + pow (Bvel.y ,2 ) );
194+
195+ // get the angle for both A and B
196+ if (Avel.x != 0.0 ) {Aangle = atan (Avel.y /Avel.x );}
197+ else {
198+ if (Avel.y > 0.0 ) {Aangle = PI / 2.0 ;}
199+ else if (Avel.y < 0.0 ) {Aangle = - PI / 2.0 ;}
200+ else {Aangle = 0.0 ;}
201+ }
202+
203+ if (Bvel.x != 0.0 ) {Bangle = atan (Bvel.y /Bvel.x );}
204+ else {
205+ if (Bvel.y > 0.0 ) {Bangle = PI / 2.0 ;}
206+ else if (Bvel.y < 0.0 ) {Bangle = - PI / 2.0 ;}
207+ else {Bangle = 0.0 ;}
208+ }
209+
210+ // Adjust the angle to be the right one.
211+ // Since atan will only yield a number between -PI/2 and PI/2 we
212+ // have to adjust it if xvel is negative.
213+ if (Avel.x < 0.0 ) {Aangle += PI;}
214+ if (Bvel.x < 0.0 ) {Bangle += PI;}
215+ ContactAngle = Aangle + Bangle;
216+
217+ TotalAMomentum.x = Atotal_v * cos (Aangle - ContactAngle) * (Aprops.mass - Bprops.mass );
218+ TotalAMomentum.x += 2.0 * Bprops.mass * Btotal_v * cos (Bangle - ContactAngle);
219+ TotalAMomentum.x /= (Aprops.mass + Bprops.mass );
220+ // x and y formulas are the same until this point
221+ TotalAMomentum.y = TotalAMomentum.x ;
222+ TotalAMomentum.x *= cos (ContactAngle);
223+ TotalAMomentum.y *= sin (ContactAngle);
224+ TotalAMomentum.x += Atotal_v * sin (Aangle - ContactAngle) * cos (ContactAngle + (PI/2.0 ) );
225+ TotalAMomentum.y += Atotal_v * cos (Aangle - ContactAngle) * cos (ContactAngle + (PI/2.0 ) );
226+
227+ // Now do B
228+ TotalBMomentum.x = Btotal_v * cos (Bangle - ContactAngle) * (Bprops.mass - Aprops.mass );
229+ TotalBMomentum.x += 2.0 * Aprops.mass * Atotal_v * cos (Aangle - ContactAngle);
230+ TotalBMomentum.x /= (Aprops.mass + Bprops.mass );
231+ // x and y formulas are the same until this point
232+ TotalBMomentum.y = TotalBMomentum.x ;
233+ TotalBMomentum.x *= cos (ContactAngle);
234+ TotalBMomentum.y *= sin (ContactAngle);
235+ TotalBMomentum.x += Btotal_v * sin (Bangle - ContactAngle) * cos (ContactAngle + (PI/2.0 ) );
236+ TotalBMomentum.y += Btotal_v * cos (Bangle - ContactAngle) * cos (ContactAngle + (PI/2.0 ) );
237+ } else {
238+ TotalAMomentum.x = Aprops.mass * Avel.x + Bprops.mass * Bvel.x ;
239+ TotalAMomentum.y = Aprops.mass * Avel.y + Bprops.mass * Bvel.y ;
240+ } // end if Perfect Inelastic or not
177241
178- Cannonballs[numA].setVelocity (NewVel);
179- NewVel.y *= -1 ;
180- NewVel.x *= -1 ;
181- Cannonballs[numB].setVelocity (NewVel);
242+ switch (Global::Physics::CollisionMethod) { // figure out what to do based on the collision method
243+ case CollidePerfectInelastic:
244+ // The balls collide and stick together
245+ // Get the new mass.
246+ Aprops.mass += Bprops.mass ;
247+ // Now we have to calculate the new radius, volume, and area so that drag will reflect the new size
248+ // we are of course assuming that density stays the same.
249+ Aprops.volume = (Aprops.mass / (double )Global::Physics::uBallDensity);
250+ // cbrt = cube root
251+ Aprops.radius = cbrt ( (double ) (3.0 *Aprops.volume ) / (double ) (4.0 *PI) );
252+ Aprops.area = (double ) (2.0 * PI * pow (Aprops.radius , 2 ) );
253+ // Now calculate the new velocity
254+ Avel.x = TotalAMomentum.x / Aprops.mass ;
255+ Avel.y = TotalAMomentum.y / Aprops.mass ;
256+ // now "kill" cannonball B and update ball A
257+ Cannonballs[numB].blnstarted = false ;
258+ Cannonballs[numA].setPhysicalProps (Aprops);
259+ Cannonballs[numA].setVelocity (Avel);
260+ break ;
261+ case CollideInelastic:
262+ // uses the same equations as below but some energy is lost.
263+ TotalAMomentum.x *= (double )Global::Physics::fMomentumLoss ;
264+ TotalAMomentum.y *= (double )Global::Physics::fMomentumLoss ;
265+ TotalBMomentum.x *= (double )Global::Physics::fMomentumLoss ;
266+ TotalBMomentum.y *= (double )Global::Physics::fMomentumLoss ;
182267
268+ case CollideElastic:
269+ // The balls collide and bounce away from each other
183270
184- /* LOC Aplace = Cannonballs[numA].getplace();
185- Aplace.x ++;
186- Aplace.y --;
187- Cannonballs[numA].setplace(Aplace);*/
271+ // All of the heavy lifting is handled above.
272+ Cannonballs[numA].setVelocity (TotalAMomentum);
273+ Cannonballs[numB].setVelocity (TotalBMomentum);
274+ break ;
275+ default : // the catch all and CollideNone
276+ // Nothing Happens!
277+ break ;
278+ } // end switch collide method
188279}
189280/* *********************************************************************************************************************************************************************/
190281BOX boxMaker (LOC place) {
0 commit comments