Explorar o código

Merge pull request #1019 from eightyeight/image-recoil-fix

Fix weapon image camera shake
Daniel Buckmaster %!s(int64=10) %!d(string=hai) anos
pai
achega
27252b0864

+ 1 - 42
Engine/source/T3D/shapeBase.cpp

@@ -940,8 +940,6 @@ ShapeBase::ShapeBase()
 
    for (i = 0; i < MaxTriggerKeys; i++)
       mTrigger[i] = false;
-
-   mWeaponCamShake = NULL;
 }
 
 
@@ -1063,15 +1061,7 @@ void ShapeBase::onRemove()
 
    if ( isClientObject() )   
    {
-      mCubeReflector.unregisterReflector();      
-
-      if ( mWeaponCamShake )
-      {
-         if ( mWeaponCamShake->isAdded )
-            gCamFXMgr.removeFX( mWeaponCamShake );
-
-         SAFE_DELETE( mWeaponCamShake );
-      }
+      mCubeReflector.unregisterReflector();
    }
 }
 
@@ -3161,40 +3151,9 @@ void ShapeBase::unpackUpdate(NetConnection *con, BitStream *stream)
                {
                   if ( imageData->lightType == ShapeBaseImageData::WeaponFireLight )                     
                      image.lightStart = Sim::getCurrentTime();                     
-                  
-                  // HACK: Only works properly if you are in control
-                  // of the one and only shapeBase object in the scene
-                  // which fires an image that uses camera shake.
-                  if ( imageData->shakeCamera )
-                  {
-                     if ( !mWeaponCamShake )
-                     {
-                        mWeaponCamShake = new CameraShake();
-                        mWeaponCamShake->remoteControlled = true;
-                     }
-
-                     mWeaponCamShake->init();
-                     mWeaponCamShake->setFrequency( imageData->camShakeFreq );
-                     mWeaponCamShake->setAmplitude( imageData->camShakeAmp );  
-                     
-                     if ( !mWeaponCamShake->isAdded )
-                     {
-                        gCamFXMgr.addFX( mWeaponCamShake );
-                        mWeaponCamShake->isAdded = true;
-                     }
-                  }
                }
                
                updateImageState(i,0);
-
-               if ( !image.triggerDown && !image.altTriggerDown )
-               {
-                  if ( mWeaponCamShake && mWeaponCamShake->isAdded )
-                  {
-                     gCamFXMgr.removeFX( mWeaponCamShake );
-                     mWeaponCamShake->isAdded = false;
-                  }
-               }
             }
             else
             {               

+ 5 - 4
Engine/source/T3D/shapeBase.h

@@ -324,7 +324,10 @@ struct ShapeBaseImageData: public GameBaseData {
    /// @{
    bool              shakeCamera;
    VectorF           camShakeFreq;
-   VectorF           camShakeAmp;         
+   VectorF           camShakeAmp;
+   F32               camShakeDuration;
+   F32               camShakeRadius;
+   F32               camShakeFalloff;
    /// @}
 
    /// Maximum number of sounds this image can play at a time.
@@ -903,9 +906,6 @@ protected:
 
    bool mFlipFadeVal;
 
-   /// Camera shake caused by weapon fire.
-   CameraShake *mWeaponCamShake;
-
  public:
 
    /// @name Collision Notification
@@ -1101,6 +1101,7 @@ protected:
    virtual void onImageAnimThreadChange(U32 imageSlot, S32 imageShapeIndex, ShapeBaseImageData::StateData* lastState, const char* anim, F32 pos, F32 timeScale, bool reset=false);
    virtual void onImageAnimThreadUpdate(U32 imageSlot, S32 imageShapeIndex, F32 dt);
    virtual void ejectShellCasing( U32 imageSlot );
+   virtual void shakeCamera( U32 imageSlot );
    virtual void updateDamageLevel();
    virtual void updateDamageState();
    virtual void onImpact(SceneObject* obj, VectorF vec);

+ 80 - 5
Engine/source/T3D/shapeImage.cpp

@@ -44,6 +44,7 @@
 #include "sfx/sfxTypes.h"
 #include "scene/sceneManager.h"
 #include "core/stream/fileStream.h"
+#include "T3D/fx/cameraFXMgr.h"
 
 //----------------------------------------------------------------------------
 
@@ -297,6 +298,9 @@ ShapeBaseImageData::ShapeBaseImageData()
    shakeCamera = false;
    camShakeFreq = Point3F::Zero;
    camShakeAmp = Point3F::Zero;
+   camShakeDuration = 1.5f;
+   camShakeRadius = 3.0f;
+   camShakeFalloff = 10.0f;
 }
 
 ShapeBaseImageData::~ShapeBaseImageData()
@@ -739,10 +743,7 @@ void ShapeBaseImageData::initPersistFields()
       "@see lightType");
 
    addField( "shakeCamera", TypeBool, Offset(shakeCamera, ShapeBaseImageData),
-      "@brief Flag indicating whether the camera should shake when this Image fires.\n\n"
-      "@note Camera shake only works properly if the player is in control of "
-      "the one and only shapeBase object in the scene which fires an Image that "
-      "uses camera shake." );
+      "@brief Flag indicating whether the camera should shake when this Image fires.\n\n" );
 
    addField( "camShakeFreq", TypePoint3F, Offset(camShakeFreq, ShapeBaseImageData),
       "@brief Frequency of the camera shaking effect.\n\n"
@@ -752,6 +753,16 @@ void ShapeBaseImageData::initPersistFields()
       "@brief Amplitude of the camera shaking effect.\n\n"
       "@see shakeCamera" );
 
