⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 particleemitter.cpp

📁 这是一款游戏中的粒子系统
💻 CPP
字号:
#include "StdAfx.h"
#include ".\particleemitter.h"


void CParticleEmitter::InitEmitIB()
{
	WORD Indices[MAX_EMIT_NUMBER*6];
	for ( USHORT i = 0 ; i < MAX_EMIT_NUMBER ; i++ )
	{
		// 左上
		Indices[i*6]	= i * 4;
		Indices[i*6+1]	= i * 4 + 1;
		Indices[i*6+2]	= i * 4 + 2;
		// 右下
		Indices[i*6+3]	= i * 4 + 2;
		Indices[i*6+4]	= i * 4 + 1;
		Indices[i*6+5]	= i * 4 + 3;
	}

	if(SUCCEEDED(m_pDevice->CreateIndexBuffer(
		sizeof(Indices),
		D3DUSAGE_WRITEONLY,
		D3DFMT_INDEX16,
		D3DPOOL_DEFAULT,
		&m_ib,
		NULL
		))){
			VOID* pIndices;
			if( FAILED( m_ib->Lock( 0, sizeof(Indices), (void**)&pIndices, 0 ) ) )
				return ;
			memcpy( pIndices, Indices, sizeof(Indices) );
			m_ib->Unlock();

		}
}

CParticleEmitter::CParticleEmitter(LPDIRECT3DDEVICE9  device,CParticleSystem* sys , const string& name , long maxparticle , long emit_ps , float spd , float size , D3DCOLOR clr )
: m_pParentSystem(sys) , m_bActive(false) , m_strName(name)
{
	m_pDevice=device;

	if(FAILED(m_pDevice->CreateVertexBuffer(
		4*MAX_EMIT_NUMBER*sizeof(Vert_PDT1),
		D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC,
		Vert_PDT1::fvf,
		D3DPOOL_DEFAULT,
		&m_vb,0))){
			MessageBox(NULL,"创建顶点缓冲区失败","",MB_OK);
			return;
		}

		InitEmitIB();
		m_vecRelPos = sys->GetPosition();

		m_ActiveList.clear();
		m_DisableList.clear();
		m_ParticlePool.clear();

		m_un32MaxParticleNum = maxparticle;

		m_fMaxEmitTime = 0.0f;
		m_fMaxEmitTimeMin = 0;
		m_fMaxEmitTimeVar = 0;

		m_fRepeatDelay = 0.0f;
		m_fRepeatDelayMin = 0;
		m_fRepeatDelayVar = 0;

		m_un32EmitNumPerSec = emit_ps;
		m_fEmitAccum = 0.0f;

		m_bInterpolation = true;
		m_vecLastPos = m_vecPos = D3DXVECTOR3(0,0,0);
		m_fElapsedTime = 0.0f;

		m_vecVelocityMin = m_vecVelocityVar = D3DXVECTOR3(0,0,0);

		m_pTexture = NULL;

		m_fInitSizeMin = size;
		m_fInitSizeVar = 0;

		m_fLifeSpanMin = 0;
		m_fLifeSpanVar = 0;

		m_clrInitClrMin = clr;
		m_clrInitClrVar = 0;

		m_AffectorVector.clear();
}

CParticleEmitter::~CParticleEmitter()
{
	Destroy();
}


void	CParticleEmitter::UpdateMatrix()
{
}


bool	CParticleEmitter::Initialize()
{
	// 生成Pool
	SetPoolSize( m_un32MaxParticleNum );

	// 将Pool影响到DisableList
	m_DisableList.clear();
	for ( int i = 0 ; i < (int)m_ParticlePool.size() ; i++ )
	{ m_DisableList.push_back( m_ParticlePool[i] ); }

	m_ActiveList.clear();
    m_textureName=new char[100];
	sprintf(m_textureName,"%s","");
	m_bActive = true;
    m_pTexture=NULL;
	return true;
}


