Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

658 lines
18 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: MOVEMENT ENTITIES TEST
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "entitylist.h"
  9. #include "entityoutput.h"
  10. #include "keyframe/keyframe.h" // BUG: this needs to move if keyframe is a standard thing
  11. #include "mathlib/mathlib.h" // FIXME: why do we still need this?
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. // Hack, sort of. These interpolators don't get to hold state, but the ones
  15. // that need state (like the rope simulator) should NOT be used as paths here.
  16. IPositionInterpolator *g_pPositionInterpolators[8] = {0,0,0,0,0,0,0,0};
  17. IPositionInterpolator* GetPositionInterpolator( int iInterp )
  18. {
  19. if( !g_pPositionInterpolators[iInterp] )
  20. g_pPositionInterpolators[iInterp] = Motion_GetPositionInterpolator( iInterp );
  21. return g_pPositionInterpolators[iInterp];
  22. }
  23. static float Fix( float angle )
  24. {
  25. while ( angle < 0 )
  26. angle += 360;
  27. while ( angle > 360 )
  28. angle -= 360;
  29. return angle;
  30. }
  31. void FixupAngles( QAngle &v )
  32. {
  33. v.x = Fix( v.x );
  34. v.y = Fix( v.y );
  35. v.z = Fix( v.z );
  36. }
  37. //-----------------------------------------------------------------------------
  38. //
  39. // Purpose: Contains a description of a keyframe
  40. // has no networked representation, so has to store origin, etc. itself
  41. //
  42. //-----------------------------------------------------------------------------
  43. class CPathKeyFrame : public CLogicalEntity
  44. {
  45. public:
  46. DECLARE_CLASS( CPathKeyFrame, CLogicalEntity );
  47. void Spawn( void );
  48. void Activate( void );
  49. void Link( void );
  50. Vector m_Origin;
  51. QAngle m_Angles; // euler angles PITCH YAW ROLL (Y Z X)
  52. Quaternion m_qAngle; // quaternion angle (generated from m_Angles)
  53. string_t m_iNextKey;
  54. float m_flNextTime;
  55. CPathKeyFrame *NextKey( int direction );
  56. CPathKeyFrame *PrevKey( int direction );
  57. float Speed( void ) { return m_flSpeed; }
  58. void SetKeyAngles( QAngle angles );
  59. CPathKeyFrame *InsertNewKey( Vector newPos, QAngle newAngles );
  60. void CalculateFrameDuration( void );
  61. protected:
  62. CPathKeyFrame *m_pNextKey;
  63. CPathKeyFrame *m_pPrevKey;
  64. float m_flSpeed;
  65. DECLARE_DATADESC();
  66. };
  67. LINK_ENTITY_TO_CLASS( keyframe_track, CPathKeyFrame );
  68. BEGIN_DATADESC( CPathKeyFrame )
  69. DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
  70. DEFINE_FIELD( m_Angles, FIELD_VECTOR ),
  71. DEFINE_FIELD( m_qAngle, FIELD_QUATERNION ),
  72. DEFINE_KEYFIELD( m_iNextKey, FIELD_STRING, "NextKey" ),
  73. DEFINE_FIELD( m_flNextTime, FIELD_FLOAT ), // derived from speed
  74. DEFINE_KEYFIELD( m_flSpeed, FIELD_FLOAT, "MoveSpeed" ),
  75. DEFINE_FIELD( m_pNextKey, FIELD_CLASSPTR ),
  76. DEFINE_FIELD( m_pPrevKey, FIELD_CLASSPTR ),
  77. END_DATADESC()
  78. //-----------------------------------------------------------------------------
  79. // Purpose: Converts inputed euler angles to internal angle format (quaternions)
  80. //-----------------------------------------------------------------------------
  81. void CPathKeyFrame::Spawn( void )
  82. {
  83. m_Origin = GetLocalOrigin();
  84. m_Angles = GetLocalAngles();
  85. SetKeyAngles( m_Angles );
  86. }
  87. //-----------------------------------------------------------------------------
  88. // Purpose: Adds the keyframe into the path after all the other keys have spawned
  89. //-----------------------------------------------------------------------------
  90. void CPathKeyFrame::Activate( void )
  91. {
  92. BaseClass::Activate();
  93. Link();
  94. CalculateFrameDuration();
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Purpose:
  98. //-----------------------------------------------------------------------------
  99. void CPathKeyFrame::CalculateFrameDuration( void )
  100. {
  101. // calculate time from speed
  102. if ( m_pNextKey && m_flSpeed > 0 )
  103. {
  104. m_flNextTime = (m_Origin - m_pNextKey->m_Origin).Length() / m_flSpeed;
  105. // couldn't get time from distance, get it from rotation instead
  106. if ( !m_flNextTime )
  107. {
  108. // speed is in degrees per second
  109. // find the largest rotation component and use that
  110. QAngle ang = m_Angles - m_pNextKey->m_Angles;
  111. FixupAngles( ang );
  112. float x = 0;
  113. for ( int i = 0; i < 3; i++ )
  114. {
  115. if ( abs(ang[i]) > x )
  116. {
  117. x = abs(ang[i]);
  118. }
  119. }
  120. m_flNextTime = x / m_flSpeed;
  121. }
  122. }
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Purpose: Links the key frame into the key frame list
  126. //-----------------------------------------------------------------------------
  127. void CPathKeyFrame::Link( void )
  128. {
  129. m_pNextKey = dynamic_cast<CPathKeyFrame*>( gEntList.FindEntityByName(NULL, m_iNextKey ) );
  130. if ( m_pNextKey )
  131. {
  132. m_pNextKey->m_pPrevKey = this;
  133. }
  134. }
  135. //-----------------------------------------------------------------------------
  136. // Purpose:
  137. // Input : angles -
  138. //-----------------------------------------------------------------------------
  139. void CPathKeyFrame::SetKeyAngles( QAngle angles )
  140. {
  141. m_Angles = angles;
  142. AngleQuaternion( m_Angles, m_qAngle );
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Purpose:
  146. // Input : direction -
  147. // Output : CPathKeyFrame
  148. //-----------------------------------------------------------------------------
  149. CPathKeyFrame* CPathKeyFrame::NextKey( int direction )
  150. {
  151. if ( direction == 1 )
  152. {
  153. return m_pNextKey;
  154. }
  155. else if ( direction == -1 )
  156. {
  157. return m_pPrevKey;
  158. }
  159. return this;
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Purpose:
  163. // Input : direction -
  164. // Output : CPathKeyFrame
  165. //-----------------------------------------------------------------------------
  166. CPathKeyFrame *CPathKeyFrame::PrevKey( int direction )
  167. {
  168. if ( direction == 1 )
  169. {
  170. return m_pPrevKey;
  171. }
  172. else if ( direction == -1 )
  173. {
  174. return m_pNextKey;
  175. }
  176. return this;
  177. }
  178. //-----------------------------------------------------------------------------
  179. // Purpose: Creates and insterts a new keyframe into the sequence
  180. // Input : newPos -
  181. // newAngles -
  182. // Output : CPathKeyFrame
  183. //-----------------------------------------------------------------------------
  184. CPathKeyFrame *CPathKeyFrame::InsertNewKey( Vector newPos, QAngle newAngles )
  185. {
  186. CPathKeyFrame *newKey = CREATE_ENTITY( CPathKeyFrame, "keyframe_track" );
  187. // copy data across
  188. newKey->SetKeyAngles( newAngles );
  189. newKey->m_Origin = newPos;
  190. newKey->m_flSpeed = m_flSpeed;
  191. newKey->SetEFlags( GetEFlags() );
  192. if ( m_iParent != NULL_STRING )
  193. {
  194. newKey->SetParent( m_iParent, NULL );
  195. }
  196. // link forward
  197. newKey->m_pNextKey = m_pNextKey;
  198. m_pNextKey->m_pPrevKey = newKey;
  199. // link back
  200. m_pNextKey = newKey;
  201. newKey->m_pPrevKey = this;
  202. // calculate new times
  203. CalculateFrameDuration();
  204. newKey->CalculateFrameDuration();
  205. return newKey;
  206. }
  207. //-----------------------------------------------------------------------------
  208. //
  209. // Purpose: Basic keyframed movement behavior
  210. //
  211. //-----------------------------------------------------------------------------
  212. class CBaseMoveBehavior : public CPathKeyFrame
  213. {
  214. public:
  215. DECLARE_CLASS( CBaseMoveBehavior, CPathKeyFrame );
  216. void Spawn( void );
  217. void Activate( void );
  218. void MoveDone( void );
  219. float SetObjectPhysicsVelocity( float moveTime );
  220. // methods
  221. virtual bool StartMoving( int direction );
  222. virtual void StopMoving( void );
  223. virtual bool IsMoving( void );
  224. // derived classes should override this to get notification of arriving at new keyframes
  225. // virtual void ArrivedAtKeyFrame( CPathKeyFrame * ) {}
  226. bool IsAtSequenceStart( void );
  227. bool IsAtSequenceEnd( void );
  228. // interpolation functions
  229. // int m_iTimeModifier;
  230. int m_iPositionInterpolator;
  231. int m_iRotationInterpolator;
  232. // animation vars
  233. float m_flAnimStartTime;
  234. float m_flAnimEndTime;
  235. float m_flAverageSpeedAcrossFrame; // for advancing time with speed (not the normal visa-versa)
  236. CPathKeyFrame *m_pCurrentKeyFrame; // keyframe currently moving from
  237. CPathKeyFrame *m_pTargetKeyFrame; // keyframe being moved to
  238. CPathKeyFrame *m_pPreKeyFrame, *m_pPostKeyFrame; // pre- and post-keyframe's for spline interpolation
  239. float m_flTimeIntoFrame;
  240. int m_iDirection; // 1 for forward, -1 for backward, and 0 for at rest
  241. float CalculateTimeAdvancementForSpeed( float moveTime, float speed );
  242. DECLARE_DATADESC();
  243. };
  244. LINK_ENTITY_TO_CLASS( move_keyframed, CBaseMoveBehavior );
  245. BEGIN_DATADESC( CBaseMoveBehavior )
  246. // DEFINE_KEYFIELD( m_iTimeModifier, FIELD_INTEGER, "TimeModifier" ),
  247. DEFINE_KEYFIELD( m_iPositionInterpolator, FIELD_INTEGER, "PositionInterpolator" ),
  248. DEFINE_KEYFIELD( m_iRotationInterpolator, FIELD_INTEGER, "RotationInterpolator" ),
  249. DEFINE_FIELD( m_pCurrentKeyFrame, FIELD_CLASSPTR ),
  250. DEFINE_FIELD( m_pTargetKeyFrame, FIELD_CLASSPTR ),
  251. DEFINE_FIELD( m_pPreKeyFrame, FIELD_CLASSPTR ),
  252. DEFINE_FIELD( m_pPostKeyFrame, FIELD_CLASSPTR ),
  253. DEFINE_FIELD( m_flAnimStartTime, FIELD_FLOAT ),
  254. DEFINE_FIELD( m_flAnimEndTime, FIELD_FLOAT ),
  255. DEFINE_FIELD( m_flAverageSpeedAcrossFrame, FIELD_FLOAT ),
  256. DEFINE_FIELD( m_flTimeIntoFrame, FIELD_FLOAT ),
  257. DEFINE_FIELD( m_iDirection, FIELD_INTEGER ),
  258. END_DATADESC()
  259. void CBaseMoveBehavior::Spawn( void )
  260. {
  261. m_pCurrentKeyFrame = this;
  262. m_flTimeIntoFrame = 0;
  263. SetMoveType( MOVETYPE_PUSH );
  264. // a move behavior is also it's first keyframe
  265. m_Origin = GetLocalOrigin();
  266. m_Angles = GetLocalAngles();
  267. BaseClass::Spawn();
  268. }
  269. void CBaseMoveBehavior::Activate( void )
  270. {
  271. BaseClass::Activate();
  272. SetMoveDoneTime( 0.5 ); // start moving in 0.2 seconds time
  273. // if we are just the basic keyframed entity, cycle our animation
  274. if ( !stricmp(GetClassname(), "move_keyframed") )
  275. {
  276. StartMoving( 1 );
  277. }
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Purpose: Checks to see if the we're at the start of the keyframe sequence
  281. // Output : Returns true on success, false on failure.
  282. //-----------------------------------------------------------------------------
  283. bool CBaseMoveBehavior::IsAtSequenceStart( void )
  284. {
  285. if ( !m_pCurrentKeyFrame )
  286. return true;
  287. if ( m_flAnimStartTime && m_flAnimStartTime >= GetLocalTime() )
  288. {
  289. if ( !m_pCurrentKeyFrame->PrevKey(1) && !m_pTargetKeyFrame )
  290. return true;
  291. }
  292. return false;
  293. }
  294. //-----------------------------------------------------------------------------
  295. // Purpose: Checks to see if we're at the end of the keyframe sequence
  296. // Output : Returns true on success, false on failure.
  297. //-----------------------------------------------------------------------------
  298. bool CBaseMoveBehavior::IsAtSequenceEnd( void )
  299. {
  300. if ( !m_pCurrentKeyFrame )
  301. return false;
  302. if ( !m_pCurrentKeyFrame->NextKey(1) && !m_pTargetKeyFrame )
  303. return true;
  304. return false;
  305. }
  306. //-----------------------------------------------------------------------------
  307. // Purpose:
  308. // Output : Returns true on success, false on failure.
  309. //-----------------------------------------------------------------------------
  310. bool CBaseMoveBehavior::IsMoving( void )
  311. {
  312. if ( m_iDirection != 0 )
  313. return true;
  314. return false;
  315. }
  316. //-----------------------------------------------------------------------------
  317. // Purpose: Starts the object moving from it's current position, in the direction indicated
  318. // Input : direction - 1 is forward through the sequence, -1 is backwards, and 0 is stop
  319. // Output : Returns true on success, false on failure.
  320. //-----------------------------------------------------------------------------
  321. bool CBaseMoveBehavior::StartMoving( int direction )
  322. {
  323. // 0 direction is to stop moving
  324. if ( direction == 0 )
  325. {
  326. StopMoving();
  327. return false;
  328. }
  329. // check to see if we should keep moving in the current direction
  330. if ( m_iDirection == direction )
  331. {
  332. // if we're at the end of the current anim key, move to the next one
  333. if ( GetLocalTime() >= m_flAnimEndTime )
  334. {
  335. m_pCurrentKeyFrame = m_pTargetKeyFrame;
  336. m_flTimeIntoFrame = 0;
  337. if ( !m_pTargetKeyFrame->NextKey(direction) )
  338. {
  339. // we've hit the end of the sequence
  340. m_flAnimEndTime = 0;
  341. m_flAnimStartTime = 0;
  342. StopMoving();
  343. return false;
  344. }
  345. // advance the target keyframe
  346. m_pTargetKeyFrame = m_pTargetKeyFrame->NextKey(direction);
  347. }
  348. }
  349. else
  350. {
  351. // we're changing direction
  352. // need to calculate current position in the frame
  353. // stop first, then start again
  354. if ( m_iDirection != 0 )
  355. {
  356. StopMoving();
  357. }
  358. m_iDirection = direction;
  359. // if we're going in reverse, swap the currentkey and targetkey (since we're going opposite dir)
  360. if ( direction == 1 )
  361. {
  362. m_pTargetKeyFrame = m_pCurrentKeyFrame->NextKey( direction );
  363. }
  364. else if ( direction == -1 )
  365. {
  366. if ( m_flTimeIntoFrame > 0 )
  367. {
  368. m_pTargetKeyFrame = m_pCurrentKeyFrame;
  369. m_pCurrentKeyFrame = m_pCurrentKeyFrame->NextKey( 1 );
  370. }
  371. else
  372. {
  373. m_pTargetKeyFrame = m_pCurrentKeyFrame->PrevKey( 1 );
  374. }
  375. }
  376. // recalculate our movement from the stored data
  377. if ( !m_pTargetKeyFrame )
  378. {
  379. StopMoving();
  380. return false;
  381. }
  382. // calculate the keyframes before and after the keyframes we're interpolating between
  383. m_pPostKeyFrame = m_pTargetKeyFrame->NextKey( direction );
  384. if ( !m_pPostKeyFrame )
  385. {
  386. m_pPostKeyFrame = m_pTargetKeyFrame;
  387. }
  388. m_pPreKeyFrame = m_pCurrentKeyFrame->PrevKey( direction );
  389. if ( !m_pPreKeyFrame )
  390. {
  391. m_pPreKeyFrame = m_pCurrentKeyFrame;
  392. }
  393. }
  394. // no target, can't move
  395. if ( !m_pTargetKeyFrame )
  396. return false;
  397. // calculate start/end time
  398. // ->m_flNextTime is the time to traverse to the NEXT key, so we need the opposite if travelling backwards
  399. if ( m_iDirection == 1 )
  400. {
  401. m_flAnimStartTime = GetLocalTime() - m_flTimeIntoFrame;
  402. m_flAnimEndTime = GetLocalTime() + m_pCurrentKeyFrame->m_flNextTime - m_flTimeIntoFrame;
  403. }
  404. else
  405. {
  406. // flip the timing, since we're in reverse
  407. if ( m_flTimeIntoFrame )
  408. m_flTimeIntoFrame = m_pTargetKeyFrame->m_flNextTime - m_flTimeIntoFrame;
  409. m_flAnimStartTime = GetLocalTime() - m_flTimeIntoFrame;
  410. m_flAnimEndTime = GetLocalTime() + m_pTargetKeyFrame->m_flNextTime - m_flTimeIntoFrame;
  411. }
  412. // calculate the average speed at which we cross
  413. float animDuration = (m_flAnimEndTime - m_flAnimStartTime);
  414. float dist = (m_pCurrentKeyFrame->m_Origin - m_pTargetKeyFrame->m_Origin).Length();
  415. m_flAverageSpeedAcrossFrame = animDuration / dist;
  416. SetMoveDoneTime( m_flAnimEndTime - GetLocalTime() );
  417. return true;
  418. }
  419. //-----------------------------------------------------------------------------
  420. // Purpose: stops the object from moving
  421. // Output : Returns true on success, false on failure.
  422. //-----------------------------------------------------------------------------
  423. void CBaseMoveBehavior::StopMoving( void )
  424. {
  425. // remember exactly where we are in the frame
  426. m_flTimeIntoFrame = 0;
  427. if ( m_iDirection == 1 )
  428. {
  429. // record the time if we're not at the end of the frame
  430. if ( GetLocalTime() < m_flAnimEndTime )
  431. {
  432. m_flTimeIntoFrame = GetLocalTime() - m_flAnimStartTime;
  433. }
  434. else
  435. {
  436. // we're actually at the end
  437. if ( m_pTargetKeyFrame )
  438. {
  439. m_pCurrentKeyFrame = m_pTargetKeyFrame;
  440. }
  441. }
  442. }
  443. else if ( m_iDirection == -1 )
  444. {
  445. // store it only as a forward movement
  446. m_pCurrentKeyFrame = m_pTargetKeyFrame;
  447. if ( GetLocalTime() < m_flAnimEndTime )
  448. {
  449. m_flTimeIntoFrame = m_flAnimEndTime - GetLocalTime();
  450. }
  451. }
  452. // stop moving totally
  453. SetMoveDoneTime( -1 );
  454. m_iDirection = 0;
  455. m_flAnimStartTime = 0;
  456. m_flAnimEndTime = 0;
  457. m_pTargetKeyFrame = NULL;
  458. SetAbsVelocity(vec3_origin);
  459. SetLocalAngularVelocity( vec3_angle );
  460. }
  461. //-----------------------------------------------------------------------------
  462. // Purpose: We have just arrived at a key, move onto the next keyframe
  463. //-----------------------------------------------------------------------------
  464. void CBaseMoveBehavior::MoveDone( void )
  465. {
  466. // if we're just a base then keep playing the anim
  467. if ( !stricmp(STRING(m_iClassname), "move_keyframed") )
  468. {
  469. int direction = m_iDirection;
  470. // start moving from the keyframe we've just reached
  471. if ( !StartMoving(direction) )
  472. {
  473. // try moving in the other direction
  474. StartMoving( -direction );
  475. }
  476. }
  477. BaseClass::MoveDone();
  478. }
  479. //-----------------------------------------------------------------------------
  480. // Purpose: Calculates a new moveTime based on the speed and the current point
  481. // in the animation.
  482. // used to advance keyframed objects that have dynamic speeds.
  483. // Input : moveTime -
  484. // Output : float - the new time in the keyframing sequence
  485. //-----------------------------------------------------------------------------
  486. float CBaseMoveBehavior::CalculateTimeAdvancementForSpeed( float moveTime, float speed )
  487. {
  488. return (moveTime * speed * m_flAverageSpeedAcrossFrame);
  489. }
  490. //-----------------------------------------------------------------------------
  491. // Purpose:
  492. // GetLocalTime() is the objects local current time
  493. // Input : destTime - new time that is being moved to
  494. // moveTime - amount of time to be advanced this frame
  495. // Output : float - the actual amount of time to move (usually moveTime)
  496. //-----------------------------------------------------------------------------
  497. float CBaseMoveBehavior::SetObjectPhysicsVelocity( float moveTime )
  498. {
  499. // make sure we have a valid set up
  500. if ( !m_pCurrentKeyFrame || !m_pTargetKeyFrame )
  501. return moveTime;
  502. // if we're not moving, we're not moving
  503. if ( !IsMoving() )
  504. return moveTime;
  505. float destTime = moveTime + GetLocalTime();
  506. // work out where we want to be, using destTime
  507. m_flTimeIntoFrame = destTime - m_flAnimStartTime;
  508. float newTime = (destTime - m_flAnimStartTime) / (m_flAnimEndTime - m_flAnimStartTime);
  509. Vector newPos;
  510. QAngle newAngles;
  511. IPositionInterpolator *pInterp = GetPositionInterpolator( m_iPositionInterpolator );
  512. if( pInterp )
  513. {
  514. // setup key frames
  515. pInterp->SetKeyPosition( -1, m_pPreKeyFrame->m_Origin );
  516. Motion_SetKeyAngles( -1, m_pPreKeyFrame->m_qAngle );
  517. pInterp->SetKeyPosition( 0, m_pCurrentKeyFrame->m_Origin );
  518. Motion_SetKeyAngles( 0, m_pCurrentKeyFrame->m_qAngle );
  519. pInterp->SetKeyPosition( 1, m_pTargetKeyFrame->m_Origin );
  520. Motion_SetKeyAngles( 1, m_pTargetKeyFrame->m_qAngle );
  521. pInterp->SetKeyPosition( 2, m_pPostKeyFrame->m_Origin );
  522. Motion_SetKeyAngles( 2, m_pPostKeyFrame->m_qAngle );
  523. // find new interpolated position & rotation
  524. pInterp->InterpolatePosition( newTime, newPos );
  525. }
  526. else
  527. {
  528. newPos.Init();
  529. }
  530. Quaternion qRot;
  531. Motion_InterpolateRotation( newTime, m_iRotationInterpolator, qRot );
  532. QuaternionAngles( qRot, newAngles );
  533. // find our velocity vector (newPos - currentPos) and scale velocity vector according to the movetime
  534. float oneOnMoveTime = 1 / moveTime;
  535. SetAbsVelocity( (newPos - GetLocalOrigin()) * oneOnMoveTime );
  536. SetLocalAngularVelocity( (newAngles - GetLocalAngles()) * oneOnMoveTime );
  537. return moveTime;
  538. }