Game Development Community

[T3D1.0 BUG] Player (ground) Impact

by Davide Archetti · in Torque 3D Professional · 10/07/2009 (6:55 am) · 3 replies

Well, I was trying to see the shake camera effect when the player impact on the ground, but this doesn't work, no matter how you set the values of groundImpactMinSpeed.
I've discovered that that function _handleCollision, that take care of the ground impact, is called inside the updatePos function, just after the _move function is called (note: I'm using standard torque collision not the physic player).
But, _handleCollision use the class variable mVelocity to compute the impact speed, but the same variable is changed inside the _move function just after a collision is detected, so when it exit the _move function its value has been decresed to the after collision speed, so the _handleCollision never see the collision happens.
I have fixed this problem, by returning from the _move function the speed just before the collision and pass this speed to the _handleCollision function, so, the new updatePos function is
bool Player::updatePos(const F32 travelTime)
{
   PROFILE_SCOPE(Player_UpdatePos);
   getTransform().getColumn(3,&delta.posVec);

   // When mounted to another object, only Z rotation used.
   if (isMounted()) {
      mVelocity = mMount.object->getVelocity();
      setPosition(Point3F(0.0f, 0.0f, 0.0f), mRot);
      setMaskBits(MoveMask);
      return true;
   }

   Point3F newPos;
	Point3F	colVel = mVelocity;		//This is the velocity returned from _move just before the collision happen

   Collision col;
   dMemset( &col, 0, sizeof( col ) );

   // DEBUG:
   //Point3F savedVelocity = mVelocity;

   // This avoids unnecessary work, but also avoids problems with
   // the physicsPlayer jitters while stationary.
   if ( mVelocity.isZero() )
      newPos = delta.posVec;
   else
   {   
      if ( mPhysicsPlayer )
      {
         newPos = mPhysicsPlayer->move( mVelocity * travelTime, &col );
         mVelocity = ( newPos - delta.posVec ) / travelTime;
      }
      else
         newPos = _move( travelTime, &col, colVel );

      // DEBUG:
      //if ( isClientObject() )
		//	Con::printf( "(client) vel: %g %g %g colObj:%x", mVelocity.x, mVelocity.y, mVelocity.z, col.object );
      //else
		//	Con::printf( "(server) vel: %g %g %g colObj:%x", mVelocity.x, mVelocity.y, mVelocity.z, col.object );
   }
   
   _handleCollision( col, colVel );   

   // Set new position
   // If on the client, calc delta for backstepping
   if (isClientObject())
   {
      delta.pos = newPos;
      delta.posVec = delta.posVec - delta.pos;
      delta.dt = 1.0f;
   }
...

the _move function
Point3F Player::_move( const F32 travelTime, Collision *outCol, Point3F& colVel )
{
   // Try and move to new pos
   F32 totalMotion  = 0.0f;
   
   // TODO: not used?
   //F32 initialSpeed = mVelocity.len();

   Point3F start;

....


         // Copy this collision out so
         // we can use it to do impacts
         // and query collision.
         *outCol = *collision;
			colVel = mVelocity;

         F32 bd = -mDot( mVelocity, collision->normal );

....

And the new _handleCollision
void Player::_handleCollision( const Collision &collision, const Point3F& colVel )
{
   //F32 bd = -mDot( mVelocity, collision.normal );
	
   F32 bd = -mDot( colVel, collision.normal);

   // shake camera on ground impact
   if( bd > mDataBlock->groundImpactMinSpeed && isControlObject() )
   {
      F32 ampScale = (bd - mDataBlock->groundImpactMinSpeed) / mDataBlock->minImpactSpeed;

      CameraShake *groundImpactShake = new CameraShake;
      groundImpactShake->setDuration( mDataBlock->groundImpactShakeDuration );
      groundImpactShake->setFrequency( mDataBlock->groundImpactShakeFreq );

      VectorF shakeAmp = mDataBlock->groundImpactShakeAmp * ampScale;
      groundImpactShake->setAmplitude( shakeAmp );
      groundImpactShake->setFalloff( mDataBlock->groundImpactShakeFalloff );
      groundImpactShake->init();
      gCamFXMgr.addFX( groundImpactShake );
   }

   if ( bd > mDataBlock->minImpactSpeed && !mMountPending ) 
   {
      if ( !isGhost() )
         onImpact( collision.object, collision.normal * bd );

      if (mDamageState == Enabled && mState != RecoverState) 
      {
         // Scale how long we're down for
         F32   value = (bd - mDataBlock->minImpactSpeed);
         F32   range = (mDataBlock->minImpactSpeed * 0.9f);
         U32   recover = mDataBlock->recoverDelay;
         if (value < range)
            recover = 1 + S32(mFloor( F32(recover) * value / range) );
         //Con::printf("Used %d recover ticks", recover);
         //Con::printf("  minImpact = %g, this one = %g", mDataBlock->minImpactSpeed, bd);
         setState(RecoverState, recover);
      }
   }

   if ( isServerObject() && bd > (mDataBlock->minImpactSpeed / 3.0f) ) 
   {
      setMaskBits(ImpactMask);
   }

   // Track collisions
   if (  !isGhost() && 
         collision.object && 
         collision.object != mContactInfo.contactObject )
      queueCollision( collision.object, /*mVelocity*/ colVel - collision.object->getVelocity() );
}




#2
06/10/2010 (11:28 am)
Logged TQA-336
#3
08/02/2010 (4:51 pm)
Fixed in 1.1 Beta 2