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

📄 vehicle.cc

📁 五行MMORPG引擎系统V1.0
💻 CC
📖 第 1 页 / 共 4 页
字号:
      mSteering.x = 0;
      mSteering.y = 0;
   }

   // Jetting flag
   if (move->trigger[3]) {
      if (!mJetting && getEnergyLevel() >= mDataBlock->minJetEnergy)
         mJetting = true;
      if (mJetting) {
         F32 newEnergy = getEnergyLevel() - mDataBlock->jetEnergyDrain;
         if (newEnergy < 0) {
            newEnergy = 0;
            mJetting = false;
         }
         setEnergyLevel(newEnergy);
      }
   }
   else
      mJetting = false;
}


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

void Vehicle::setPosition(const Point3F& pos,const QuatF& rot)
{
   MatrixF mat;
   rot.setMatrix(&mat);
   mat.setColumn(3,pos);
   Parent::setTransform(mat);
}

void Vehicle::setRenderPosition(const Point3F& pos, const QuatF& rot)
{
   MatrixF mat;
   rot.setMatrix(&mat);
   mat.setColumn(3,pos);
   Parent::setRenderTransform(mat);
}

void Vehicle::setTransform(const MatrixF& newMat)
{
   mRigid.setTransform(newMat);
   Parent::setTransform(newMat);
   mRigid.atRest = false;
   mContacts.count = 0;
}


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

void Vehicle::disableCollision()
{
   Parent::disableCollision();
   for (ShapeBase* ptr = getMountList(); ptr; ptr = ptr->getMountLink())
      ptr->disableCollision();
}

void Vehicle::enableCollision()
{
   Parent::enableCollision();
   for (ShapeBase* ptr = getMountList(); ptr; ptr = ptr->getMountLink())
      ptr->enableCollision();
}


//----------------------------------------------------------------------------
/** Update the physics
*/

void Vehicle::updatePos(F32 dt)
{
   Point3F origVelocity = mRigid.linVelocity;

   // Update internal forces acting on the body.
   mRigid.clearForces();
   updateForces(dt);

   // Update collision information based on our current pos.
   bool collided = false;
   if (!mRigid.atRest) {
      collided = updateCollision(dt);

      // Now that all the forces have been processed, lets
      // see if we're at rest.  Basically, if the kinetic energy of
      // the vehicles is less than some percentage of the energy added
      // by gravity for a short period, we're considered at rest.
      // This should really be part of the rigid class...
      if (mCollisionList.count) {
         F32 k = mRigid.getKineticEnergy();
         F32 G = sVehicleGravity * dt;
         F32 Kg = 0.5 * mRigid.mass * G * G;
         if (k < sRestTol * Kg && ++restCount > sRestCount)
            mRigid.setAtRest();
      }
      else
         restCount = 0;
   }

   // Integrate forward
   if (!mRigid.atRest)
      mRigid.integrate(dt);



#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsServerObject 未处理...
#endif

   // Deal with client and server scripting, sounds, etc.
   if (isServerObject()) {

      // Check triggers and other objects that we normally don't
      // collide with.  This function must be called before notifyCollision
      // as it will queue collision.
      checkTriggers();

      // Invoke the onCollision notify callback for all the objects
      // we've just hit.
      notifyCollision();

      // Server side impact script callback
      if (collided) {
         VectorF collVec = mRigid.linVelocity - origVelocity;
         F32 collSpeed = collVec.len();
         if (collSpeed > mDataBlock->minImpactSpeed)
            onImpact(collVec);
      }

      // Water script callbacks
      if (!inLiquid && mWaterCoverage != 0.0f) {
         Con::executef(mDataBlock,4,"onEnterLiquid",scriptThis(), Con::getFloatArg(mWaterCoverage), Con::getIntArg(mLiquidType));
         inLiquid = true;
      }
      else if (inLiquid && mWaterCoverage == 0.0f) {
         Con::executef(mDataBlock,3,"onLeaveLiquid",scriptThis(), Con::getIntArg(mLiquidType));
         inLiquid = false;
      }

   }
   else {

      // Play impact sounds on the client.
      if (collided) {
         F32 collSpeed = (mRigid.linVelocity - origVelocity).len();
         S32 impactSound = -1;
         if (collSpeed >= mDataBlock->hardImpactSpeed)
            impactSound = VehicleData::Body::HardImpactSound;
         else
            if (collSpeed >= mDataBlock->softImpactSpeed)
               impactSound = VehicleData::Body::SoftImpactSound;

         if (impactSound != -1 && mDataBlock->body.sound[impactSound] != NULL)
            alxPlay(mDataBlock->body.sound[impactSound], &getTransform());
      }

      // Water volume sounds
      F32 vSpeed = getVelocity().len();
      if (!inLiquid && mWaterCoverage >= 0.8f) {
         if (vSpeed >= mDataBlock->hardSplashSoundVel)
            alxPlay(mDataBlock->waterSound[VehicleData::ImpactHard], &getTransform());
         else
            if (vSpeed >= mDataBlock->medSplashSoundVel)
               alxPlay(mDataBlock->waterSound[VehicleData::ImpactMedium], &getTransform());
         else
            if (vSpeed >= mDataBlock->softSplashSoundVel)
               alxPlay(mDataBlock->waterSound[VehicleData::ImpactSoft], &getTransform());
         inLiquid = true;
      }
      else
         if(inLiquid && mWaterCoverage < 0.8f) {
            if (vSpeed >= mDataBlock->exitSplashSoundVel)
               alxPlay(mDataBlock->waterSound[VehicleData::ExitWater], &getTransform());
         inLiquid = false;
      }
   }
}


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

