📄 lightning.cc
字号:
pEvent->mStart.x = strikePoint.x;
pEvent->mStart.y = strikePoint.y;
pEvent->mTarget = targetObj;
nc->postNetEvent(pEvent);
}
}
//--------------------------------------------------------------------------
void Lightning::strikeObject(ShapeBase*)
{
AssertFatal(isServerObject(), "Error, client objects may not initiate lightning!");
AssertFatal(false, "Lightning::strikeObject is not implemented.");
}
//--------------------------------------------------------------------------
U32 Lightning::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
{
U32 retMask = Parent::packUpdate(con, mask, stream);
// Only write data if this is the initial packet or we've been inspected.
if (stream->writeFlag(mask & (InitialUpdateMask | ExtendedInfoMask)))
{
// Initial update
mathWrite(*stream, getPosition());
mathWrite(*stream, mObjScale);
stream->write(strikeWidth);
stream->write(chanceToHitTarget);
stream->write(strikeRadius);
stream->write(boltStartRadius);
stream->write(color.red);
stream->write(color.green);
stream->write(color.blue);
stream->write(fadeColor.red);
stream->write(fadeColor.green);
stream->write(fadeColor.blue);
stream->write(useFog);
stream->write(strikesPerMinute);
}
return retMask;
}
//--------------------------------------------------------------------------
void Lightning::unpackUpdate(NetConnection* con, BitStream* stream)
{
Parent::unpackUpdate(con, stream);
if (stream->readFlag())
{
// Initial update
Point3F pos;
mathRead(*stream, &pos);
setPosition( pos );
mathRead(*stream, &mObjScale);
stream->read(&strikeWidth);
stream->read(&chanceToHitTarget);
stream->read(&strikeRadius);
stream->read(&boltStartRadius);
stream->read(&color.red);
stream->read(&color.green);
stream->read(&color.blue);
stream->read(&fadeColor.red);
stream->read(&fadeColor.green);
stream->read(&fadeColor.blue);
stream->read(&useFog);
stream->read(&strikesPerMinute);
}
}
//--------------------------------------------------------------------------
void Lightning::applyDamage( const Point3F& hitPosition,
const Point3F& hitNormal,
SceneObject* hitObject)
{
#ifdef TGE_RPGCLIENT2 /// TGE_RPGIsClientObject
if (hitObject != NULL)
#else
if (!isClientObject() && hitObject != NULL)
#endif
{
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, 5, "applyDamage",
Con::getIntArg(getId()),
Con::getIntArg(hitObject->getId()),
posArg,
normalArg);
}
}
//**************************************************************************
// Lightning Bolt
//**************************************************************************
LightningBolt::LightningBolt()
{
width = 0.1;
startPoint.zero();
endPoint.zero();
chanceOfSplit = 0.0;
isFading = false;
elapsedTime = 0.0;
lifetime = 1.0;
startRender = false;
}
//--------------------------------------------------------------------------
// Destructor
//--------------------------------------------------------------------------
LightningBolt::~LightningBolt()
{
splitList.free();
}
//--------------------------------------------------------------------------
// Generate nodes
//--------------------------------------------------------------------------
void LightningBolt::NodeManager::generateNodes()
{
F32 overallDist = VectorF( endPoint - startPoint ).magnitudeSafe();
F32 minDistBetweenNodes = overallDist / (numNodes-1);
F32 maxDistBetweenNodes = minDistBetweenNodes / mCos( maxAngle * M_PI / 180.0 );
VectorF mainLineDir = endPoint - startPoint;
mainLineDir.normalizeSafe();
for( U32 i=0; i<numNodes; i++ )
{
Node node;
if( i == 0 )
{
node.point = startPoint;
node.dirToMainLine = mainLineDir;
nodeList[i] = node;
continue;
}
if( i == numNodes - 1 )
{
node.point = endPoint;
nodeList[i] = node;
break;
}
Node lastNode = nodeList[i-1];
F32 segmentLength = gRandGen.randF( minDistBetweenNodes, maxDistBetweenNodes );
VectorF segmentDir = MathUtils::randomDir( lastNode.dirToMainLine, 0, maxAngle );
node.point = lastNode.point + segmentDir * segmentLength;
node.dirToMainLine = endPoint - node.point;
node.dirToMainLine.normalizeSafe();
nodeList[i] = node;
}
}
//--------------------------------------------------------------------------
// Render bolt
//--------------------------------------------------------------------------
void LightningBolt::render( const Point3F &camPos )
{
if( !startRender )
{
return;
}
if( !isFading )
{
generateMinorNodes();
}
glBegin( GL_TRIANGLE_STRIP );
U32 i;
for( i=0; i<mMinorNodes.size(); i++ )
{
if( i+1 == mMinorNodes.size() )
{
renderSegment( mMinorNodes[i], camPos, true );
}
else
{
renderSegment( mMinorNodes[i], camPos, false );
}
}
glEnd();
LightningBolt *curBolt = NULL;
for( curBolt = splitList.next( curBolt ); curBolt; curBolt = splitList.next( curBolt ) )
{
if( isFading )
{
curBolt->isFading = true;
}
curBolt->render( camPos );
}
}
//--------------------------------------------------------------------------
// Render segment
//--------------------------------------------------------------------------
void LightningBolt::renderSegment( NodeManager &segment, const Point3F &camPos, bool renderLastPoint )
{
F32 totalLen = 0;
for( int i=0; i<segment.numNodes; i++ )
{
Point3F curPoint = segment.nodeList[i].point;
Point3F nextPoint;
Point3F segDir;
if( i == (segment.numNodes-1) )
{
if( renderLastPoint )
{
segDir = curPoint - segment.nodeList[i-1].point;
}
else
{
continue;
}
}
else
{
nextPoint = segment.nodeList[i+1].point;
segDir = nextPoint - curPoint;
}
totalLen = segDir.len();
segDir.normalizeSafe();
Point3F dirFromCam = curPoint - camPos;
Point3F crossVec;
mCross(dirFromCam, segDir, &crossVec);
crossVec.normalize();
crossVec *= width * 0.5;
glTexCoord2f( i, 1.0 );
glVertex3fv( curPoint - crossVec );
glTexCoord2f( i, 0.0 );
glVertex3fv( curPoint + crossVec );
}
}
//----------------------------------------------------------------------------
// Find height
//----------------------------------------------------------------------------
F32 LightningBolt::findHeight( Point3F &point, SceneGraph *sceneManager )
{
TerrainBlock* pTerrain = sceneManager->getCurrentTerrain();
if( !pTerrain ) return 0.0;
Point3F terrPt = point;
pTerrain->getWorldTransform().mulP(terrPt);
F32 h;
if (pTerrain->getHeight(Point2F(terrPt.x, terrPt.y), &h))
{
return h;
}
return 0.0;
}
//----------------------------------------------------------------------------
// Generate lightning bolt
//----------------------------------------------------------------------------
void LightningBolt::generate()
{
mMajorNodes.startPoint = startPoint;
mMajorNodes.endPoint = endPoint;
mMajorNodes.numNodes = numMajorNodes;
mMajorNodes.maxAngle = maxMajorAngle;
mMajorNodes.generateNodes();
generateMinorNodes();
}
//----------------------------------------------------------------------------
// Generate Minor Nodes
//----------------------------------------------------------------------------
void LightningBolt::generateMinorNodes()
{
mMinorNodes.clear();
for( int i=0; i<mMajorNodes.numNodes - 1; i++ )
{
NodeManager segment;
segment.startPoint = mMajorNodes.nodeList[i].point;
segment.endPoint = mMajorNodes.nodeList[i+1].point;
segment.numNodes = numMinorNodes;
segment.maxAngle = maxMinorAngle;
segment.generateNodes();
mMinorNodes.increment(1);
mMinorNodes[i] = segment;
}
}
//----------------------------------------------------------------------------
// Recursive algo to create bolts that split off from main bolt
//----------------------------------------------------------------------------
void LightningBolt::createSplit( Point3F startPoint, Point3F endPoint, U32 depth, F32 width )
{
if( depth == 0 ) return;
F32 chanceToEnd = gRandGen.randF();
if( chanceToEnd > 0.70 ) return;
if( width < 0.75 ) width = 0.75;
VectorF diff = endPoint - startPoint;
F32 length = diff.len();
diff.normalizeSafe();
LightningBolt newBolt;
newBolt.startPoint = startPoint;
newBolt.endPoint = endPoint;
newBolt.width = width;
newBolt.numMajorNodes = 3;
newBolt.maxMajorAngle = 30;
newBolt.numMinorNodes = 3;
newBolt.maxMinorAngle = 10;
newBolt.startRender = true;
newBolt.generate();
splitList.link( newBolt );
VectorF newDir1 = MathUtils::randomDir( diff, 10.0, 45.0 );
Point3F newEndPoint1 = endPoint + newDir1 * gRandGen.randF( 0.5, 1.5 ) * length;
VectorF newDir2 = MathUtils::randomDir( diff, 10.0, 45.0 );
Point3F newEndPoint2 = endPoint + newDir2 * gRandGen.randF( 0.5, 1.5 ) * length;
createSplit( endPoint, newEndPoint1, depth - 1, width * 0.30 );
createSplit( endPoint, newEndPoint2, depth - 1, width * 0.30 );
}
//----------------------------------------------------------------------------
// Start split - kick off the recursive 'createSplit' procedure
//----------------------------------------------------------------------------
void LightningBolt::startSplits()
{
for( U32 i=0; i<mMajorNodes.numNodes-1; i++ )
{
if( gRandGen.randF() > 0.3 ) continue;
Node node = mMajorNodes.nodeList[i];
Node node2 = mMajorNodes.nodeList[i+1];
VectorF segDir = node2.point - node.point;
F32 length = segDir.len();
segDir.normalizeSafe();
VectorF newDir = MathUtils::randomDir( segDir, 20.0, 40.0 );
Point3F newEndPoint = node.point + newDir * gRandGen.randF( 0.5, 1.5 ) * length;
createSplit( node.point, newEndPoint, 4, width * 0.30 );
}
}
//----------------------------------------------------------------------------
// Update
//----------------------------------------------------------------------------
void LightningBolt::update( F32 dt )
{
elapsedTime += dt;
F32 percentDone = elapsedTime / lifetime;
if( elapsedTime > fadeTime )
{
isFading = true;
percentFade = percentDone + (fadeTime/lifetime);
}
if( elapsedTime > renderTime && !startRender )
{
startRender = true;
isFading = false;
elapsedTime = 0.0;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -