Ballistics.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. //////////////////////////////////////////////////////////////////////////
  2. // Modenov Ivan 2006
  3. //////////////////////////////////////////////////////////////////////////
  4. #include "pch.h"
  5. #include ".\ballistics.h"
  6. #include "..\common_h\defines.h"
  7. const float Ballistics::gravity_ = -9.8f;
  8. // конструктор
  9. Ballistics::Ballistics() :
  10. curTime_(0.0f),
  11. v0_(0.0f),
  12. v1_(0.0f),
  13. startSpeed_(0.0f),
  14. curPos_(0.0f),
  15. bValid_(false)
  16. {
  17. }
  18. // деструктор
  19. Ballistics::~Ballistics()
  20. {
  21. }
  22. // устанавливает новую траекторию
  23. bool Ballistics::SetTrajectoryParams(const Vector& v0, const Vector& v1, float startSpeed, float minAngle, float maxAngle)
  24. {
  25. SetCommonTrajectoryParams(v0,v1);
  26. startSpeed_ = startSpeed;
  27. isPhysicsFly_ = true;
  28. bValid_ = ComputeShootAngle( v0_, v1_, startSpeed_, angle_, minAngle, maxAngle );
  29. g_ = gravity_;
  30. fTotalTime_ = GetTotalFlightTime();
  31. return bValid_;
  32. }
  33. bool Ballistics::SetTrajectoryParamsByTime(const Vector& v0, const Vector& v1, float fMinHeight, float fTime)
  34. {
  35. SetCommonTrajectoryParams(v0,v1);
  36. isPhysicsFly_ = false;
  37. bValid_ = true;
  38. fTotalTime_ = fTime;
  39. height_ = fMinHeight;
  40. //bValid_ = ComputeShootParams(v0, v1, fMinHeight, fTime, startSpeed_, angle_, fTotalTime_, g_);
  41. //return bValid_;
  42. return true;
  43. }
  44. // возвращает полное время полета
  45. float Ballistics::GetTotalFlightTime() const
  46. {
  47. return ComputeFlightTime((v1_-v0_).GetLengthXZ(), angle_, startSpeed_);
  48. }
  49. // расчитывает положение снаряда в произвольный момент времени
  50. Vector Ballistics::GetPosition(float time) const
  51. {
  52. if (!bValid_)
  53. return v0_;
  54. if( isPhysicsFly_ )
  55. {
  56. Vector pos;
  57. ComputePosition(v0_, v1_, g_, startSpeed_, angle_, time, pos);
  58. return pos;
  59. }
  60. return v0_;
  61. }
  62. // расчитывает новое положение снаряда
  63. void Ballistics::Step(float deltaTime)
  64. {
  65. curTime_ += deltaTime;
  66. if( isPhysicsFly_ )
  67. {
  68. ComputePosition(v0_, v1_, g_, startSpeed_, angle_, curTime_, curPos_);
  69. }
  70. else
  71. {
  72. if( curTime_ < fTotalTime_ )
  73. {
  74. float k = curTime_ / fTotalTime_;
  75. curPos_.Lerp( v0_, v1_, k );
  76. curPos_.y += k*(1.f-k) * height_ * 4.f;
  77. }
  78. else
  79. {
  80. curPos_ = v1_;
  81. curTime_ = fTotalTime_;
  82. }
  83. }
  84. }
  85. // расчитывает угол, под которым надо
  86. // запустить снаряд, чтобы он попал в заданную точку
  87. bool Ballistics::ComputeShootAngle(const Vector& v0, const Vector& v1, float startSpeed, float & angle, float minAngle, float maxAngle)
  88. {
  89. float B = (v1-v0).GetLengthXZ();
  90. float A = gravity_*B*B/(2*startSpeed*startSpeed);
  91. float C = A - (v1-v0).y;
  92. float D = B*B-4*A*C;
  93. if (D < 0.0f)
  94. {
  95. return false;
  96. }
  97. float angle0 = atan((-B + sqrt(D))/(2*A));
  98. float angle1 = atan((-B - sqrt(D))/(2*A));
  99. /* Vector dir = v1 - v0;
  100. float fdist = dir.Normalize();
  101. float ftime = fdist / startSpeed;
  102. float fVSpeed = -gravity_ * ftime * .5f;
  103. float fRealVSpeed = dir.y * startSpeed + fVSpeed;
  104. float fRealHSpeed = dir.GetLengthXZ() * startSpeed;
  105. angle = atan2(fRealVSpeed,fRealHSpeed);
  106. if( angle < minAngle || angle > maxAngle )
  107. {
  108. api->Trace("ComputeShootAngle angle limit: speed=%.2f, dist=%.2f, angle=%.3f, limit=%.3f - %.3f",
  109. startSpeed, fdist, angle, minAngle, maxAngle );
  110. return false;
  111. }
  112. return true;*/
  113. if ( angle0 < minAngle && angle1 < minAngle ||
  114. angle0 > maxAngle && angle1 > maxAngle ||
  115. angle0 < minAngle && angle1 > maxAngle ||
  116. angle0 > maxAngle && angle1 < minAngle)
  117. {
  118. return false;
  119. }
  120. if( angle0 < minAngle || angle0 > maxAngle )
  121. {
  122. angle = angle1;
  123. return true;
  124. }
  125. if( angle1 < minAngle || angle1 > maxAngle )
  126. {
  127. angle = angle0;
  128. return true;
  129. }
  130. // выбор угла ближайшего к 45 градусам
  131. angle = fabs(angle0 - PI/4) < fabs(angle1 - PI/4) ? angle0 : angle1;
  132. return true;
  133. }
  134. // расчитывает время полета снаряда между точками
  135. bool Ballistics::ComputeFlightTime(const Vector& v0, const Vector& v1, float startSpeed, float & time)
  136. {
  137. float angle;
  138. if ( !ComputeShootAngle(v0, v1, startSpeed, angle) )
  139. return false;
  140. float distance = (v1-v0).GetLengthXZ();
  141. time = distance/(startSpeed*cos(angle));
  142. return true;
  143. }
  144. // расчитывает время полета снаряда между точками
  145. float Ballistics::ComputeFlightTime(float distanceXZ, float angle, float startSpeed)
  146. {
  147. return distanceXZ/(startSpeed*cos(angle));
  148. }
  149. // расчитывает положение снаряда в любой точке траектории
  150. bool Ballistics::ComputePosition(const Vector& start, const Vector& end, float g, float startSpeed, float angle, float time, Vector & pos)
  151. {
  152. Vector dir = end - start;
  153. dir.y = 0;
  154. dir.Normalize();
  155. pos.x = start.x + dir.x*time*startSpeed*cos(angle);
  156. pos.y = start.y + startSpeed*sin(angle)*time + g*time*time*0.5f;
  157. pos.z = start.z + dir.z*time*startSpeed*cos(angle);
  158. return true;
  159. }
  160. void Ballistics::DebugDraw(IRender & render, dword color)
  161. {
  162. float fMaxTime = GetTotalFlightTime();
  163. float fTimeStep = fMaxTime * 0.05f;
  164. if( fTimeStep < 0.1f ) fTimeStep = 0.1f;
  165. RS_LINE lines[100];
  166. lines[0].dwColor = color;
  167. lines[0].vPos = v0_;
  168. long n=1;
  169. for( float fTime=fTimeStep; n<50; fTime += fTimeStep, n++ )
  170. {
  171. if( fTime > fMaxTime ) fTime = fMaxTime;
  172. lines[n*2].dwColor = color;
  173. ComputePosition(v0_, v1_, g_, startSpeed_, angle_, fTime, lines[n*2].vPos);
  174. lines[n*2-1].dwColor = color;
  175. lines[n*2-1].vPos = lines[n*2].vPos;
  176. if( fTime >= fMaxTime )
  177. break;
  178. }
  179. Matrix mWorldSave = render.GetWorld();
  180. render.SetWorld( Matrix() );
  181. render.DrawLines( lines, n, "dbgLine" );
  182. render.SetWorld(mWorldSave);
  183. }