Steve_Yorkshire Posted April 5, 2016 Share Posted April 5, 2016 Projectiles are a little boring having only one explosion and if you want to use an animated particle sprite sheet or an explosion model it's going to get even more repetitive.Here's the general idea, the projectile has up to 4 explosion datablocks instead of 1. On exploding the projectile looks up how many explosion datablocks in can reference and then randomly chooses one. If it can't find any additional explosions it will default to the single stock one. Obviously you can do the same with water explosions, but ehre I'm only using dirt/dry explosions.I am currently in "art mode" so here's a -**warning of terrible C++ ahead** - feel free to expand on the idea and make it less horrible.First up, add new datablocks and information for explosions to the projectile. Here I am using the stock projectile in art/datablocks/Lurker.cs. This requires adding new particles and emitters, as well as editing the stock BulletDirtExplosion emitters to make it easier to see. //... datablock ParticleData(BulletDirtDust) { textureName = "art/particles/impact"; dragCoefficient = "1"; gravityCoefficient = "-0.100122"; windCoefficient = 0; inheritedVelFactor = 0.0; constantAcceleration = "-0.83"; lifetimeMS = 800; lifetimeVarianceMS = 300; spinRandomMin = -180.0; spinRandomMax = 180.0; useInvAlpha = true; colors[0] = "0.496063 0.393701 0.299213 0.692913"; colors[1] = "0.692913 0.614173 0.535433 0.346457"; colors[2] = "0.897638 0.84252 0.795276 0"; sizes[0] = "0.997986"; sizes[1] = "2"; sizes[2] = "2.5"; times[0] = 0.0; times[1] = "0.498039"; times[2] = 1.0; animTexName = "art/particles/impact"; }; datablock ParticleEmitterData(BulletDirtDustEmitter) { ejectionPeriodMS = 20; periodVarianceMS = 10; ejectionVelocity = "1"; velocityVariance = 1.0; thetaMin = 0.0; thetaMax = 180.0; lifetimeMS = 250; particles = "BulletDirtDust"; blendStyle = "ADDITIVE";//yorks "NORMAL"; }; //yorks start datablock ParticleData(BulletDirtDust1) { textureName = "art/particles/impact"; dragCoefficient = "1"; gravityCoefficient = "-0.1"; windCoefficient = 0; inheritedVelFactor = 0.0; constantAcceleration = "-0.83"; lifetimeMS = 800; lifetimeVarianceMS = 300; spinRandomMin = -180.0; spinRandomMax = 180.0; useInvAlpha = true; colors[0] = "1 0 0 0"; colors[1] = "1 0 0.0 0.5"; colors[2] = "1 0 0.0 0"; sizes[0] = "1"; sizes[1] = "2"; sizes[2] = "2.5"; times[0] = 0.0; times[1] = "0.5"; times[2] = 1.0; animTexName = "art/particles/impact"; }; datablock ParticleEmitterData(BulletDirtDust1Emitter) { ejectionPeriodMS = 20; periodVarianceMS = 10; ejectionVelocity = "1"; velocityVariance = 1.0; thetaMin = 0.0; thetaMax = 180.0; lifetimeMS = 250; particles = "BulletDirtDust1"; blendStyle = "ADDITIVE"; }; datablock ParticleData(BulletDirtDust2) { textureName = "art/particles/impact"; dragCoefficient = "1"; gravityCoefficient = "-0.1"; windCoefficient = 0; inheritedVelFactor = 0.0; constantAcceleration = "-0.83"; lifetimeMS = 800; lifetimeVarianceMS = 300; spinRandomMin = -180.0; spinRandomMax = 180.0; useInvAlpha = true; colors[0] = "0.0 0.0 1 1"; colors[1] = "0.0 0.0 1 0.5"; colors[2] = "0.0 0.0 1 0"; sizes[0] = "1"; sizes[1] = "2"; sizes[2] = "3"; times[0] = 0.0; times[1] = "0.5"; times[2] = 1.0; animTexName = "art/particles/impact"; }; datablock ParticleEmitterData(BulletDirtDust2Emitter) { ejectionPeriodMS = 20; periodVarianceMS = 10; ejectionVelocity = "1"; velocityVariance = 1.0; thetaMin = 0.0; thetaMax = 180.0; lifetimeMS = 250; particles = "BulletDirtDust2"; blendStyle = "ADDITIVE"; }; datablock ParticleData(BulletDirtDust3) { textureName = "art/particles/impact"; dragCoefficient = "1"; gravityCoefficient = "-0.1"; windCoefficient = 0; inheritedVelFactor = 0.0; constantAcceleration = "-0.83"; lifetimeMS = 800; lifetimeVarianceMS = 300; spinRandomMin = -180.0; spinRandomMax = 180.0; useInvAlpha = true; colors[0] = "0.0 1 0 1"; colors[1] = "0.0 1 0 0.5"; colors[2] = "0.0 1 0 0"; sizes[0] = "1"; sizes[1] = "2"; sizes[2] = "3"; times[0] = 0.0; times[1] = "0.5"; times[2] = 1.0; animTexName = "art/particles/impact"; }; datablock ParticleEmitterData(BulletDirtDust3Emitter) { ejectionPeriodMS = 20; periodVarianceMS = 10; ejectionVelocity = "1"; velocityVariance = 1.0; thetaMin = 0.0; thetaMax = 180.0; lifetimeMS = 250; particles = "BulletDirtDust3"; blendStyle = "ADDITIVE"; }; //yorks end //----------------------------------------------------------------------------- // Explosion //----------------------------------------------------------------------------- datablock ExplosionData(BulletDirtExplosion) { soundProfile = BulletImpactSound; lifeTimeMS = 65; // Volume particles particleEmitter = BulletDirtDustEmitter; particleDensity = 4; particleRadius = 0.3; //yorks start /* // Point emission emitter[0] = BulletDirtSprayEmitter; emitter[1] = BulletDirtSprayEmitter; emitter[2] = BulletDirtRocksEmitter; */ // Point emission emitter[0] = BulletDirtDustEmitter; emitter[1] = BulletDirtDustEmitter; emitter[2] = BulletDirtDustEmitter; //yorks end }; //yorks start datablock ExplosionData(BulletDirtExplosion1) { soundProfile = BulletImpactSound; lifeTimeMS = 65; // Volume particles particleEmitter = BulletDirtDust1Emitter; particleDensity = 4; particleRadius = 0.3; // Point emission emitter[0] = BulletDirtDust1Emitter; emitter[1] = BulletDirtDust1Emitter; emitter[2] = BulletDirtDust1Emitter; }; datablock ExplosionData(BulletDirtExplosion2) { soundProfile = BulletImpactSound; lifeTimeMS = 65; // Volume particles particleEmitter = BulletDirtDust2Emitter; particleDensity = 4; particleRadius = 0.3; // Point emission emitter[0] = BulletDirtDust2Emitter; emitter[1] = BulletDirtDust2Emitter; emitter[2] = BulletDirtDust2Emitter; }; datablock ExplosionData(BulletDirtExplosion3) { soundProfile = BulletImpactSound; lifeTimeMS = 65; // Volume particles particleEmitter = BulletDirtDust3Emitter; particleDensity = 4; particleRadius = 0.3; // Point emission emitter[0] = BulletDirtDust3Emitter; emitter[1] = BulletDirtDust3Emitter; emitter[2] = BulletDirtDust3Emitter; }; //yorks end //... datablock ProjectileData( BulletProjectile ) { projectileShapeName = ""; directDamage = 5; radiusDamage = 0; damageRadius = 0.5; areaImpulse = 0.5; impactForce = 1; explosion = BulletDirtExplosion; decal = BulletHoleDecal; //yorks start explosion1 = BulletDirtExplosion1; explosion2 = BulletDirtExplosion2; explosion3 = BulletDirtExplosion3; //yorks end muzzleVelocity = 120; velInheritFactor = 1; armingDelay = 0; lifetime = 992; fadeDelay = 1472; bounceElasticity = 0; bounceFriction = 0; isBallistic = false; gravityMod = 1; }; //... So we have now have 4 explosions which will show white (original), red, blue and green so we can see the difference.Next up we need to crack open the C++. Open up soure/T3D/projectile.h and list the new explosion data. /... ExplosionData* explosion; S32 explosionId; //yorks start ExplosionData* explosion1; S32 explosion1Id; ExplosionData* explosion2; S32 explosion2Id; ExplosionData* explosion3; S32 explosion3Id; //yorks end ExplosionData* waterExplosion; // Water Explosion Datablock //... And then the meat of the sandwich, source/T3D/projectile.cpp. ProjectileData::ProjectileData() { //... explosion = NULL; explosionId = 0; //yorks start explosion1 = NULL; explosion1Id = 0; explosion2 = NULL; explosion2Id = 0; explosion3 = NULL; explosion3Id = 0; //yorks end waterExplosion = NULL; //... } //... void ProjectileData::initPersistFields() { //... addField("explosion", TYPEID< ExplosionData >(), Offset(explosion, ProjectileData), "@brief Explosion datablock used when the projectile explodes outside of water.\n\n"); addField("waterExplosion", TYPEID< ExplosionData >(), Offset(waterExplosion, ProjectileData), "@brief Explosion datablock used when the projectile explodes underwater.\n\n"); //yorks start addField("explosion1", TYPEID< ExplosionData >(), Offset(explosion1, ProjectileData), "@brief Explosion1 datablock used when the projectile explodes outside of water.\n\n"); addField("explosion2", TYPEID< ExplosionData >(), Offset(explosion2, ProjectileData), "@brief Explosion2 datablock used when the projectile explodes outside of water.\n\n"); addField("explosion3", TYPEID< ExplosionData >(), Offset(explosion3, ProjectileData), "@brief Explosion3 datablock used when the projectile explodes outside of water.\n\n"); //yorks end addField("splash", TYPEID< SplashData >(), Offset(splash, ProjectileData), "@brief Splash datablock used to create splash effects as the projectile enters or leaves water\n\n"); //... } //... bool ProjectileData::preload(bool server, String &errorStr) { //... if (!explosion && explosionId != 0) if (Sim::findObject(explosionId, explosion) == false) Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(explosion): %d", explosionId); //yorks start if (!explosion1 && explosion1Id != 0) if (Sim::findObject(explosion1Id, explosion1) == false) Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(explosion1): %d", explosion1Id); if (!explosion2 && explosion2Id != 0) if (Sim::findObject(explosion2Id, explosion2) == false) Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(explosion2): %d", explosion2Id); if (!explosion3 && explosion3Id != 0) if (Sim::findObject(explosion3Id, explosion3) == false) Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(explosion3): %d", explosion3Id); //yorks end if (!waterExplosion && waterExplosionId != 0) //... } //-------------------------------------------------------------------------- void ProjectileData::packData(BitStream* stream) { //... if (stream->writeFlag(explosion != NULL)) stream->writeRangedU32(explosion->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast); //yorks start if (stream->writeFlag(explosion1 != NULL)) stream->writeRangedU32(explosion1->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast); if (stream->writeFlag(explosion2 != NULL)) stream->writeRangedU32(explosion2->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast); if (stream->writeFlag(explosion3 != NULL)) stream->writeRangedU32(explosion3->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast); //yorks end if (stream->writeFlag(waterExplosion != NULL)) //... } void ProjectileData::unpackData(BitStream* stream) { //... if (stream->readFlag()) explosionId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); //yorks start if (stream->readFlag()) explosion1Id = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); if (stream->readFlag()) explosion2Id = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); if (stream->readFlag()) explosion3Id = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); //yorks end if (stream->readFlag()) //... } //... void Projectile::explode( const Point3F &p, const Point3F &n, const U32 collideType ) { //... else { // Client just plays the explosion at the right place... // Explosion* pExplosion = NULL; //yorks in S32 mRandomize = 0; if (mDataBlock->waterExplosion && pointInWater(p)) { pExplosion = new Explosion; pExplosion->onNewDataBlock(mDataBlock->waterExplosion, false); } else /*yorks out start if (mDataBlock->explosion) { pExplosion = new Explosion; pExplosion->onNewDataBlock(mDataBlock->explosion, false); } //yorks out end */ //yorks in start { //yorks start with 1 continue check with others if exists else default to normal explosion if (mDataBlock->explosion1) { //yorks we have >1 explosion, check for others if (mDataBlock->explosion2) { if (mDataBlock->explosion3) mRandomize = 3; else mRandomize = 2; } else mRandomize = 1; } //yorks get the random if (mRandomize == 0) { //stock explosion if (mDataBlock->explosion) { pExplosion = new Explosion; pExplosion->onNewDataBlock(mDataBlock->explosion, false); } } else { //yorks get random number betweem 0 and mRandomize S32 mChoose = (gRandGen.randI(0, mRandomize)); if (mChoose == 1) { pExplosion = new Explosion; pExplosion->onNewDataBlock(mDataBlock->explosion1, false); } else { if (mChoose == 2) { pExplosion = new Explosion; pExplosion->onNewDataBlock(mDataBlock->explosion2, false); } else { if (mChoose == 3) { pExplosion = new Explosion; pExplosion->onNewDataBlock(mDataBlock->explosion3, false); } else { pExplosion = new Explosion; pExplosion->onNewDataBlock(mDataBlock->explosion, false); } } } } } //yorks in end if( pExplosion ) //... } //... And that should be that. It ain't elegant but it works, as I said up top, feel free to improve it (no really plz). :lol: And this is what it looks like in action:KdaqnWd11Ck Quote Link to comment Share on other sites More sharing options...
TRON Posted April 5, 2016 Share Posted April 5, 2016 Looks at C++ codeOMG, my Eyes! My eyes!! Quote Link to comment Share on other sites More sharing options...
Steve_Yorkshire Posted April 5, 2016 Author Share Posted April 5, 2016 @TRONhttp://pbs.twimg.com/media/BvyOwM9IcAAtLcQ.jpg :P Quote Link to comment Share on other sites More sharing options...
Duion Posted April 5, 2016 Share Posted April 5, 2016 Whats wrong with the C++ ? Quote Link to comment Share on other sites More sharing options...
deathbravo Posted April 6, 2016 Share Posted April 6, 2016 nothing wrong. artistic mode Quote Link to comment Share on other sites More sharing options...
rlranft Posted April 6, 2016 Share Posted April 6, 2016 I dunno, I kind of like giant if/else blocks.... Quote Link to comment Share on other sites More sharing options...
Duion Posted April 6, 2016 Share Posted April 6, 2016 I have seen much bigger if/else blocks from steve. Quote Link to comment Share on other sites More sharing options...
Azaezel Posted April 8, 2016 Share Posted April 8, 2016 Nice idea. as a note on the ExplosionData* explosion; S32 explosionId; variants:https://github.com/GarageGames/Torque3D/blob/7bba3ee2de610c2757bc70eba10db869bab72a85/Engine/source/T3D/fx/particle.cpp#L203 that PDC_NUM_KEYS bit's how you can pack those into a script-exposed array. Quote Link to comment Share on other sites More sharing options...
Steve_Yorkshire Posted May 3, 2016 Author Share Posted May 3, 2016 I've had a bit more of play around using the subExplosion type found in explosion.cpp/h: //projectile.h class ProjectileData : public GameBaseData { //... public: enum ExplosionConsts { EC_MAX_EXPLOSIONS = 4, }; // variables set in datablock definition: //... S32 fadeDelay; // the IRangeValidatorScaled field validator /* ExplosionData* explosion; S32 explosionId; */ ExplosionData* explosionList[EC_MAX_EXPLOSIONS]; S32 explosionIDList[EC_MAX_EXPLOSIONS]; ExplosionData* waterExplosion; // Water Explosion Datablock //... //projectile.cpp //... void ProjectileData::initPersistFields() { //... //addField("explosion", TYPEID< ExplosionData >(), Offset(explosion, ProjectileData), // "@brief Explosion datablock used when the projectile explodes outside of water.\n\n"); addField("explosion", TYPEID< ExplosionData >(), Offset(explosionList, ProjectileData), EC_MAX_EXPLOSIONS, "List of additional ExplosionData objects to create at the start of the " "explosion."); addField("waterExplosion", TYPEID< ExplosionData >(), Offset(waterExplosion, ProjectileData), "@brief Explosion datablock used when the projectile explodes underwater.\n\n"); //... } //... bool ProjectileData::preload(bool server, String &errorStr) { //... Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(particleWaterEmitter): %d", particleWaterEmitterId); /* if (!explosion && explosionId != 0) if (Sim::findObject(explosionId, explosion) == false) Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(explosion): %d", explosionId); */ for (S32 k = 0; k { if (!explosionList[k] && explosionIDList[k] != 0) { if (Sim::findObject(explosionIDList[k], explosionList[k]) == false) { Con::errorf(ConsoleLogEntry::General, "ExplosionData::onAdd: Invalid packet, bad datablockId(explosion): 0x%x", explosionIDList[k]); } } } if (!waterExplosion && waterExplosionId != 0) //... } //... void ProjectileData::packData(BitStream* stream) { //... /* if (stream->writeFlag(explosion != NULL)) stream->writeRangedU32(explosion->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast); */ for (S32 i = 0; i { if (stream->writeFlag(explosionList != NULL)) { stream->writeRangedU32(explosionList->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast); } } if (stream->writeFlag(waterExplosion != NULL)) //... } void ProjectileData::unpackData(BitStream* stream) { //... /* if (stream->readFlag()) explosionId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); */ for (S32 k = 0; k { if (stream->readFlag()) { explosionIDList[k] = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); } } if (stream->readFlag()) waterExplosionId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); //... } //... void Projectile::explode( const Point3F &p, const Point3F &n, const U32 collideType ) { //... }However it all rather ground to a halt because I am not familiar with how to get the explosionList[EC_MAX_EXPLOSIONS] in the actual explode() function of projectile.cpp. :? Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.