📄 projectile.cc
字号:
Point3F tangent = bounceVel - rInfo.normal * mDot(bounceVel, rInfo.normal);
mCurrVelocity -= tangent * mDataBlock->bounceFriction;
// Now, take elasticity into account for modulating the speed of the grenade
mCurrVelocity *= mDataBlock->bounceElasticity;
U32 timeLeft = 1.0 * (1.0 - rInfo.t);
oldPosition = rInfo.point + rInfo.normal * 0.05;
newPosition = oldPosition + (mCurrVelocity * ((timeLeft/1000.0) * TickMs));
}
}
}
// re-enable the collision response on the source object now
// that we are done processing the ballistic movment
if (bool(mSourceObject))
mSourceObject->enableCollision();
if(isClientObject())
{
emitParticles(mCurrPosition, newPosition, mCurrVelocity, TickMs);
updateSound();
}
mCurrDeltaBase = newPosition;
mCurrBackDelta = mCurrPosition - newPosition;
mCurrPosition = newPosition;
MatrixF xform(true);
xform.setColumn(3, mCurrPosition);
setTransform(xform);
}
void Projectile::advanceTime(F32 dt)
{
Parent::advanceTime(dt);
if (mHidden == true || dt == 0.0)
return;
if (mActivateThread &&
mProjectileShape->getDuration(mActivateThread) > mProjectileShape->getTime(mActivateThread) + dt)
{
mProjectileShape->advanceTime(dt, mActivateThread);
}
else
{
if (mMaintainThread)
{
mProjectileShape->advanceTime(dt, mMaintainThread);
}
else if (mActivateThread && mDataBlock->maintainSeq != -1)
{
mMaintainThread = mProjectileShape->addThread();
mProjectileShape->setTimeScale(mMaintainThread, 1);
mProjectileShape->setSequence(mMaintainThread, mDataBlock->maintainSeq, 0);
mProjectileShape->advanceTime(dt, mMaintainThread);
}
}
}
void Projectile::interpolateTick(F32 delta)
{
Parent::interpolateTick(delta);
if(mHidden == true)
return;
Point3F interpPos = mCurrDeltaBase + mCurrBackDelta * delta;
Point3F dir = mCurrVelocity;
if(dir.isZero())
dir.set(0,0,1);
else
dir.normalize();
MatrixF xform(true);
xform = MathUtils::createOrientFromDir(dir);
xform.setPosition(interpPos);
setRenderTransform(xform);
// fade out the projectile image
S32 time = (S32)(mCurrTick - delta);
if(time > mDataBlock->fadeDelay)
{
F32 fade = F32(time - mDataBlock->fadeDelay);
mFadeValue = 1.0 - (fade / F32(mDataBlock->lifetime));
}
else
mFadeValue = 1.0;
updateSound();
}
//--------------------------------------------------------------------------
void Projectile::onCollision(const Point3F& hitPosition, const Point3F& hitNormal, SceneObject* hitObject)
{
// No client specific code should be placed or branched from this function
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsClientObject
if(isClientObject())
return;
#endif
if (hitObject != NULL && isServerObject())
{
char *posArg = Con::getArgBuffer(64);
char *normalArg = Con::getArgBuffer(64);
dSprintf(posArg, 64, "%g %g %g", hitPosition.x, hitPosition.y, hitPosition.z);
dSprintf(normalArg, 64, "%g %g %g", hitNormal.x, hitNormal.y, hitNormal.z);
Con::executef(mDataBlock, 6, "onCollision",
scriptThis(),
Con::getIntArg(hitObject->getId()),
Con::getFloatArg(mFadeValue),
posArg,
normalArg);
}
}
//--------------------------------------------------------------------------
U32 Projectile::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
{
U32 retMask = Parent::packUpdate(con, mask, stream);
// Initial update
if (stream->writeFlag(mask & GameBase::InitialUpdateMask))
{
Point3F pos;
getTransform().getColumn(3, &pos);
stream->writeCompressedPoint(pos);
F32 len = mCurrVelocity.len();
if(stream->writeFlag(len > 0.02))
{
Point3F outVel = mCurrVelocity;
outVel *= 1 / len;
stream->writeNormalVector(outVel, 10);
len *= 32.0; // 5 bits for fraction
if(len > 8191)
len = 8191;
stream->writeInt((S32)len, 13);
}
stream->writeRangedU32(mCurrTick, 0, MaxLivingTicks);
if (bool(mSourceObject))
{
// Potentially have to write this to the client, let's make sure it has a
// ghost on the other side...
S32 ghostIndex = con->getGhostIndex(mSourceObject);
if (stream->writeFlag(ghostIndex != -1))
{
stream->writeRangedU32(U32(ghostIndex), 0, GhostConnection::MaxGhostCount);
stream->writeRangedU32(U32(mSourceObjectSlot),
0, ShapeBase::MaxMountedImages - 1);
}
else // havn't recieved the ghost for the source object yet, try again later
retMask |= GameBase::InitialUpdateMask;
}
else
stream->writeFlag(false);
}
// explosion update
if (stream->writeFlag((mask & ExplosionMask) && mHidden))
{
mathWrite(*stream, mExplosionPosition);
mathWrite(*stream, mExplosionNormal);
stream->write(mCollideHitType);
}
// bounce update
if (stream->writeFlag(mask & BounceMask))
{
// Bounce against dynamic object
mathWrite(*stream, mCurrPosition);
mathWrite(*stream, mCurrVelocity);
}
return retMask;
}
void Projectile::unpackUpdate(NetConnection* con, BitStream* stream)
{
Parent::unpackUpdate(con, stream);
// initial update
if (stream->readFlag())
{
Point3F pos;
stream->readCompressedPoint(&pos);
if(stream->readFlag())
{
stream->readNormalVector(&mCurrVelocity, 10);
mCurrVelocity *= stream->readInt(13) / 32.0f;
}
else
mCurrVelocity.set(0, 0, 0);
mCurrDeltaBase = pos;
mCurrBackDelta = mCurrPosition - pos;
mCurrPosition = pos;
setPosition(mCurrPosition);
mCurrTick = stream->readRangedU32(0, MaxLivingTicks);
if (stream->readFlag())
{
mSourceObjectId = stream->readRangedU32(0, GhostConnection::MaxGhostCount);
mSourceObjectSlot = stream->readRangedU32(0, ShapeBase::MaxMountedImages - 1);
NetObject* pObject = con->resolveGhost(mSourceObjectId);
if (pObject != NULL)
mSourceObject = dynamic_cast<ShapeBase*>(pObject);
}
else
{
mSourceObjectId = -1;
mSourceObjectSlot = -1;
mSourceObject = NULL;
}
}
// explosion update
if (stream->readFlag())
{
Point3F explodePoint;
Point3F explodeNormal;
mathRead(*stream, &explodePoint);
mathRead(*stream, &explodeNormal);
stream->read(&mCollideHitType);
// start the explosion visuals
explode(explodePoint, explodeNormal, mCollideHitType);
}
// bounce update
if (stream->readFlag())
{
mathRead(*stream, &mCurrPosition);
mathRead(*stream, &mCurrVelocity);
}
}
//--------------------------------------------------------------------------
void Projectile::prepModelView(SceneState* state)
{
Point3F targetVector;
if( mDataBlock->faceViewer )
{
targetVector = state->getCameraPosition() - getRenderPosition();
targetVector.normalize();
MatrixF explOrient = MathUtils::createOrientFromDir( targetVector );
explOrient.setPosition( getRenderPosition() );
dglMultMatrix( &explOrient );
}
else
{
dglMultMatrix( &getRenderTransform() );
}
}
//--------------------------------------------------------------------------
bool Projectile::prepRenderImage(SceneState* state, const U32 stateKey,
const U32 /*startZone*/, const bool /*modifyBaseState*/)
{
if (isLastState(state, stateKey))
return false;
setLastState(state, stateKey);
if (mHidden == true || mFadeValue <= (1.0/255.0))
return false;
// 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)) {
SceneRenderImage* image = new SceneRenderImage;
image->obj = this;
image->isTranslucent = true;
image->sortType = SceneRenderImage::Point;
state->setImageRefPoint(this, image);
// For projectiles, the datablock pointer is a good enough sort key, since they aren't
// skinned at all...
image->textureSortKey = (U32)(dsize_t)mDataBlock;
state->insertRenderImage(image);
}
return false;
}
static ColorF cubeColors[8] = {
ColorF(0, 0, 0), ColorF(1, 0, 0), ColorF(0, 1, 0), ColorF(0, 0, 1),
ColorF(1, 1, 0), ColorF(1, 0, 1), ColorF(0, 1, 1), ColorF(1, 1, 1)
};
static Point3F cubePoints[8] = {
Point3F(-1, -1, -1), Point3F(-1, -1, 1), Point3F(-1, 1, -1), Point3F(-1, 1, 1),
Point3F( 1, -1, -1), Point3F( 1, -1, 1), Point3F( 1, 1, -1), Point3F( 1, 1, 1)
};
static U32 cubeFaces[6][4] = {
{ 0, 2, 6, 4 }, { 0, 2, 3, 1 }, { 0, 1, 5, 4 },
{ 3, 2, 6, 7 }, { 7, 6, 4, 5 }, { 3, 7, 5, 1 }
};
static void wireCube(const Point3F& size, const Point3F& pos)
{
glDisable(GL_CULL_FACE);
for(int i = 0; i < 6; i++) {
glBegin(GL_LINE_LOOP);
for(int vert = 0; vert < 4; vert++) {
int idx = cubeFaces[i][vert];
glVertex3f(cubePoints[idx].x * size.x + pos.x, cubePoints[idx].y * size.y + pos.y, cubePoints[idx].z * size.z + pos.z);
}
glEnd();
}
}
void Projectile::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 );
glScalef( mDataBlock->scale.x, mDataBlock->scale.y, mDataBlock->scale.z );
if(mProjectileShape)
{
AssertFatal(mProjectileShape != NULL,
"Projectile::renderObject: Error, projectile shape should always be present in renderObject");
mProjectileShape->selectCurrentDetail();
mProjectileShape->animate();
Point3F cameraOffset;
mObjToWorld.getColumn(3,&cameraOffset);
cameraOffset -= state->getCameraPosition();
F32 fogAmount = state->getHazeAndFog(cameraOffset.len(),cameraOffset.z);
if (mFadeValue == 1.0)
{
mProjectileShape->setupFog(fogAmount, state->getFogColor());
}
else
{
mProjectileShape->setupFog(0.0, state->getFogColor());
mProjectileShape->setAlphaAlways(mFadeValue * (1.0 - fogAmount));
}
mProjectileShape->render();
}
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
dglSetViewport(viewport);
// Debugging Bounding Box
if (!mProjectileShape || gShowBoundingBox)
{
glDisable(GL_DEPTH_TEST);
Point3F box;
glPushMatrix();
dglMultMatrix(&getRenderTransform());
box = (mObjBox.min + mObjBox.max) * 0.5;
glTranslatef(box.x,box.y,box.z);
box = (mObjBox.max - mObjBox.min) * 0.5;
glScalef(box.x,box.y,box.z);
glColor3f(1, 0, 1);
wireCube(Point3F(1,1,1),Point3F(0,0,0));
glPopMatrix();
glPushMatrix();
box = (mWorldBox.min + mWorldBox.max) * 0.5;
glTranslatef(box.x,box.y,box.z);
box = (mWorldBox.max - mWorldBox.min) * 0.5;
glScalef(box.x,box.y,box.z);
glColor3f(0, 1, 1);
wireCube(Point3F(1,1,1),Point3F(0,0,0));
glPopMatrix();
glEnable(GL_DEPTH_TEST);
}
dglSetCanonicalState();
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
}
bool Projectile::pointInWater(const Point3F &point)
{
SimpleQueryList sql;
if (isServerObject())
gServerSceneGraph->getWaterObjectList(sql);
else
gClientSceneGraph->getWaterObjectList(sql);
for (U32 i = 0; i < sql.mList.size(); i++)
{
WaterBlock* pBlock = dynamic_cast<WaterBlock*>(sql.mList[i]);
if (pBlock && pBlock->isPointSubmergedSimple( point ))
return true;
}
return false;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -