EnergyProjectile for TGEA 1.8.1+
by CdnGater · 05/03/2009 (6:50 am) · 38 comments
This is a first cut at a generic EnergyProjectile that is flexible enough to provide a number of different effects. Just drop the code into the T3D directory in the source, compile and then play with it. Configuring this to be used is like configuring any other weapon, except use EnergyProjectile instead of just the standard Porjectile.
Edit: I did not like the way the beams were being rendered. This way it much better. Also added a screenshot, nothing fancy just to show a blaster effect.
#include "console/consoleTypes.h"
#include "core/stream/bitStream.h"
#include "sceneGraph/sceneState.h"
#include "sceneGraph/sceneGraph.h"
#include "T3D/shapeBase.h"
#include "ts/tsShapeInstance.h"
#include "gfx/primBuilder.h"
#include "gfx/gfxDevice.h"
#include "gfx/gfxTransformSaver.h"
#include "math/mRandom.h"
#include "math/mathIO.h"
#include "math/mathUtils.h"
#include "renderInstance/renderPassManager.h"
#include "T3D/projectile.h"
class ExplosionData;
class ShapeBase;
class TSShapeInstance;
class TSThread;
//--------------------------------------------------------------------------
class EnergyProjectileData : public ProjectileData
{
typedef ProjectileData Parent;
public:
bool beamEnabled;
bool beamPulse;
F32 beamStartRadius;
F32 beamMidRadius;
F32 beamEndRadius;
F32 beamFrontSegmentLength;
F32 beamBackSegmentLength;
StringTableEntry beamMaterialList;
bool sparkEnabled;
StringTableEntry sparkMaterialList;
F32 sparkRadius;
F32 sparkStep;
F32 sparkRotationStep;
S32 interval;
EnergyProjectileData();
void packData(BitStream*);
void unpackData(BitStream*);
static void initPersistFields();
DECLARE_CONOBJECT(EnergyProjectileData);
};
DECLARE_CONSOLETYPE(EnergyProjectileData)
//--------------------------------------------------------------------------
class EnergyProjectile : public Projectile
{
typedef Projectile Parent;
EnergyProjectileData* mDataBlock;
protected:
GFXTexHandle mBeamTextureHandles[20];
MaterialList mBeamMaterialList;
GFXTexHandle mSparkTextureHandles[20];
MaterialList mSparkMaterialList;
S32 mBeamNumTextures;
S32 mBeamIndex;
S32 mSparkNumTextures;
S32 mSparkIndex;
F32 mSparkRadius;
S32 mLastTime;
F32 mRange;
F32 mSparkRotation;
Point3F mEndPosition;
Point3F mMuzzlePosition;
Point3F mMuzzleVector;
Point3F mMuzzleVelocity;
void loadDml();
bool onAdd();
bool onNewDataBlock(GameBaseData*);
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *conn, BitStream *stream);
void processTick(const Move* move);
bool prepRenderImage(SceneState*, const U32, const U32, const bool);
void renderObject(ObjectRenderInst *ri, BaseMatInstance*);
void RenderBeamSegment( Point3F pStart, Point3F pEnd, F32 startRadius, F32 endRadius, F32 vStart, F32 vEnd );
GFXStateBlockRef mBlendInvSrcAlphaSB;
GFXStateBlockRef mBlendSB;
ObjectRenderInst::RenderDelegate mRenderDelegate;
public:
static void initPersistFields();
EnergyProjectile();
~EnergyProjectile();
DECLARE_CONOBJECT(EnergyProjectile);
};
IMPLEMENT_CO_DATABLOCK_V1(EnergyProjectileData);
IMPLEMENT_CO_NETOBJECT_V1(EnergyProjectile);
//--------------------------------------------------------------------------
//
EnergyProjectileData::EnergyProjectileData()
{
ProjectileData::ProjectileData();
beamEnabled = false;
beamPulse = true;
beamStartRadius = 0.0;
beamMidRadius = 0.0;
beamEndRadius = 0.0;
beamFrontSegmentLength = 0.0;
beamBackSegmentLength = 0.0;
beamMaterialList = NULL;
sparkEnabled = false;
sparkMaterialList = NULL;
sparkRadius = 0.0;
sparkStep = 0.0;
sparkRotationStep = 0.0f;
interval = 0;
}
//--------------------------------------------------------------------------
IMPLEMENT_CONSOLETYPE(EnergyProjectileData)
IMPLEMENT_GETDATATYPE(EnergyProjectileData)
IMPLEMENT_SETDATATYPE(EnergyProjectileData)
void EnergyProjectileData::initPersistFields()
{
Parent::initPersistFields();
addNamedField(beamEnabled, TypeBool, EnergyProjectileData);
addNamedField(beamPulse, TypeBool, EnergyProjectileData);
addNamedField(beamStartRadius, TypeF32, EnergyProjectileData);
addNamedField(beamMidRadius, TypeF32, EnergyProjectileData);
addNamedField(beamEndRadius, TypeF32, EnergyProjectileData);
addNamedField(beamFrontSegmentLength, TypeF32, EnergyProjectileData);
addNamedField(beamBackSegmentLength, TypeF32, EnergyProjectileData);
addNamedField(beamMaterialList, TypeFilename, EnergyProjectileData);
addNamedField(sparkEnabled, TypeBool, EnergyProjectileData);
addNamedField(sparkMaterialList, TypeFilename, EnergyProjectileData);
addNamedField(sparkRadius, TypeF32, EnergyProjectileData);
addNamedField(sparkStep, TypeF32, EnergyProjectileData);
addNamedField(sparkRotationStep, TypeF32, EnergyProjectileData);
addNamedField(interval, TypeS32, EnergyProjectileData);
}
//--------------------------------------------------------------------------
void EnergyProjectileData::packData(BitStream* stream)
{
Parent::packData(stream);
stream->writeFlag(beamEnabled);
stream->writeFlag(beamPulse);
stream->writeFloat(beamStartRadius/20.0, 8);
stream->writeFloat(beamMidRadius/20.0, 8);
stream->writeFloat(beamEndRadius/20.0, 8);
stream->writeFloat(beamFrontSegmentLength/20.0, 8);
stream->writeFloat(beamBackSegmentLength/20.0, 8);
stream->writeString(beamMaterialList);
stream->writeFlag(sparkEnabled);
stream->writeString(sparkMaterialList);
stream->writeFloat(sparkRadius/20.0, 8);
stream->writeFloat(sparkStep, 8);
stream->writeFloat(sparkRotationStep, 8);
stream->writeInt(interval, 32);
}
void EnergyProjectileData::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
beamEnabled = stream->readFlag();
beamPulse = stream->readFlag();
beamStartRadius = stream->readFloat(8) * 20;
beamMidRadius = stream->readFloat(8) * 20;
beamEndRadius = stream->readFloat(8) * 20;
beamFrontSegmentLength = stream->readFloat(8) * 20;
beamBackSegmentLength = stream->readFloat(8) * 20;
beamMaterialList = StringTable->insert(stream->readSTString());
sparkEnabled = stream->readFlag();
sparkMaterialList = StringTable->insert(stream->readSTString());
sparkRadius = stream->readFloat(8) * 20;
sparkStep = stream->readFloat(8);
sparkRotationStep = stream->readFloat(8);
interval = stream->readInt(32);
}
//--------------------------------------------------------------------------
EnergyProjectile::EnergyProjectile()
{
mLastTime = 0;
mBeamIndex = 0;
mSparkIndex = 0;
mSparkRadius = 0.0;
mSparkRotation = 0.0;
mRange = 0;
mRenderDelegate.bind(this, &EnergyProjectile::renderObject);
}
EnergyProjectile::~EnergyProjectile()
{
}
//--------------------------------------------------------------------------
void EnergyProjectile::initPersistFields()
{
Parent::initPersistFields();
addField("range", TypeF32, Offset(mRange, EnergyProjectile));
}
//--------------------------------------------------------------------------
U32 EnergyProjectile::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
{
U32 retMask = Parent::packUpdate(con, mask, stream);
if (stream->writeFlag(mask & GameBase::InitialUpdateMask))
{
// Initial update
stream->write(mRange);
}
return retMask;
}
void EnergyProjectile::unpackUpdate(NetConnection* con, BitStream* stream)
{
Parent::unpackUpdate(con, stream);
if (stream->readFlag())
{
// initial update
stream->read(&mRange);
}
}
//--------------------------------------------------------------------------
void EnergyProjectile::loadDml()
{
S32 x;
mBeamNumTextures = 0;
mSparkNumTextures = 0;
FileStream *stream = NULL;
if (mDataBlock->beamEnabled && mDataBlock->beamMaterialList[0])
{
stream = FileStream::createAndOpen( mDataBlock->beamMaterialList, Torque::FS::File::Read );
if(stream)
{
char path[1024], *p;
dStrcpy(path, mDataBlock->beamMaterialList);
if ((p = dStrrchr(path, '/')) != NULL)
*p = 0;
mBeamMaterialList.read(*stream);
stream->close();
delete stream;
mBeamMaterialList.load(path);
for(x = 0; x < mBeamMaterialList.size(); ++x, ++mBeamNumTextures)
mBeamTextureHandles[x] = mBeamMaterialList.getMaterial(x);
}
}
if (mDataBlock->sparkEnabled && mDataBlock->sparkMaterialList[0])
{
stream = FileStream::createAndOpen( mDataBlock->sparkMaterialList, Torque::FS::File::Read );
if(stream)
{
char path[1024], *p;
dStrcpy(path, mDataBlock->sparkMaterialList);
if ((p = dStrrchr(path, '/')) != NULL)
*p = 0;
mSparkMaterialList.read(*stream);
stream->close();
delete stream;
mSparkMaterialList.load(path);
for(x = 0; x < mSparkMaterialList.size(); ++x, ++mSparkNumTextures)
mSparkTextureHandles[x] = mSparkMaterialList.getMaterial(x);
}
}
}
//--------------------------------------------------------------------------
bool EnergyProjectile::onAdd()
{
if(!Parent::onAdd())
return false;
if (!isServerObject())
{
loadDml();
mSparkRadius = mDataBlock->sparkRadius;
mMuzzlePosition = mInitialPosition;
mMuzzleVelocity = mCurrVelocity;
}
return true;
}
bool EnergyProjectile::onNewDataBlock(GameBaseData* dptr)
{
mDataBlock = dynamic_cast<EnergyProjectileData*>(dptr);
if (!mDataBlock || !Parent::onNewDataBlock(dptr))
return false;
return true;
}
void EnergyProjectile::processTick(const Move* move)
{
GameBase::processTick(move);
mCurrTick++;
// See if we can get out of here the easy way ...
if (isServerObject() && mCurrTick >= mDataBlock->lifetime)
{
deleteObject();
return;
}
else if (mHidden == true)
return;
if (mDataBlock->beamEnabled && mDataBlock->beamPulse)
{
if (mSourceObject)
{
MatrixF muzzleTrans;
mSourceObject->getMuzzleTransform(mSourceObjectSlot, &muzzleTrans);
muzzleTrans.getColumn(3, &mMuzzlePosition);
muzzleTrans.getColumn(1, &mMuzzleVector);
mEndPosition = mMuzzleVector * mRange;
mEndPosition += mMuzzlePosition;
mSourceObject->disableCollision();
RayInfo rInfo;
if (getContainer()->castRay(mMuzzlePosition, mEndPosition, csmDynamicCollisionMask | csmStaticCollisionMask, &rInfo) == true)
{
mEndPosition = rInfo.point;
}
mSourceObject->enableCollision();
mMuzzleVelocity = mMuzzleVector * mDataBlock->muzzleVelocity;;
}
mCurrPosition = mMuzzlePosition + mMuzzleVelocity * (F32(mCurrTick) * (F32(TickMs) / 1000.0f));
mCurrVelocity = mMuzzleVelocity;
}
// ... otherwise, we have to do some simulation work.
RayInfo rInfo;
Point3F oldPosition;
Point3F newPosition;
oldPosition = mCurrPosition;
newPosition = oldPosition + mCurrVelocity * (F32(TickMs) / 1000.0f);
if (bool(mSourceObject))
mSourceObject->disableCollision();
if (getContainer()->castRay(oldPosition, newPosition, csmDynamicCollisionMask | csmStaticCollisionMask, &rInfo) == true)
{
if(isServerObject() && (rInfo.object->getType() & csmStaticCollisionMask) == 0)
setMaskBits(BounceMask);
if(mCurrTick > mDataBlock->armingDelay)
{
MatrixF xform(true);
xform.setColumn(3, rInfo.point);
setTransform(xform);
mCurrPosition = rInfo.point;
mCurrVelocity = Point3F(0, 0, 0);
U32 objectType = rInfo.object->getType();
if(mSourceObject)
mSourceObject->enableCollision();
onCollision(rInfo.point, rInfo.normal, rInfo.object);
explode(rInfo.point, rInfo.normal, objectType );
}
else
{
if(mDataBlock->isBallistic)
{
Point3F bounceVel = mCurrVelocity - rInfo.normal * (mDot( mCurrVelocity, rInfo.normal ) * 2.0);;
mCurrVelocity = bounceVel;
Point3F tangent = bounceVel - rInfo.normal * mDot(bounceVel, rInfo.normal);
mCurrVelocity -= tangent * mDataBlock->bounceFriction;
mCurrVelocity *= mDataBlock->bounceElasticity;
F32 timeLeft = 1.0f - rInfo.t;
oldPosition = rInfo.point + rInfo.normal * 0.05f;
newPosition = oldPosition + (mCurrVelocity * ((timeLeft/1000.0f) * TickMs));
}
}
}
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);
}
//--------------------------------------------------------------------------
bool EnergyProjectile::prepRenderImage(SceneState* state, const U32 stateKey,
const U32 /*startZone*/, const bool /*modifyBaseState*/)
{
// Return if last state.
if (isLastState(state, stateKey)) return false;
// Set Last State.
setLastState(state, stateKey);
if (mHidden == true || mFadeValue <= (1.0/255.0))
return false;
// Is Object Rendered?
if (state->isObjectRendered(this))
{
ObjectRenderInst *ri = gRenderInstManager->allocInst<ObjectRenderInst>();
ri->mRenderDelegate = mRenderDelegate;
ri->state = state;
ri->type = RenderPassManager::RIT_ObjectTranslucent;
ri->translucent = true;
ri->calcSortPoint(this, state->getCameraPosition());
gRenderInstManager->addInst( ri );
}
return false;
}
void EnergyProjectile::renderObject(ObjectRenderInst *ri, BaseMatInstance* overrideMat)
{
SceneState* state = ri->state;
MatrixF projection = GFX->getProjectionMatrix();
RectI viewport = GFX->getViewport();
GFX->setViewport(viewport);
GFX->setProjectionMatrix(projection);
// set up the graphics
if (mBlendInvSrcAlphaSB.isNull())
{
GFXStateBlockDesc desc;
desc.setCullMode( GFXCullNone );
desc.setZEnable(false);
desc.zWriteEnable = false;
desc.samplersDefined = true;
desc.samplers[0].textureColorOp = GFXTOPModulate;
desc.samplers[1].textureColorOp = GFXTOPDisable;
desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
mBlendInvSrcAlphaSB = GFX->createStateBlock(desc);
desc.samplers[0].textureColorOp = GFXTOPDisable;
mBlendSB = GFX->createStateBlock(desc);
}
GFX->setStateBlock(mBlendInvSrcAlphaSB);
S32 thisTime = Sim::getCurrentTime();
S32 timeDelta = thisTime - mLastTime;
if (timeDelta > mDataBlock->interval)
{
if (mBeamNumTextures > 0)
{
mBeamIndex ++;
if (mBeamIndex >= mBeamNumTextures)
mBeamIndex = 0;
}
if (mSparkNumTextures > 0)
{
mSparkIndex ++;
if (mSparkIndex >= mSparkNumTextures)
mSparkIndex = 0;
}
mSparkRadius += mDataBlock->sparkStep;
mSparkRotation += mDataBlock->sparkRotationStep;
mLastTime = thisTime;
}
// Select the objects' texture.
GFX->disableShaders();
GFX->setupGenericShaders( GFXDevice::GSModColorTexture );
if (mDataBlock->beamEnabled && mBeamNumTextures > 0)
{
// Set Colour/Alpha.
GFX->setTexture(0, mBeamTextureHandles[mBeamIndex]);
if (mDataBlock->beamPulse)
{
RenderBeamSegment(mMuzzlePosition, mCurrPosition, mDataBlock->beamStartRadius, mDataBlock->beamMidRadius, 0.0, 0.5 );
RenderBeamSegment(mCurrPosition, mEndPosition, mDataBlock->beamMidRadius, mDataBlock->beamEndRadius, 0.5, 1.0 );
}
else
{
Point3F dirV = mCurrVelocity;
dirV.normalize();
F32 clientDist = (mInitialPosition - mCurrPosition).len();
F32 beamFrontLength = mDataBlock->beamFrontSegmentLength;
if (beamFrontLength > clientDist)
beamFrontLength = clientDist;
F32 beamBackLength = mDataBlock->beamBackSegmentLength;
if (beamBackLength > clientDist)
beamBackLength = clientDist;
Point3F posFrontMod = dirV * beamFrontLength;
Point3F posBackMod = dirV * beamBackLength;
RenderBeamSegment(mCurrPosition - posBackMod, mCurrPosition, mDataBlock->beamStartRadius, mDataBlock->beamMidRadius, 0.0, 0.5 );
RenderBeamSegment(mCurrPosition, mCurrPosition + posFrontMod, mDataBlock->beamMidRadius, mDataBlock->beamEndRadius, 0.5, 1.0 );
}
}
if (mDataBlock->sparkEnabled && mSparkNumTextures > 0 && mSparkRadius > 0.0f)
{
// Initialize points with basic info
Point3F points[4];
points[0] = Point3F(-mSparkRadius, 0.0, -mSparkRadius);
points[1] = Point3F( mSparkRadius, 0.0, -mSparkRadius);
points[2] = Point3F( mSparkRadius, 0.0, mSparkRadius);
points[3] = Point3F(-mSparkRadius, 0.0, mSparkRadius);
GFX->setTexture(0, mSparkTextureHandles[mSparkIndex]);
// Get info we need to adjust points
MatrixF camView = GFX->getWorldMatrix();
camView.transpose();
F32 sy, cy;
mSinCos(mDegToRad(mSparkRotation), sy, cy);
// Finalize points
for(int i = 0; i < 4; i++)
{
// rotate
points[i].set(cy * points[i].x - sy * points[i].z, 0.0, sy * points[i].x + cy * points[i].z);
// align with camera
camView.mulP(points[i]);
// offset
points[i] += mCurrPosition;
}
PrimBuild::color4f(1,1,1,1);
PrimBuild::begin( GFXTriangleFan, 4 );
PrimBuild::texCoord2f(0, 0);
PrimBuild::vertex3fv(points[0]);
PrimBuild::texCoord2f(1, 0);
PrimBuild::vertex3fv(points[1]);
PrimBuild::texCoord2f(1, 1);
PrimBuild::vertex3fv(points[2]);
PrimBuild::texCoord2f(0, 1);
PrimBuild::vertex3fv(points[3]);
PrimBuild::end();
}
GFX->disableShaders();
}
void EnergyProjectile::RenderBeamSegment( Point3F pStart, Point3F pEnd, F32 startRadius, F32 endRadius, F32 vStart, F32 vEnd )
{
Point3F dirV = mCurrVelocity;
dirV.normalize();
MatrixF orient = MathUtils::createOrientFromDir( dirV );
Point3F sPt1, sPt2, ePt1, ePt2;
PrimBuild::color4f(1,1,1,1);
{
sPt1 = Point3F(startRadius,0,0);
sPt2 = Point3F(-startRadius,0,0);
orient.mulV( sPt1 );
sPt1 += pStart;
orient.mulV( sPt2 );
sPt2 += pStart;
ePt1 = Point3F(endRadius,0,0);
ePt2 = Point3F(-endRadius,0,0);
orient.mulV( ePt1 );
ePt1 += pEnd;
orient.mulV( ePt2 );
ePt2 += pEnd;
PrimBuild::begin(GFXTriangleFan, 4);
PrimBuild::texCoord2f(0, vStart);
PrimBuild::vertex3f(sPt1.x, sPt1.y, sPt1.z);
PrimBuild::texCoord2f(1, vStart);
PrimBuild::vertex3f(sPt2.x, sPt2.y, sPt2.z);
PrimBuild::texCoord2f(1, vEnd);
PrimBuild::vertex3f(ePt2.x, ePt2.y, ePt2.z);
PrimBuild::texCoord2f(0, vEnd);
PrimBuild::vertex3f(ePt1.x, ePt1.y, ePt1.z);
PrimBuild::end();
}
{
sPt1 = Point3F(0,0,startRadius);
sPt2 = Point3F(0,0,-startRadius);
orient.mulV( sPt1 );
sPt1 += pStart;
orient.mulV( sPt2 );
sPt2 += pStart;
ePt1 = Point3F(0,0,endRadius);
ePt2 = Point3F(0,0,-endRadius);
orient.mulV( ePt1 );
ePt1 += pEnd;
orient.mulV( ePt2 );
ePt2 += pEnd;
PrimBuild::begin(GFXTriangleFan, 4);
PrimBuild::texCoord2f(0, vStart);
PrimBuild::vertex3f(sPt1.x, sPt1.y, sPt1.z);
PrimBuild::texCoord2f(1, vStart);
PrimBuild::vertex3f(sPt2.x, sPt2.y, sPt2.z);
PrimBuild::texCoord2f(1, vEnd);
PrimBuild::vertex3f(ePt2.x, ePt2.y, ePt2.z);
PrimBuild::texCoord2f(0, vEnd);
PrimBuild::vertex3f(ePt1.x, ePt1.y, ePt1.z);
PrimBuild::end();
}
{
sPt1 = Point3F(startRadius,0,startRadius);
sPt2 = Point3F(-startRadius,0,-startRadius);
orient.mulV( sPt1 );
sPt1 += pStart;
orient.mulV( sPt2 );
sPt2 += pStart;
ePt1 = Point3F(endRadius,0,endRadius);
ePt2 = Point3F(-endRadius,0,-endRadius);
orient.mulV( ePt1 );
ePt1 += pEnd;
orient.mulV( ePt2 );
ePt2 += pEnd;
PrimBuild::begin(GFXTriangleFan, 4);
PrimBuild::texCoord2f(0, vStart);
PrimBuild::vertex3f(sPt1.x, sPt1.y, sPt1.z);
PrimBuild::texCoord2f(1, vStart);
PrimBuild::vertex3f(sPt2.x, sPt2.y, sPt2.z);
PrimBuild::texCoord2f(1, vEnd);
PrimBuild::vertex3f(ePt2.x, ePt2.y, ePt2.z);
PrimBuild::texCoord2f(0, vEnd);
PrimBuild::vertex3f(ePt1.x, ePt1.y, ePt1.z);
PrimBuild::end();
}
{
sPt1 = Point3F(startRadius,0,-startRadius);
sPt2 = Point3F(-startRadius,0,startRadius);
orient.mulV( sPt1 );
sPt1 += pStart;
orient.mulV( sPt2 );
sPt2 += pStart;
ePt1 = Point3F(endRadius,0,-endRadius);
ePt2 = Point3F(-endRadius,0,endRadius);
orient.mulV( ePt1 );
ePt1 += pEnd;
orient.mulV( ePt2 );
ePt2 += pEnd;
PrimBuild::begin(GFXTriangleFan, 4);
PrimBuild::texCoord2f(0, vStart);
PrimBuild::vertex3f(sPt1.x, sPt1.y, sPt1.z);
PrimBuild::texCoord2f(1, vStart);
PrimBuild::vertex3f(sPt2.x, sPt2.y, sPt2.z);
PrimBuild::texCoord2f(1, vEnd);
PrimBuild::vertex3f(ePt2.x, ePt2.y, ePt2.z);
PrimBuild::texCoord2f(0, vEnd);
PrimBuild::vertex3f(ePt1.x, ePt1.y, ePt1.z);
PrimBuild::end();
}
}Edit: I did not like the way the beams were being rendered. This way it much better. Also added a screenshot, nothing fancy just to show a blaster effect.
About the author
#23
05/06/2009 (6:11 pm)
The thin blue line I mentioned is due to me using the energy.png from the swarmgun as I had indicated and nothing to do with the emitters.
#24
05/06/2009 (6:16 pm)
Here it is:datablock ShapeBaseImageData(Gun_1aImage)
{
// Basic Item properties
shapeFile = "~/data/shapes/weapons/Gun_1a/swarmgun.dts";
emap = true;
// Specify mount point & offset for 3rd person, and eye offset
// for first person rendering.
mountPoint = 0;
firstPerson = false;
offset = "0 0.25 0";
eyeOffset = "0.45 0.55 -0.5";
// The model may be backwards
// rotation = "0.0 0.0 1.0 180.0";
// eyeRotation = "0.0 0.0 1.0 180.0";
// When firing from a point offset from the eye, muzzle correction
// will adjust the muzzle vector to point to the eye LOS point.
// Since this weapon doesn't actually fire from the muzzle point,
// we need to turn this off.
correctMuzzleVector = true;
// Add the WeaponImage namespace as a parent, WeaponImage namespace
// provides some hooks into the inventory system.
className = "WeaponImage";
// Projectile && Ammo.
item = Gun_1a;
ammo = Gun_1aAmmo;
projectile = Gun_1aProjectile;
projectileType = EnergyProjectile;
casing = Gun_1aShell;
shellExitDir = "1.0 0.3 1.0";
shellExitOffset = "0.15 -0.56 -0.1";
shellExitVariance = 15.0;
shellVelocity = 3.0;
// Images have a state system which controls how the animations
// are run, which sounds are played, script callbacks, etc. This
// state system is downloaded to the client so that clients can
// predict state changes and animate accordingly. The following
// system supports basic ready->fire->reload transitions as
// well as a no-ammo->dryfire idle state.
// Initial start up state
stateName[0] = "Preactivate";
stateTransitionOnLoaded[0] = "Activate";
stateTransitionOnNoAmmo[0] = "NoAmmo";
// Activating the gun. Called when the weapon is first
// mounted and there is ammo.
stateName[1] = "Activate";
stateTransitionOnTimeout[1] = "Ready";
stateTimeoutValue[1] = 0.5;
stateSequence[1] = "Activate";
// Ready to fire, just waiting for the trigger
stateName[2] = "Ready";
stateTransitionOnNoAmmo[2] = "NoAmmo";
stateTransitionOnTriggerDown[2] = "Fire";
// Fire the weapon. Calls the fire script which does
// the actual work.
stateName[3] = "Fire";
stateTransitionOnTimeout[3] = "Reload";
stateTimeoutValue[3] = 0.2;
stateFire[3] = true;
stateRecoil[3] = LightRecoil;
stateAllowImageChange[3] = false;
stateSequence[3] = "Fire";
stateScript[3] = "onFire";
//stateEmitter[3] = Gun_1aFireEmitter;
//stateEmitterTime[3] = 0.3;
stateSound[3] = Gun_1aFireSound;
// Play the relead animation, and transition into
stateName[4] = "Reload";
stateTransitionOnNoAmmo[4] = "NoAmmo";
stateTransitionOnTimeout[4] = "Ready";
stateTimeoutValue[4] = 0.2;
stateAllowImageChange[4] = false;
stateSequence[4] = "Reload";
stateEjectShell[4] = true;
stateSound[4] = Gun_1aReloadSound;
// No ammo in the weapon, just idle until something
// shows up. Play the dry fire sound if the trigger is
// pulled.
stateName[5] = "NoAmmo";
stateTransitionOnAmmo[5] = "Reload";
stateSequence[5] = "NoAmmo";
stateTransitionOnTriggerDown[5] = "DryFire";
// No ammo dry fire
stateName[6] = "DryFire";
stateTimeoutValue[6] = 0.2;
stateTransitionOnTimeout[6] = "NoAmmo";
stateScript[6] = "onDryFire";
};
#25
Lasers can't fire without ammo ;)
try changing
to
Assuming you still have the orginal SwarmGun still there, or give yourself some of the Gun_1aAmmo.
My lasers still need ammo and use clips of power to fire.
05/06/2009 (6:21 pm)
Humm, do you have any Ammo ? Gun_1aAmmoLasers can't fire without ammo ;)
try changing
ammo = Gun_1aAmmo;
to
ammo = RocketLauncherAmmo;
Assuming you still have the orginal SwarmGun still there, or give yourself some of the Gun_1aAmmo.
My lasers still need ammo and use clips of power to fire.
#26
And I can confirm the weapon is firing and destroying objects in my level, just cant see the projectile at all
Oh, I unequip the previous weapon first through console:
$player.unmountimage(0)
05/06/2009 (6:34 pm)
I'm using this to equip the weapon:function armHGa() // Development function. Arms the target player with this weapon in mount 0, gives ammo (doesn't deplete currently)
{ // For testing purposes.
// mount the weapon
$player.mountImage( Gun_1aImage, 0 );
// give some ammo
$player.setImageAmmo( 0, true );
}And I can confirm the weapon is firing and destroying objects in my level, just cant see the projectile at all
Oh, I unequip the previous weapon first through console:
$player.unmountimage(0)
#27
Lets try from the top again.
Can you get yourself a new copy of TGEA 1.8.1 and install it?
Create the file T3D/EnergyProjectile.cpp and copy the stuff I posted.
Make the appropriot changes to the Projectile class.
Now open the template project and compile
Get the red_beam.png and red.dml from the resource I linked and put them in TGEA_1_8_1/Projects/Template/Game/ScriptsAndAssets/Data/Shapes/Weapons/Laserbeam
Now open the the file
TGEA_1_8_1/Projects/Template/Game/ScriptsAndAssets/Server/scripts/weapons/SwarmGun.cs
Look for datablock EnergyProjectileData(RocketLauncherProjectile) and make it to look like the following
Scroll Down to datablock ShapeBaseImageData(RocketLauncherImage)
change
to look like
Once done, go to TGEA_1_8_1/Projects/Template/Game and run the newly created EXE, if you compiled in debug, Template_DEBUG.exe
Thats all the changes I did to a stock TGEA 1.8.1 and it worked. Does this work for you?
Had another thought, your on windows? or Mac?
PS. You wont see the projectile, but its used for collision. You should be seeing beams though, and why your not, is confusing.
05/06/2009 (6:55 pm)
Ok, I am at a loss then.Lets try from the top again.
Can you get yourself a new copy of TGEA 1.8.1 and install it?
Create the file T3D/EnergyProjectile.cpp and copy the stuff I posted.
Make the appropriot changes to the Projectile class.
Now open the template project and compile
Get the red_beam.png and red.dml from the resource I linked and put them in TGEA_1_8_1/Projects/Template/Game/ScriptsAndAssets/Data/Shapes/Weapons/Laserbeam
Now open the the file
TGEA_1_8_1/Projects/Template/Game/ScriptsAndAssets/Server/scripts/weapons/SwarmGun.cs
Look for datablock EnergyProjectileData(RocketLauncherProjectile) and make it to look like the following
datablock EnergyProjectileData(RocketLauncherProjectile)
{
projectileShapeName = "~/data/shapes/weapons/SwarmGun/rocket.dts";
directDamage = 20;
radiusDamage = 20;
damageRadius = 5;
areaImpulse = 2000;
explosion = RocketExplosion;
particleEmitter = RocketEmitter;
muzzleVelocity = 100;
velInheritFactor = 1;
armingDelay = 0;
lifetime = 6000;
fadeDelay = 1500;
bounceElasticity = 0;
bounceFriction = 0;
isBallistic = true;
gravityMod = 0.10;
hasLight = true;
lightRadius = 4.0;
lightColor = "0.5 0.5 0";
beamEnabled = true;
beamPulse = true;
beamStartRadius = 0.2;
beamMidRadius = 0.3;
beamEndRadius = 0.2;
beamFrontSegmentLength = 5;
beamBackSegmentLength = 10;
beamMaterialList = "~/data/shapes/weapons/laserbeam/red.dml";
sparkEnabled = false;
sparkMaterialList = "~/data/shapes/weapons/laserbeam/spark.dml";
sparkRadius = 0.3;
sparkStep = 0.0;
sparkRotationStep = 0.0;
interval = 5;
};Scroll Down to datablock ShapeBaseImageData(RocketLauncherImage)
change
projectileType = Projectile;
to look like
projectileType = EnergyProjectile;
Once done, go to TGEA_1_8_1/Projects/Template/Game and run the newly created EXE, if you compiled in debug, Template_DEBUG.exe
Thats all the changes I did to a stock TGEA 1.8.1 and it worked. Does this work for you?
Had another thought, your on windows? or Mac?
PS. You wont see the projectile, but its used for collision. You should be seeing beams though, and why your not, is confusing.
#28
I guess I am completely at a loss as well...
BTW:
Rather than redo the EnergyProjectile.cpp, projectile.cpp, and projectile.h, I simply used the ones I made early from the one that was NOT working, and it DID work, so the problem is NOT with those 3 files...
05/06/2009 (7:22 pm)
Hmmmm that works perfectly...I guess I am completely at a loss as well...
BTW:
Rather than redo the EnergyProjectile.cpp, projectile.cpp, and projectile.h, I simply used the ones I made early from the one that was NOT working, and it DID work, so the problem is NOT with those 3 files...
#29
The only thing I can think of, in your original project is to add some debug logging.
Around line 460 in EnergyProjectile, find
add
Around line 527 in EnergyProjectile, look for
add
Run your app, and see if you see those messages.
Otherwise, without getting your full sourcecode and app so I can debug it, I don't think there is any more I can do as it works in stock TGEA 1.8.1.
05/06/2009 (7:38 pm)
That is good to know.The only thing I can think of, in your original project is to add some debug logging.
Around line 460 in EnergyProjectile, find
ObjectRenderInst *ri = gRenderInstManager->allocInst<ObjectRenderInst>();
add
Con::printf("** Queue Laser Render Object ** ");
ObjectRenderInst *ri = gRenderInstManager->allocInst<ObjectRenderInst>();Around line 527 in EnergyProjectile, look for
if (mDataBlock->beamEnabled && mBeamNumTextures > 0)
add
Con::printf("** Laser Render %d %d **",mDataBlock->beamEnabled, mBeamNumTextures ); // Note, should probably display 1 1 for the values
if (mDataBlock->beamEnabled && mBeamNumTextures > 0)Run your app, and see if you see those messages.
Otherwise, without getting your full sourcecode and app so I can debug it, I don't think there is any more I can do as it works in stock TGEA 1.8.1.
#30
Now I just need to merge in my code 1 line at a time to see when it breaks....
Oh, and even though I am using the red laser beam, I am getting a white beam in my game...
When I ran it in the Template project, it was indeed red... The weird part is that I used the swarmgun.cs from the working Template project with the red beam to make my new one, so I don't see why it's coming out white...
But hey, I got the gun in the game! :)
05/06/2009 (7:44 pm)
Well, I got it down to my weapon's .cs file. I completely replaced it with the default swarmgun.cs, added in your changes, and it is now working in my game. :)Now I just need to merge in my code 1 line at a time to see when it breaks....
Oh, and even though I am using the red laser beam, I am getting a white beam in my game...
When I ran it in the Template project, it was indeed red... The weird part is that I used the swarmgun.cs from the working Template project with the red beam to make my new one, so I don't see why it's coming out white...
But hey, I got the gun in the game! :)
#31
1. The rendering cuts out when shooting objects at close range.
2. The muzzle point/start of the rendering should probably move with the position of the muzzle. In other words, doing a side step doesn't leave a floating render if you have more than one image in the dml.
Just a couple of suggestions. The second one should be very easy to fix, not sure about the first though. I am probably going to try to do it on my end so if I get there first I will share.
05/06/2009 (11:12 pm)
Well I got it to work but made a couple of observations that probably need fixed.1. The rendering cuts out when shooting objects at close range.
2. The muzzle point/start of the rendering should probably move with the position of the muzzle. In other words, doing a side step doesn't leave a floating render if you have more than one image in the dml.
Just a couple of suggestions. The second one should be very easy to fix, not sure about the first though. I am probably going to try to do it on my end so if I get there first I will share.
#32
Don't forget:
Change:
datablock ProjectileData(Gun_1Projectile)
To:
datablock EnergyProjectileData(Gun_1Projectile)
LOL!!
So I am getting this to work with all my guns now... no idea why it wouldn't work yesterday.
Last problem then:
I am using the red_beam.png and red.dml from that laser resource, but my beam is white... any ideas?
05/07/2009 (8:13 am)
EDITED:Don't forget:
Change:
datablock ProjectileData(Gun_1Projectile)
To:
datablock EnergyProjectileData(Gun_1Projectile)
LOL!!
So I am getting this to work with all my guns now... no idea why it wouldn't work yesterday.
Last problem then:
I am using the red_beam.png and red.dml from that laser resource, but my beam is white... any ideas?
#33
05/11/2009 (7:43 am)
Seems like the beam type should overload the collision method and do a simple ray cast from the muzzle point . . . I like them being derived from projectile so we can just load them into weapons, but maybe EnergyBeam should be a new projectile type that handles collisions and rendering differently?
#34
05/11/2009 (7:47 am)
sorry to be rude. Nice work BTW!
#35
08/26/2009 (11:29 pm)
Simon, I have integrated this into my Enhanced Projectiles system so it could use all of the things I added with that resource and of course with my version which is far more updated than the original there are even more options. What I wanted to ask is if you would mind me releasing my new version of my resource with my integrated version of yours combined?
#36
Go right ahead, glad someone else has gotten something out of it and enhanced it even more.
08/26/2009 (11:39 pm)
Go right ahead, glad someone else has gotten something out of it and enhanced it even more.
#37
01/18/2012 (10:11 am)
I ported this to T3D 1.2 today, I will be looking at posting a new resource with this file.
#38
01/18/2012 (7:34 pm)
Preview of the weapon in action using the energyProjectile in T3D 1.2, resource pending.
Torque 3D Owner Nicolai Dutka
//particleEmitter = Gun_1aEmitter;
I did that and my entire projectile completely disappeared. Your code should be creating the 'beam' without using an emitter, so that line shouldn't be needed...