00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "../object/physics.h"
00028 #include <stdlib.h>
00029 #include <iostream>
00030 #include "../game/config.h"
00031 #include "../game/game_mode.h"
00032 #include "../game/time.h"
00033 #include "../tool/debug.h"
00034 #include "../tool/math_tools.h"
00035 #include "../map/wind.h"
00036
00037
00038 const double STOP_REBOUND_LIMIT = 0.5 ;
00039 const double AIR_RESISTANCE_FACTOR = 40.0 ;
00040 const double PHYS_DELTA_T = 0.02 ;
00041 const double PENDULUM_REBOUND_FACTOR = 0.8 ;
00042
00043 Physics::Physics ()
00044 {
00045 m_extern_force.Clear();
00046 m_pos_x.Clear();
00047 m_pos_y.Clear();
00048
00049 m_fix_point_gnd.Clear();
00050 m_fix_point_dxy.Clear();
00051 m_rope_angle.Clear();
00052 m_rope_length.Clear();
00053
00054 m_rope_elasticity = 10.0 ;
00055 m_elasticity_damping = 0.20 ;
00056 m_balancing_damping = 0.40 ;
00057
00058 m_motion_type = NoMotion ;
00059 m_elasticity_off = true;
00060
00061 m_last_move = Time::GetInstance()->Read() ;
00062 }
00063
00064 void Physics::ResetConstants()
00065 {
00066
00067 *((ObjectConfig*)this) = m_cfg;
00068 }
00069
00070 Physics::~Physics () {}
00071
00072
00073
00074
00075
00076
00077
00078 void Physics::SetPhysXY(double x, double y)
00079 {
00080 m_pos_x.x0 = x;
00081 m_pos_y.x0 = y;
00082 }
00083
00084 void Physics::SetPhysXY(const Point2d &position){
00085 SetPhysXY(position.x, position.y);
00086 }
00087
00088 double Physics::GetPhysX() const
00089 {
00090 return m_pos_x.x0;
00091 }
00092
00093 double Physics::GetPhysY() const
00094 {
00095 return m_pos_y.x0;
00096 }
00097
00098 Point2d Physics::GetPos() const{
00099 return Point2d( m_pos_x.x0, m_pos_y.x0);
00100 }
00101
00102 void Physics::SetPhysSize (double width, double height)
00103 {
00104 m_phys_width = width ;
00105 m_phys_height = height ;
00106 }
00107
00108
00109 void Physics::SetMass(double mass)
00110 {
00111 m_mass = mass ;
00112 }
00113
00114
00115 void Physics::SetWindFactor (double factor)
00116 {
00117 m_wind_factor = factor;
00118 }
00119
00120
00121 void Physics::SetAirResistFactor (double factor)
00122 {
00123 m_air_resist_factor = factor;
00124 }
00125
00126
00127 void Physics::SetGravityFactor (double factor)
00128 {
00129 m_gravity_factor = factor;
00130 }
00131
00132 void Physics::SetSpeed (double length, double angle)
00133 {
00134 Point2d vector( length*cos(angle), length*sin(angle) );
00135 SetSpeedXY(vector);
00136 }
00137
00138 void Physics::SetSpeedXY (Point2d vector)
00139 {
00140 if (EgalZero(vector.x)) vector.x = 0;
00141 if (EgalZero(vector.y)) vector.y = 0;
00142 bool was_moving = IsMoving();
00143
00144 m_pos_x.x1 = vector.x ;
00145 m_pos_y.x1 = vector.y ;
00146 m_motion_type = FreeFall ;
00147
00148 if (!was_moving && IsMoving()) StartMoving();
00149 }
00150
00151 void Physics::AddSpeed (double length, double angle)
00152 {
00153 Point2d vector( length*cos(angle), length*sin(angle) );
00154 AddSpeedXY (vector);
00155 }
00156
00157 void Physics::AddSpeedXY (Point2d vector)
00158 {
00159 if (EgalZero(vector.x)) vector.x = 0;
00160 if (EgalZero(vector.y)) vector.y = 0;
00161 bool was_moving = IsMoving();
00162
00163 m_pos_x.x1 += vector.x ;
00164 m_pos_y.x1 += vector.y ;
00165 m_motion_type = FreeFall ;
00166
00167 if (!was_moving && IsMoving()) StartMoving();
00168 }
00169
00170 void Physics::GetSpeed(double &norm, double &angle) const
00171 {
00172 Point2d speed ;
00173
00174 switch (m_motion_type) {
00175 case FreeFall:
00176 GetSpeedXY(speed);
00177 norm = speed.Norm();
00178 angle = speed.ComputeAngle();
00179 break ;
00180
00181 case Pendulum:
00182
00183
00184 norm = fabs(m_rope_length.x0 * m_rope_angle.x1);
00185
00186 if (m_rope_angle.x1 > 0)
00187 angle = fabs(m_rope_angle.x0) ;
00188 else
00189 angle = fabs(m_rope_angle.x0) - M_PI ;
00190
00191 if (m_rope_angle.x0 < 0)
00192 angle = -angle ;
00193 break;
00194
00195 case NoMotion:
00196 norm = 0.0;
00197 angle = 0.0;
00198 break;
00199
00200 default:
00201 assert(false);
00202 break ;
00203 }
00204 }
00205
00206 void Physics::GetSpeedXY(Point2d &vector) const
00207 {
00208 if(!IsMoving())
00209 {
00210 vector.Clear();
00211 return;
00212 }
00213 vector.SetValues(m_pos_x.x1, m_pos_y.x1);
00214 }
00215
00216 Point2d Physics::GetSpeed() const
00217 {
00218 Point2d tmp;
00219 GetSpeedXY(tmp);
00220 return tmp;
00221 }
00222
00223 double Physics::GetAngularSpeed() const
00224 {
00225 return m_rope_angle.x1 ;
00226 }
00227
00228 double Physics::GetSpeedAngle() const
00229 {
00230 double angle ;
00231 Point2d speed ;
00232
00233 GetSpeedXY(speed);
00234 angle = speed.ComputeAngle();
00235
00236 return angle ;
00237 }
00238
00239 void Physics::SetExternForce (double length, double angle)
00240 {
00241 Point2d vector(length*cos(angle), length*sin(angle));
00242
00243 SetExternForceXY(vector);
00244 }
00245
00246 void Physics::SetExternForceXY (Point2d vector)
00247 {
00248 bool was_moving = IsMoving();
00249
00250 m_extern_force.SetValues(vector);
00251
00252 if (!was_moving && IsMoving())
00253 StartMoving();
00254 }
00255
00256
00257 void Physics::SetPhysFixationPointXY(double g_x, double g_y, double dx,
00258 double dy)
00259 {
00260 double fix_point_x, fix_point_y ;
00261 double old_length ;
00262
00263 Point2d V ;
00264 m_fix_point_gnd.x = g_x ;
00265 m_fix_point_gnd.y = g_y ;
00266 m_fix_point_dxy.x = dx ;
00267 m_fix_point_dxy.y = dy ;
00268
00269
00270
00271 fix_point_x = m_pos_x.x0 + dx ;
00272 fix_point_y = m_pos_y.x0 + dy ;
00273
00274 old_length = m_rope_length.x0 ;
00275 m_rope_length.x0 = Point2d(fix_point_x,fix_point_y).Distance( Point2d(g_x,g_y) );
00276
00277 if (m_motion_type == Pendulum)
00278 {
00279
00280
00281 m_rope_angle.x1 = m_rope_angle.x1 * old_length / m_rope_length.x0 ;
00282 }
00283 else
00284 {
00285
00286
00287 V.x = fix_point_x - g_x ;
00288 V.y = fix_point_y - g_y ;
00289 m_rope_angle.x0 = M_PI_2 - V.ComputeAngle() ;
00290
00291
00292 m_rope_angle.x1 = (m_pos_x.x1 * cos(m_rope_angle.x0) +
00293 m_pos_y.x1 * sin(m_rope_angle.x0) ) / m_rope_length.x0;
00294
00295
00296 m_rope_angle.x2 = 0 ;
00297
00298 bool was_moving = IsMoving();
00299 m_motion_type = Pendulum ;
00300 if (!was_moving && IsMoving()) StartMoving();
00301 }
00302 }
00303
00304 void Physics::UnsetPhysFixationPoint()
00305 {
00306 double speed_norm, angle ;
00307
00308 GetSpeed (speed_norm, angle);
00309
00310 angle = -angle ;
00311
00312 SetSpeed(speed_norm, angle);
00313
00314 m_pos_x.x2 = 0 ;
00315 m_pos_y.x2 = 0 ;
00316
00317 m_rope_angle.Clear();
00318 m_rope_length.Clear();
00319
00320 m_motion_type = FreeFall ;
00321 }
00322
00323 void Physics::ChangePhysRopeSize(double dl)
00324 {
00325 if ((dl < 0) && (m_rope_length.x0 < 0.5))
00326 return ;
00327
00328 bool was_moving = IsMoving();
00329
00330 m_rope_length.x0 += dl ;
00331
00332
00333 m_rope_angle.x1 = m_rope_angle.x1 * (m_rope_length.x0 - dl) / m_rope_length.x0 ;
00334
00335 if (!was_moving && IsMoving()) StartMoving();
00336 }
00337
00338 double Physics::GetRopeAngle()
00339 {
00340 return m_rope_angle.x0 ;
00341 }
00342
00343 double Physics::GetRopeLength()
00344 {
00345 return m_rope_length.x0;
00346 }
00347
00348
00349
00350
00351
00352 void Physics::StartMoving()
00353 {
00354 m_last_move = Time::GetInstance()->Read();
00355
00356 if (m_motion_type == NoMotion)
00357 m_motion_type = FreeFall ;
00358
00359 MSG_DEBUG ("physic.physic", "Start moving.");
00360 }
00361
00362 void Physics::StopMoving()
00363 {
00364 if (IsMoving()) MSG_DEBUG ("physic.physic", "End of a movement...");
00365
00366 m_pos_x.x1 = 0 ;
00367 m_pos_x.x2 = 0 ;
00368 m_pos_y.x1 = 0 ;
00369 m_pos_y.x2 = 0 ;
00370 if (m_motion_type != Pendulum)
00371 m_motion_type = NoMotion ;
00372
00373 m_extern_force.Clear();
00374 }
00375
00376 bool Physics::IsMoving() const
00377 {
00378 return ( (!EgalZero(m_pos_x.x1)) ||
00379 (!EgalZero(m_pos_y.x1)) ||
00380 (!m_extern_force.IsNull() ) ||
00381 (m_motion_type != NoMotion) ) ;
00382
00383 }
00384
00385 bool Physics::IsFalling() const
00386 {
00387 return ( ( m_motion_type == FreeFall ) &&
00388 ( m_pos_y.x1 > 0.1) );
00389 }
00390
00391
00392 void Physics::ComputePendulumNextXY (double delta_t)
00393 {
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410 m_rope_angle.ComputeOneEulerStep(
00411 1,
00412 m_balancing_damping + 2 * m_rope_length.x1 / m_rope_length.x0,
00413 0,
00414 -GameMode::GetInstance()->gravity / m_rope_length.x0 * sin (m_rope_angle.x0)
00415 +m_extern_force.x / m_rope_length.x0 * cos (m_rope_angle.x0),
00416 delta_t);
00417
00418 double x = m_fix_point_gnd.x - m_fix_point_dxy.x
00419 + m_rope_length.x0 * sin(m_rope_angle.x0);
00420 double y = m_fix_point_gnd.y - m_fix_point_dxy.y
00421 + m_rope_length.x0 * cos(m_rope_angle.x0);
00422
00423
00424
00425
00426 SetPhysXY(x,y);
00427 }
00428
00429
00430 void Physics::ComputeFallNextXY (double delta_t)
00431 {
00432 double speed_norm, speed_angle ;
00433 double air_resistance_factor ;
00434
00435 double weight_force ;
00436 double wind_force ;
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446 weight_force = GameMode::GetInstance()->gravity * m_gravity_factor * m_mass ;
00447
00448
00449
00450 wind_force = wind.GetStrength() * m_wind_factor ;
00451
00452
00453
00454 GetSpeed(speed_norm, speed_angle);
00455
00456 air_resistance_factor = AIR_RESISTANCE_FACTOR * m_air_resist_factor ;
00457
00458 MSG_DEBUG( "physic.fall", "Fall %s; mass %5f, weight %5f, wind %5f, air %5f", typeid(*this).name(), m_mass, weight_force,wind_force, air_resistance_factor);
00459
00460
00461 m_pos_x.ComputeOneEulerStep(m_mass, air_resistance_factor, 0,
00462 wind_force + m_extern_force.x, delta_t);
00463
00464
00465 m_pos_y.ComputeOneEulerStep(m_mass, air_resistance_factor, 0,
00466 weight_force + m_extern_force.y, delta_t);
00467
00468
00469
00470
00471
00472
00473 }
00474
00475
00476 Point2d Physics::ComputeNextXY(double delta_t){
00477 if (m_motion_type == FreeFall)
00478 ComputeFallNextXY(delta_t);
00479
00480 if (m_motion_type == Pendulum)
00481 ComputePendulumNextXY(delta_t);
00482
00483 m_last_move = Time::GetInstance()->Read() ;
00484
00485 return Point2d(m_pos_x.x0, m_pos_y.x0);
00486 }
00487
00488 void Physics::RunPhysicalEngine()
00489 {
00490 double step_t, delta_t = (Time::GetInstance()->Read() - m_last_move) / 1000.0;
00491 Point2d oldPos;
00492 Point2d newPos;
00493
00494 step_t = PHYS_DELTA_T;
00495
00496
00497
00498
00499
00500
00501 while (delta_t > 0.0){
00502 if (delta_t < PHYS_DELTA_T)
00503 step_t = delta_t ;
00504
00505 oldPos = GetPos();
00506
00507 newPos = ComputeNextXY(step_t);
00508
00509 if( newPos != oldPos) {
00510
00511 MSG_DEBUG( "physic.move", "Move %s (%f, %f) -> (%f, %f)", typeid(*this).name(), oldPos.x, oldPos.y, newPos.x, newPos.y);
00512 NotifyMove(oldPos, newPos);
00513 }
00514
00515 delta_t -= PHYS_DELTA_T ;
00516 }
00517
00518 return;
00519 }
00520
00521
00522 void Physics::Rebound(Point2d contactPos, double contact_angle)
00523 {
00524 double norme, angle;
00525
00526
00527 GetSpeed(norme, angle);
00528
00529 switch (m_motion_type) {
00530 case FreeFall :
00531 if (m_rebounding)
00532 {
00533
00534
00535 if(contact_angle == NAN)
00536 angle = angle + M_PI ;
00537 else
00538 angle = M_PI - angle -2.0 * contact_angle;
00539
00540
00541 norme = norme * m_rebound_factor;
00542
00543
00544 SetSpeed(norme, angle);
00545
00546
00547 if (norme < STOP_REBOUND_LIMIT){
00548 StopMoving();
00549 return;
00550 }
00551 SignalRebound();
00552 }
00553 else
00554 StopMoving();
00555 break;
00556
00557 case Pendulum:
00558 {
00559 Point2d V ;
00560
00561
00562 V.x = m_pos_x.x0 + m_fix_point_dxy.x - m_fix_point_gnd.x;
00563 V.y = m_pos_y.x0 + m_fix_point_dxy.y - m_fix_point_gnd.y;
00564
00565 m_rope_angle.x0 = M_PI_2 - V.ComputeAngle();
00566
00567
00568 V.x = PENDULUM_REBOUND_FACTOR * norme * cos(angle);
00569 V.y = PENDULUM_REBOUND_FACTOR * norme * sin(angle);
00570
00571 angle = angle + M_PI;
00572
00573 m_rope_angle.x1 = (norme * cos(angle) * cos(m_rope_angle.x0) +
00574 norme * sin(angle) * sin(m_rope_angle.x0) ) / m_rope_length.x0;
00575
00576 m_rope_angle.x2 = 0;
00577 m_extern_force.Clear();
00578 }
00579 break ;
00580
00581 default:
00582 break ;
00583 }
00584
00585 }
00586
00587 void Physics::SignalGhostState(bool) {}
00588 void Physics::SignalDeath() {}
00589 void Physics::SignalDrowning() {}
00590 void Physics::SignalRebound() {}