void Vehicle::updateForces(F32 /*dt*/)
{
   // Nothing here.
}


//-----------------------------------------------------------------------------
/** Update collision information
   Update the convex state and check for collisions. If the object is in
   collision, impact and contact forces are generated.
*/

bool Vehicle::updateCollision(F32 dt)
{
   // Update collision information
   MatrixF mat,cmat;
   mConvex.transform = &mat;
   mRigid.getTransform(&mat);
   cmat = mConvex.getTransform();

   mCollisionList.count = 0;
   CollisionState *state = mConvex.findClosestState(cmat, getScale(), mDataBlock->collisionTol);
   if (state && state->dist <= mDataBlock->collisionTol) {
      //resolveDisplacement(ns,state,dt);
      mConvex.getCollisionInfo(cmat, getScale(), &mCollisionList, mDataBlock->collisionTol);
   }

   // Resolve collisions
   bool collided = resolveCollision(mRigid,mCollisionList);
   resolveContacts(mRigid,mCollisionList,dt);
   return collided;
}


//----------------------------------------------------------------------------
/** Resolve collision impacts
   Handle collision impacts, as opposed to contacts. Impulses are calculated based
   on standard collision resolution formulas.
*/
bool Vehicle::resolveCollision(Rigid&  ns,CollisionList& cList)
{
   // Apply impulses to resolve collision
   bool colliding, collided = false;

   do {
      colliding = false;
      for (S32 i = 0; i < cList.count; i++) {
         Collision& c = cList.collision[i];
         if (c.distance < mDataBlock->collisionTol) {
            // Velocity into surface
            Point3F v,r;
            ns.getOriginVector(c.point,&r);
            ns.getVelocity(r,&v);
            F32 vn = mDot(v,c.normal);

            // Only interested in velocities greater than sContactTol,
            // velocities less than that will be dealt with as contacts
            // "constraints".
            if (vn < -mDataBlock->contactTol) {

               // Apply impulses to the rigid body to keep it from
               // penetrating the surface.
               ns.resolveCollision(cList.collision[i].point,
                  cList.collision[i].normal);
               colliding = collided  = true;

               // Keep track of objects we collide with
#ifdef TGE_RPGCLIENT2 /// TGE_RPGIsClientObject
               if (c.object->getTypeMask() & ShapeBaseObjectType) 
#else
               if (!isGhost() && c.object->getTypeMask() & ShapeBaseObjectType) 
#endif
					{
                  ShapeBase* col = static_cast<ShapeBase*>(c.object);
                  queueCollision(col,v - col->getVelocity());
               }
            }
         }
      }
   } while (colliding);

   return collided;
}

//----------------------------------------------------------------------------
/** Resolve contact forces
   Resolve contact forces using the "penalty" method. Forces are generated based
   on the depth of penetration and the moment of inertia at the point of contact.
*/
bool Vehicle::resolveContacts(Rigid& ns,CollisionList& cList,F32 dt)
{
   // Use spring forces to manage contact constraints.
   bool collided = false;
   Point3F t,p(0,0,0),l(0,0,0);
   for (S32 i = 0; i < cList.count; i++) {
      Collision& c = cList.collision[i];
      if (c.distance < mDataBlock->collisionTol) {

         // Velocity into the surface
         Point3F v,r;
         ns.getOriginVector(c.point,&r);
         ns.getVelocity(r,&v);
         F32 vn = mDot(v,c.normal);

         // Only interested in velocities less than mDataBlock->contactTol,
         // velocities greater than that are dealt with as collisions.
         if (mFabs(vn) < mDataBlock->contactTol) {
            collided = true;

            // Penetration force. This is actually a spring which
            // will seperate the body from the collision surface.
            F32 zi = 2 * mFabs(mRigid.getZeroImpulse(r,c.normal));
            F32 s = (mDataBlock->collisionTol - c.distance) * zi - ((vn / mDataBlock->contactTol) * zi);
            Point3F f = c.normal * s;

            // Friction impulse, calculated as a function of the
            // amount of force it would take to stop the motion
            // perpendicular to the normal.
            Point3F uv = v - (c.normal * vn);
            F32 ul = uv.len();
            if (s > 0 && ul) {
               uv /= -ul;
               F32 u = ul * ns.getZeroImpulse(r,uv);
               s *= mRigid.friction;
               if (u > s)
                  u = s;
               f += uv * u;
            }

            // Accumulate forces
            p += f;
            mCross(r,f,&t);
            l += t;
         }
      }
   }

   // Contact constraint forces act over time...
   ns.linMomentum += p * dt;
   ns.angMomentum += l * dt;
   ns.updateVelocity();
   return true;
}


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