+   addField( "camShakeDuration", TypeF32, Offset(camShakeDuration, ShapeBaseImageData),
+      "Duration (in seconds) to shake the camera." );
+
+   addField( "camShakeRadius", TypeF32, Offset(camShakeRadius, ShapeBaseImageData),
+      "Radial distance that a camera's position must be within relative to the "
+      "center of the explosion to be shaken." );
+
+   addField( "camShakeFalloff", TypeF32, Offset(camShakeFalloff, ShapeBaseImageData),
+      "Falloff value for the camera shake." );
+
    addField( "casing", TYPEID< DebrisData >(), Offset(casing, ShapeBaseImageData),
       "@brief DebrisData datablock to use for ejected casings.\n\n"
       "@see stateEjectShell" );
@@ -1028,6 +1039,9 @@ void ShapeBaseImageData::packData(BitStream* stream)
    {      
       mathWrite( *stream, camShakeFreq );
       mathWrite( *stream, camShakeAmp );
+      stream->write( camShakeDuration );
+      stream->write( camShakeRadius );
+      stream->write( camShakeFalloff );
    }
 
    mathWrite( *stream, shellExitDir );
@@ -1208,7 +1222,10 @@ void ShapeBaseImageData::unpackData(BitStream* stream)
    if ( shakeCamera )
    {
       mathRead( *stream, &camShakeFreq );
-      mathRead( *stream, &camShakeAmp );      
+      mathRead( *stream, &camShakeAmp );
+      stream->read( &camShakeDuration );
+      stream->read( &camShakeRadius );
+      stream->read( &camShakeFalloff );
    }
 
    mathRead( *stream, &shellExitDir );
@@ -2596,6 +2613,10 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force)
       ejectShellCasing( imageSlot );
    }
 
+   // Shake camera on client.
+   if (isGhost() && nextStateData.fire && image.dataBlock->shakeCamera) {
+      shakeCamera( imageSlot );
+   }
 
    // Server must animate the shape if it is a firestate...
    if (isServerObject() && (image.dataBlock->state[newState].fire || image.dataBlock->state[newState].altFire))
@@ -3342,3 +3363,57 @@ void ShapeBase::ejectShellCasing( U32 imageSlot )
 
    casing->init( shellPos, shellVel );
 }
+
+void ShapeBase::shakeCamera( U32 imageSlot )
+{
+   MountedImage& image = mMountedImageList[imageSlot];
+   ShapeBaseImageData* imageData = image.dataBlock;
+
+   if (!imageData->shakeCamera)
+      return;
+
+   // Warning: this logic was duplicated from Explosion.
+
+   // first check if explosion is near camera
+   GameConnection* connection = GameConnection::getConnectionToServer();
+   ShapeBase *obj = dynamic_cast<ShapeBase*>(connection->getControlObject());
+
+   bool applyShake = true;
+
+   if (obj)
+   {
+      ShapeBase* cObj = obj;
+      while ((cObj = cObj->getControlObject()) != 0)
+      {
+         if (cObj->useObjsEyePoint())
+         {
+            applyShake = false;
+            break;
+         }
+      }
+   }
+
+   if (applyShake && obj)
+   {
+      VectorF diff;
+      getMuzzlePoint(imageSlot, &diff);
+      diff = obj->getPosition() - diff;
+      F32 dist = diff.len();
+      if (dist < imageData->camShakeRadius)
+      {
+         CameraShake *camShake = new CameraShake;
+         camShake->setDuration(imageData->camShakeDuration);
+         camShake->setFrequency(imageData->camShakeFreq);
+
+         F32 falloff =  dist / imageData->camShakeRadius;
+         falloff = 1.0f + falloff * 10.0f;
+         falloff = 1.0f / (falloff * falloff);
+
+         VectorF shakeAmp = imageData->camShakeAmp * falloff;
+         camShake->setAmplitude(shakeAmp);
+         camShake->setFalloff(imageData->camShakeFalloff);
+         camShake->init();
+         gCamFXMgr.addFX(camShake);
+      }
+   }
+}

+ 4 - 3
Templates/Full/game/art/datablocks/weapons/Ryder.cs

@@ -192,9 +192,9 @@ datablock ShapeBaseImageData(RyderWeaponImage)
    lightBrightness = 2;
 
    // Shake camera while firing.
-   shakeCamera = false;
-   camShakeFreq = "0 0 0";
-   camShakeAmp = "0 0 0";
+   shakeCamera = "1";
+   camShakeFreq = "10 10 10";
+   camShakeAmp = "5 5 5";
 
    // Images have a state system which controls how the animations
    // are run, which sounds are played, script callbacks, etc. This
@@ -361,4 +361,5 @@ datablock ShapeBaseImageData(RyderWeaponImage)
    stateSequenceTransitionOut[13]   = true;
    stateAllowImageChange[13]        = false;
    stateSequence[13]                = "sprint";
+   camShakeDuration = "0.2";
 };