void	CParticleEmitter::Generate( float fElapsed )
{
	long inewpar = 0;
	m_fElapsedTime += fElapsed;

	// 是否可以开始生成
	if ( m_bActive )
	{
		// 检测Elapsed和EmitRate的倍数关系(即计算与EmitPerSec的乘数关系),大于1的部分按照倍数生成,余数累积
		m_fEmitAccum += fElapsed * m_un32EmitNumPerSec;
		inewpar = (long)m_fEmitAccum;
		m_fEmitAccum -= inewpar;
		// 这时inewpar记录了新Particle的数量

		// 看此次发射是否到了终结的时刻
		if ( m_fMaxEmitTimeMin != 0.0f )
		{
			if ( m_fElapsedTime > m_fMaxEmitTime )
			{
				SetActive(false);
				m_fElapsedTime = 0.0f;
			}
		}
	}
	// 否则看是否触发了Repeat条件
	else
	{
		if ( m_fRepeatDelay != 0.0f )
		{
			if ( m_fElapsedTime > m_fRepeatDelay )
			{
				SetActive(true);
				// 计算新的Emit和Repeat
				m_fMaxEmitTime = m_fMaxEmitTimeMin + RangeRandom( 0.0f , m_fMaxEmitTimeVar );
				m_fRepeatDelay = m_fRepeatDelayMin + RangeRandom( 0.0f , m_fRepeatDelayVar );
				m_fElapsedTime = 0.0f;
			}
		}
		inewpar = 0;
	}

	// 按照前面的粒子数量产生新粒子
	D3DXVECTOR3	vec;
	if ( inewpar ) { vec = m_vecPos - m_vecLastPos;	vec /= (float)inewpar; }

	for ( long i = 0 ; i < inewpar ; i++ )
	{
		if ( m_DisableList.size() == 0 )
		{ break; }

		CParticle* par = m_DisableList.front();
		m_DisableList.pop_front();

		// 计算插值点位置(如果需要),否则,插值点位置等同于当前位置
		if ( m_bInterpolation )
		{ m_vecInterpolatePos = m_vecPos - (float)i * vec; }
		else
		{ m_vecInterpolatePos = m_vecPos; }

		// 先进行自动配置,最后通过Creator修正
		// 使用插值点位置
		par->m_vecPosition = m_vecInterpolatePos;

		// 注册粒子的父Emitter和初始信息
		par->m_pParentEmitter = this;
		par->m_vecInitPosition = par->m_vecPosition;

		// 生成新粒子的大小信息
		GenerateSize( par );
		// 生成新粒子的速度信息
		GenerateVelocity( par );
		// 生成新粒子的生命信息
		GenerateLife( par );
		// 生成新粒子的颜色信息
		GenerateColor( par );

		// Creator修正
		for ( long j = 0 ; j < (long)m_AffectorVector.size() ; j++ )
		{ 
			m_AffectorVector[j]->Create( par ); 
		}

		m_ActiveList.push_back(par);
	}
}


void	CParticleEmitter::GenerateSize( CParticle* particle )
{
	particle->m_fSize = m_fInitSizeMin + RangeRandom( 0.0f , m_fInitSizeVar );
}


void	CParticleEmitter::GenerateVelocity( CParticle* particle )
{
	particle->m_vecVelocity.x = m_vecVelocityMin.x + RangeRandom( 0.0f , m_vecVelocityVar.x );
	particle->m_vecVelocity.y = m_vecVelocityMin.y + RangeRandom( 0.0f , m_vecVelocityVar.y );
	particle->m_vecVelocity.z = m_vecVelocityMin.z + RangeRandom( 0.0f , m_vecVelocityVar.z );
}


void	CParticleEmitter::GenerateLife( CParticle* particle )
{
	particle->m_fElapsedLife = m_fLifeSpanMin + RangeRandom( 0.0f , m_fLifeSpanVar );
}


void	CParticleEmitter::GenerateColor( CParticle* particle )
{
	static USHORT a,r,g,b;
	a = m_InitAMin + (UCHAR)RangeRandom( 0.0f , (float)m_InitAVar );
	r = m_InitRMin + (UCHAR)RangeRandom( 0.0f , (float)m_InitRVar );
	g = m_InitGMin + (UCHAR)RangeRandom( 0.0f , (float)m_InitGVar );
	b = m_InitBMin + (UCHAR)RangeRandom( 0.0f , (float)m_InitBVar );
	if ( a > 255 ){ a = 255; }
	if ( r > 255 ){ r = 255; }
	if ( g > 255 ){ g = 255; }
	if ( b > 255 ){ b = 255; }
	particle->m_clrColor = D3DCOLOR_ARGB(a,r,g,b);
}


