@@ -20,34 +20,31 @@ clsCannonball::clsCannonball() {
2020 blndragenabled_ = false ;
2121 blnstarted_ = false ;
2222 blncheckphysics_ = true ;
23- deltat_ = (1.00 / 60.00 ) ;
24- acc_.x = 0.00 ;
25- acc_.y = global::physics::kGravity ;
23+ deltat_ = (1.00 / 60.00 );
24+ forces_ = {0 ,0 };
25+ acc_ = {0.00 , global::physics::kGravity };
26+ spin_ = 1.0 ;
2627
2728 props_.radius = 5.0 ; // in meters
2829 props_.density = global::physics::kBallDensity ; // density of steel in kg/m^3
2930
30- place_.x = 0 ;
31- place_.y = 0 ;
31+ place_ = {0 ,0 };
3232 dblLOC_.x = (double ) place_.x ;
3333 dblLOC_.y = (double ) place_.y ;
3434
35- vel_.x = 0 ;
36- vel_.y = 0 ;
35+ vel_ = {0 ,0 };
3736
3837 srand (time (NULL ));
3938
40- color_.Red = rand () % 255 ;
41- color_.Green = rand () % 255 ;
42- color_.Blue = rand () % 255 ;
39+ color_ = {(Uint8)rand () % 255 ,(Uint8)rand () % 255 ,(Uint8)rand () % 255 };
4340
4441 if (global::config.values .blnDrawPathOnScreen ) {
4542 // Reserve element spots equal to the number of max
4643 // locations we are going to keep track of
4744 path_.reserve (global::config.values .uintMaxNumPastPoints );
4845
4946 // fill the new vector with "empty" values
50- for (uchar i = 0 ; i < global::config.values .uintMaxNumPastPoints ; ++i) {
47+ for (int i = 0 ; i < global::config.values .uintMaxNumPastPoints ; ++i) {
5148 path_.push_back ({0 ,0 });
5249 } // end for max past points
5350 if (global::blnDebugMode) { printf (" Path values initialized.\n " ); }
@@ -91,37 +88,41 @@ void clsCannonball::dragUpdateAcc(void) {
9188 // /
9289 // ///////////////////////////////////////////////
9390
94- acc_.x = 0.0 ;
95- acc_.y = global::physics::kGravity ;
9691 if (vel_.x != 0.0 && vel_.y != 0.0 && props_.mass != 0.0 ) {
9792 double flow_velocity = sqrt (pow (vel_.x ,2 ) + pow (vel_.y ,2 ));
98- double drag_force = (double ) (0.5 * global::physics::kDensityAir *
99- flow_velocity * global::physics::kDragCofficient
100- * props_.area );
101- double drag_acc = (double ) (drag_force / props_.mass );
93+ double Re = (global::physics::kDensityAir * props_.radius * 2 * flow_velocity);
94+ Re /= global::physics::kAirDynViscosity ;
95+ double drag_force;
96+
97+ if (Re < 1 ) {
98+ // use Stokes' Law for drag
99+ drag_force = 6.0 * M_PI * global::physics::kAirDynViscosity *
100+ props_.radius * flow_velocity;
101+ } else {
102+ // use newton drag
103+
104+ drag_force = (double ) (0.5 * global::physics::kDensityAir *
105+ pow (flow_velocity,2 ) * global::physics::kDragCofficient
106+ * props_.area );
107+ } // end if re < 1
108+
109+ // convert force to acceleration
102110 double angle;
103111
104- angle = (vel_.x != 0.0 ) ? atan (vel_.y / vel_.x ) : M_PI / 2.0 ;
112+ angle = (vel_.x != 0.0 ) ? atan (vel_.y / vel_.x ) : M_PI / 2 ;
105113 angle += vel_.x < 0.0 ? M_PI : 0.0 ;
106114
107- acc_.x += drag_acc * cos (angle);
108- acc_.y += drag_acc * sin (angle);
109- // Please recall fGravity is negative
110- double friction = (double )global::physics::kKineticFriction *
111- (double )global::physics::kGravity * props_.mass ;
112- updateCollisionBox ();
113- // Update acc for Friction values
114- if ( collisionbox_.bottom < screen_place_.h ||
115- collisionbox_.top > screen::screenatt.height ) {
116- // Ball is in contact with floor or ceiling update x acc
117- acc_.x += friction * (vel_.x < 0.0 ? -1.0 : 1.0 );
118- }
119-
120- if ( collisionbox_.left < (screen_place_.w /2 ) ||
121- collisionbox_.right > screen::screenatt.width ) {
122- // Ball is in contact with the wall update y acc.
123- acc_.y += friction * (vel_.y < 0.0 ? -1.0 : 1.0 );
124- }
115+ // update force values
116+ forces_.x -= drag_force * cos (angle);
117+ forces_.y -= drag_force * sin (angle);
118+
119+
120+ // Calculate Buoyancy
121+ double force_buoyancy;
122+ force_buoyancy = global::physics::kDensityAir * props_.volume *
123+ -1 * global::physics::kGravity ;
124+
125+ forces_.y += force_buoyancy;
125126 } // end if things equal 0
126127}
127128/* ****************************************************************************/
@@ -143,38 +144,52 @@ void clsCannonball::update(double newdeltat) {
143144 blncheckphysics_ = true ; // enable on update
144145 deltat_ = newdeltat;
145146
146- if (blndragenabled_) { dragUpdateAcc (); }
147+ // reset the forces so strange things don't happen
148+ forces_ = {0.0 , props_.mass * global::physics::kGravity };
149+
150+ if (blndragenabled_) {
151+ doMagnusEffect ();
152+ dragUpdateAcc ();
153+ }
154+ doFriction ();
155+
156+ acc_.x = forces_.x / props_.mass ;
157+ acc_.y = forces_.y / props_.mass ;
147158
148159 vel_.x = (vel_.x + acc_.x * deltat_);
149160 vel_.y = (vel_.y + acc_.y * deltat_);
150161
151162 // get new velocities if collision with edges
163+
164+ double coefres = (global::config.values .uchrCollisionMethod == CollideInelastic) ?
165+ global::physics::kCoefficientRestitution : 1.0 ;
166+
167+
152168 /* TODO (GamerMan7799#2#): Make this stuff simpler */
153169 if (collisionbox_.left < screen_place_.w / 2 ) {
154- vel_.x *= -1 * global::physics:: kCoefficientRestitution ;
155- vel_.y *= global::physics:: kCoefficientRestitution ;
156- dblLOC_.x ++ ;
170+ vel_.x *= -1 * coefres ;
171+ vel_.y *= coefres ;
172+ dblLOC_.x = screen_place_. w ;
157173 }
158174
159175 if (collisionbox_.right > (screen::screenatt.width )) {
160- vel_.x *= -1 * global::physics:: kCoefficientRestitution ;
161- vel_.y *= global::physics:: kCoefficientRestitution ;
162- dblLOC_.x -- ;
176+ vel_.x *= -1 * coefres ;
177+ vel_.y *= coefres ;
178+ dblLOC_.x = screen::screenatt. width - screen_place_. w / 2 ;
163179 }
164180
165181 if (collisionbox_.bottom > (screen::screenatt.height )) {
166- vel_.x *= global::physics:: kCoefficientRestitution ;
167- vel_.y *= -1 * global::physics:: kCoefficientRestitution ;
168- dblLOC_.y ++ ;
182+ vel_.x *= coefres ;
183+ vel_.y *= -1 * coefres ;
184+ dblLOC_.y = screen_place_. h / 2 ;
169185 }
170186
171187 if (collisionbox_.top < 0 ) {
172- vel_.x *= global::physics:: kCoefficientRestitution ;
173- vel_.y *= -1 * global::physics:: kCoefficientRestitution ;
174- dblLOC_.y -- ;
188+ vel_.x *= coefres ;
189+ vel_.y *= -1 * coefres ;
190+ dblLOC_.y = (screen::screenatt. height ) - screen_place_. h / 2 ;
175191 }
176192
177-
178193 dblLOC_.x = dblLOC_.x + vel_.x * deltat_ /* + 0.5 * acc_.x * pow(deltat_,2)*/ ;
179194 dblLOC_.y = dblLOC_.y + vel_.y * deltat_ /* + 0.5 * acc_.y * pow(deltat_,2)*/ ;
180195
@@ -262,6 +277,9 @@ void clsCannonball::setValues(double r, LOC init_place,
262277
263278 acc_ = {0.00 , global::physics::kGravity };
264279
280+ spin_ = (rand () % 1000 - 500 ) / 500 ;
281+
282+
265283 place_ = init_place;
266284 dblLOC_ = { (double ) place_.x ,
267285 (double ) place_.y };
@@ -271,6 +289,8 @@ void clsCannonball::setValues(double r, LOC init_place,
271289 blnstarted_ = true ;
272290
273291 dragCalcValues ();
292+
293+ forces_ = {0.00 , global::physics::kGravity * props_.mass };
274294 blndragenabled_ = global::config.values .blnDragMode ;
275295}
276296/* ****************************************************************************/
@@ -350,7 +370,7 @@ void clsCannonball::drawPath(LOC newplace) {
350370 // Now draw the path
351371 SDL_Rect dst;
352372 dst.w = dst.h = 1 ;
353- for (uint i = 0 ; i < global::config. values . uintMaxNumPastPoints ; ++i) {
373+ for (uint i = 0 ; i < path_. size () ; ++i) {
354374 dst.y = screen::screenatt.height - (path_[i].y );
355375 dst.x = (path_[i].x );
356376 SDL_RenderCopy (screen::screenatt.ren , screen::screenatt.pixel , NULL , &dst);
@@ -370,4 +390,57 @@ void clsCannonball::updateCollisionBox() {
370390 collisionbox_.right = collisionbox_.left + screen_place_.w ;
371391}
372392/* ****************************************************************************/
393+ void clsCannonball::doFriction () {
394+ // ///////////////////////////////////////////////
395+ // / @brief Updates values based on friction
396+ // ///////////////////////////////////////////////
397+
398+ // normal force is mass * gravity - buoyancy (if drag is enabled)
399+ double normal_force = (-1 ) * props_.mass * global::physics::kGravity ;
400+ double buoyancy = (-1 ) * global::physics::kDensityAir *
401+ global::physics::kGravity *
402+ props_.volume ;
403+ if (blndragenabled_) { normal_force -= buoyancy; }
404+
405+ double friction = (double )global::physics::kKineticFriction *
406+ normal_force;
407+ updateCollisionBox ();
408+ // Update acc for Friction values
409+ if ( collisionbox_.bottom < screen_place_.h ||
410+ collisionbox_.top > screen::screenatt.height ) {
411+ // Ball is in contact with floor or ceiling update x acc
412+ forces_.x += friction * (vel_.x < 0.0 ? -1.0 : 1.0 );
413+ } // end if touching top/bottom
414+
415+
416+ // Since there really isn't a normal force when the ball contacts
417+ // the edges, this section is commented out.
418+ /*
419+ if ( collisionbox_.left < (screen_place_.w /2 ) ||
420+ collisionbox_.right > screen::screenatt.width ) {
421+ // Ball is in contact with the wall update y acc.
422+ forces_.y += friction * (vel_.y < 0.0 ? -1.0 : 1.0);
423+ // add normal force
424+ forces_.x += normal_force * (collisionbox_.right > screen::screenatt.width) ?
425+ 1.0 : -1.0;
426+ } // end if touching side edges */
427+ }
428+ /* ****************************************************************************/
429+ void clsCannonball::doMagnusEffect () {
430+ // ///////////////////////////////////////////////
431+ // / @brief Calculates the Magnus Effect caused by the ball's spin
432+ // ///////////////////////////////////////////////
433+
434+ double magnus_force = pow (M_PI,2 ) * pow (props_.radius ,3 ) *
435+ global::physics::kDensityAir ;
373436
437+ forces_.x -= magnus_force * vel_.y * spin_;
438+ forces_.y += magnus_force * vel_.x * spin_;
439+ }
440+ /* ****************************************************************************/
441+ void clsCannonball::addForce (dblXY newforces) {
442+
443+ forces_.x += newforces.x ;
444+ forces_.y += newforces.y ;
445+ }
446+ /* ****************************************************************************/
0 commit comments