FlameThrower: Proposed Modification - Page 3

FlameThrower: Proposed Modification

Discuss the source code and development of Spring Engine in general from a technical point of view. Patches go here too.

Moderator: Moderators

User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Almost there. I just have to figure out why it's not working right at the end of its TimeToLive:

Image
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Ok, just about done. Fixed the problems at the start and end conditions- it was a just a simple logic error in the end.

Now I just have to clean up and make sure it's timing about right, and I'm going to be super-duper nice to everybody, and set up defaults for FlameThrowers, so that old weapons won't be too badly broken in 0.73b... and then submit the patch. Whew!
espylaub
Posts: 205
Joined: 01 May 2006, 11:35

Post by espylaub »

Looks pretty good. Denser, bigger sprites that fade to black via red would be nice. Can they float upwards at the end? As smoke?
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

The size, texture and dispersion amount of the sprites is entirely under a modder's control, FYI. As for turning into "smoke" at the end of their lifetime, setting GroundBounce=1 achieves that goal, visually speaking. I'd like to take a whack at making a FlameThrower that's physically accurate, and obeys gravity, at some point, but not today- I need to get back to work on NanoBlobs to get it prepared for release-day.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Ok, just need to speed this up by about 2X, put in the default values so that standard flamethrowers are still backwards-compatible, and test one last time.

Image
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

And... here we go! I've even put in backwards-compatibility code, that will make it so that current flamethrowers won't have to change a thing. The example screenshot below is using only default values!

Image

So... here's my sourcecode. I have taken the liberty of chopping out the irrelevant sections of WeaponDefHandler.cpp, because otherwise it runs for pages.

WeaponDefHandler.cpp:

Code: Select all

	} else if(weaponDefs[id].type=="flame"){
		//CFlameProjectile
		weaponDefs[id].visuals.texture1 = &ph->explotex;
		sunparser->GetTDef(weaponDefs[id].size, tempsize , weaponname + "\\size");
		sunparser->GetDef(weaponDefs[id].sizeGrowth, "0.1", weaponname + "\\sizeGrowth");
		sunparser->GetDef(weaponDefs[id].intensity, "0.9", weaponname + "\\intensity");
		weaponDefs[id].visuals.color=sunparser->GetFloat3(float3(1.0,0.8,0.3),weaponname + "\\rgbcolor");
		weaponDefs[id].visuals.color2=sunparser->GetFloat3(float3(0.05,0.0,0.0),weaponname + "\\rgbcolor2");
FlameThrower.h:

Code: Select all

#ifndef __FLAME_THROWER_H__
#define __FLAME_THROWER_H__

#include "Weapon.h"

class CFlameThrower :
	public CWeapon
{
public:
	CFlameThrower(CUnit* owner);
	~CFlameThrower(void);
	void Fire(void);
	bool TryTarget(const float3 &pos,bool userTarget,CUnit* unit);
	void Update(void);
	float3 color;
	float3 color2;
};

#endif // __FLAME_THROWER_H__
FlameThrower.cpp:

Code: Select all

#include "StdAfx.h"
#include "FlameThrower.h"
#include "Sim/Units/Unit.h"
#include "Sound.h"
#include "Map/Ground.h"
#include "Game/GameHelper.h"
#include "Sim/Projectiles/FlameProjectile.h"
#include "WeaponDefHandler.h"
#include "mmgr.h"

CFlameThrower::CFlameThrower(CUnit* owner)
: CWeapon(owner)
{
}

CFlameThrower::~CFlameThrower(void)
{
}

void CFlameThrower::Fire(void)
{
	float3 dir=targetPos-weaponPos;
	dir.Normalize();
	float3 spread=(gs->randVector()*sprayangle+salvoError)*0.2;
	spread-=dir*0.001;

	new CFlameProjectile(weaponDef->visuals.color,weaponDef->visuals.color2,weaponDef->intensity,weaponPos,dir*projectileSpeed,spread,owner,damages,weaponDef,(int)(range/projectileSpeed*1.2));
	if(fireSoundId && (!weaponDef->soundTrigger || salvoLeft==salvoSize-1))
		sound->PlaySound(fireSoundId,owner,fireSoundVolume);
}

bool CFlameThrower::TryTarget(const float3 &pos,bool userTarget,CUnit* unit)
{
	if(!CWeapon::TryTarget(pos,userTarget,unit))
		return false;

	if(unit){
		if(unit->isUnderWater)
			return false;
	} else {
		if(pos.y<0)
			return false;
	}

	float3 dir=pos-weaponPos;
	float length=dir.Length();
	if(length==0)
		return true;

	dir/=length;

	float g=ground->LineGroundCol(weaponPos,pos);
	if(g>0 && g<length*0.9)
		return false;

	if(helper->LineFeatureCol(weaponPos,dir,length))
		return false;

	if(avoidFriendly && helper->TestCone(weaponPos,dir,length,(accuracy+sprayangle),owner->allyteam,owner)){
		return false;
	}
	return true;
}

void CFlameThrower::Update(void)
{
	if(targetType!=Target_None){
		weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
		wantedDir=targetPos-weaponPos;
		wantedDir.Normalize();
	}
	CWeapon::Update();
}
FlameProjectile.h:

Code: Select all

#ifndef __FLAME_PROJECTILE_H__
#define __FLAME_PROJECTILE_H__

#include "WeaponProjectile.h"
#include "Sim/Misc/DamageArray.h"

class CFlameProjectile :
	public CWeaponProjectile
{
public:
	CFlameProjectile(const float3& color,const float3& color2, float intensity,const float3& pos,const float3& speed,const float3& spread,CUnit* owner,const DamageArray& damages, WeaponDef *weaponDef, int ttl=50);
	~CFlameProjectile(void);
	float3 color;
	float3 color2;
	float intensity;
	float3 spread;
	float curTime;
	float invttl;
	void Update(void);
	void Draw(void);
	void Collision(CUnit* unit);
	void Collision(void);
	int ShieldRepulse(CPlasmaRepulser* shield,float3 shieldPos, float shieldForce, float shieldMaxSpeed);
};

#endif // __FLAME_PROJECTILE_H__
And, of course, what you actually want to read, FlameProjectile.cpp. Man, this was a lot've work for such a tiny amount of new code ;)

Code: Select all

#include "StdAfx.h"
#include "FlameProjectile.h"
#include "Rendering/GL/VertexArray.h"
#include "Game/Camera.h"
#include "Map/Ground.h"
#include "mmgr.h"
#include "ProjectileHandler.h"
#include "Sim/Weapons/WeaponDefHandler.h"

CFlameProjectile::CFlameProjectile(const float3& color, const float3& color2, float intensity, const float3& pos, const float3& speed, const float3& spread, CUnit* owner, const DamageArray& damages, WeaponDef *weaponDef, int ttl)
: CWeaponProjectile(pos,speed,owner,0,ZeroVector,weaponDef,damages,0),
	color(color),
	color2(color2),
	intensity(intensity),
	spread(spread),
	curTime(0)
{
	invttl=1.0/ttl;
	SetRadius(weaponDef->size);
	drawRadius=weaponDef->size;
}

CFlameProjectile::~CFlameProjectile(void)
{
}

void CFlameProjectile::Collision(void)
{
	float3 norm=ground->GetNormal(pos.x,pos.z);
	float ns=speed.dot(norm);
	speed-=norm*ns*1;
	pos.y+=0.05;
	curTime+=0.05;
}

void CFlameProjectile::Collision(CUnit* unit)
{
	CWeaponProjectile::Collision(unit);
}

void CFlameProjectile::Update(void)
{
	pos+=speed;
	speed+=spread;

	SetRadius(radius+weaponDef->sizeGrowth);
	drawRadius=(radius+weaponDef->sizeGrowth);

	curTime+=invttl;
	if(curTime>1){
		curTime=1;
		deleteMe=true;
	}
}

void CFlameProjectile::Draw(void)
{
	float ColorA;
	float ColorB;
	float ColorC;
	inArray=true;
	unsigned char col[4];
	if(curTime>=0.000000)
	{
		if(color.x-(curTime*2)<0)
		{
		ColorA=0;
		}else{
		ColorA=color.x-(curTime*2);
		}
		if(color.y-(curTime*2)<0)
		{
		ColorB=0;
		}else{
		ColorB=color.y-(curTime*2);
		}
		if(color.z-(curTime*2)<0)
		{
		ColorC=0;
		}else{
		ColorC=color.z-(curTime*2);
		}
	col[0]=(unsigned char) ((ColorA+(color2.x*(curTime*2)))*intensity*255);
	col[1]=(unsigned char) ((ColorB+(color2.y*(curTime*2)))*intensity*255);
	col[2]=(unsigned char) ((ColorC+(color2.z*(curTime*2)))*intensity*255);
	col[3]=3;
	}
	
		float3 interPos=pos+speed*gu->timeOffset;
		va->AddVertexTC(interPos-camera->right*radius-camera->up*radius,weaponDef->visuals.texture1->xstart ,weaponDef->visuals.texture1->ystart ,col);
		va->AddVertexTC(interPos+camera->right*radius-camera->up*radius,weaponDef->visuals.texture1->xend ,weaponDef->visuals.texture1->ystart ,col);
		va->AddVertexTC(interPos+camera->right*radius+camera->up*radius,weaponDef->visuals.texture1->xend ,weaponDef->visuals.texture1->yend ,col);
		va->AddVertexTC(interPos-camera->right*radius+camera->up*radius,weaponDef->visuals.texture1->xstart ,weaponDef->visuals.texture1->yend ,col);
}

int CFlameProjectile::ShieldRepulse(CPlasmaRepulser* shield,float3 shieldPos, float shieldForce, float shieldMaxSpeed)
{
	float3 dir=pos-shieldPos;
	dir.Normalize();
	if(dir.dot(speed)<shieldMaxSpeed){
		speed+=dir*shieldForce;
		return 2;
	}
	return 0;
}
User avatar
knorke
Posts: 7971
Joined: 22 Feb 2006, 01:02

Post by knorke »

Good work, that looks cool.
So it is also possible to have arcing flames or flying acid like the Zerg Hydraliks from SC?
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Arcing flames, not yet.

I will want to try combining gravity-effected weapons with the flamethrower code at some point, because the way that flamethrowers work right now has always really bothered me, but not today- I have about 4 hours left to work on NanoBlobs before I go to work :P

Zerg spray... well, how's this (this is a quickie, obviously):

Image
User avatar
FizWizz
Posts: 1998
Joined: 17 Aug 2005, 11:42

Post by FizWizz »

:o
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Post by AF »

Is ti me or do the default flames in spring atm look a lot more intense than those in your shot? Perhaps its the alpha making them less opaque than currently........

Maybe you can add alpha starting/ending values
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

@Fiz:

Y'know, it changes purely based on the amount of time it's alive. I could see some very nice PPC FX come from this ;)

Also, I should mention that this works with TGAs with an alpha, so if you give it a starting value of "1 1 1" for RGBColor, then it'll use the starting values of the bitmap, and color-shift it from there. The possibilities are, shall we say... fairly open :-)

@AF:

I think it just has to do with the source bitmap. If we do an apples-vs-apples test, you can see that it's no more intense. This is the current released dev. preview:

Image




<comes back from testing>

Hmm. No, AF's right. Even a pure alpha-block isn't a pure tone. I'll have to change my sourcecode then.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Okie doke, problem solved. Minor issues, really. However, it did point out something to me: the default TGA files for certain FX don't have proper alpha channels! Big problem!

Image

Here is the changed source. Note that intensity no longer has any effect on colors (there's really no need, I'm not sure what I was thinking there) and intensity falls off with time, taking the opacity of the texture down with time. When the particle is 2 seconds old, it becomes invisible, unless intensity is higher than 1.0.

Code: Select all

#include "StdAfx.h"
#include "FlameProjectile.h"
#include "Rendering/GL/VertexArray.h"
#include "Game/Camera.h"
#include "Map/Ground.h"
#include "mmgr.h"
#include "ProjectileHandler.h"
#include "Sim/Weapons/WeaponDefHandler.h"

CFlameProjectile::CFlameProjectile(const float3& color, const float3& color2, float intensity, const float3& pos, const float3& speed, const float3& spread, CUnit* owner, const 

DamageArray& damages, WeaponDef *weaponDef, int ttl)
: CWeaponProjectile(pos,speed,owner,0,ZeroVector,weaponDef,damages,0),
	color(color),
	color2(color2),
	intensity(intensity),
	spread(spread),
	curTime(0)
{
	invttl=1.0/ttl;
	SetRadius(weaponDef->size);
	drawRadius=weaponDef->size;
}

CFlameProjectile::~CFlameProjectile(void)
{
}

void CFlameProjectile::Collision(void)
{
	float3 norm=ground->GetNormal(pos.x,pos.z);
	float ns=speed.dot(norm);
	speed-=norm*ns*1;
	pos.y+=0.05;
	curTime+=0.05;
}

void CFlameProjectile::Collision(CUnit* unit)
{
	CWeaponProjectile::Collision(unit);
}

void CFlameProjectile::Update(void)
{
	pos+=speed;
	speed+=spread;

	SetRadius(radius+weaponDef->sizeGrowth);
	drawRadius=(radius+weaponDef->sizeGrowth);

	curTime+=invttl;
	if(curTime>1){
		curTime=1;
		deleteMe=true;
	}
}

void CFlameProjectile::Draw(void)
{
	float ColorA;
	float ColorB;
	float ColorC;
	inArray=true;
	unsigned char col[4];
	if(curTime>=0.000000)
	{
		if(color.x-(curTime*2)<0)
		{
		ColorA=0;
		}else{
		ColorA=color.x-(curTime*2);
		}
		if(color.y-(curTime*2)<0)
		{
		ColorB=0;
		}else{
		ColorB=color.y-(curTime*2);
		}
		if(color.z-(curTime*2)<0)
		{
		ColorC=0;
		}else{
		ColorC=color.z-(curTime*2);
		}
	col[0]=(unsigned char) ((ColorA+(color2.x*(curTime*2)))*255);
	col[1]=(unsigned char) ((ColorB+(color2.y*(curTime*2)))*255);
	col[2]=(unsigned char) ((ColorC+(color2.z*(curTime*2)))*255);
	col[3]=(intensity*(curTime/2))*255;
	}
	
		float3 interPos=pos+speed*gu->timeOffset;
		va->AddVertexTC(interPos-camera->right*radius-camera->up*radius,weaponDef->visuals.texture1->xstart ,weaponDef->visuals.texture1->ystart ,col);
		va->AddVertexTC(interPos+camera->right*radius-camera->up*radius,weaponDef->visuals.texture1->xend ,weaponDef->visuals.texture1->ystart ,col);
		va->AddVertexTC(interPos+camera->right*radius+camera->up*radius,weaponDef->visuals.texture1->xend ,weaponDef->visuals.texture1->yend ,col);
		va->AddVertexTC(interPos-camera->right*radius+camera->up*radius,weaponDef->visuals.texture1->xstart ,weaponDef->visuals.texture1->yend ,col);
}

int CFlameProjectile::ShieldRepulse(CPlasmaRepulser* shield,float3 shieldPos, float shieldForce, float shieldMaxSpeed)
{
	float3 dir=pos-shieldPos;
	dir.Normalize();
	if(dir.dot(speed)<shieldMaxSpeed){
		speed+=dir*shieldForce;
		return 2;
	}
	return 0;
}
espylaub
Posts: 205
Joined: 01 May 2006, 11:35

Post by espylaub »

Argh wrote: Image
fuck yes!
User avatar
NOiZE
Balanced Annihilation Developer
Posts: 3984
Joined: 28 Apr 2005, 19:29

Post by NOiZE »

HOLY CRAP Argh, that's ... That's INSANELY BEAUTIFULL!!!!!!


Wow


sorry

calm down :-)
User avatar
Caydr
Omnidouche
Posts: 7179
Joined: 16 Oct 2004, 19:40

Post by Caydr »

Get it committed for the next version or I'll ban you.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

I'm working on it. JC wants the code to be really tight, though, so I've had to do some editing along the way, to make sure it meets standards, and isn't just sloppy, inefficient coding that just happens to work ;)
User avatar
KDR_11k
Game Developer
Posts: 8293
Joined: 25 Jun 2006, 08:44

Post by KDR_11k »

Does it use additive or alpha blending?
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Both. However, only the additive is directly controllable. The alpha comes from the bitmap- you have no control over it, other than by rebuilding the bitmap, of course.
User avatar
KDR_11k
Game Developer
Posts: 8293
Joined: 25 Jun 2006, 08:44

Post by KDR_11k »

Alpha AND additive? How does that work? glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA)?
User avatar
TechnoTone
Posts: 165
Joined: 23 Aug 2005, 22:02

Post by TechnoTone »

Wow - that looks awesome.

I'd like to suggest another possible improvement though. Notice how there are descrete positions for the flames when they are quite small:

Image

Perhaps if the start position of each one was to have a random element to it - along the line of the firing axis - this could be eliminated too? I hope that makes sense.
Post Reply

Return to “Engine”