motorcycle.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWPhys *
  23. * *
  24. * $Archive:: /Commando/Code/wwphys/motorcycle.cpp $*
  25. * *
  26. * Author:: Greg Hjelstrom *
  27. * *
  28. * $Modtime:: 8/17/01 8:45p $*
  29. * *
  30. * $Revision:: 28 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "motorcycle.h"
  36. #include "physcontrol.h"
  37. #include "persistfactory.h"
  38. #include "simpledefinitionfactory.h"
  39. #include "wwphysids.h"
  40. #include "wwhack.h"
  41. #include "wwprofile.h"
  42. DECLARE_FORCE_LINK(motorcycle);
  43. /*
  44. ** Declare a PersistFactory for MotorcycleClasses
  45. */
  46. SimplePersistFactoryClass<MotorcycleClass,PHYSICS_CHUNKID_MOTORCYCLE> _MotorcycleFactory;
  47. /*
  48. ** Chunk-ID's used by MotorcycleClass
  49. */
  50. enum
  51. {
  52. MOTORCYCLE_CHUNK_WHEELEDVEHICLE = 0x06511110,
  53. MOTORCYCLE_CHUNK_VARIABLES,
  54. MOTORCYCLE_VARIABLE_LEANK0 = 0x00,
  55. MOTORCYCLE_VARIABLE_LEANK1 = 0x01,
  56. };
  57. MotorcycleClass::MotorcycleClass(void) :
  58. LeanK0(18.0f),
  59. LeanK1(5.0f)
  60. {
  61. }
  62. void MotorcycleClass::Init(const MotorcycleDefClass & def)
  63. {
  64. WheeledVehicleClass::Init(def);
  65. LeanK0 = def.LeanK0;
  66. LeanK1 = def.LeanK1;
  67. }
  68. MotorcycleClass::~MotorcycleClass(void)
  69. {
  70. }
  71. void MotorcycleClass::Compute_Force_And_Torque(Vector3 * force,Vector3 * torque)
  72. {
  73. static float MAX_ROLL = DEG_TO_RADF(20.0f);
  74. static float MAX_VDOT = 15.0f; // at this speed, cycle will lean over MAX_ROLL
  75. static float MAX_TURN = 1.0f; // at this turn, cycle will lean over MAX_ROLL
  76. static float MAX_LVEL = 10.0f;
  77. {
  78. WWPROFILE("MotorcycleClass::Compute_Force_And_Torque");
  79. // Read the controller inputs
  80. // Accept either strafe or turn as a turn command
  81. float turn_left = 0.0f;
  82. if (Get_Controller() != NULL) {
  83. if (WWMath::Fabs(Controller->Get_Turn_Left()) > WWMath::Fabs(Controller->Get_Move_Left())) {
  84. turn_left = Controller->Get_Turn_Left();
  85. } else {
  86. turn_left = Controller->Get_Move_Left();
  87. }
  88. }
  89. // What is our rotation about our x axis, we want it to be zero always
  90. Vector3 yvec;
  91. Get_Transform().Get_Y_Vector(&yvec);
  92. float roll = atan2(yvec.Z,sqrt(yvec.X * yvec.X + yvec.Y * yvec.Y));
  93. float target_roll;
  94. float vdot = Vector3::Dot_Product(Get_Transform().Get_X_Vector(),Velocity);
  95. // compute our lateral velocity, first we need a vector in the lateral direction
  96. Vector3 lateral_vel = Velocity - vdot * Get_Transform().Get_X_Vector();
  97. float lvel_sign = WWMath::Sign(Vector3::Dot_Product(lateral_vel,Get_Transform().Get_Y_Vector()));
  98. lateral_vel.Z = 0;
  99. float lvel = lateral_vel.Length();
  100. if (lvel > 0.0f) {
  101. float clamp_lvel = lvel/MAX_LVEL;
  102. if (clamp_lvel > 1.0f) clamp_lvel = 1.0f;
  103. float clamp_turn = turn_left/MAX_TURN;
  104. if (clamp_turn > 1.0f) clamp_turn = 1.0f;
  105. if (clamp_turn < -1.0f) clamp_turn = -1.0f;
  106. target_roll = MAX_ROLL * lvel_sign * clamp_lvel;
  107. } else {
  108. target_roll = 0.0f;
  109. }
  110. // What is our angular velocity about the x axis we want it to be zero as well
  111. float droll = Vector3::Dot_Product(AngularVelocity,Get_Transform().Get_X_Vector());
  112. WWASSERT(WWMath::Is_Valid_Float(roll));
  113. WWASSERT(WWMath::Is_Valid_Float(target_roll));
  114. WWASSERT(WWMath::Is_Valid_Float(droll));
  115. WWASSERT(WWMath::Is_Valid_Float(torque->X));
  116. WWASSERT(WWMath::Is_Valid_Float(torque->Y));
  117. WWASSERT(WWMath::Is_Valid_Float(torque->Z));
  118. // Apply a balancing torque
  119. *torque += (LeanK0 * (target_roll - roll) + LeanK1 * (0.0f - droll)) * Get_Transform().Get_X_Vector();
  120. // Record the amount that the character on the bike should lean
  121. LeanValue = (target_roll - roll) / MAX_ROLL;
  122. }
  123. // Parent classes compute their forces and torques
  124. WheeledVehicleClass::Compute_Force_And_Torque(force,torque);
  125. }
  126. void MotorcycleClass::Compute_Inertia(void)
  127. {
  128. WheeledVehicleClass::Compute_Inertia();
  129. }
  130. const PersistFactoryClass & MotorcycleClass::Get_Factory (void) const
  131. {
  132. return _MotorcycleFactory;
  133. }
  134. bool MotorcycleClass::Save (ChunkSaveClass &csave)
  135. {
  136. csave.Begin_Chunk(MOTORCYCLE_CHUNK_WHEELEDVEHICLE);
  137. WheeledVehicleClass::Save(csave);
  138. csave.End_Chunk();
  139. csave.Begin_Chunk(MOTORCYCLE_CHUNK_VARIABLES);
  140. WRITE_MICRO_CHUNK(csave,MOTORCYCLE_VARIABLE_LEANK0,LeanK0);
  141. WRITE_MICRO_CHUNK(csave,MOTORCYCLE_VARIABLE_LEANK1,LeanK1);
  142. csave.End_Chunk();
  143. return true;
  144. }
  145. bool MotorcycleClass::Load (ChunkLoadClass &cload)
  146. {
  147. while (cload.Open_Chunk()) {
  148. switch(cload.Cur_Chunk_ID()) {
  149. case MOTORCYCLE_CHUNK_WHEELEDVEHICLE:
  150. WheeledVehicleClass::Load(cload);
  151. break;
  152. case MOTORCYCLE_CHUNK_VARIABLES:
  153. while (cload.Open_Micro_Chunk()) {
  154. switch(cload.Cur_Micro_Chunk_ID()) {
  155. READ_MICRO_CHUNK(cload,MOTORCYCLE_VARIABLE_LEANK0,LeanK0);
  156. READ_MICRO_CHUNK(cload,MOTORCYCLE_VARIABLE_LEANK1,LeanK1);
  157. }
  158. cload.Close_Micro_Chunk();
  159. }
  160. break;
  161. default:
  162. WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
  163. break;
  164. }
  165. cload.Close_Chunk();
  166. }
  167. return true;
  168. }
  169. /***********************************************************************************************
  170. **
  171. ** MotorcycleDefClass Implementation
  172. **
  173. ***********************************************************************************************/
  174. /*
  175. ** Persist factory for MotorcycleDefClass
  176. */
  177. SimplePersistFactoryClass<MotorcycleDefClass,PHYSICS_CHUNKID_MOTORCYCLEDEF> _MotorcycleDefFactory;
  178. /*
  179. ** Definition factory for MotorcycleDefClass. This makes it show up in the editor
  180. */
  181. DECLARE_DEFINITION_FACTORY(MotorcycleDefClass, CLASSID_MOTORCYCLEDEF, "Motorcycle") _MotorcycleDefDefFactory;
  182. /*
  183. ** Chunk ID's used by MotorcycleDefClass
  184. */
  185. enum
  186. {
  187. MOTORCYCLEDEF_CHUNK_WHEELEDVEHICLEDEF = 0x00516000, // (parent class)
  188. MOTORCYCLEDEF_CHUNK_VARIABLES,
  189. MOTORCYCLEDEF_VARIABLE_LEANK0 = 0x00,
  190. MOTORCYCLEDEF_VARIABLE_LEANK1,
  191. };
  192. MotorcycleDefClass::MotorcycleDefClass(void) :
  193. LeanK0(18.0f),
  194. LeanK1(5.0f)
  195. {
  196. // make our parameters editable!
  197. FLOAT_EDITABLE_PARAM(MotorcycleDefClass, LeanK0, 0.01f, 100000.0f);
  198. FLOAT_EDITABLE_PARAM(MotorcycleDefClass, LeanK1, 0.01f, 100000.0f);
  199. }
  200. uint32 MotorcycleDefClass::Get_Class_ID (void) const
  201. {
  202. return CLASSID_MOTORCYCLEDEF;
  203. }
  204. PersistClass * MotorcycleDefClass::Create(void) const
  205. {
  206. MotorcycleClass * obj = NEW_REF(MotorcycleClass,());
  207. obj->Init(*this);
  208. return obj;
  209. }
  210. const PersistFactoryClass & MotorcycleDefClass::Get_Factory (void) const
  211. {
  212. return _MotorcycleDefFactory;
  213. }
  214. bool MotorcycleDefClass::Save(ChunkSaveClass &csave)
  215. {
  216. csave.Begin_Chunk(MOTORCYCLEDEF_CHUNK_WHEELEDVEHICLEDEF);
  217. WheeledVehicleDefClass::Save(csave);
  218. csave.End_Chunk();
  219. csave.Begin_Chunk(MOTORCYCLEDEF_CHUNK_VARIABLES);
  220. WRITE_MICRO_CHUNK(csave,MOTORCYCLEDEF_VARIABLE_LEANK0,LeanK0);
  221. WRITE_MICRO_CHUNK(csave,MOTORCYCLEDEF_VARIABLE_LEANK1,LeanK1);
  222. csave.End_Chunk();
  223. return true;
  224. }
  225. bool MotorcycleDefClass::Load(ChunkLoadClass &cload)
  226. {
  227. while (cload.Open_Chunk()) {
  228. switch(cload.Cur_Chunk_ID()) {
  229. case MOTORCYCLEDEF_CHUNK_WHEELEDVEHICLEDEF:
  230. WheeledVehicleDefClass::Load(cload);
  231. break;
  232. case MOTORCYCLEDEF_CHUNK_VARIABLES:
  233. while (cload.Open_Micro_Chunk()) {
  234. switch(cload.Cur_Micro_Chunk_ID()) {
  235. READ_MICRO_CHUNK(cload,MOTORCYCLEDEF_VARIABLE_LEANK0,LeanK0);
  236. READ_MICRO_CHUNK(cload,MOTORCYCLEDEF_VARIABLE_LEANK1,LeanK1);
  237. }
  238. cload.Close_Micro_Chunk();
  239. }
  240. break;
  241. }
  242. cload.Close_Chunk();
  243. }
  244. return true;
  245. }
  246. bool MotorcycleDefClass::Is_Type(const char * type_name)
  247. {
  248. if (stricmp(type_name,MotorcycleDefClass::Get_Type_Name()) == 0) {
  249. return true;
  250. } else {
  251. return WheeledVehicleDefClass::Is_Type(type_name);
  252. }
  253. }