bool Vehicle::resolveDisplacement(Rigid& ns,CollisionState *state, F32 dt)
{
   SceneObject* obj = (state->a->getObject() == this)?
       state->b->getObject(): state->a->getObject();

   if (obj->isDisplacable() && ((obj->getTypeMask() & ShapeBaseObjectType) != 0))
   {
      // Try to displace the object by the amount we're trying to move
      Point3F objNewMom = ns.linVelocity * obj->getMass() * 1.1;
      Point3F objOldMom = obj->getMomentum();
      Point3F objNewVel = objNewMom / obj->getMass();

      Point3F myCenter;
      Point3F theirCenter;
      getWorldBox().getCenter(&myCenter);
      obj->getWorldBox().getCenter(&theirCenter);
      if (mDot(myCenter - theirCenter, objNewMom) >= 0.0f || objNewVel.len() < 0.01)
      {
         objNewMom = (theirCenter - myCenter);
         objNewMom.normalize();
         objNewMom *= 1.0f * obj->getMass();
         objNewVel = objNewMom / obj->getMass();
      }

      obj->setMomentum(objNewMom);
      if (obj->displaceObject(objNewVel * 1.1 * dt) == true)
      {
         // Queue collision and change in velocity
         VectorF dv = (objOldMom - objNewMom) / obj->getMass();
         queueCollision(static_cast<ShapeBase*>(obj), dv);
         return true;
      }
   }

   return false;
}


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

void Vehicle::updateWorkingCollisionSet(const U32 mask)
{
   // First, we need to adjust our velocity for possible acceleration.  It is assumed
   // that we will never accelerate more than 20 m/s for gravity, plus 30 m/s for
   // jetting, and an equivalent 10 m/s for vehicle accel.  We also assume that our
   // working list is updated on a Tick basis, which means we only expand our box by
   // the possible movement in that tick, plus some extra for caching purposes
   Box3F convexBox = mConvex.getBoundingBox(getTransform(), getScale());
   F32 len = (mRigid.linVelocity.len() + 50) * TickSec;
   F32 l = (len * 1.1) + 0.1;  // fudge factor
   convexBox.min -= Point3F(l, l, l);
   convexBox.max += Point3F(l, l, l);

   disableCollision();
   mConvex.updateWorkingList(convexBox, mask);
   enableCollision();
}


//----------------------------------------------------------------------------
/** Check collisions with trigger and items
   Perform a container search using the current bounding box
   of the main body, wheels are not included.  This method should
   only be called on the server.
*/
void Vehicle::checkTriggers()
{
   Box3F bbox = mConvex.getBoundingBox(getTransform(), getScale());
   gServerContainer.findObjects(bbox,sTriggerMask,findCallback,this);
}

/** The callback used in by the checkTriggers() method.
   The checkTriggers method uses a container search which will
   invoke this callback on each obj that matches.
*/
void Vehicle::findCallback(SceneObject* obj,void *key)
{
   Vehicle* vehicle = reinterpret_cast<Vehicle*>(key);
   U32 objectMask = obj->getTypeMask();

   // Check: triggers, corpses and items, basically the same things
   // that the player class checks for
   if (objectMask & TriggerObjectType) {
      Trigger* pTrigger = static_cast<Trigger*>(obj);
      pTrigger->potentialEnterObject(vehicle);
   }
   else if (objectMask & CorpseObjectType) {
      ShapeBase* col = static_cast<ShapeBase*>(obj);
      vehicle->queueCollision(col,vehicle->getVelocity() - col->getVelocity());
   }
   else if (objectMask & ItemObjectType) {
      Item* item = static_cast<Item*>(obj);
      if (vehicle != item->getCollisionObject())
         vehicle->queueCollision(item,vehicle->getVelocity() - item->getVelocity());
   }
}


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

void Vehicle::writePacketData(GameConnection *connection, BitStream *stream)

⌨️ 快捷键说明

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