void	CParticleEmitter::Update( float fElapsed )
{
	// 记录上一次位置,供位置插值用
	m_vecLastPos = m_vecPos;
	// 父System位置是否变化,需要影响过来
	m_vecPos = m_pParentSystem->GetPosition() + m_vecRelPos;

	// 是否到了上限
	if( (long)m_ActiveList.size() < m_un32MaxParticleNum )
	{
		// 没有到上限就可以处理生成粒子的逻辑
		Generate( fElapsed );
	}

	if ( m_ActiveList.empty() )
	{ return; }

	// 对所有Active的粒子进行Update
	ParticleList::iterator it = m_ActiveList.begin();
	for ( ; it != m_ActiveList.end() ; )
	{
		if ( !UpdateParticle( fElapsed , *it ) )
		{
			// 如果失效就取消此粒子
			m_DisableList.push_back( *it );
			it = m_ActiveList.erase( it );
		}
		else
		{
			// 否则,步进下一个
			++it;
		}
	}
}


bool	CParticleEmitter::UpdateParticle( float fElapsed , CParticle* particle )
{
	if( !m_AffectorVector.empty() )
	{
		for ( int i = 0 ; i < (int)m_AffectorVector.size() ; ++i )
		{ 
			m_AffectorVector[i]->Logic( particle , fElapsed ); 
		}
	}

	// 位置
	particle->m_vecPosition += particle->m_vecVelocity * fElapsed;
	// 生命
	particle->m_fElapsedLife -= fElapsed;

	if ( particle->m_fElapsedLife <= 0.0f )
	{ return false; }

	return true;
}


void	CParticleEmitter::Render(D3DXVECTOR3 camDir)
{
	// 重设世界矩阵为0,0,0

	D3DXMATRIX matWorld;
	D3DXMatrixIdentity( &matWorld );
	m_pDevice->SetTransform(D3DTS_WORLD,&matWorld);
	////////////////////////////////////////////
	//成billborad效果
    D3DXVECTOR3 eddy;
	D3DXVECTOR3 dir=D3DXVECTOR3(0,0,1);
	D3DXVec3Cross(&eddy,&dir,&camDir);
	float dot=D3DXVec3Dot(&dir,&camDir);
	float angle=(180*acos(dot))/D3DX_PI;
	if(D3DXVec3Length(&eddy)<=0)
		angle=0;
	D3DXMatrixRotationAxis(&matWorld,&eddy,angle);
	m_pDevice->SetTransform(D3DTS_WORLD,&matWorld);
	/////////////////////////////////////////////
	// 关闭光照
	m_pDevice->SetRenderState( D3DRS_LIGHTING , false );

	// 纹理操作
	if(m_pTexture!=NULL&&strlen(m_textureName)>0){
		m_pDevice->SetTexture(0,m_pTexture);
	}
	m_pDevice->SetTextureStageState( 0 , D3DTSS_COLOROP,   D3DTOP_MODULATE );
	m_pDevice->SetTextureStageState( 0 , D3DTSS_COLORARG1, D3DTA_TEXTURE );
	m_pDevice->SetTextureStageState( 0 , D3DTSS_COLORARG2, D3DTA_DIFFUSE );
	m_pDevice->SetTextureStageState( 0 , D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
	m_pDevice->SetTextureStageState( 0 , D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
	m_pDevice->SetTextureStageState( 0 , D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );

	m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE , true );
	m_pDevice->SetRenderState( D3DRS_SRCBLEND , D3DBLEND_SRCALPHA );
	m_pDevice->SetRenderState( D3DRS_DESTBLEND , D3DBLEND_ONE );
	m_pDevice->SetRenderState( D3DRS_ZENABLE , false );
	m_pDevice->SetRenderState( D3DRS_ZWRITEENABLE , false );
	RenderGeometry();
	m_pDevice->SetRenderState( D3DRS_ZENABLE , true );
	m_pDevice->SetRenderState( D3DRS_ZWRITEENABLE , true );
	m_pDevice->SetTexture(0,NULL);
}


void	CParticleEmitter::RenderGeometry()
{
	if ( m_ActiveList.empty() )
	{ return; }

	// Look与摄像机Look相同但Y=0
	D3DXVECTOR3 B_look =m_pParentSystem->m_look;
	D3DXVec3Normalize( &B_look , &B_look );

	// Up为摄像机的Up
	D3DXVECTOR3 B_up = m_pParentSystem->m_up;
	D3DXVec3Normalize( &B_up , &B_up );

	// Right由Up叉乘Look
	D3DXVECTOR3 B_right ;
	D3DXVec3Cross( &B_right , &B_up , &B_look );
	D3DXVec3Normalize( &B_right , &B_right );
	// 填入数据
	long i = 0;
	ParticleList::iterator it = m_ActiveList.begin();
	for ( ; it != m_ActiveList.end() ; ++it )
	{
		float halfsize = (*it)->m_fSize*0.5f;

		m_PartDatas[i].pos = (*it)->m_vecPosition + B_up * halfsize - B_right * halfsize;
		m_PartDatas[i+1].pos = (*it)->m_vecPosition + B_up * halfsize + B_right * halfsize;
		m_PartDatas[i+2].pos = (*it)->m_vecPosition - B_up * halfsize - B_right * halfsize;
		m_PartDatas[i+3].pos = (*it)->m_vecPosition - B_up * halfsize + B_right * halfsize;

		m_PartDatas[i].clr = (*it)->m_clrColor;
		m_PartDatas[i].tex.u = 0.0f;	m_PartDatas[i].tex.v = 0.0f;
		m_PartDatas[i+1].clr = (*it)->m_clrColor;
		m_PartDatas[i+1].tex.u = 1.0f;	m_PartDatas[i+1].tex.v = 0.0f;
		m_PartDatas[i+2].clr = (*it)->m_clrColor;
		m_PartDatas[i+2].tex.u = 0.0f;	m_PartDatas[i+2].tex.v = 1.0f;
		m_PartDatas[i+3].clr = (*it)->m_clrColor;
		m_PartDatas[i+3].tex.u = 1.0f;	m_PartDatas[i+3].tex.v = 1.0f;

		i += 4;
	}

	// 写VB
	void* pDst ;
	m_vb->Lock(0, sizeof(m_PartDatas) ,(void **)&pDst,0);
	memcpy( pDst , m_PartDatas , sizeof(m_PartDatas) );
	m_vb->Unlock();
	m_pDevice->SetStreamSource( 0 , m_vb , 0 , sizeof(Vert_PDT1));
	m_pDevice->SetFVF(Vert_PDT1::fvf);	
	m_pDevice->SetIndices( m_ib);
	m_pDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST , 0 , 0 ,(UINT)m_ActiveList.size()*4 , 0 , (UINT)m_ActiveList.size()*2 );
}


void	CParticleEmitter::Destroy()
{
	m_bActive = false;
	m_fElapsedTime = 0.0f;
	for ( long i = 0 ; i < (long)m_ParticlePool.size() ; i++ )
	{ SAFE_DELETE(m_ParticlePool[i]); }
	m_ParticlePool.clear();
	m_ActiveList.clear();
	m_DisableList.clear();

	DestroyPlugs();
}

void	CParticleEmitter::AddAffector( CParticleAffector* pAffector )
{
	m_AffectorVector.push_back( pAffector );
}


void	CParticleEmitter::DestroyPlugs()
{
	for ( long i = 0 ; i < (long)m_AffectorVector.size() ; i++ )
	{ SAFE_DELETE( m_AffectorVector[i] ); }
	SAFE_RELEASE(m_pTexture);
	SAFE_RELEASE(m_ib);
	SAFE_RELEASE(m_vb);
}


void	CParticleEmitter::SetParentSystem( CParticleSystem* sys )
{
	m_pParentSystem = sys;
}

void	CParticleEmitter::SetActive( bool setting)
{
	if( setting && m_un32MaxParticleNum && m_un32EmitNumPerSec && m_fInitSizeMin )
	{
		m_bActive = setting;
	}
	else
	{
		m_bActive = false;
		m_vecLastPos = m_vecPos = D3DXVECTOR3(0,0,0);
	}
}

void	CParticleEmitter::SetMaxParticleNumber( long num )
{
	m_un32MaxParticleNum = num;

	if ( m_un32MaxParticleNum > MAX_EMIT_NUMBER )
	{ m_un32MaxParticleNum = MAX_EMIT_NUMBER; }
}


void	CParticleEmitter::SetEmitRate( long num_ps )
{
	m_un32EmitNumPerSec = num_ps;
}


void	CParticleEmitter::SetEmitRepeat( float emitmin , float delaymin , float emitvar , float delayvar)
{
	m_fMaxEmitTimeMin = emitmin;	
	m_fMaxEmitTimeVar = emitvar;

	m_fRepeatDelayMin = delaymin;	
	m_fRepeatDelayVar = delayvar;
}


void	CParticleEmitter::SetRelativePos( const D3DXVECTOR3& rel )
{
	if ( m_pParentSystem )
	{
		m_vecRelPos = rel;	
		m_vecPos = m_vecRelPos + m_pParentSystem->GetPosition();
	}
}

void	CParticleEmitter::SetSpeed( const D3DXVECTOR3& spd , const D3DXVECTOR3& var)
{
	m_vecVelocityMin = spd;	
	m_vecVelocityVar = var;
}


void	CParticleEmitter::SetSize( float initmin , float initvar)
{
	m_fInitSizeMin = initmin;	
	m_fInitSizeVar = initvar;
}

void	CParticleEmitter::SetLifeSpan( float min , float var)
{
	m_fLifeSpanMin = min;	
	m_fLifeSpanVar = var;
}

void	CParticleEmitter::SetColor( const D3DCOLORVALUE& clr , const D3DCOLORVALUE& var )
{
	m_clrInitClrMin = D3DCOLOR_COLORVALUE( clr.r , clr.g , clr.b , clr.a );
	m_clrInitClrVar = D3DCOLOR_COLORVALUE( var.r , var.g , var.b , var.a );
}

void	CParticleEmitter::SetColor( D3DCOLOR clr , D3DCOLOR var )
{
	m_clrInitClrMin = clr;	
	m_clrInitClrVar = var;
}


bool  CParticleEmitter::SetTexture( char *texName )
{
	if(strlen(texName)<=0){
		sprintf(m_textureName,"%s","");
		if(m_pTexture){
			SAFE_RELEASE(m_pTexture);
		}	
		return false;
	}
	if(strcmp(m_textureName,texName)==0)
		return true;
	else{
		sprintf(m_textureName,"%s",texName);
	}
	// 调用D3DX函数生成
	if(m_pTexture){
		SAFE_RELEASE(m_pTexture);
	}

	if( FAILED(D3DXCreateTextureFromFile( m_pDevice,texName,&m_pTexture)))
	{
		MessageBox(NULL,"加载纹理失败","失败",MB_OK);
		return false;
	}
	return true;
}

void	CParticleEmitter::SetPoolSize( unsigned int size )
{
	long oldSize = (long)m_ParticlePool.size();

	if ( size == oldSize )	{ return; }
	// 如果新的小于等于旧的,需要重生成整个Pool
	else if( (long)size < oldSize )
	{
		long decr = oldSize - size;
		for ( long i = 0 ; i < (long)m_ParticlePool.size() ; i++ )
		{ SAFE_DELETE(m_ParticlePool[i]); }

		oldSize = 0;
	}
	// 分配空间
	m_ParticlePool.reserve(size);
	m_ParticlePool.resize(size);

	// Create new particles
	for( size_t i = oldSize; i < size; i++ )
	{
		m_ParticlePool[i] = new CParticle;
	}
}

void CParticleEmitter::SetName(string str){
	m_strName=str;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -