📄 game_particle.cpp
字号:
#include "Game_User.h"
const DWORD CParticleSystem::POINTVERTEX::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;
CParticleSystem::CParticleSystem(LPDIRECT3DDEVICE9 pDevice,char *strTexture)
{
m_dwType = 1;
m_pDevice =pDevice;
m_EmitVel =1.0f; //范围
m_EmitRate = 30; //速度
m_EmitAngle =D3DX_PI*0.02f; //角度
m_fTime =0.0f; //开始时间
m_fGravity =-9.8f; //地心引力
m_fParticleLife =1.0f; //生命期
m_fParticleFade =2.0f; //淡出
m_fParticleSize =100.0f; //粒子的大小
m_dwParticles = 0;
m_dwParticlesLim = 50 ;
m_bMoving = false;
m_bLive = false;
m_dwAttackNum = 0;
m_dwMagicNum = 0;
m_dwFlush = 512;//512; //小块粒子
m_dwDiscard = m_dwFlush*64; //缓冲区大小
m_dwBase = m_dwDiscard; //缓冲区的起始位置
m_vPosition =D3DXVECTOR3(0,50,0);
m_vIntersectPoint =D3DXVECTOR3(0,-50,0);
m_clrEmit =0xFFFF8040;
m_clrFade =0x018080FF;
m_fYaw =D3DX_PI*1.5f; //水平角
m_fPitch =D3DX_PI*0.0f; //垂直角
m_vDirection = D3DXVECTOR3(cosf(m_fYaw)*cosf(m_fPitch),sinf(m_fPitch),sinf(m_fYaw)*cosf(m_fPitch));
m_pTexture = NULL; // 纹理
m_pParticles = NULL; //生存粒子
m_pParticlesFree = NULL; //消亡粒子
m_pVB = NULL; //顶点缓冲
D3DXCreateTextureFromFile(m_pDevice,strTexture,&m_pTexture);//从文件加载纹理
RestoreDeviceObjects();
}
CParticleSystem::~CParticleSystem()
{
InvalidateDeviceObjects();
while( m_pParticles )
{
PARTICLE* pSpark = m_pParticles;
m_pParticles = pSpark->m_pNext;
delete pSpark;
}
while( m_pParticlesFree )
{
PARTICLE *pSpark = m_pParticlesFree;
m_pParticlesFree = pSpark->m_pNext;
delete pSpark;
}
}
HRESULT CParticleSystem::RestoreDeviceObjects()
{
HRESULT hr;
if(FAILED(hr = m_pDevice->CreateVertexBuffer( m_dwDiscard *
sizeof(POINTVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY | D3DUSAGE_POINTS,
POINTVERTEX::FVF, D3DPOOL_DEFAULT, &m_pVB, NULL )))
{
return E_FAIL;
}
return S_OK;
}
HRESULT CParticleSystem::InvalidateDeviceObjects()
{
SAFE_RELEASE(m_pTexture);
SAFE_RELEASE(m_pVB );
return S_OK;
}
HRESULT CParticleSystem::Update( float fSecsPerFrame)
{
PARTICLE *pParticle, **ppParticle;
D3DMATRIX matLocal; //用于将粒子的本地坐标,转换到世界空间的矩阵
D3DVECTOR vDirLocal; //粒子的本地坐标
D3DVECTOR vPosLocal;
//本地坐标矩阵的z方向
matLocal._31=m_vDirection.x;
matLocal._32=m_vDirection.y;
matLocal._33=m_vDirection.z;
//本地坐标矩阵的x方向
if(fabsf(m_vDirection.y)<1)
{
matLocal._11=m_vDirection.z;
matLocal._12=0 ;
matLocal._13=-m_vDirection.x;
}
else
{
matLocal._11=1;
matLocal._12=0;
matLocal._13=0;
}
//本地坐标矩阵的y方向
matLocal._21=-matLocal._12*matLocal._33+matLocal._13*matLocal._32;
matLocal._22=-matLocal._13*matLocal._31+matLocal._11*matLocal._33;
matLocal._23=-matLocal._11*matLocal._32+matLocal._12*matLocal._31;
matLocal._41=0;
matLocal._42=0;
matLocal._43=0;
matLocal._44=1;
m_fTime += fSecsPerFrame;
ppParticle = &m_pParticles;
//更新粒子状态
while( *ppParticle )
{ pParticle = *ppParticle;
// 计算新位置
float fT = m_fTime - pParticle->m_fTime0;
//设置加速度
//落下时
//衰减
pParticle->m_fFade -= fSecsPerFrame;
pParticle->m_vPos = pParticle->m_vVel0 * fT + pParticle->m_vPos0;
pParticle->m_vPos.y += (0.5f * m_fGravity) * (fT * fT);
pParticle->m_vVel.y = pParticle->m_vVel0.y + m_fGravity * fT;
//删除旧粒子,落地的粒子
if( pParticle->m_vPos.y <0 || m_fTime-pParticle->m_fTime0>m_fParticleLife )// m_fRadius)
{
//删除这个粒子,把它加入到消亡链表
*ppParticle = pParticle->m_pNext;
pParticle->m_pNext = m_pParticlesFree;
m_pParticlesFree = pParticle;
m_dwParticles--;
}
else
{
ppParticle = &pParticle->m_pNext;
}
}
//发射新粒子,每次至少发射一个粒子
DWORD dwParticlesEmit = m_dwParticles+
DWORD(fSecsPerFrame*m_EmitRate>=1?m_EmitRate*fSecsPerFrame: //发射率算出来的数量大于1
fmodf(m_fTime,1/m_EmitRate)<fSecsPerFrame?1:0); //波形分析,t2=t%T2<T1时,应该发射一个粒子
while( m_dwParticles < m_dwParticlesLim && m_dwParticles < dwParticlesEmit )
{
if( m_pParticlesFree ) //如果消亡粒子链表里有,就从消亡链表里取出一个节点
{
pParticle = m_pParticlesFree;
m_pParticlesFree = pParticle->m_pNext;
}
else //如果没有,就再创建
{
if( NULL == ( pParticle = new PARTICLE ) )
return E_OUTOFMEMORY;
}
pParticle->m_pNext = m_pParticles; //加入到活动链表
m_pParticles = pParticle;
m_dwParticles++;
FLOAT fRand1 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 2.0f;
FLOAT fRand2 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * m_EmitAngle*0.5f; // m_EmitAngle锥形角度,所以是一半
FLOAT Speed = ((FLOAT)rand()/(FLOAT)RAND_MAX*0.2f+0.8f) * m_EmitVel;
//初始化新加入的粒子
vDirLocal.x=Speed* cosf(fRand1) * sinf(fRand2);
vDirLocal.y=Speed* sinf(fRand1) * sinf(fRand2);
vDirLocal.z=Speed* cosf(fRand2);
fRand1=((FLOAT)rand()/(FLOAT)RAND_MAX*2);
fRand2=((FLOAT)rand()/(FLOAT)RAND_MAX*2);
switch(m_dwType)
{
case EMITTERTYPE_PLANAR_QUADRATE:
vPosLocal.x=fRand1*m_EmitWidth;
vPosLocal.y=fRand2*m_EmitWidth;
vPosLocal.z=0;
break;
case EMITTERTYPE_PLANAR_ROUND:
fRand2*=D3DX_PI;
fRand1*=m_EmitWidth;
vPosLocal.x=fRand1*sinf(fRand2);
vPosLocal.y=fRand1*cosf(fRand2);
vPosLocal.z=0;
break;
default:
vPosLocal.x=0;
vPosLocal.y=0;
vPosLocal.z=0;
break;
}
pParticle->m_vVel0.x =vDirLocal.x*matLocal._11+vDirLocal.y*matLocal._21+vDirLocal.z*matLocal._31;//10* cosf(fRand1) * sinf(fRand2) * 2.5f;
pParticle->m_vVel0.y =vDirLocal.x*matLocal._12+vDirLocal.y*matLocal._22+vDirLocal.z*matLocal._32;//10* cosf(fRand1) * sinf(fRand2) * 2.5f;
pParticle->m_vVel0.z =vDirLocal.x*matLocal._13+vDirLocal.y*matLocal._23+vDirLocal.z*matLocal._33;//10* cosf(fRand1) * sinf(fRand2) * 2.5f;
pParticle->m_vPos0.x =m_vPosition.x+vPosLocal.x*matLocal._11+vPosLocal.y*matLocal._21+vPosLocal.z*matLocal._31;//10* cosf(fRand1) * sinf(fRand2) * 2.5f;
pParticle->m_vPos0.y =m_vPosition.y+vPosLocal.x*matLocal._12+vPosLocal.y*matLocal._22+vPosLocal.z*matLocal._32;//10* cosf(fRand1) * sinf(fRand2) * 2.5f;
pParticle->m_vPos0.z =m_vPosition.z+vPosLocal.x*matLocal._13+vPosLocal.y*matLocal._23+vPosLocal.z*matLocal._33;//10* cosf(fRand1) * sinf(fRand2) * 2.5f;
pParticle->m_vPos = pParticle->m_vPos0;
pParticle->m_vVel = pParticle->m_vVel0;
pParticle->m_clrEmit=m_clrEmit;
pParticle->m_clrFade=m_clrFade;
pParticle->m_fFade = m_fParticleFade;
pParticle->m_fTime0 = m_fTime;
}
return S_OK;
}
//
bool CParticleSystem::MoveTo(D3DXVECTOR3 IntersectPoint,D3DXVECTOR3 * vPosition,float tFrameTime, float Speed)
{
static float disXZ = 0.0f, dist = 0.0f;
disXZ = DistanceXZOfTwoVec3(IntersectPoint, *vPosition);
dist = DistanceOfTowVec3(IntersectPoint, *vPosition, disXZ);
m_fYaw = GetYaw(IntersectPoint, *vPosition);
m_fPitch = GetPitch(IntersectPoint, *vPosition);
vPosition->x += tFrameTime*Speed*sinf(m_fYaw)*cosf(m_fPitch);
vPosition->z += tFrameTime*Speed*cosf(m_fYaw)*cosf(m_fPitch);
vPosition->y += tFrameTime*Speed*sinf(m_fPitch);
if(dist <= tFrameTime*Speed)
{
return false;
}
else
return true;
}
HRESULT CParticleSystem::Render(float tFrame,D3DXVECTOR3 * IntersectPoint)
{
if(IntersectPoint->y >=0)
m_vIntersectPoint.y = IntersectPoint->y+50;
m_vIntersectPoint.x = IntersectPoint->x;
m_vIntersectPoint.z = IntersectPoint->z;
Update2(tFrame);
HRESULT hr;
D3DMATRIX matWorld;
memset(&matWorld,0,sizeof(matWorld));
matWorld._11=1;
matWorld._22=1;
matWorld._33=1;
matWorld._44=1;
m_pDevice->SetTransform(D3DTS_WORLD,&matWorld);
m_pDevice->SetTexture(0,m_pTexture);
m_pDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
m_pDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
m_pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
m_pDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE);
m_pDevice->SetRenderState( D3DRS_LIGHTING,FALSE);
m_pDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, TRUE );
m_pDevice->SetRenderState( D3DRS_POINTSCALEENABLE, TRUE );
m_pDevice->SetRenderState( D3DRS_POINTSIZE, FtoDW(m_fParticleSize) );
m_pDevice->SetRenderState( D3DRS_POINTSIZE_MIN, FtoDW(0.00f) );
m_pDevice->SetRenderState( D3DRS_POINTSCALE_A, FtoDW(0.00f) );
m_pDevice->SetRenderState( D3DRS_POINTSCALE_B, FtoDW(0.00f) );
m_pDevice->SetRenderState( D3DRS_POINTSCALE_C, FtoDW(1.00f) );
m_pDevice->SetStreamSource( 0, m_pVB, 0, sizeof(POINTVERTEX) );
m_pDevice->SetFVF( POINTVERTEX::FVF );
PARTICLE* pParticle = m_pParticles;
POINTVERTEX* pVertices;
DWORD dwNumParticlesToRender = 0;
//锁定顶点缓冲区,以小块填充,如果所有的小块都填充了,就绘制它们,然后再锁定下一个块,
//如果空间用完了,就从头开始,使用DISCARD方式销毁
m_dwBase += m_dwFlush;
if(m_dwBase >= m_dwDiscard)
m_dwBase = 0;
//dwBase开始是没有使用的缓冲区, 要使用m_dwFlush个顶点
if( FAILED( hr = m_pVB->Lock( m_dwBase * sizeof(POINTVERTEX), m_dwFlush * sizeof(POINTVERTEX),
(void**) &pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
{
return hr;
}
// 借助 D3DLOCK_NOOVERWRITE 对 VB 进行 Lock (锁定)。这告知 Direct3D 和驱动程序,
// 您将要添加顶点,而并不修改您先前批处理过的顶点。 因此,如果当时正在进行一项 DMA
// 操作,则并不中断该操作.
// Render each particle
while( pParticle )
{
D3DXVECTOR3 vPos(pParticle->m_vPos);
D3DXVECTOR3 vVel(pParticle->m_vVel);
FLOAT fLengthSq = D3DXVec3LengthSq(&vVel);
UINT dwSteps;
if( fLengthSq < 1.0f ) dwSteps = 2;
else if( fLengthSq < 4.00f ) dwSteps = 3;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -