📄 explosion.cc
字号:
}
void Explosion::onRemove()
{
for( int i=0; i<ExplosionData::EC_NUM_EMITTERS; i++ )
{
if( mEmitterList[i] )
{
mEmitterList[i]->deleteWhenEmpty();
mEmitterList[i] = NULL;
}
}
if (mSceneManager != NULL)
mSceneManager->removeObjectFromScene(this);
if (getContainer() != NULL)
getContainer()->removeObject(this);
Parent::onRemove();
}
bool Explosion::onNewDataBlock(GameBaseData* dptr)
{
mDataBlock = dynamic_cast<ExplosionData*>(dptr);
if (!mDataBlock || !Parent::onNewDataBlock(dptr))
return false;
scriptOnNewDataBlock();
return true;
}
//--------------------------------------------------------------------------
bool Explosion::prepRenderImage(SceneState* state, const U32 stateKey,
const U32 /*startZone*/, const bool /*modifyBaseState*/)
{
if (isLastState(state, stateKey))
return false;
setLastState(state, stateKey);
// This should be sufficient for most objects that don't manage zones, and
// don't need to return a specialized RenderImage...
if (state->isObjectRendered(this))
{
Point3F explosionPos;
mObjToWorld.getColumn(3,&explosionPos);
if (mExplosionInstance)
{
Point3F cameraOffset = explosionPos - state->getCameraPosition();
mFog = state->getHazeAndFog(cameraOffset.len(),cameraOffset.z);
}
else
{
mFog = 0.0;
}
SceneRenderImage* image = new SceneRenderImage;
image->obj = this;
image->isTranslucent = true;
image->sortType = SceneRenderImage::Point;
image->textureSortKey = (U32)(dsize_t)mDataBlock;
state->setImageRefPoint(this, image);
state->insertRenderImage(image);
}
return false;
}
void Explosion::setCurrentScale()
{
F32 t = F32(mCurrMS) / F32(mEndingMS);
for( U32 i = 1; i < ExplosionData::EC_NUM_TIME_KEYS; i++ )
{
if( mDataBlock->times[i] >= t )
{
F32 firstPart = t - mDataBlock->times[i-1];
F32 total = mDataBlock->times[i] -
mDataBlock->times[i-1];
firstPart /= total;
mObjScale = (mDataBlock->sizes[i-1] * (1.0 - firstPart)) +
(mDataBlock->sizes[i] * firstPart);
return;
}
}
}
void Explosion::prepModelView(SceneState* state)
{
MatrixF rotMatrix( true );
Point3F targetVector;
if (mDataBlock->faceViewer == true)
{
targetVector = getPosition() - state->getCameraPosition();
targetVector.normalize();
rotMatrix.set( EulerF( 0.0, mRandAngle, 0.0 ) );
}
else
{
targetVector = mInitialNormal;
}
// rotate explosion each time so it's a little different
MatrixF explOrient = MathUtils::createOrientFromDir( targetVector );
explOrient.mul( rotMatrix );
explOrient.setPosition( getPosition() );
dglMultMatrix( &explOrient );
setCurrentScale();
glScalef(mObjScale.x, mObjScale.y, mObjScale.z);
}
void Explosion::renderObject(SceneState* state, SceneRenderImage*)
{
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
RectI viewport;
glMatrixMode(GL_PROJECTION);
glPushMatrix();
dglGetViewport(&viewport);
// Uncomment this if this is a "simple" (non-zone managing) object
state->setupObjectProjection(this);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
prepModelView(state);
if( mExplosionInstance )
{
mExplosionInstance->animate();
if (mFade == 1.0)
{
mExplosionInstance->setupFog(mFog, state->getFogColor());
}
else
{
mExplosionInstance->setupFog(0.0, state->getFogColor());
mExplosionInstance->setAlphaAlways(mFade * (1.0 - mFog));
}
mExplosionInstance->render();
}
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glScalef( 1.0, 1.0, 1.0 );
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
dglSetViewport(viewport);
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
}
//--------------------------------------------------------------------------
void Explosion::registerLights(LightManager * lightManager, bool lightingScene)
{
if (lightingScene)
return;
// Update the light's info and add it to the scene, the light will
// only be visible for this current frame.
getRenderTransform().getColumn(3, &mLight.mPos);
F32 t = F32(mCurrMS) / F32(mEndingMS);
mLight.mRadius = mDataBlock->lightStartRadius +
(mDataBlock->lightEndRadius - mDataBlock->lightStartRadius) * t;
mLight.mColor = mDataBlock->lightStartColor +
(mDataBlock->lightEndColor - mDataBlock->lightStartColor) * t;
lightManager->addLight(&mLight);
}
//--------------------------------------------------------------------------
void Explosion::processTick(const Move*)
{
mCurrMS += TickMs;
if( mCurrMS >= mEndingMS )
deleteObject();
if( (mCurrMS > mDelayMS) && !mActive )
explode();
}
void Explosion::advanceTime(F32 dt)
{
if (dt == 0.0)
return;
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsServerObject
if(!isServerObject())
return;
#endif
updateEmitters( dt );
if( mExplosionInstance )
mExplosionInstance->advanceTime(dt, mExplosionThread);
}
//----------------------------------------------------------------------------
// Update emitters
//----------------------------------------------------------------------------
void Explosion::updateEmitters( F32 dt )
{
Point3F pos = getPosition();
for( int i=0; i<ExplosionData::EC_NUM_EMITTERS; i++ )
{
if( mEmitterList[i] )
{
mEmitterList[i]->emitParticles( pos, pos, mInitialNormal, Point3F( 0.0, 0.0, 0.0 ), (U32)(dt * 1000));
}
}
}
//----------------------------------------------------------------------------
// Launch Debris
//----------------------------------------------------------------------------
void Explosion::launchDebris( Point3F &axis )
{
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsServerObject
if(!isServerObject())
return;
#endif
bool hasDebris = false;
for( int j=0; j<ExplosionData::EC_NUM_DEBRIS_TYPES; j++ )
{
if( mDataBlock->debrisList[j] )
{
hasDebris = true;
break;
}
}
if( !hasDebris )
{
return;
}
Point3F axisx;
if (mFabs(axis.z) < 0.999f)
mCross(axis, Point3F(0, 0, 1), &axisx);
else
mCross(axis, Point3F(0, 1, 0), &axisx);
axisx.normalize();
Point3F pos = getPosition() + Point3F( 0.0, 0.0, 0.5 );
U32 numDebris = mDataBlock->debrisNum + sgRandom.randI( -mDataBlock->debrisNumVariance, mDataBlock->debrisNumVariance );
for( int i=0; i<numDebris; i++ )
{
Point3F launchDir = MathUtils::randomDir( axis, mDataBlock->debrisThetaMin, mDataBlock->debrisThetaMax,
mDataBlock->debrisPhiMin, mDataBlock->debrisPhiMax );
F32 debrisVel = mDataBlock->debrisVelocity + mDataBlock->debrisVelocityVariance * sgRandom.randF( -1.0, 1.0 );
launchDir *= debrisVel;
Debris *debris = new Debris;
debris->setDataBlock( mDataBlock->debrisList[0] );
debris->setTransform( getTransform() );
debris->init( pos, launchDir );
if( !debris->registerObject() )
{
Con::warnf( ConsoleLogEntry::General, "Could not register debris for class: %s", mDataBlock->getName() );
delete debris;
debris = NULL;
}
}
}
//----------------------------------------------------------------------------
// Spawn sub explosions
//----------------------------------------------------------------------------
void Explosion::spawnSubExplosions()
{
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsServerObject
if(!isServerObject())
return;
#endif
for( S32 i=0; i<ExplosionData::EC_MAX_SUB_EXPLOSIONS; i++ )
{
if( mDataBlock->explosionList[i] )
{
MatrixF trans = getTransform();
Explosion* pExplosion = new Explosion;
pExplosion->setDataBlock( mDataBlock->explosionList[i] );
pExplosion->setTransform( trans );
pExplosion->setInitialState( trans.getPosition(), mInitialNormal, 1);
if (!pExplosion->registerObject())
delete pExplosion;
}
}
}
//----------------------------------------------------------------------------
// Explode
//----------------------------------------------------------------------------
bool Explosion::explode()
{
mActive = true;
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsServerObject
if(!isServerObject())
return true;
#endif
launchDebris( mInitialNormal );
spawnSubExplosions();
if (bool(mDataBlock->explosionShape) && mDataBlock->explosionAnimation != -1)
{
mExplosionInstance = new TSShapeInstance(mDataBlock->explosionShape, true);
mExplosionThread = mExplosionInstance->addThread();
mExplosionInstance->setSequence(mExplosionThread, mDataBlock->explosionAnimation, 0);
mExplosionInstance->setTimeScale(mExplosionThread, mDataBlock->playSpeed);
mCurrMS = 0;
mEndingMS = U32(mExplosionInstance->getScaledDuration(mExplosionThread) * 1000.0f);
mObjScale.convolve(mDataBlock->explosionScale);
mObjBox = mDataBlock->explosionShape->bounds;
resetWorldBox();
}
if (mDataBlock->soundProfile)
alxPlay(mDataBlock->soundProfile, &getTransform() );
if (mDataBlock->particleEmitter)
{
ParticleEmitter* emitter = new ParticleEmitter;
emitter->setDataBlock(mDataBlock->particleEmitter);
emitter->registerObject();
emitter->emitParticles(getPosition(), mInitialNormal, mDataBlock->particleRadius,
Point3F(0, 0, 0), U32(mDataBlock->particleDensity * mFade));
emitter->deleteWhenEmpty();
}
for( int i=0; i<ExplosionData::EC_NUM_EMITTERS; i++ )
{
if( mDataBlock->emitterList[i] != NULL )
{
ParticleEmitter * pEmitter = new ParticleEmitter;
pEmitter->setDataBlock( mDataBlock->emitterList[i] );
if( !pEmitter->registerObject() )
{
Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() );
SAFE_DELETE(pEmitter);
}
mEmitterList[i] = pEmitter;
}
}
return true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -