⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 projectile.cc

📁 五行MMORPG引擎系统V1.0
💻 CC
📖 第 1 页 / 共 3 页
字号:
F32 Projectile::getUpdatePriority(CameraScopeQuery *camInfo, U32 updateMask, S32 updateSkips)
{
   F32 ret = Parent::getUpdatePriority(camInfo, updateMask, updateSkips);
   // if the camera "owns" this object, it should have a slightly higher priority
   if(mSourceObject == camInfo->camera)
      return ret + 0.2;
   return ret;
}

bool Projectile::onAdd()
{
   if(!Parent::onAdd())
      return false;

   if (isServerObject())
   {
      ShapeBase* ptr;
      if (Sim::findObject(mSourceObjectId, ptr))
         mSourceObject = ptr;
      else
      {
         if (mSourceObjectId != -1)
            Con::errorf(ConsoleLogEntry::General, "Projectile::onAdd: mSourceObjectId is invalid");
         mSourceObject = NULL;
      }

      mCurrTick = 0;
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsClientObject
   }
   else
   {
#endif
      if (bool(mDataBlock->projectileShape))
      {
         mProjectileShape = new TSShapeInstance(mDataBlock->projectileShape, isClientObject());

         if (mDataBlock->activateSeq != -1)
         {
            mActivateThread = mProjectileShape->addThread();
            mProjectileShape->setTimeScale(mActivateThread, 1);
            mProjectileShape->setSequence(mActivateThread, mDataBlock->activateSeq, 0);
         }
      }
      if (mDataBlock->particleEmitter != NULL)
      {
         ParticleEmitter* pEmitter = new ParticleEmitter;
         pEmitter->onNewDataBlock(mDataBlock->particleEmitter);
         if (pEmitter->registerObject() == false)
         {
            Con::warnf(ConsoleLogEntry::General, "Could not register particle emitter for particle of class: %s", mDataBlock->getName());
            delete pEmitter;
            pEmitter = NULL;
         }
         mParticleEmitter = pEmitter;
      }
      if (mDataBlock->particleWaterEmitter != NULL)
      {
         ParticleEmitter* pEmitter = new ParticleEmitter;
         pEmitter->onNewDataBlock(mDataBlock->particleWaterEmitter);
         if (pEmitter->registerObject() == false)
         {
            Con::warnf(ConsoleLogEntry::General, "Could not register particle emitter for particle of class: %s", mDataBlock->getName());
            delete pEmitter;
            pEmitter = NULL;
         }
         mParticleWaterEmitter = pEmitter;
      }
      if (mDataBlock->hasLight == true)
         Sim::getLightSet()->addObject(this);
   }
   if (bool(mSourceObject))
      processAfter(mSourceObject);

   // Setup our bounding box
   if (bool(mDataBlock->projectileShape) == true)
      mObjBox = mDataBlock->projectileShape->bounds;
   else
      mObjBox = Box3F(Point3F(0, 0, 0), Point3F(0, 0, 0));
   resetWorldBox();
   addToScene();

   return true;
}


void Projectile::onRemove()
{
   if (bool(mParticleEmitter)) {
      mParticleEmitter->deleteWhenEmpty();
      mParticleEmitter = NULL;
   }
   if (bool(mParticleWaterEmitter)) {
      mParticleWaterEmitter->deleteWhenEmpty();
      mParticleWaterEmitter = NULL;
   }
   if (mSoundHandle != NULL_AUDIOHANDLE) {
      alxStop(mSoundHandle);
      mSoundHandle = NULL_AUDIOHANDLE;
   }

   removeFromScene();
   Parent::onRemove();
}


bool Projectile::onNewDataBlock(GameBaseData* dptr)
{
   mDataBlock = dynamic_cast<ProjectileData*>(dptr);
   if (!mDataBlock || !Parent::onNewDataBlock(dptr))
      return false;

   return true;
}


//--------------------------------------------------------------------------

void Projectile::registerLights(LightManager * lightManager, bool lightingScene)
{
   if(lightingScene)
      return;

   if (mDataBlock->hasLight && mHidden == false)
   {
      mLight.mType = LightInfo::Point;
      getRenderTransform().getColumn(3, &mLight.mPos);
      mLight.mRadius = mDataBlock->lightRadius;
      if (mDataBlock->hasWaterLight && pointInWater(mLight.mPos))
         mLight.mColor = mDataBlock->waterLightColor;
      else
      mLight.mColor  = mDataBlock->lightColor;
      lightManager->addLight(&mLight);
   }
}

//----------------------------------------------------------------------------

