PhysicsUpdate.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // PhysicsUpdate.h
  24. // Simple rigid body physics
  25. // Author: Michael S. Booth, November 2001
  26. #pragma once
  27. #ifndef _PHYSICSUPDATE_H_
  28. #define _PHYSICSUPDATE_H_
  29. #include "Common/AudioEventRTS.h"
  30. #include "Common/GameAudio.h"
  31. #include "GameLogic/Module/BehaviorModule.h"
  32. #include "GameLogic/Module/UpdateModule.h"
  33. #include "GameLogic/Module/CollideModule.h"
  34. enum ObjectID;
  35. enum PhysicsTurningType
  36. {
  37. TURN_NEGATIVE = -1,
  38. TURN_NONE = 0,
  39. TURN_POSITIVE = 1
  40. };
  41. //-------------------------------------------------------------------------------------------------
  42. class PhysicsBehaviorModuleData : public UpdateModuleData
  43. {
  44. public:
  45. Real m_mass;
  46. Real m_shockResistance;
  47. Real m_shockMaxYaw;
  48. Real m_shockMaxPitch;
  49. Real m_shockMaxRoll;
  50. Real m_forwardFriction;
  51. Real m_lateralFriction;
  52. Real m_ZFriction;
  53. Real m_aerodynamicFriction; // The percent of the wind resistance effect you suffer from
  54. Real m_centerOfMassOffset; // Distance the center of mass is from the center of geometry, to control pitch rate
  55. Bool m_killWhenRestingOnGround; // when airborne==false and vel==0, kill it.
  56. Bool m_allowBouncing;
  57. Bool m_allowCollideForce;
  58. Real m_minFallSpeedForDamage;
  59. Real m_fallHeightDamageFactor;
  60. Real m_pitchRollYawFactor;
  61. const WeaponTemplate* m_vehicleCrashesIntoBuildingWeaponTemplate;
  62. const WeaponTemplate* m_vehicleCrashesIntoNonBuildingWeaponTemplate;
  63. PhysicsBehaviorModuleData();
  64. static void buildFieldParse(MultiIniFieldParse& p);
  65. };
  66. //-------------------------------------------------------------------------------------------------
  67. /**
  68. * Simple rigid body physics update module
  69. */
  70. class PhysicsBehavior : public UpdateModule,
  71. public CollideModuleInterface
  72. {
  73. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( PhysicsBehavior, "PhysicsBehavior" )
  74. MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA( PhysicsBehavior, PhysicsBehaviorModuleData )
  75. public:
  76. PhysicsBehavior( Thing *thing, const ModuleData* moduleData );
  77. // virtual destructor prototype defined by MemoryPoolObject
  78. static Int getInterfaceMask() { return UpdateModule::getInterfaceMask() | (MODULEINTERFACE_COLLIDE); }
  79. virtual void onObjectCreated();
  80. // BehaviorModule
  81. virtual CollideModuleInterface* getCollide() { return this; }
  82. // CollideModuleInterface
  83. virtual void onCollide( Object *other, const Coord3D *loc, const Coord3D *normal );
  84. virtual Bool wouldLikeToCollideWith(const Object* other) const { return false; }
  85. virtual Bool isCarBombCrateCollide() const { return false; }
  86. virtual Bool isHijackedVehicleCrateCollide() const { return false; }
  87. virtual Bool isRailroad() const { return false;}
  88. virtual Bool isSalvageCrateCollide() const { return false; }
  89. virtual Bool isSabotageBuildingCrateCollide() const { return FALSE; }
  90. // UpdateModuleInterface
  91. virtual UpdateSleepTime update();
  92. // Disabled conditions to process -- all
  93. virtual DisabledMaskType getDisabledTypesToProcess() const { return DISABLEDMASK_ALL; }
  94. void applyForce( const Coord3D *force ); ///< apply a force at the object's CG
  95. void applyShock( const Coord3D *force ); ///< apply a shockwave force against the object's CG
  96. void applyRandomRotation(); ///< apply a random rotation at the object's CG
  97. void addVelocityTo(const Coord3D* vel) ;
  98. /**
  99. identical to applyForce, except that no forward friction will be applied to the physics
  100. this frame. (lateral and z-friction will still be applied.)
  101. */
  102. void applyMotiveForce( const Coord3D *force );
  103. /** This is a force clear for when objects are going out of bounds, so the locomotor
  104. can push them back into legal space. */
  105. void clearAcceleration() { m_accel.zero(); }
  106. /**
  107. add the velocity of 'this' to 'that'... useful when a unit disgorges another unit
  108. and you want to maintain relative velocities
  109. */
  110. void transferVelocityTo(PhysicsBehavior* that) const;
  111. /// @todo Rotations should be handled by this system as well (MSB)
  112. void setAngles( Real yaw, Real pitch, Real roll );
  113. Real getMass() const;
  114. void setMass( Real mass ) { m_mass = mass; }
  115. Real getCenterOfMassOffset() const { return getPhysicsBehaviorModuleData()->m_centerOfMassOffset; }
  116. const Coord3D *getAcceleration() const { return &m_prevAccel; } ///< get last frame's acceleration
  117. const Coord3D *getVelocity() const { return &m_vel; } ///< get current velocity
  118. Real getVelocityMagnitude() const; ///< return velocity magnitude (speed)
  119. Real getForwardSpeed2D() const; ///< compute speed along object's 2d direction vector
  120. Real getForwardSpeed3D() const; ///< compute speed along object's 3d direction vector
  121. ObjectID getCurrentOverlap() const; ///< return object(s) being overlapped
  122. ObjectID getPreviousOverlap() const; ///< return object(s) that were overlapped last frame
  123. ObjectID getLastCollidee() const; ///< return object that was last collided with... can be quite old
  124. Bool isCurrentlyOverlapped(Object *obj) const;
  125. Bool wasPreviouslyOverlapped(Object *obj) const;
  126. void addOverlap(Object *obj);
  127. Bool isMotive() const;
  128. PhysicsTurningType getTurning(void) const { return m_turning; } ///< 0 = not turning, -1 = turn negative, 1 = turn positive.
  129. void setTurning(PhysicsTurningType turning) { m_turning = turning; }
  130. /** This is a force scrub for velocity when ai objects are colliding. */
  131. void scrubVelocity2D( Real desiredVelocity );
  132. // note that, unlike scrubVelocity2D(), this is a signed limit
  133. void scrubVelocityZ( Real desiredVelocity );
  134. void setPitchRate(Real pitch);
  135. void setRollRate(Real roll);
  136. void setYawRate(Real yaw);
  137. /*
  138. stickToGround and allowToFall seem contradictory... here's the deal.
  139. if stickToGround is true, you stick to the ground, otherwise your z isn't messed with.
  140. HOWEVER, if allowToFall is true, stickToGround is ignored, and z is never messed with.
  141. Also, allowToFall is reset to "false" when you hit the ground, so you can set it with
  142. (relatively) little fear.
  143. */
  144. void setAllowToFall(Bool allow) { setFlag(ALLOW_TO_FALL, allow); }
  145. void setStickToGround(Bool allow) { setFlag(STICK_TO_GROUND, allow); }
  146. void setAllowBouncing(Bool allow) { setFlag(ALLOW_BOUNCE, allow); }
  147. void setAllowCollideForce(Bool allow) { setFlag(ALLOW_COLLIDE_FORCE, allow); }
  148. void setAllowAirborneFriction(Bool allow) { setFlag(APPLY_FRICTION2D_WHEN_AIRBORNE, allow); }
  149. void setImmuneToFallingDamage(Bool allow) { setFlag(IMMUNE_TO_FALLING_DAMAGE, allow); }
  150. void setStunned(Bool allow) { setFlag(IS_STUNNED, allow); }
  151. Bool getAllowToFall() const { return getFlag(ALLOW_TO_FALL); }
  152. void setIsInFreeFall(Bool allow) { setFlag(IS_IN_FREEFALL, allow); }
  153. Bool getIsInFreeFall() const { return getFlag(IS_IN_FREEFALL); }
  154. Bool getIsStunned() const { return getFlag(IS_STUNNED); }
  155. void setExtraBounciness(Real b) { m_extraBounciness = b; }
  156. void setExtraFriction(Real b) { m_extraFriction = b; }
  157. void setBounceSound(const AudioEventRTS* bounceSound);
  158. const AudioEventRTS* getBounceSound() { return m_bounceSound ? &m_bounceSound->m_event : TheAudio->getValidSilentAudioEvent(); }
  159. /**
  160. Reset all values (vel, accel, etc) to starting values.
  161. You should ALMOST NEVER use this; it's intended for cases where you need
  162. to nuke everything, like when an existing object goes off the map and you
  163. want to bring it back on with all-new values, and want to start with a clean
  164. slate. Rule of thumb: if the object was in existence on the map in the previous
  165. frame, don't call this... apply forces instead!
  166. */
  167. void resetDynamicPhysics();
  168. void setIgnoreCollisionsWith(const Object* obj);
  169. Bool isIgnoringCollisionsWith(ObjectID id) const;
  170. inline Bool getAllowCollideForce() const { return getFlag(ALLOW_COLLIDE_FORCE); }
  171. protected:
  172. /*
  173. Physics runs in its own phase, after AI, but before all others.
  174. It's actually quite important that AI (the thing that drives Locomotors) and Physics
  175. run in the same order, relative to each other, for a given object; otherwise,
  176. interesting oscillations can occur in some situations, with friction being applied
  177. either before or after the locomotive force, making for huge stuttery messes. (srj)
  178. */
  179. virtual SleepyUpdatePhase getUpdatePhase() const { return PHASE_PHYSICS; }
  180. Real getAerodynamicFriction() const;
  181. Real getForwardFriction() const;
  182. Real getLateralFriction() const;
  183. Real getZFriction() const;
  184. void applyGravitationalForces();
  185. void applyFrictionalForces();
  186. Bool handleBounce(Real oldZ, Real newZ, Real groundZ, Coord3D* bounceForce);
  187. void applyYPRDamping(Real factor);
  188. UpdateSleepTime calcSleepTime() const;
  189. void doBounceSound(const Coord3D& prevPos);
  190. Bool checkForOverlapCollision(Object *other);
  191. void testStunnedUnitForDestruction(void);
  192. private:
  193. enum PhysicsFlagsType
  194. {
  195. // Note - written out in save/load xfer; don't change these numbers.
  196. STICK_TO_GROUND = 0x0001,
  197. ALLOW_BOUNCE = 0x0002,
  198. APPLY_FRICTION2D_WHEN_AIRBORNE = 0x0004,
  199. UPDATE_EVER_RUN = 0x0008,
  200. WAS_AIRBORNE_LAST_FRAME = 0x0010,
  201. ALLOW_COLLIDE_FORCE = 0x0020,
  202. ALLOW_TO_FALL = 0x0040,
  203. HAS_PITCHROLLYAW = 0x0080,
  204. IMMUNE_TO_FALLING_DAMAGE = 0x0100,
  205. IS_IN_FREEFALL = 0x0200,
  206. IS_IN_UPDATE = 0x0400,
  207. IS_STUNNED = 0x0800,
  208. };
  209. /*
  210. Note: these are private because you should never manipulate these directly,
  211. even if you are a subclass... if you want to change the acceleration, you
  212. MUST call applyForce().
  213. */
  214. Real m_yawRate; ///< rate of rotation around up vector
  215. Real m_rollRate; ///< rate of rotation around forward vector
  216. Real m_pitchRate; ///< rate or rotation around side vector
  217. DynamicAudioEventRTS* m_bounceSound; ///< The sound for when this thing bounces, or NULL
  218. Coord3D m_accel; ///< current acceleration
  219. Coord3D m_prevAccel; ///< last frame's acceleration
  220. Coord3D m_vel; ///< current velocity
  221. PhysicsTurningType m_turning; ///< 0 = not turning, -1 = turn negative, 1 = turn positive.
  222. ObjectID m_ignoreCollisionsWith;
  223. Int m_flags;
  224. Real m_mass;
  225. ObjectID m_currentOverlap; ///< object(s) being overlapped, if any
  226. ObjectID m_previousOverlap; ///< last frame's object(s) being overlapped
  227. ObjectID m_lastCollidee; ///< ID of the last object I collided with, can be quite old.
  228. UnsignedInt m_motiveForceExpires; ///< frames at which "recent" applyMotiveForce is no longer considered
  229. Real m_extraBounciness; ///< modifier to ground stiffness
  230. Real m_extraFriction; ///< modifier to friction(s)
  231. ProjectileUpdateInterface* m_pui;
  232. mutable Real m_velMag; ///< magnitude of cur vel (recalced when m_vel changes)
  233. Bool m_originalAllowBounce; ///< orignal state of allow bounce
  234. inline void setFlag(PhysicsFlagsType f, Bool set) { if (set) m_flags |= f; else m_flags &= ~f; }
  235. inline Bool getFlag(PhysicsFlagsType f) const { return (m_flags & f) != 0; }
  236. };
  237. //-------------------------------------------------------------------------------------------------
  238. inline ObjectID PhysicsBehavior::getCurrentOverlap() const
  239. {
  240. return m_currentOverlap;
  241. }
  242. //-------------------------------------------------------------------------------------------------
  243. inline ObjectID PhysicsBehavior::getPreviousOverlap() const
  244. {
  245. return m_previousOverlap;
  246. }
  247. inline ObjectID PhysicsBehavior::getLastCollidee() const
  248. {
  249. return m_lastCollidee;
  250. }
  251. #endif // _PHYSICSUPDATE_H_