void Projectile::emitParticles(const Point3F& from, const Point3F& to, const Point3F& vel, const U32 ms)
{
   if( mHidden )
      return;

   Point3F axis = -vel;

   if( axis.isZero() )
      axis.set( 0.0, 0.0, 1.0 );
   else
      axis.normalize();

   bool fromWater = pointInWater(from);
   bool toWater   = pointInWater(to);

   if (!fromWater && !toWater && bool(mParticleEmitter))                                        // not in water
      mParticleEmitter->emitParticles(from, to, axis, vel, ms);
   else if (fromWater && toWater && bool(mParticleWaterEmitter))                                // in water
      mParticleWaterEmitter->emitParticles(from, to, axis, vel, ms);
   else if (!fromWater && toWater && bool(mParticleEmitter) && bool(mParticleWaterEmitter))     // entering water
   {
      // cast the ray to get the surface point of the water
      RayInfo rInfo;
      if (gClientContainer.castRay(from, to, WaterObjectType, &rInfo))
      {
         MatrixF trans = getTransform();
         trans.setPosition(rInfo.point);

         Splash *splash = new Splash();
         splash->onNewDataBlock(mDataBlock->splash);
         splash->setTransform(trans);
         splash->setInitialState(trans.getPosition(), Point3F(0.0, 0.0, 1.0));
         if (!splash->registerObject())
         {
            delete splash;
            splash = NULL;
         }

         // create an emitter for the particles out of water and the particles in water
         mParticleEmitter->emitParticles(from, rInfo.point, axis, vel, ms);
         mParticleWaterEmitter->emitParticles(rInfo.point, to, axis, vel, ms);
      }
   }
   else if (fromWater && !toWater && bool(mParticleEmitter) && bool(mParticleWaterEmitter))     // leaving water
   {
      // cast the ray in the opposite direction since that point is out of the water, otherwise
      //  we hit water immediately and wont get the appropriate surface point
      RayInfo rInfo;
      if (gClientContainer.castRay(to, from, WaterObjectType, &rInfo))
      {
         MatrixF trans = getTransform();
         trans.setPosition(rInfo.point);

         Splash *splash = new Splash();
         splash->onNewDataBlock(mDataBlock->splash);
         splash->setTransform(trans);
         splash->setInitialState(trans.getPosition(), Point3F(0.0, 0.0, 1.0));
         if (!splash->registerObject())
         {
            delete splash;
            splash = NULL;
         }

         // create an emitter for the particles out of water and the particles in water
         mParticleEmitter->emitParticles(rInfo.point, to, axis, vel, ms);
         mParticleWaterEmitter->emitParticles(from, rInfo.point, axis, vel, ms);
      }
   }
}


//----------------------------------------------------------------------------

class ObjectDeleteEvent : public SimEvent
{
public:
   void process(SimObject *object)
   {
      object->deleteObject();
   }
};

void Projectile::explode(const Point3F& p, const Point3F& n, const U32 collideType)
{
   // Make sure we don't explode twice...
   if (mHidden == true)
      return;

   mHidden = true;

   if (isServerObject()) {
      // Do what the server needs to do, damage the surrounding objects, etc.
      mExplosionPosition = p + (n*0.01);
      mExplosionNormal = n;
      mCollideHitType  = collideType;

      char buffer[128];
      dSprintf(buffer, sizeof(buffer),  "%g %g %g", mExplosionPosition.x,
                                                    mExplosionPosition.y,
                                                    mExplosionPosition.z);
      Con::executef(mDataBlock, 4, "onExplode", scriptThis(), buffer, Con::getFloatArg(mFadeValue));

      setMaskBits(ExplosionMask);
		Sim::postEvent(this, new ObjectDeleteEvent, Sim::getCurrentTime() + DeleteWaitTime);
   
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsClientObject
	} else {
#endif
      // Client just plays the explosion at the right place...
      //
      Explosion* pExplosion = NULL;

      if (mDataBlock->waterExplosion && pointInWater(p))
      {
         pExplosion = new Explosion;
         pExplosion->onNewDataBlock(mDataBlock->waterExplosion);
      }
      else
      if (mDataBlock->explosion)
      {
         pExplosion = new Explosion;
         pExplosion->onNewDataBlock(mDataBlock->explosion);
      }

      if( pExplosion )
      {
         MatrixF xform(true);
         xform.setPosition(p);
         pExplosion->setTransform(xform);
         pExplosion->setInitialState(p, n);
         pExplosion->setCollideType( collideType );
         if (pExplosion->registerObject() == false)
         {
            Con::errorf(ConsoleLogEntry::General, "Projectile(%s)::explode: couldn't register explosion",
                        mDataBlock->getName() );
            delete pExplosion;
            pExplosion = NULL;
         }

         if(mDataBlock->decalCount > 0)
         {
            if(collideType & (TerrainObjectType | InteriorObjectType))
            {
               // randomly choose a decal between 0 and (decal count - 1)
               U32 idx = (U32)(mCeil(mDataBlock->decalCount * Platform::getRandom()) - 1.0f);

               // this should never choose a NULL idx, but check anyway
               if(mDataBlock->decals[idx] != NULL)
               {
                  DecalManager *decalMngr = gClientSceneGraph->getCurrentDecalManager();
                  if(decalMngr)
                     decalMngr->addDecal(p, n, mDataBlock->decals[idx]);
               }
            }
         }
      }

      // Client object
      updateSound();
   }
   }

void Projectile::updateSound()
{
   if (!mDataBlock->sound)
      return;

   if (mHidden && mSoundHandle != NULL_AUDIOHANDLE)
   {
      alxStop(mSoundHandle);
      mSoundHandle = NULL_AUDIOHANDLE;
   }
   else if(!mHidden)
   {
      if (mSoundHandle == NULL_AUDIOHANDLE)
         mSoundHandle = alxPlay(mDataBlock->sound, &getRenderTransform(), &getPosition());
      alxSourceMatrixF(mSoundHandle, &getRenderTransform());
   }
}

Point3F Projectile::getVelocity() const
{
   return mCurrVelocity;
}

void Projectile::processTick(const Move* move)
{
   Parent::processTick(move);

   mCurrTick++;
   if(mSourceObject && mCurrTick > SourceIdTimeoutTicks)
   {
      mSourceObject = 0;
      mSourceObjectId = 0;
   }

   // See if we can get out of here the easy way ...
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsServerObject
   if (isServerObject() && mCurrTick >= mDataBlock->lifetime)
   {
      deleteObject();
      return;
   }
   else 
#endif
		if (mHidden == true)
      return;

   // ... otherwise, we have to do some simulation work.
   F32 timeLeft;
   RayInfo rInfo;
   Point3F oldPosition;
   Point3F newPosition;

   oldPosition = mCurrPosition;
   if(mDataBlock->isBallistic)
      mCurrVelocity.z -= 9.81 * mDataBlock->gravityMod * (F32(TickMs) / 1000.0f);

   newPosition = oldPosition + mCurrVelocity * (F32(TickMs) / 1000.0f);

   // disable the source objects collision reponse while we determine
   // if the projectile is capable of moving from the old position
   // to the new position, otherwise we'll hit ourself
   if (bool(mSourceObject))
      mSourceObject->disableCollision();

   // Determine if the projectile is going to hit any object between the previous
   // position and the new position. This code is executed both on the server
   // and on the client (for prediction purposes). It is possible that the server
   // will have registered a collision while the client prediction has not. If this
   // happens the client will be corrected in the next packet update.
   if (getContainer()->castRay(oldPosition, newPosition, csmDynamicCollisionMask | csmStaticCollisionMask, &rInfo) == true)
   {
      // make sure the client knows to bounce
      if(isServerObject() && (rInfo.object->getType() & csmStaticCollisionMask) == 0)
         setMaskBits(BounceMask);

      // Next order of business: do we explode on this hit?
      if(mCurrTick > mDataBlock->armingDelay)
      {
         MatrixF xform(true);
         xform.setColumn(3, rInfo.point);
         setTransform(xform);
         mCurrPosition    = rInfo.point;
         mCurrVelocity    = Point3F(0, 0, 0);

         // Get the object type before the onCollision call, in case
         // the object is destroyed.
         U32 objectType = rInfo.object->getType();

         // re-enable the collision response on the source object since
         // we need to process the onCollision and explode calls
         if(mSourceObject)
            mSourceObject->enableCollision();

         // Ok, here is how this works:
         // onCollision is called to notify the server scripts that a collision has occured, then
         // a call to explode is made to start the explosion process. The call to explode is made
         // twice, once on the server and once on the client.
         // The server process is responsible for two things:
         //    1) setting the ExplosionMask network bit to guarantee that the client calls explode
         //    2) initiate the explosion process on the server scripts
         // The client process is responsible for only one thing:
         //    1) drawing the appropriate explosion

         // It is possible that during the processTick the server may have decided that a hit
         // has occured while the client prediction has decided that a hit has not occured.
         // In this particular scenario the client will have failed to call onCollision and
         // explode during the processTick. However, the explode function will be called
         // during the next packet update, due to the ExplosionMask network bit being set.
         // onCollision will remain uncalled on the client however, therefore no client
         // specific code should be placed inside the function!
         onCollision(rInfo.point, rInfo.normal, rInfo.object);
         explode(rInfo.point, rInfo.normal, objectType );

         // break out of the collision check, since we've exploded
         // we dont want to mess with the position and velocity
      }
      else
      {
         if(mDataBlock->isBallistic)
         {
            // Otherwise, this represents a bounce.  First, reflect our velocity
            //  around the normal...
            Point3F bounceVel = mCurrVelocity - rInfo.normal * (mDot( mCurrVelocity, rInfo.normal ) * 2.0);;
            mCurrVelocity = bounceVel;

            // Add in surface friction...

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -