突然相遇:
然后死掉.
源代码以及实现方法:
首先定义一个Character类为角色的基类,然后英雄魔兽(战士)类Warcraft与托尼(法师)类Timy继承于它。分别实现对应的方法。
角色类有许多的方法,也有一些需要子类实现的虚函数方法。
Character.h:
//=============================================================================
//一个封装了游戏角色类的头文件
//=============================================================================
#pragma once
#include
#include
#include "AnimationClass.h"
#include "AnimInstanceClass.h"
#include "DirectInputClass.h"
#include
//血条的顶点定义
struct CUSTOMVERTEX
{
float x, y, z;
float u, v;
CUSTOMVERTEX(float _x, float _y, float _z, float _u, float _v):
x(_x), y(_y), z(_z), u(_u), v(_v){}
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_TEX1)
//定义角色类型
#define CHARACTER_TOWER 0 //防御塔
#define CHARACTER_WARCRAFT 1 //魔兽
#define CHARACTER_TINY 2 //提尼
class Warcraft;
class Tower;
class Tiny;
//游戏角色类
class Character
{
friend class Warcraft;
friend class Tower;
friend class Tiny;
private:
LPDIRECT3DDEVICE9 m_pd3dDevice; //设备指针
AnimInstanceClass *m_pAnimInstance; //骨骼动画实力
D3DXMATRIX m_matrix; //变换矩阵
D3DXVECTOR3 m_position; //角色的位置
LPDIRECT3DVERTEXBUFFER9 m_pHpBuffer; //血条的顶点缓存
LPDIRECT3DTEXTURE9 m_pHpTexture; //血条的纹理
LPDIRECT3DVERTEXBUFFER9 m_pHpBackBuffer; //血条背景缓存
LPDIRECT3DTEXTURE9 m_pHpBackTexture; //血条背景纹理
int m_team; //角色的队伍
int m_anim; //角色动画状态
float m_attackTime; //角色攻击时间
float m_attackWait; //角色攻击冷却时间
int m_hp; //角色生命值
int m_maxHp; //角色最大生命值
bool dead; //角色是否死亡
float m_attackRate; //角色攻击范围
int m_aggress; //角色攻击力
float m_modelRadius; //角色模型半径
int m_id; //角色类型
public:
Character(LPDIRECT3DDEVICE9 pd3dDevice, AnimationClass *pAnimation, float attackWait, //构造函数
int maxHp, float attackRate, int aggress, D3DXVECTOR3 startPos, int team, float modelRadius, int id);
int GetAnimation(); //获取角色动画状态
D3DXVECTOR3 GetPosition(); //获取角色位置
float GetAttackTime(); //获取角色攻击时间
float GetAttackWait(); //获取角色攻击冷却时间
float GetModelRadius(); //获取角色模型半径
HRESULT SetAnimationByName(LPCSTR animName); //根据名字设置骨骼动画
void SetAnimationMatrix(D3DXMATRIX *pMatrix); //设置骨骼动画矩阵
void SetPosition(D3DXVECTOR3 *position); //设置游戏角色位置
void SetAnimation(int anim); //设置角色骨骼动画
void Damage(int damage); //角色受到的伤害
bool isDead() {return dead;} //返回玩家是否死亡
float VectorCross(float x1, float y1, float x2, float y2); //向量的叉积
virtual void Render(float fDeltaTime, D3DXMATRIX *viewMat) = 0; //渲染游戏角色
virtual void Attack(std::vector &enemy) = 0; //攻击
virtual void Ready() = 0; //原地准备
virtual void PlayAnimation() = 0; //播放动画
virtual void Update(float fDeltaTime) = 0; //更新游戏角色
virtual void Dead() = 0; //死亡
virtual void AI(std::vector &enemy, std::vector &friends) = 0; //AI
virtual void SetMatrix() = 0; //对骨骼动画进行矩阵变换
virtual ~Character(void) = 0; //析构函数
virtual int GetExp() = 0; //返回角色死亡后返回的经验值
virtual void AddExp(int exp) = 0; //角色获得经验值
virtual void UserControl(DirectInputClass *pInput, std::vector &enemy, std::vector &friends) = 0; //玩家控制
virtual int GetLevel() = 0; //返回角色等级
virtual int GetKillNum() = 0; //返回击杀数
virtual int GetDeadNum() = 0; //返回死亡数
virtual int GetReviveTime() = 0; //返回复活时间
};
Character.cpp:
//=============================================================================
//一个封装了游戏角色类的头文件
//=============================================================================
#include "Character.h"
//构造函数
Character::Character(LPDIRECT3DDEVICE9 pd3dDevice, AnimationClass *pAnimation, float attackWait,
int maxHp, float attackRate, int aggress, D3DXVECTOR3 startPos, int team, float modelRadius, int id)
{
m_pd3dDevice = pd3dDevice;
m_pAnimInstance = new AnimInstanceClass(pAnimation);
D3DXMatrixIdentity(&m_matrix);
m_attackWait = attackWait;
m_attackTime = attackWait;
m_maxHp = maxHp;
m_hp = maxHp;
dead = false;
m_attackRate = attackRate;
m_aggress = aggress;
m_position = startPos;
m_pHpBuffer = NULL;
m_pHpTexture = NULL;
m_pHpBackBuffer = NULL;
m_pHpBackTexture = NULL;
m_team = team;
m_anim = ANIMATION_READY;
m_modelRadius = modelRadius;
m_id = id;
//根据队伍创建相应的血条纹理
if(m_team == BLUE)
D3DXCreateTextureFromFile(m_pd3dDevice, L"Textures\\bloodBlue.png", &m_pHpTexture);
else if(m_team == RED)
D3DXCreateTextureFromFile(m_pd3dDevice, L"Textures\\bloodRed.png", &m_pHpTexture);
D3DXCreateTextureFromFile(m_pd3dDevice, L"Textures\\bloodBack.png", &m_pHpBackTexture);
m_pd3dDevice->CreateVertexBuffer(4 * sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_MANAGED, &m_pHpBuffer, 0);
m_pd3dDevice->CreateVertexBuffer(4 * sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_MANAGED, &m_pHpBackBuffer, 0);
}
//析构函数
Character::~Character(void)
{
SAFE_DELETE(m_pAnimInstance);
SAFE_RELEASE(m_pHpBuffer);
SAFE_RELEASE(m_pHpTexture);
SAFE_RELEASE(m_pHpBackBuffer);
SAFE_RELEASE(m_pHpBackTexture);
}
//根据名字设置骨骼动画
HRESULT Character::SetAnimationByName(LPCSTR animName)
{
return m_pAnimInstance->SetAnimationByName(animName);
}
//设置骨骼动画矩阵
void Character::SetAnimationMatrix(D3DXMATRIX *pMatrix)
{
m_matrix = *pMatrix;
}
//获取角色位置
D3DXVECTOR3 Character::GetPosition()
{
return m_position;
}
//设置游戏角色位置
void Character::SetPosition(D3DXVECTOR3 *position)
{
m_position = *position;
}
//角色受到的伤害
void Character::Damage(int damage)
{
m_hp -= damage;
if(m_hp <= 0)
Dead();
}
//获取角色动画状态
int Character::GetAnimation()
{
return m_anim;
}
//设置角色骨骼动画
void Character::SetAnimation(int anim)
{
m_anim = anim;
}
//向量的叉积
float Character::VectorCross(float x1, float y1, float x2, float y2)
{
return x1*y2 - x2*y1;
}
//获取角色攻击时间
float Character::GetAttackTime()
{
return m_attackTime;
}
//获取角色攻击冷却时间
float Character::GetAttackWait()
{
return m_attackWait;
}
//获取角色模型半径
float Character::GetModelRadius()
{
return m_modelRadius;
}
然后是它的英雄子类。
Warcraft.h:
//=============================================================================
//一个实现了魔兽的类的头文件
//=============================================================================
#pragma once
#include "Character.h"
#include "TerrainClass.h"
const int totalExpWarcraft[15] = {100,150,210,280,360,430,500,580,670,770,880,1000,1150,1300,1500}; //各等级的总的经验值
const int totalHpWarcraft[15] = {616,700,784,869,953,1037,1121,1205,1289,1373,1457,1541,1625,1709,1793}; //各等级总的HP
const float WarcraftRotSpeed = 1.0f; //旋转速度
const float WarcraftAttackWait = 1.0f; //攻击冷却时间
const float WarcraftAttackRate = 600.0f; //攻击范围
const int WarcraftAggress = 100; //攻击力
const int WarcraftRadius = 100; //模型范围
const int WarcraftTransSpeed = 4.0f; //移动速度
class Warcraft : public Character
{
private:
D3DXVECTOR3 m_lookVec; //面对的方向向量
D3DXVECTOR3 m_startPos; //起始位置
float m_angleUp; //绕Y轴旋转的角度
float m_angleStart; //起始旋转角度
float m_reviveTime; //复活时间
TerrainClass *m_pTerrain; //地形类指针
int m_level; //等级
int m_exp; //经验值
int m_nKill; //击杀数
int m_nDead; //死亡数
public:
Warcraft(LPDIRECT3DDEVICE9 pd3dDevice, AnimationClass *pAnimation, D3DXVECTOR3 startPos, int team,
TerrainClass *pTerrain, float m_angleStart); //构造函数
~Warcraft(void); //析构函数
void SetMatrix(); //对骨骼动画进行矩阵变换
void MoveForward(std::vector &enemy, std::vector &friends); //前进
void RotationLeft(); //左转
void RotationRight(); //右转
void Attack(std::vector &enemy); //攻击
void Ready(); //准备
void PlayAnimation(); //播放动画
void Update(float fDeltaTime); //更新
void Dead(); //死亡
void AI(std::vector &enemy, std::vector &friends); //AI
bool isBlocked(D3DXVECTOR3 *position, std::vector &enemy, std::vector &friends);//阻挡函数
int GetExp(); //返回角色死亡后返回的经验值,为当前经验值的一半
void AddExp(int exp); //角色获得经验值
int GetLevel(); //返回角色等级
int GetKillNum(); //返回击杀数
int GetDeadNum(); //返回死亡数
int GetReviveTime(); //返回复活时间
void Render(float fDeltaTime, D3DXMATRIX *billboardMat); //渲染游戏角色
void UserControl(DirectInputClass *pInput, std::vector &enemy, std::vector &friends); //玩家控制
};
Warcraft.cpp:
//=============================================================================
//一个实现了魔兽的类的源文件
//=============================================================================
#include "Warcraft.h"
//构造函数
Warcraft::Warcraft(LPDIRECT3DDEVICE9 pd3dDevice, AnimationClass *pAnimation, D3DXVECTOR3 startPos, int team, TerrainClass *pTerrain, float angleStart):
Character(pd3dDevice, pAnimation, WarcraftAttackWait,totalHpWarcraft[0], WarcraftAttackRate, WarcraftAggress, startPos, team,
WarcraftRadius, CHARACTER_WARCRAFT),
m_lookVec(D3DXVECTOR3(1, 0, 1)),
m_startPos(startPos),
m_pTerrain(pTerrain),
m_angleUp(angleStart),
m_angleStart(angleStart),
m_reviveTime(REVIVE_TIME),
m_level(1),
m_exp(totalExpWarcraft[0]),
m_nKill(0),
m_nDead(0)
{
}
//析构函数
Warcraft::~Warcraft(void)
{
}
//前进
void Warcraft::MoveForward(std::vector &enemy, std::vector &friends)
{
//攻击状态不能移动
if(m_anim == ANIMATION_ATTACK)
return;
//改变动画状态为移动
m_anim = ANIMATION_RUN;
D3DXVECTOR3 target;
//计算下一个目标位置,即当前位置加面对的方向向量乘移动速度
target = m_position + m_lookVec*WarcraftTransSpeed;
//如果目标位置没有被阻挡,设置此目标位置为角色位置。
if(!isBlocked(&target, enemy, friends))
{
SetPosition(&target);
SetMatrix();
}
}
//准备
void Warcraft::Ready()
{
//改变动画状态为准备
if(m_anim != ANIMATION_ATTACK)
m_anim = ANIMATION_READY;
}
//攻击
void Warcraft::Attack(std::vector &enemy)
{
if(m_attackTime == m_attackWait)
{
//改变动画状态为攻击
m_anim = ANIMATION_ATTACK;
//减少m_attackTime,使其检测到已经进行了攻击
m_attackTime -= 0.000001f;
//在攻击范围内的敌人,都会受到伤害
for(int i = 0; i < enemy.size(); ++i)
if(!enemy[i]->isDead())
{
double length = D3DXVec3Length(&(enemy[i]->GetPosition() - m_position)) - m_modelRadius;
if(length <= m_attackRate)
{
enemy[i]->Damage(m_aggress);
if(enemy[i]->isDead())
AddExp(enemy[i]->GetExp());
}
}
}
}
//左转
void Warcraft::RotationLeft()
{
//减少绕Y轴旋转的角度
m_angleUp -= WarcraftRotSpeed / 100;
SetMatrix();
}
//右转
void Warcraft::RotationRight()
{
//增加绕Y轴旋转的角度
m_angleUp += WarcraftRotSpeed / 100;
SetMatrix();
}
//播放动画
void Warcraft::PlayAnimation()
{
//根据不同的动画状态,播放不同的动画
switch(m_anim)
{
case ANIMATION_READY:
m_pAnimInstance->SetAnimationByName("ready");
break;
case ANIMATION_RUN:
m_pAnimInstance->SetAnimationByName("run");
break;
case ANIMATION_ATTACK:
m_pAnimInstance->SetAnimationByName("magicAttack");
break;
}
}
//更新
void Warcraft::Update(float fDeltaTime)
{
//更新攻击时间
if(m_anim == ANIMATION_ATTACK)
{
m_attackTime -= fDeltaTime;
if(m_attackTime < 0)
{
m_attackTime = m_attackWait;
m_anim = ANIMATION_READY;
}
}
//死亡后,更新复活时间
if(dead)
{
m_reviveTime -= fDeltaTime;
if(m_reviveTime < 0)
{
m_reviveTime = REVIVE_TIME;
dead = false;
SetMatrix();
}
}
//更新血条与血条背景的顶点缓存
CUSTOMVERTEX *pVertices = NULL;
m_pHpBackBuffer->Lock(0, 4*sizeof(CUSTOMVERTEX), (void**)&pVertices, 0);
pVertices[0] = CUSTOMVERTEX(-500.0f, 0.0f, 0.0f, 0.0f, 1.0f);
pVertices[1] = CUSTOMVERTEX(-500.0f, 40.0f, 0.0f, 0.0f, 0.0f);
pVertices[2] = CUSTOMVERTEX(500.0f, 0.0f, 0.0f, 1.0f, 1.0f);
pVertices[3] = CUSTOMVERTEX(500.0f, 40.0f, 0.0f, 1.0f, 0.0f);
m_pHpBackBuffer->Unlock();
float hpPosX = -500.0f + (float)m_hp / m_maxHp * 1000;
pVertices = NULL;
m_pHpBuffer->Lock(0, 4*sizeof(CUSTOMVERTEX), (void**)&pVertices, 0);
pVertices[0] = CUSTOMVERTEX(-500.0f, 0.0f, 0.0f, 0.0f, 1.0f);
pVertices[1] = CUSTOMVERTEX(-500.0f, 40.0f, 0.0f, 0.0f, 0.0f);
pVertices[2] = CUSTOMVERTEX(hpPosX, 0.0f, 0.0f, 1.0f, 1.0f);
pVertices[3] = CUSTOMVERTEX(hpPosX, 40.0f, 0.0f, 1.0f, 0.0f);
m_pHpBuffer->Unlock();
}
//死亡
void Warcraft::Dead()
{
//初始化位置,hp,旋转角度,增加死亡数目
dead = true;
m_position = m_startPos;
m_hp = m_maxHp;
m_angleUp = m_angleStart;
++m_nDead;
}
//AI
void Warcraft::AI(std::vector &enemy, std::vector &friends)
{
//如果血量少于1/5,旋转角度为初始起始旋转角度+180度,转身并前进逃跑。
if((float)m_hp / m_maxHp <= 0.2)
{
m_angleUp = m_angleStart + D3DX_PI;
MoveForward(enemy, friends);
return;
}
//否则寻找在攻击范围内的敌人,进行攻击,如果敌人在自己观察向量的左边,向左转,如果在右边向右转
for(int i = 0; i < enemy.size(); ++i)
{
if(enemy[i]->isDead())
continue;
D3DXVECTOR3 v = enemy[i]->GetPosition() - m_position;
float length = D3DXVec3Length(&v) - m_modelRadius;
if(length <= m_attackRate)
{
Attack(enemy);
float num = VectorCross(m_lookVec.x, m_lookVec.z, v.x, v.z);
if(num > 0.0f)
RotationLeft();
else if(num < 0.0f)
RotationRight();
return;
}
}
//否则设定绕Y轴旋转的角度为初始角度并前进
m_angleUp = m_angleStart;
MoveForward(enemy, friends);
}
//阻挡函数
bool Warcraft::isBlocked(D3DXVECTOR3 *position, std::vector &enemy, std::vector &friends)
{
//获取该位置的高度值
float height = m_pTerrain->GetPositionHeight(position); //高度值大于200则阻挡
if(height >= 200)
return true;
//检测模型与防御塔的距离,如果距离小于两模型半径之和,则发生碰撞,即发生阻挡。
for(int i = 0; i < enemy.size(); ++i)
if(enemy[i]->m_id == CHARACTER_TOWER)
{
float length = D3DXVec3Length(&(*position - enemy[i]->GetPosition()));
if(length < m_modelRadius + enemy[i]->m_modelRadius)
return true;
}
for(int i = 0; i < friends.size(); ++i)
if(friends[i]->m_id == CHARACTER_TOWER)
{
float length = D3DXVec3Length(&(*position - friends[i]->GetPosition()));
if(length < m_modelRadius + friends[i]->m_modelRadius)
return true;
}
return false;
}
//对骨骼动画进行矩阵变换
void Warcraft::SetMatrix()
{
//计算旋转矩阵,平移矩阵
D3DXVECTOR3 lookVec(1, 0, 0);
D3DXMATRIX playerMat, transMat, rotMat;
D3DXMatrixRotationY(&rotMat, m_angleUp);
D3DXMatrixTranslation(&transMat, m_position.x, m_position.y, m_position.z);
D3DXVec3TransformCoord(&m_lookVec, &lookVec, &rotMat);
playerMat = m_matrix * rotMat * transMat;
m_pAnimInstance->SetAnimationMatrix(&playerMat);
}
//返回角色死亡后返回的经验值,为当前经验值的一半
int Warcraft::GetExp()
{
return totalExpWarcraft[m_level - 1] / 2;
}
//角色获得经验值
void Warcraft::AddExp(int exp)
{
m_exp += exp;
++m_nKill;
//升级
if(m_exp >= totalExpWarcraft[m_level])
{
m_level = min(m_level+1, 15);
m_maxHp = totalHpWarcraft[m_level-1];
//攻击力少量提升
m_aggress += 20;
}
}
//返回角色等级
int Warcraft::GetLevel()
{
return m_level;
}
//返回击杀数
int Warcraft::GetKillNum()
{
return m_nKill;
}
//返回死亡数
int Warcraft::GetDeadNum()
{
return m_nDead;
}
//渲染游戏角色
void Warcraft::Render(float fDeltaTime, D3DXMATRIX *billboardMat)
{
//关闭光照
m_pd3dDevice->SetRenderState(D3DRS_LIGHTING, false);
//渲染骨骼动画
m_pAnimInstance->RenderAnimation(fDeltaTime);
//设置公告板矩阵
billboardMat->_41 = m_position.x;
billboardMat->_42 = m_position.y + 1000;
billboardMat->_43 = m_position.z;
m_pd3dDevice->SetTransform(D3DTS_WORLD, billboardMat);
//渲染血条背景
m_pd3dDevice->SetTexture(0, m_pHpBackTexture);
m_pd3dDevice->SetStreamSource(0, m_pHpBackBuffer, 0, sizeof(CUSTOMVERTEX));
m_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
//渲染血条
m_pd3dDevice->SetTexture(0, m_pHpTexture);
m_pd3dDevice->SetStreamSource(0, m_pHpBuffer, 0, sizeof(CUSTOMVERTEX));
m_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
m_pd3dDevice->SetRenderState(D3DRS_LIGHTING, true);
}
//返回复活时间
int Warcraft::GetReviveTime()
{
return (int)m_reviveTime;
}
//玩家控制
void Warcraft::UserControl(DirectInputClass *pDInput, std::vector &enemy, std::vector &friends)
{
if (pDInput->IsKeyDown(DIK_A))
RotationLeft();
else if (pDInput->IsKeyDown(DIK_D))
RotationRight();
else if (pDInput->IsKeyDown(DIK_W))
MoveForward(enemy, friends);
else if(pDInput->IsKeyDown(DIK_J))
Attack(enemy);
else
Ready();
}
说一下魔兽类的关键方法的实现吧。
前进:首先判断一下如果是出于攻击状态的话是没法攻击的,是属于霸体状态的。然后我们获取角色的位置,计算一下下一帧的位置,就是当前位置加上面对方向向量乘上移动速度即可。最后需要判断一下该位置有没有障碍物,有的话是没法移动的。
攻击冷却:m_attackTime初始值为m_attackWait。m_attackTime=m_attackWait时可以进行攻击。m_attackTime用来统计攻击后的时间,攻击后随时间减小,小于0后变为m_attackWait,冷却就完成了。
攻击:攻击有冷却时间,首先判断是否到达冷却时间,如果到了冷却时间,就可以改变动画状态,开始播放攻击动画。然后从敌人容器中选择活着的敌人,判断是否处于攻击范围内。是的话进行攻击,如果敌方英雄死亡则自身获得相应的经验值。
转向:我们在类里定义一个m_angleUp表示绕Y轴旋转的角度。转向的时候加上或者剪去一定比例的转向速度,最后根据角度计算变换矩阵变换即可。
更新:对各种状态的更新,如攻击时间m_attackTime,死亡后复活时间,血条顶点缓存信息。
AI:如果血量少于1/5,旋转角度为初始起始旋转角度加上180度,转身并前进逃跑,否则寻找在攻击范围内的敌人,进行攻击,如果敌人在自己观察向量的左边,向左转,如果在右边向右转,否则设定绕Y轴旋转的角度为初始角度并前进。这里有个小细节:如何判断敌人在自己左边还是右边呢?我们可以通过面朝向量与自己与敌人向量叉积来判断,叉积大于0说明敌人在左边,反之在右边。
阻挡函数:首先获取一下该位置的高度值,大于200说明有障碍物。否则检查角色与防御塔的距离,果距离小于两模型半径之和,则发生碰撞,即发生阻挡。
渲染:用公告板技术对血条的位置进行实时的变化,使之时刻对着相机。
Tiny.h:
#pragma once
//=============================================================================
//一个实现了提尼的类的头文件
//=============================================================================
#include "Character.h"
#include "TerrainClass.h"
#include "FireParticleClass.h"
const int totalExpTiny[15] = {100,150,210,280,360,430,500,580,670,770,880,1000,1150,1300,1500}; //各等级的总的经验值
const int totalHpTiny[15] = {416,500,584,669,753,837,921,1005,1089,1173,1257,1341,1425,1509,1593}; //各等级总的HP
const float TinyRotSpeed = 1.0f; //旋转速度
const float TinyAttackWait = 2.0f; //攻击冷却时间
const float TinyAttackRate = 2500.0f; //攻击范围
const int TinyAggress = 0; //攻击力
const int TinyRadius = 100; //模型范围
const int TinyTransSpeed = 3.0f; //移动速度
//=============================================================================
//提尼的类
//=============================================================================
class Tiny : public Character
{
private:
D3DXVECTOR3 m_lookVec; //面对的方向向量
D3DXVECTOR3 m_startPos; //起始位置
float m_angleUp; //绕Y轴旋转的角度
float m_angleStart; //起始旋转角度
float m_reviveTime; //复活时间
TerrainClass *m_pTerrain; //地形类指针
FireParticleClass *m_pFireParticle; //火球粒子系统类指针
int m_level; //等级
int m_exp; //经验值
int m_nKill; //击杀数
int m_nDead; //死亡数
int m_index; //在队伍数组中的下标
public:
Tiny(LPDIRECT3DDEVICE9 pd3dDevice, AnimationClass *pAnimation, D3DXVECTOR3 startPos, int team, //构造函数
TerrainClass *pTerrain, float m_angleStart, FireParticleClass *pFireParticle, int index);
~Tiny(void); //析构函数
void SetMatrix(); //对骨骼动画进行矩阵变换
void MoveForward(std::vector &enemy, std::vector &friends); //前进
void RotationLeft(); //左转
void RotationRight(); //右转
void Attack(std::vector &enemy); //攻击
void Ready(); //准备
void PlayAnimation(); //播放动画
void Update(float fDeltaTime); //更新
void Dead(); //死亡
void AI(std::vector &enemy, std::vector &friends); //AI
bool isBlocked(D3DXVECTOR3 *position, std::vector &enemy, std::vector &friends); //阻挡函数
int GetExp(); //返回角色死亡后返回的经验值,为当前经验值的一半
void AddExp(int exp); //角色获得经验值
int GetLevel(); //返回角色等级
int GetKillNum(); //返回击杀数
int GetDeadNum(); //返回死亡数
int GetReviveTime(); //返回复活时间
void Render(float fDeltaTime, D3DXMATRIX *billboardMat); //渲染游戏角色
void UserControl(DirectInputClass *pInput, std::vector &enemy, std::vector &friends); //玩家控制
};
Tiny.cpp:
//=============================================================================
//一个实现了提尼的类的源文件
//=============================================================================
#include "Tiny.h"
//构造函数
Tiny::Tiny(LPDIRECT3DDEVICE9 pd3dDevice, AnimationClass *pAnimation, D3DXVECTOR3 startPos, int team,
TerrainClass *pTerrain, float angleStart, FireParticleClass *pFireParticle, int index):
Character(pd3dDevice, pAnimation, TinyAttackWait, totalHpTiny[0], TinyAttackRate, TinyAggress, startPos, team, TinyRadius, CHARACTER_TINY),
m_lookVec(D3DXVECTOR3(-1, 0, -1)),
m_startPos(startPos),
m_pTerrain(pTerrain),
m_angleUp(angleStart),
m_angleStart(angleStart),
m_reviveTime(REVIVE_TIME),
m_level(1),
m_exp(totalExpTiny[0]),
m_nKill(0),
m_nDead(0),
m_pFireParticle(pFireParticle),
m_index(index)
{
}
//析构函数
Tiny::~Tiny(void)
{
}
//前进
void Tiny::MoveForward(std::vector &enemy, std::vector &friends)
{
//改变动画状态为移动
m_anim = ANIMATION_RUN;
//计算下一个目标位置,即当前位置加面对的方向向量乘移动速度
D3DXVECTOR3 target;
target = m_position + m_lookVec*TinyTransSpeed;
//如果目标位置没有被阻挡,设置此目标位置为角色位置。
if(!isBlocked(&target, enemy, friends))
{
SetPosition(&target);
SetMatrix();
}
}
//准备
void Tiny::Ready()
{
//改变动画状态为准备
m_anim = ANIMATION_READY;
}
//攻击
void Tiny::Attack(std::vector &enemy)
{
if(m_attackTime == m_attackWait)
{
//改变动画状态为攻击
m_anim = ANIMATION_ATTACK;
//减少m_attackTime,使其检测到已经进行了攻击
m_attackTime -= 0.000001f;
mciSendString(L"play fire from 0", NULL, 0, NULL);
//增加火球粒子
m_pFireParticle->AddFireParticle(m_position, rand() % 3, m_team, m_lookVec, m_index, m_aggress);
}
}
//左转
void Tiny::RotationLeft()
{
//减少绕Y轴旋转的角度
m_angleUp -= TinyRotSpeed / 100;
SetMatrix();
}
//右转
void Tiny::RotationRight()
{
//增加绕Y轴旋转的角度
m_angleUp += TinyRotSpeed / 100;
SetMatrix();
}
//播放动画
void Tiny::PlayAnimation()
{
//根据不同的动画状态,播放不同的动画
switch(m_anim)
{
case ANIMATION_READY:
m_pAnimInstance->SetAnimationByName("Loiter");
break;
case ANIMATION_RUN:
m_pAnimInstance->SetAnimationByName("Walk");
break;
case ANIMATION_ATTACK:
m_pAnimInstance->SetAnimationByName("Wave");
break;
}
}
//更新
void Tiny::Update(float fDeltaTime)
{
//更新攻击时间
if(m_attackTime < m_attackWait)
{
m_attackTime -= fDeltaTime;
if(m_attackTime < 0)
m_attackTime = m_attackWait;
}
//死亡后,更新复活时间
if(dead)
{
m_reviveTime -= fDeltaTime;
if(m_reviveTime < 0)
{
m_reviveTime = REVIVE_TIME;
dead = false;
SetMatrix();
}
}
//更新血条与血条背景的顶点缓存
CUSTOMVERTEX *pVertices = NULL;
m_pHpBackBuffer->Lock(0, 4*sizeof(CUSTOMVERTEX), (void**)&pVertices, 0);
pVertices[0] = CUSTOMVERTEX(-500.0f, 0.0f, 0.0f, 0.0f, 1.0f);
pVertices[1] = CUSTOMVERTEX(-500.0f, 40.0f, 0.0f, 0.0f, 0.0f);
pVertices[2] = CUSTOMVERTEX(500.0f, 0.0f, 0.0f, 1.0f, 1.0f);
pVertices[3] = CUSTOMVERTEX(500.0f, 40.0f, 0.0f, 1.0f, 0.0f);
m_pHpBackBuffer->Unlock();
float hpPosX = -500.0f + (float)m_hp / m_maxHp * 1000;
pVertices = NULL;
m_pHpBuffer->Lock(0, 4*sizeof(CUSTOMVERTEX), (void**)&pVertices, 0);
pVertices[0] = CUSTOMVERTEX(-500.0f, 0.0f, 0.0f, 0.0f, 1.0f);
pVertices[1] = CUSTOMVERTEX(-500.0f, 40.0f, 0.0f, 0.0f, 0.0f);
pVertices[2] = CUSTOMVERTEX(hpPosX, 0.0f, 0.0f, 1.0f, 1.0f);
pVertices[3] = CUSTOMVERTEX(hpPosX, 40.0f, 0.0f, 1.0f, 0.0f);
m_pHpBuffer->Unlock();
}
//死亡
void Tiny::Dead()
{
//初始化位置,hp,旋转角度,增加死亡数目
dead = true;
m_position = m_startPos;
m_hp = m_maxHp;
m_angleUp = m_angleStart;
++m_nDead;
}
//AI
void Tiny::AI(std::vector &enemy, std::vector &friends)
{
//如果血量少于1/5,旋转角度为初始起始旋转角度+180度,转身并前进逃跑。
if((float)m_hp / m_maxHp <= 0.2)
{
m_angleUp = m_angleStart + D3DX_PI;
MoveForward(enemy, friends);
return;
}
//否则寻找在攻击范围内的敌人,进行攻击,如果敌人在自己观察向量的左边,向左转,如果在右边向右转
for(int i = 0; i < enemy.size(); ++i)
{
if(enemy[i]->isDead())
continue;
D3DXVECTOR3 v = enemy[i]->GetPosition() - m_position;
float length = D3DXVec3Length(&v) - m_modelRadius;
if(length <= m_attackRate)
{
Attack(enemy);
float num = VectorCross(m_lookVec.x, m_lookVec.z, v.x, v.z);
if(num > 0.0f)
RotationLeft();
else if(num < 0.0f)
RotationRight();
return;
}
}
//否则设定绕Y轴旋转的角度为初始角度并前进
m_angleUp = m_angleStart;
MoveForward(enemy, friends);
}
//阻挡函数
bool Tiny::isBlocked(D3DXVECTOR3 *position, std::vector &enemy, std::vector &friends)
{
//获取该位置的高度值
float height = m_pTerrain->GetPositionHeight(position);
if(height >= 200) //高度值大于200则阻挡
return true;
//检测模型与防御塔的距离,如果距离小于两模型半径之和,则发生碰撞,即发生阻挡。
for(int i = 0; i < enemy.size(); ++i)
if(enemy[i]->m_id == CHARACTER_TOWER)
{
float length = D3DXVec3Length(&(*position - enemy[i]->GetPosition()));
if(length < m_modelRadius + enemy[i]->m_modelRadius)
return true;
}
for(int i = 0; i < friends.size(); ++i)
if(friends[i]->m_id == CHARACTER_TOWER)
{
float length = D3DXVec3Length(&(*position - friends[i]->GetPosition()));
if(length < m_modelRadius + friends[i]->m_modelRadius)
return true;
}
return false;
}
//对骨骼动画进行矩阵变换
void Tiny::SetMatrix()
{
//计算旋转矩阵,平移矩阵
D3DXVECTOR3 lookVec(1, 0, 0);
D3DXMATRIX playerMat, transMat, rotMat;
D3DXMatrixRotationY(&rotMat, m_angleUp);
D3DXMatrixTranslation(&transMat, m_position.x, m_position.y, m_position.z);
D3DXVec3TransformCoord(&m_lookVec, &lookVec, &rotMat);
playerMat = m_matrix * rotMat * transMat;
m_pAnimInstance->SetAnimationMatrix(&playerMat);
}
//返回角色死亡后返回的经验值,为当前经验值的一半
int Tiny::GetExp()
{
return totalExpTiny[m_level - 1] / 2;
}
//角色获得经验值
void Tiny::AddExp(int exp)
{
m_exp += exp;
++m_nKill;
//升级
if(m_exp >= totalExpTiny[m_level])
{
m_level = min(m_level+1, 15);
m_maxHp = totalHpTiny[m_level-1];
//攻击力少量提升
m_aggress += 20;
}
}
//返回角色等级
int Tiny::GetLevel()
{
return m_level;
}
//返回击杀数
int Tiny::GetKillNum()
{
return m_nKill;
}
//返回死亡数
int Tiny::GetDeadNum()
{
return m_nDead;
}
//渲染游戏角色
void Tiny::Render(float fDeltaTime, D3DXMATRIX *billboardMat)
{
//关闭光照
m_pd3dDevice->SetRenderState(D3DRS_LIGHTING, false);
//渲染骨骼动画
m_pAnimInstance->RenderAnimation(fDeltaTime);
//设置公告板矩阵
billboardMat->_41 = m_position.x;
billboardMat->_42 = m_position.y + 1000;
billboardMat->_43 = m_position.z;
m_pd3dDevice->SetTransform(D3DTS_WORLD, billboardMat);
//渲染血条背景
m_pd3dDevice->SetTexture(0, m_pHpBackTexture);
m_pd3dDevice->SetStreamSource(0, m_pHpBackBuffer, 0, sizeof(CUSTOMVERTEX));
m_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
//渲染血条
m_pd3dDevice->SetTexture(0, m_pHpTexture);
m_pd3dDevice->SetStreamSource(0, m_pHpBuffer, 0, sizeof(CUSTOMVERTEX));
m_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
m_pd3dDevice->SetRenderState(D3DRS_LIGHTING, true);
}
//返回复活时间
int Tiny::GetReviveTime()
{
return (int)m_reviveTime;
}
//玩家控制
void Tiny::UserControl(DirectInputClass *pDInput, std::vector &enemy, std::vector &friends)
{
if (pDInput->IsKeyDown(DIK_A))
RotationLeft();
else if (pDInput->IsKeyDown(DIK_D))
RotationRight();
else if (pDInput->IsKeyDown(DIK_W))
MoveForward(enemy, friends);
else if(pDInput->IsKeyDown(DIK_J))
Attack(enemy);
else
Ready();
}
Tiny类基本上与魔兽类是一样的。
攻击:与魔兽类不同的是攻击的时候直接调用火球粒子系统类添加一个火球就可以了。
相机类:
CameraClass.h新加的方法:
void CameraFollow(D3DXVECTOR3 *target, D3DXVECTOR3 *offset); //相机跟随函数
CameraClass.cpp新加的方法:
//-----------------------------------------------------------------------------
//相机跟随
//-----------------------------------------------------------------------------
void CameraClass::CameraFollow(D3DXVECTOR3 *target, D3DXVECTOR3 *offset)
{
//设置相机位置为目标位置加偏移量
m_vCameraPosition = *target + *offset;
}
火球粒子系统类:
FireParticleClass.h:
//=============================================================================
//一个封装了火球粒子系统的类的头文件
//=============================================================================
#pragma once
#include
#include
#include
#include
#include "D3DUtil.h"
#include "Character.h"
#include "TerrainClass.h"
//-------------------------------------------------------------------------------------------------
//火球粒子的FVF顶点结构和顶点格式
//-------------------------------------------------------------------------------------------------
struct POINTVERTEX
{
float x, y, z; //顶点位置
float u, v; //顶点纹理坐标
};
#define D3DFVF_POINTVERTEX (D3DFVF_XYZ | D3DFVF_TEX1)
const float fireTime = 3.0f; //火球最大存在时间
const float fireTransSpeed = 6.0f; //火球移动速度
const int totalAggress[3] = {100, 200, 300}; //火球的攻击力
const int totalRadiu[3] = {50, 80, 150}; //火球的半径大小
//-------------------------------------------------------------------------------------------------
//雪花粒子结构体的定义
//-------------------------------------------------------------------------------------------------
struct FIREPARTICLE
{
int m_textureIndex; //纹理索引数
int m_team; //所在队伍
float m_age; //存在时间
int m_aggress; //攻击力
D3DXVECTOR3 m_lookVec; //移动向量
D3DXVECTOR3 m_position; //火球位置
float m_radiu; //火球半径
int m_teamIndex; //所属英雄下标
};
//-------------------------------------------------------------------------------------------------
//粒子系统类的定义
//-------------------------------------------------------------------------------------------------
class FireParticleClass
{
private:
LPDIRECT3DDEVICE9 m_pd3dDevice; //d3d设备对象
LPDIRECT3DVERTEXBUFFER9 m_pVertexBuffer; //粒子顶点缓存
std::list m_fires; //火球链表
LPDIRECT3DTEXTURE9 m_pTextures[3]; //火球纹理数组
public:
FireParticleClass(LPDIRECT3DDEVICE9 pd3dDevice); //构造函数
~FireParticleClass(void); //析构函数
HRESULT InitFireParticle(); //粒子系统初始化函数
void AddFireParticle(D3DXVECTOR3 pos, int index, int team, D3DXVECTOR3 lookVec, int teamIndex, int aggress); //增加火球粒子函数
void UpdateFireParticle(float fElapsedTime); //粒子系统更新函数
void RenderFireParticle(D3DXMATRIX *billboardMat); //粒子系统渲染函数
void CollisionDetection(std::vector &Red, std::vector &Blue, TerrainClass *pTerrain); //粒子系统碰撞检测函数
void Clear(); //粒子系统清理函数
};
FireParticleClass.cpp:
//=============================================================================
//一个封装了雪花粒子系统的类的源文件
//=============================================================================
#include "FireParticleClass.h"
//-------------------------------------------------------------------------------------------------
//构造函数
//-------------------------------------------------------------------------------------------------
FireParticleClass::FireParticleClass(LPDIRECT3DDEVICE9 pd3dDevice)
{
//给各个参数赋值
m_pd3dDevice = pd3dDevice;
m_pVertexBuffer = NULL;
for(int i = 0; i < 3; ++i)
m_pTextures[i] = NULL;
}
//-------------------------------------------------------------------------------------------------
//粒子系统初始化函数
//-------------------------------------------------------------------------------------------------
HRESULT FireParticleClass::InitFireParticle()
{
//创建火花粒子顶点缓存
HRESULT hr;
HR(m_pd3dDevice->CreateVertexBuffer(4*sizeof(POINTVERTEX), 0, D3DFVF_POINTVERTEX,
D3DPOOL_MANAGED, &m_pVertexBuffer, NULL));
//填充火球粒子顶点缓存
POINTVERTEX vertices[] =
{
{ -300.0f, 0.0f, 0.0f, 0.0f, 1.0f, },
{ -300.0f, 600.0f, 0.0f, 0.0f, 0.0f, },
{ 300.0f, 0.0f, 0.0f, 1.0f, 1.0f, },
{ 300.0f, 600.0f, 0.0f, 1.0f, 0.0f, }
};
void *pVertices = NULL;
//加锁
HR(m_pVertexBuffer->Lock(0, sizeof(vertices), &pVertices, 0));
//访问
memcpy(pVertices, vertices, sizeof(vertices));
//解锁
m_pVertexBuffer->Unlock();
//创建3种火球纹理
wchar_t filename[40] = {0};
for(int i = 0; i < 3; ++i)
{
swprintf_s(filename, L"Textures\\fire%d.bmp", i+1);
HR(D3DXCreateTextureFromFile(m_pd3dDevice, filename, &m_pTextures[i]));
}
return S_OK;
}
//-------------------------------------------------------------------------------------------------
//增加火球粒子函数
//-------------------------------------------------------------------------------------------------
void FireParticleClass::AddFireParticle(D3DXVECTOR3 pos, int index, int team, D3DXVECTOR3 lookVec, int teamIndex, int aggress)
{
//纹理索引不正确,返回
if(index < 0 || index >= 3)
return;
FIREPARTICLE fire;
fire.m_position = pos;
fire.m_age = 0.0f;
fire.m_aggress = totalAggress[index] + aggress;
fire.m_team = team;
fire.m_textureIndex = index;
fire.m_lookVec = lookVec;
fire.m_radiu = totalRadiu[index];
fire.m_teamIndex = teamIndex;
m_fires.push_back(fire);
}
//-------------------------------------------------------------------------------------------------
//粒子系统更新函数
//-------------------------------------------------------------------------------------------------
void FireParticleClass::UpdateFireParticle(float fElapsedTime)
{
std::list::iterator it;
//for循环,更新每个粒子设为当前位置和存在时间, 如果有粒子存在时间超过了最大存在时间,从链表中移除
for(it = m_fires.begin(); it != m_fires.end();)
{
it->m_position += it->m_lookVec * fireTransSpeed;
it->m_age += fElapsedTime;
if(it->m_age >= fireTime)
it = m_fires.erase(it);
else
++it;
}
}
//-------------------------------------------------------------------------------------------------
//粒子系统渲染函数
//-------------------------------------------------------------------------------------------------
void FireParticleClass::RenderFireParticle(D3DXMATRIX *billboardMat)
{
//设置纹理状态
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); //将纹理颜色混合的第一个参数用于输出
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); //纹理颜色混合的第一个参数就取纹理颜色值
m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); //缩小过滤状态采用线性过滤
m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); //放大过滤状态采用线性过滤
//设置Alpha设置系数 将源图像与目标图像颜色值相加,黑色部分(0,0,0)变为目标颜色,白色部分仍然不变
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true); //打开alpha混合
m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); //源混合系数设为1
m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); //目标融合系数设为1
//设置剔除模式为不剔除任何面
m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
//渲染火球
std::list::iterator it;
for(it = m_fires.begin(); it != m_fires.end(); ++it)
{
//构造并设置当前火球粒子的世界矩阵
billboardMat->_41 = it->m_position.x;
billboardMat->_42 = it->m_position.y;
billboardMat->_43 = it->m_position.z;
m_pd3dDevice->SetTransform(D3DTS_WORLD, billboardMat);
m_pd3dDevice->SetTexture(0, m_pTextures[it->m_textureIndex]); //设置当前纹理
//渲染火球粒子
m_pd3dDevice->SetStreamSource(0, m_pVertexBuffer, 0, sizeof(POINTVERTEX)); //把包含几何体信息的顶点缓存与渲染流水线关联
m_pd3dDevice->SetFVF(D3DFVF_POINTVERTEX); //设置FVF灵活顶点模式
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); //绘制
}
//恢复之前渲染模式 alpha混合,剔除状态
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
}
//-------------------------------------------------------------------------------------------------
//析构函数
//-------------------------------------------------------------------------------------------------
FireParticleClass::~FireParticleClass(void)
{
SAFE_RELEASE(m_pVertexBuffer);
for(int i = 0; i < 3; ++i)
SAFE_RELEASE(m_pTextures[i]);
m_fires.clear();
}
//-------------------------------------------------------------------------------------------------
//粒子系统清理函数
//-------------------------------------------------------------------------------------------------
void FireParticleClass::Clear()
{
m_fires.clear();
}
//-------------------------------------------------------------------------------------------------
//粒子系统碰撞检测函数
//-------------------------------------------------------------------------------------------------
void FireParticleClass::CollisionDetection(std::vector &Red, std::vector &Blue, TerrainClass *pTerrain)
{
std::list::iterator it;
for(it = m_fires.begin(); it != m_fires.end();)
{
if(it->m_team == RED)
{
for(int i = 0; i < Blue.size(); ++i)
if(!Blue[i]->isDead()) //英雄没有死亡
{
//如果距离小于火球距离加模型距离,碰撞发生。
float length = D3DXVec3Length(&(it->m_position - Blue[i]->GetPosition()));
if(length <= it->m_radiu + Blue[i]->GetModelRadius())
{
mciSendString(L"play boom from 0", NULL, 0, NULL);
Blue[i]->Damage(it->m_aggress);
if(Blue[i]->isDead()) //英雄死亡,火球所属英雄获得死亡英雄的经验值
Red[it->m_teamIndex]->AddExp(Blue[i]->GetExp());
it = m_fires.erase(it); //销毁火球
break;
}
}
}
else
{
for(int i = 0; i < Red.size(); ++i)
if(!Red[i]->isDead())
{
float length = D3DXVec3Length(&(it->m_position - Red[i]->GetPosition()));
if(length <= it->m_radiu + Red[i]->GetModelRadius())
{
mciSendString(L"play boom from 0", NULL, 0, NULL);
Red[i]->Damage(it->m_aggress);
if(Red[i]->isDead())
Blue[it->m_teamIndex]->AddExp(Red[i]->GetExp());
it = m_fires.erase(it);
break;
}
}
}
if(it != m_fires.end())
{
float height = pTerrain->GetPositionHeight(&(it->m_position));
if(height >= 200) //碰到了墙壁,销毁火球
{
mciSendString(L"play boom from 0", NULL, 0, NULL);
it = m_fires.erase(it);
}
else
++it;
}
}
}
首先,定义了一个火球粒子结构体,表示一个火球粒子。然后在火球粒子系统类中定义一个链表。每当有新的粒子加入就放入量表中,当粒子死亡后就从链表中删除掉。
增加火球粒子:首先判断火球粒子索引是否正确,因为我们只有三种粒子。然后定义并初始化粒子,最后放入链表中。
更新粒子系统:循环更新每个粒子的位置,通过移动向量乘速度计算新的位置;生存时间,如果死亡则从链表中删除粒子。
渲染粒子系统:首先设置纹理状态,然后设置Alpha设置系数 将源图像与目标图像颜色值相加,黑色部分(0,0,0)变为目标颜色,白色部分仍然不变 ,实现透明贴图。设置剔除模式为不剔除任何面,然后就可以设置变换矩阵并渲染了。
碰撞检测函数:参数为包含红队与蓝队的容器还有地形类。首先遍历所有火球,然后判断火球的队伍编号,与相反队伍中的对象进行检测,如果对象没有死亡且火球与对象距离小于火球与对象模型半径之和,就发生了碰撞,对象受到伤害。然后将火球从链表中删除。最后判断是否与地形中障碍物发生碰撞。如果高度大于200说明碰到了障碍物,这时就要将其从链表中删除。
防御塔Tower类:
Tower.h:
//=============================================================================
//一个实现了防御塔的类的头文件
//=============================================================================
#pragma once
#include
#include
#include "AnimationClass.h"
#include "AnimInstanceClass.h"
#include "Character.h"
const int TowerMaxHp = 2000; //防御塔最大生命
const int TowerExp = 100; //死亡后返回的经验值
const float TowerAttackWait = 5.0f; //攻击冷却时间
const float TowerAttackRate = 2700.0f; //攻击范围
const int TowerAggress = 100; //攻击力
const int TowerRadius = 500; //模型半径
//防御塔类
class Tower : public Character
{
public:
Tower(LPDIRECT3DDEVICE9 pd3dDevice, AnimationClass *pAnimation, D3DXVECTOR3 startPos, int team); //构造函数
~Tower(void); //析构函数
void Attack(std::vector &enemy); //攻击
void Ready(); //准备
void PlayAnimation(); //播放动画
void Update(float fDeltaTime); //更新
void Dead(); //死亡
void AI(std::vector &enemy, std::vector &friends); //AI
void SetMatrix(); //对骨骼动画进行矩阵变换
int GetExp(); //返回角色死亡后返回的经验值,为当前经验值
void Render(float fDeltaTime, D3DXMATRIX *billboardMat); //渲染游戏角色
void UserControl(DirectInputClass *pInput, std::vector &enemy, std::vector &friends); //玩家控制
int GetLevel(); //返回角色等级
int GetKillNum(); //返回击杀数
int GetDeadNum(); //返回死亡数
int GetReviveTime(); //返回复活时间
void AddExp(int exp); //角色获得经验值
};
Tower.cpp:
//=============================================================================
//一个实现了防御塔的类的源文件
//=============================================================================
#include "Tower.h"
//构造函数
Tower::Tower(LPDIRECT3DDEVICE9 pd3dDevice, AnimationClass *pAnimation, D3DXVECTOR3 startPos, int team):
Character(pd3dDevice, pAnimation, TowerAttackWait, TowerMaxHp, TowerAttackRate, TowerAggress, startPos, team, TowerRadius, CHARACTER_TOWER)
{
}
//析构函数
Tower::~Tower(void)
{
}
//准备
void Tower::Ready()
{
m_anim = ANIMATION_READY;
}
//攻击
void Tower::Attack(std::vector &enemy)
{
//改变动画状态为攻击
if(m_attackTime == m_attackWait)
{
m_anim = ANIMATION_ATTACK;
//减少m_attackTime,使其检测到已经进行了攻击
m_attackTime -= 0.000001f;
for(int i = 0; i < enemy.size(); ++i)
if(!enemy[i]->isDead())
{
//角色与敌人距离为模型距离减去敌人模型半径,如果在攻击范围之内,给出伤害
double length = D3DXVec3Length(&(enemy[i]->GetPosition() - m_position)) - m_modelRadius;
if(length <= m_attackRate)
{
enemy[i]->Damage(m_aggress);
break;
}
}
}
}
//播放动画
void Tower::PlayAnimation()
{
m_pAnimInstance->SetAnimationByName("idle");
}
//更新
void Tower::Update(float fDeltaTime)
{
//更新攻击事件
if(m_anim == ANIMATION_ATTACK)
{
m_attackTime -= fDeltaTime;
if(m_attackTime < 0)
{
m_attackTime = m_attackWait;
m_anim = ANIMATION_READY;
}
}
//更新血条与血条背景的顶点缓存
CUSTOMVERTEX *pVertices = NULL;
m_pHpBackBuffer->Lock(0, 4*sizeof(CUSTOMVERTEX), (void**)&pVertices, 0);
pVertices[0] = CUSTOMVERTEX(-500.0f, 0.0f, 0.0f, 0.0f, 1.0f);
pVertices[1] = CUSTOMVERTEX(-500.0f, 40.0f, 0.0f, 0.0f, 0.0f);
pVertices[2] = CUSTOMVERTEX(500.0f, 0.0f, 0.0f, 1.0f, 1.0f);
pVertices[3] = CUSTOMVERTEX(500.0f, 40.0f, 0.0f, 1.0f, 0.0f);
m_pHpBackBuffer->Unlock();
float hpPosX = -500.0f + (float)m_hp / m_maxHp * 1000;
pVertices = NULL;
m_pHpBuffer->Lock(0, 4*sizeof(CUSTOMVERTEX), (void**)&pVertices, 0);
pVertices[0] = CUSTOMVERTEX(-500.0f, 0.0f, 0.0f, 0.0f, 1.0f);
pVertices[1] = CUSTOMVERTEX(-500.0f, 40.0f, 0.0f, 0.0f, 0.0f);
pVertices[2] = CUSTOMVERTEX(hpPosX, 0.0f, 0.0f, 1.0f, 1.0f);
pVertices[3] = CUSTOMVERTEX(hpPosX, 40.0f, 0.0f, 1.0f, 0.0f);
m_pHpBuffer->Unlock();
}
//死亡
void Tower::Dead()
{
dead = true;
}
//AI
void Tower::AI(std::vector &enemy, std::vector &friends)
{
Attack(enemy);
}
//对骨骼动画进行矩阵变换
void Tower::SetMatrix()
{
//计算平移矩阵
D3DXMATRIX playerMat, transMat;
D3DXMatrixTranslation(&transMat, m_position.x, m_position.y, m_position.z);
playerMat = m_matrix * transMat;
m_pAnimInstance->SetAnimationMatrix(&playerMat);
}
//返回角色死亡后返回的经验值
int Tower::GetExp()
{
return TowerExp;
}
//渲染游戏角色
void Tower::Render(float fDeltaTime, D3DXMATRIX *billboardMat)
{
m_pAnimInstance->RenderAnimation(fDeltaTime);
//设置公告板矩阵
billboardMat->_41 = m_position.x;
billboardMat->_42 = m_position.y + 1300;
billboardMat->_43 = m_position.z;
m_pd3dDevice->SetTransform(D3DTS_WORLD, billboardMat);
//渲染血条背景
m_pd3dDevice->SetTexture(0, m_pHpBackTexture);
m_pd3dDevice->SetStreamSource(0, m_pHpBackBuffer, 0, sizeof(CUSTOMVERTEX));
m_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
//渲染血条
m_pd3dDevice->SetTexture(0, m_pHpTexture);
m_pd3dDevice->SetStreamSource(0, m_pHpBuffer, 0, sizeof(CUSTOMVERTEX));
m_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
}
//玩家控制
void Tower::UserControl(DirectInputClass *pInput, std::vector &enemy, std::vector &friends)
{
}
//返回角色等级
int Tower::GetLevel()
{
return 0;
}
//返回击杀数
int Tower::GetKillNum()
{
return 0;
}
//返回死亡数
int Tower::GetDeadNum()
{
return 0;
}
//返回复活时间
int Tower::GetReviveTime()
{
return 0;
}
//角色获得经验值
void Tower::AddExp(int exp)
{
}
最后就是主函数类了:
WinMain.cpp:
#include
#include
#include
#include
#include "CameraClass.h"
#include "DirectInputClass.h"
#include "SkyBoxClass.h"
#include "TerrainClass.h"
#include "AnimationClass.h"
#include "D3DGUIClass.h"
#include "FireParticleClass.h"
#include "Warcraft.h"
#include "Tower.h"
#include "Tiny.h"
using std::vector;
#define WINDOW_TITLE L"Direct 3D 战术竞技游戏示例"
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib, "winmm.lib")
const D3DXVECTOR3 left = D3DXVECTOR3(-1, 0, 0); //相机移动的方向向量
const D3DXVECTOR3 right = D3DXVECTOR3(1, 0, 0);
const D3DXVECTOR3 up = D3DXVECTOR3(0,0,1);
const D3DXVECTOR3 down = D3DXVECTOR3(0,0,-1);
const int CameraSpeed = 10; //相机移动速度
//---------------------------------------【全局变量声明部分】------------------------------------------------
//描述:全局变量的声明
//-----------------------------------------------------------------------------------------------------------
LPDIRECT3DDEVICE9 g_pd3dDevice; //Direct 3D设备对象
DirectInputClass *g_pDInput; //一个DirectInput类的指针
LPD3DXFONT g_pTextAdapterName; //显卡名字的2D文本
LPD3DXFONT g_pTextHelper; //帮助文本的2D文本
LPD3DXFONT g_pTextInfor; //绘制信息的2D文本
LPD3DXFONT g_pTextFPS; //FPS文本的2D文本
LPD3DXFONT g_pTextCharacter; //角色信息的2D文本
RECT formatRect; //屏幕区域
wchar_t g_strAdapterName[60]; //包括显卡名字的字符串
wchar_t g_strFPS[50]; //包含帧频率的字符数组
wchar_t g_strHelpter[50]; //帮助文本的字符数组
CameraClass *g_pCamera; //虚拟摄像机指针
SkyBoxClass *g_pSkyBox; //天空盒类的指针
FireParticleClass *g_pFireParticle; //火球粒子类的指针
TerrainClass *g_pTerrain; //地形类的指针
AnimationClass *g_pWarcraftAnim; //魔兽骨骼动画类的指针
AnimationClass *g_pTowerAnim; //防御塔骨骼动画类的指针
AnimationClass *g_pTinyAnim; //提尼骨骼动画类的指针
vector Red, Blue; //红队 蓝队存储数组
Character *player, *enemy, *towerRed, *towerBlue; //玩家,敌人,红塔,蓝塔
int g_currentGUI = GUI_MAIN_SCREEN; //当前GUI,默认为主界面GUI
D3DGUIClass *g_mainGUI; //主界面GUI类指针
D3DGUIClass *g_startGUI; //开始游戏GUI类指针
D3DGUIClass *g_overGUI; //游戏结束GUI类指针
bool g_LMBDown; //鼠标左键是否按下
int g_MouseX, g_MouseY; //鼠标的坐标位置
int g_playerID = CHARACTER_WARCRAFT; //玩家选择的英雄ID 初始值为魔兽
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HRESULT Direct3D_Init(HWND); //在这个函数中继续Direct3D的初始化
HRESULT Objects_Init(HWND); //在这个函数中进行要绘制的物体的资源初始化
void Direct3D_Render(HWND, float); //在这个函数中进行Direct3D渲染代码的书写
void Direct3D_ClearUp(); //在这个函数中清理COM资源以及其他资源
float Get_FPS();
void Direct3D_Update(float);
void HelpText_Render(HWND);
void Init(); //初始化游戏资源
void Clear(); //清理游戏资源
void LoadMusic(); //加载游戏音乐
//----------------------------------------【WinMain()函数】-------------------------------------------------
//描述:Windows应用程序的入口函数
//-------------------------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wndClass = {0};
wndClass.cbSize = sizeof(WNDCLASSEX);
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = (WNDPROC)WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = (HICON)LoadImage(NULL, L"Textures\\icon.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = L"3DGameBase";
if(!RegisterClassEx(&wndClass))
return -1;
HWND hWnd = CreateWindow(L"3DGameBase", WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);
MoveWindow(hWnd, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, true);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
g_pDInput = new DirectInputClass();
if(FAILED(g_pDInput->Init(hWnd, hInstance, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE)))
MessageBox(hWnd, L"Direct3D Input初始化失败!", L"消息窗口", 0);
if(FAILED(Direct3D_Init(hWnd)))
MessageBox(hWnd, L"Direct3D 初始化失败!", L"消息窗口", 0);
MSG msg = {0};
while(msg.message != WM_QUIT)
{
static float fLastTime = timeGetTime(); //上帧渲染时间
static float fCurrTime = timeGetTime(); //此帧渲染时间
static float fTimeDelta = 0.0f;
fCurrTime = timeGetTime();
fTimeDelta = (fCurrTime - fLastTime) / 1000.f; //上帧到此帧经过的时间
fLastTime = fCurrTime; //把此次渲染时间赋给上次渲染时间
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Direct3D_Update(fTimeDelta);
Direct3D_Render(hWnd, fTimeDelta);
}
}
//调用自定义的资源清理函数Direct3D_ClearUp();进行退出前的资源清理
Direct3D_ClearUp();
UnregisterClass(L"3DGameBase", wndClass.hInstance);
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_PAINT:
ValidateRect(hWnd, NULL); //使窗口区域生效
break;
case WM_KEYDOWN:
if(wParam == VK_ESCAPE)
{
mciSendString(L"play bgm from 0", NULL, 0, NULL);
g_currentGUI = GUI_MAIN_SCREEN;
}
break;
case WM_LBUTTONDOWN:
g_LMBDown = true;
break;
case WM_LBUTTONUP:
g_LMBDown = false;
break;
case WM_MOUSEMOVE:
g_MouseX = LOWORD(lParam);
g_MouseY = HIWORD(lParam);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
//---------------------------------------------【 LoadMusic()函数】-----------------------------------------
//描述:游戏音乐资源的加载
//---------------------------------------------------------------------------------------------------------------
void LoadMusic()
{
mciSendString(L"open Musics\\背景.wav alias bgm", NULL, 0, NULL);
mciSendString(L"open Musics\\点击.mp3 alias click", NULL, 0, NULL);
mciSendString(L"open Musics\\火球.mp3 alias fire", NULL, 0, NULL);
mciSendString(L"open Musics\\胜利.wav alias victory", NULL, 0, NULL);
mciSendString(L"open Musics\\失败.wav alias defeat", NULL, 0, NULL);
mciSendString(L"open Musics\\炸弹爆炸.wav alias boom", NULL, 0, NULL);
}
//---------------------------------------------【Direct3D_Init()函数】-----------------------------------------
//描述:Direct3D初始化函数,进行Direct3D的初始化
//---------------------------------------------------------------------------------------------------------------
HRESULT Direct3D_Init(HWND hWnd)
{
//---------------------------------------------------------------------------------------------------------------
//【Direct3D初始化步骤一】:创建Direct3D接口对象,以便用该Direct3D对象创建Direct3D设备对象
//---------------------------------------------------------------------------------------------------------------
LPDIRECT3D9 pD3D = NULL; //Direct3D接口对象的创建。
if((pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL) //初始化Direct3D接口对象,并进行DirectX版本协商。
return E_FAIL;
//---------------------------------------------------------------------------------------------------------------
//【Direct3D初始化步骤二】:获取硬件设备信息
//---------------------------------------------------------------------------------------------------------------
D3DCAPS9 caps;
int vp = 0;
if(FAILED(pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps)))
return E_FAIL;
if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; //支持硬件顶点运算,采用硬件顶点运算
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //不支持硬件顶点运算,采用软件顶点运算
//---------------------------------------------------------------------------------------------------------------
//【Direct3D初始化步骤三】:填充D3DPRESENT_PARAMETERS结构体
//---------------------------------------------------------------------------------------------------------------
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.BackBufferWidth = WINDOW_WIDTH;
d3dpp.BackBufferHeight = WINDOW_HEIGHT;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.Windowed = true;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = 0;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
//---------------------------------------------------------------------------------------------------------------
//【Direct3D初始化步骤四】:创建Direct3D设备接口。
//---------------------------------------------------------------------------------------------------------------
if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, vp, &d3dpp, &g_pd3dDevice)))
return E_FAIL;
//获取显卡信息到g_strAdapterName中,并在显卡名称前加上“当前显卡型号:”字符串
//定义一个D3DADAPTER_IDENTIFIER9结构体,用于存储显卡信息
D3DADAPTER_IDENTIFIER9 Adapter;
//调用GetAdapterIdentifier,获取显卡信息
if(FAILED(pD3D->GetAdapterIdentifier(0, 0, &Adapter)))
return E_FAIL;
//显卡名称现在已经在Adapter.Description中了,但是其为char类型,我们要将其转为wchar_t类型
int len = MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, NULL, 0);
//这步操作完成后,g_strAdapterName中就为当前我们的显卡类型名的wchar_t型字符串了
MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, g_strAdapterName, len);
//定义一个临时字符串,且方便了把"当前显卡型号:"字符串引入我们的目的字符串中
wchar_t tempName[50] = L"当前显卡型号:";
//把当前我们的显卡名加到“当前显卡型号:”字符串后面,结果存在TempName中
wcscat_s(tempName, g_strAdapterName);
//把TempName中的结果拷贝到全局变量g_strAdapterName中
wcscpy_s(g_strAdapterName, tempName);
SAFE_RELEASE(pD3D); //LPDIRECT3D9接口对象的使命完成,将其释放掉
if(FAILED(Objects_Init(hWnd))) // 调用一次Objects_Init,进行渲染资源的初始化
return E_FAIL;
return S_OK;
}
//------------------------------------------【Objects_Init()】函数---------------------------------------------
//描述:渲染资源初始化函数,在此函数中进行要被渲染的物体的资源的初始化
//---------------------------------------------------------------------------------------------------------------
HRESULT Objects_Init(HWND hWnd)
{
//创建字体
if(FAILED(D3DXCreateFont(g_pd3dDevice, 36, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0, L"Calibri", &g_pTextFPS)))
return E_FAIL;
if(FAILED(D3DXCreateFont(g_pd3dDevice, 20, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0, L"华文中宋", &g_pTextAdapterName)))
return E_FAIL;
if(FAILED(D3DXCreateFont(g_pd3dDevice, 23, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0, L"微软雅黑", &g_pTextHelper)))
return E_FAIL;
if(FAILED(D3DXCreateFont(g_pd3dDevice, 26, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0, L"黑体", &g_pTextInfor)))
return E_FAIL;
if(FAILED(D3DXCreateFont(g_pd3dDevice, 60, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0, L"微软雅黑", &g_pTextCharacter)))
return E_FAIL;
//创建并初始化虚拟摄像机
g_pCamera = new CameraClass(g_pd3dDevice);
g_pCamera->SetCameraPosition(&D3DXVECTOR3(0.0f, 0.0f, -200.0f)); //设置摄像机所在的位置
g_pCamera->SetTargetPosition(&D3DXVECTOR3(0.0f, 0.0f, 0.0f)); //设置目标观察点所在的位置
g_pCamera->SetViewMatrix(); //设置取景变换矩阵
g_pCamera->SetProjMatrix();
//创建并初始化天空对象
g_pSkyBox = new SkyBoxClass(g_pd3dDevice);
//从文件加载前,后,左,右,上的纹理图
g_pSkyBox->LoadSkyTextureFromFile(L"Textures\\TropicalSunnyDayFront2048.png", L"Textures\\TropicalSunnyDayBack2048.png",
L"Textures\\TropicalSunnyDayRight2048.png", L"Textures\\TropicalSunnyDayLeft2048.png", L"Textures\\TropicalSunnyDayUp2048.png");
//设置天空盒的边长
g_pSkyBox->InitSkyBox(50000);
//创建并初始化地形类
g_pTerrain = new TerrainClass(g_pd3dDevice);
g_pTerrain->LoadTerrainFromFile(L"Textures\\hightMap.raw", L"Textures\\地形.png");
g_pTerrain->InitTerrain(200, 200, 100.0f, 10.0f);
//创建并初始化火球粒子系统类
g_pFireParticle = new FireParticleClass(g_pd3dDevice);
g_pFireParticle->InitFireParticle();
// 设置光照
D3DLIGHT9 light;
light.Type = D3DLIGHT_DIRECTIONAL;
light.Ambient = D3DXCOLOR(0.7f, 0.7f, 0.7f, 1.0f);
light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
light.Specular = D3DXCOLOR(0.9f, 0.9f, 0.9f, 1.0f);
light.Direction = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
g_pd3dDevice->SetLight(0, &light);
g_pd3dDevice->LightEnable(0, true);
g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true);
g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, true);
//创建并初始化主界面类
g_mainGUI = new D3DGUIClass(g_pd3dDevice, WINDOW_WIDTH, WINDOW_HEIGHT);
g_mainGUI->CreateTextFont(L"微软雅黑", 60);
g_mainGUI->AddBackground(L"Textures\\GameMain.jpg");
g_mainGUI->AddStaticText(STATIC_TEXT_ID, L"战术竞技游戏示例", 550, 0, D3DCOLOR_XRGB(255,255,255), 0);
g_mainGUI->AddButton(BUTTON_SIMPLE_ID, 600, 570, L"Textures\\localUp.png", L"Textures\\localOver.png", L"Textures\\localDown.png");
g_mainGUI->AddButton(BUTTON_QUIT_ID, 600, 630, L"Textures\\quitUp.png", L"Textures\\quitOver.png", L"Textures\\quitDown.png");
//创建并初始化开始游戏界面类
g_startGUI = new D3DGUIClass(g_pd3dDevice, WINDOW_WIDTH, WINDOW_HEIGHT);
g_startGUI->CreateTextFont(L"Calibri", 60);
g_startGUI->AddBackground(L"Textures\\GameStart.jpg");
g_startGUI->AddStaticText(STATIC_TEXT_ID, L"请选择您的英雄", 0, 0, D3DCOLOR_XRGB(0, 0, 255), 0);
g_startGUI->AddButton(BUTTON_START_ID, 900, 570, L"Textures\\startUp.png", L"Textures\\startOver.png", L"Textures\\startDown.png");
g_startGUI->AddButton(BUTTON_WARCRAFT_ID, 100, 400, L"Textures\\moshouUp.png", L"Textures\\moshouOver.png", L"Textures\\moshouDown.png");
g_startGUI->AddButton(BUTTON_BACK_ID, 900, 630, L"Textures\\backUp.png", L"Textures\\backOver.png", L"Textures\\backDown.png");
g_startGUI->AddButton(BUTTON_TINY_ID, 500, 400, L"Textures\\tinyUp.png", L"Textures\\tinyOver.png", L"Textures\\tinyDown.png");
//创建并初始化游戏结束界面类
g_overGUI = new D3DGUIClass(g_pd3dDevice, WINDOW_WIDTH, WINDOW_HEIGHT);
g_overGUI->CreateTextFont(L"华文中宋", 60);
g_overGUI->AddBackground(L"Textures\\GameOver.jpg");
g_overGUI->AddButton(BUTTON_BACK_ID, 600, 600, L"Textures\\backUp.png", L"Textures\\backOver.png", L"Textures\\backDown.png");
//创建并初始化骨骼动画类
g_pWarcraftAnim = new AnimationClass(g_pd3dDevice);
g_pWarcraftAnim->InitAnimation(L"GameMedia\\moshou.x");
g_pTowerAnim = new AnimationClass(g_pd3dDevice);
g_pTowerAnim->InitAnimation(L"GameMedia\\tower.X");
g_pTinyAnim = new AnimationClass(g_pd3dDevice);
g_pTinyAnim->InitAnimation(L"GameMedia\\tiny.X");
//获取用户区窗口区域
GetClientRect(hWnd, &formatRect);
LoadMusic(); //音乐资源加载
mciSendString(L"play bgm from 0", NULL, 0, NULL); //播放背景音乐
return S_OK;
}
//------------------------------------------【Init()】函数---------------------------------------------
//描述:进行开始游戏前的游戏资源的加载
//---------------------------------------------------------------------------------------------------------------
void Init()
{
//设置一些变换矩阵
D3DXMATRIX originMat, scaleMat, rotXMat, rotYMat;
D3DXMatrixRotationX(&rotXMat, -D3DX_PI / 2);
D3DXMatrixRotationY(&rotYMat, D3DX_PI / 2);
//根据玩家选择的英雄,进行游戏对象的创建与初始化。
switch(g_playerID)
{
case CHARACTER_WARCRAFT:
D3DXMatrixScaling(&scaleMat, 10, 10, 10);
originMat = scaleMat * rotXMat;
player = new Warcraft(g_pd3dDevice, g_pWarcraftAnim, D3DXVECTOR3(-7000, 0, -7000), BLUE, g_pTerrain, -D3DX_PI / 6);
player->SetAnimationMatrix(&originMat);
player->SetMatrix();
Blue.push_back(player);
break;
case CHARACTER_TINY:
D3DXMatrixScaling(&scaleMat, 1.5, 1.5, 1.5);
originMat = scaleMat * rotXMat * rotYMat;
player = new Tiny(g_pd3dDevice, g_pTinyAnim, D3DXVECTOR3(-7000, 0, -7000), BLUE, g_pTerrain, -D3DX_PI / 6, g_pFireParticle, 0);
player->SetAnimationMatrix(&originMat);
player->SetMatrix();
Blue.push_back(player);
break;
}
//设置随机数种子
srand(time(NULL));
//根据敌人随机选择的英雄,进行游戏对象的创建与初始化。
if(rand() % 2 == 0)
{
D3DXMatrixScaling(&scaleMat, 10, 10, 10);
originMat = scaleMat * rotXMat;
enemy = new Warcraft(g_pd3dDevice, g_pWarcraftAnim, D3DXVECTOR3(7000, 0, 7000), RED, g_pTerrain, D3DX_PI * 3/4);
enemy->SetAnimationMatrix(&originMat);
enemy->SetMatrix();
Red.push_back(enemy);
}
else
{
D3DXMatrixScaling(&scaleMat, 1.5, 1.5, 1.5);
originMat = scaleMat * rotXMat * rotYMat;
enemy = new Tiny(g_pd3dDevice, g_pTinyAnim, D3DXVECTOR3(7000, 0, 7000), RED, g_pTerrain, D3DX_PI * 3/4, g_pFireParticle, 0);
enemy->SetAnimationMatrix(&originMat);
enemy->SetMatrix();
Red.push_back(enemy);
}
//进行防御塔的创建与初始化。
D3DXMatrixScaling(&scaleMat, 0.1, 0.1, 0.1);
originMat = scaleMat * rotXMat;
towerRed = new Tower(g_pd3dDevice, g_pTowerAnim, D3DXVECTOR3(8000, 0, 8000), RED);
towerRed->SetAnimationMatrix(&originMat);
towerRed->SetMatrix();
towerBlue = new Tower(g_pd3dDevice, g_pTowerAnim, D3DXVECTOR3(-8000, 0, -8000), BLUE);
towerBlue->SetAnimationMatrix(&originMat);
towerBlue->SetMatrix();
//把创建的游戏对象放入相应的队伍里。
Blue.push_back(towerBlue);
Red.push_back(towerRed);
}
//------------------------------------------【Clear()】函数------------------------------------------------------
//描述:进行开始游戏前的游戏资源的清理
//---------------------------------------------------------------------------------------------------------------
void Clear()
{
for(int i = 0; i < Blue.size(); ++i)
SAFE_DELETE(Blue[i]);
for(int i = 0; i < Red.size(); ++i)
SAFE_DELETE(Red[i]);
Red.clear();
Blue.clear();
g_pFireParticle->Clear();
g_playerID = CHARACTER_WARCRAFT;
}
//------------------------------------------【Direct3D_Update()】函数------------------------------------------------------
//描述:进行游戏的更新操作
//---------------------------------------------------------------------------------------------------------------
void Direct3D_Update(float fTimeDelta)
{
//如果不是游戏进行界面,就退出
if(g_currentGUI != GUI_GAME_SCREEN)
return;
//如果一方的防御塔被破坏,另一方取得胜利
if(towerRed->isDead() || towerBlue->isDead())
{
//播放相应的音效
if(towerRed->isDead())
mciSendString(L"play victory from 0", NULL, 0, NULL);
else
mciSendString(L"play defeat from 0", NULL, 0, NULL);
//切换当前GUI为游戏结束GUI
g_currentGUI = GUI_OVER_SCREEN;
return;
}
//使用DirectInput类读取数据
g_pDInput->GetInput();
//玩家控制
if(!player->isDead())
player->UserControl(g_pDInput, Red, Blue);
//AI控制
if(!enemy->isDead())
enemy->AI(Blue, Red);
//播放动画,更新
player->PlayAnimation();
player->Update(fTimeDelta);
enemy->PlayAnimation();
enemy->Update(fTimeDelta);
towerBlue->PlayAnimation();
towerBlue->Update(fTimeDelta);
if(!towerBlue->isDead())
towerBlue->AI(Red, Blue);
towerRed->PlayAnimation();
towerRed->Update(fTimeDelta);
if(!towerRed->isDead())
towerRed->AI(Blue, Red);
if(!player->isDead()) //玩家没有死亡
{
//相机的跟随,设定新的相机位置与观察位置
D3DXVECTOR3 target = player->GetPosition();
g_pCamera->CameraFollow(&target, &(D3DXVECTOR3(0, 4000, -4000)));
g_pCamera->SetTargetPosition(&target);
}
else //否则玩家死亡后
{
//键盘控制进行相机的移动
D3DXVECTOR3 position, target;
g_pCamera->GetCameraPosition(&position);
g_pCamera->GetTargetPosition(&target);
if (g_pDInput->IsKeyDown(DIK_A))
{
g_pCamera->SetCameraPosition(&(position + left * CameraSpeed));
g_pCamera->SetTargetPosition(&(target + left* CameraSpeed));
}
if (g_pDInput->IsKeyDown(DIK_D))
{
g_pCamera->SetCameraPosition(&(position + right * CameraSpeed));
g_pCamera->SetTargetPosition(&(target + right * CameraSpeed));
}
if (g_pDInput->IsKeyDown(DIK_W))
{
g_pCamera->SetCameraPosition(&(position + up * CameraSpeed));
g_pCamera->SetTargetPosition(&(target + up * CameraSpeed));
}
if (g_pDInput->IsKeyDown(DIK_S))
{
g_pCamera->SetCameraPosition(&(position + down * CameraSpeed));
g_pCamera->SetTargetPosition(&(target + down * CameraSpeed));
}
}
//设置相机的变换矩阵
g_pCamera->SetViewMatrix();
//更新火球粒子系统并进行碰撞检测。
g_pFireParticle->UpdateFireParticle(fTimeDelta);
g_pFireParticle->CollisionDetection(Red, Blue, g_pTerrain);
}
//------------------------------------------【GUICallBack()】函数------------------------------------------------
//描述:进行GUI系统组件的回调函数
//---------------------------------------------------------------------------------------------------------------
void GUICallBack(int id, int state)
{
switch(id)
{
case BUTTON_SIMPLE_ID:
if(state == UGP_BUTTON_DOWN) //点击按钮
{
mciSendString(L"play click from 0", NULL, 0, NULL);
Clear(); //清理游戏资源
g_currentGUI = GUI_START_SCREEN; //改变GUI为开始游戏GUI
g_LMBDown = false;
}
break;
case BUTTON_BACK_ID:
if(state == UGP_BUTTON_DOWN)
{
mciSendString(L"play click from 0", NULL, 0, NULL);
mciSendString(L"play bgm from 0", NULL, 0, NULL);
g_currentGUI = GUI_MAIN_SCREEN; //改变GUI为主界面GUI
g_LMBDown = false;
}
break;
case BUTTON_WARCRAFT_ID:
if(state == UGP_BUTTON_DOWN)
{
mciSendString(L"play click from 0", NULL, 0, NULL);
g_playerID = CHARACTER_WARCRAFT; //改变玩家英雄为魔兽
g_LMBDown = false;
}
break;
case BUTTON_TINY_ID:
if(state == UGP_BUTTON_DOWN)
{
mciSendString(L"play click from 0", NULL, 0, NULL);
g_playerID = CHARACTER_TINY; //改变玩家英雄为提尼
g_LMBDown = false;
}
break;
case BUTTON_START_ID:
if(state == UGP_BUTTON_DOWN)
{
mciSendString(L"play click from 0", NULL, 0, NULL);
mciSendString(L"stop bgm", NULL, 0, NULL);
Init(); //初始化游戏资源
g_currentGUI = GUI_GAME_SCREEN;
g_LMBDown = false;
}
break;
case BUTTON_QUIT_ID:
if(state == UGP_BUTTON_DOWN)
{
mciSendString(L"play click from 0", NULL, 0, NULL);
g_LMBDown = false;
PostQuitMessage(0); //退出游戏
}
break;
}
}
//----------------------------------------【Direct3D_Render()函数】--------------------------------------------
//描述:使用Direct3D进行渲染
//---------------------------------------------------------------------------------------------------------------
void Direct3D_Render(HWND hWnd, float fTimeDelta)
{
//---------------------------------------------------------------------------------------------------------------
//【Direct3D渲染步骤一】:清屏操作
//---------------------------------------------------------------------------------------------------------------
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 108, 255), 1.0f, 0);
//---------------------------------------------------------------------------------------------------------------
//【Direct3D渲染步骤二】:开始绘制
//---------------------------------------------------------------------------------------------------------------
g_pd3dDevice->BeginScene(); //开始绘制
//---------------------------------------------------------------------------------------------------------------
//【Direct3D渲染步骤三】:正式绘制
//---------------------------------------------------------------------------------------------------------------
//根据当前的GUI来绘制相应的GUI
if(g_currentGUI == GUI_MAIN_SCREEN)
ProcessGUI(g_mainGUI, g_LMBDown, g_MouseX, g_MouseY, GUICallBack);
else if(g_currentGUI == GUI_START_SCREEN)
ProcessGUI(g_startGUI, g_LMBDown, g_MouseX, g_MouseY, GUICallBack);
else if(g_currentGUI == GUI_OVER_SCREEN)
ProcessGUI(g_overGUI, g_LMBDown, g_MouseX, g_MouseY, GUICallBack);
else
{
//绘制天空
D3DXMATRIX matSky,matTransSky,matRotSky;
D3DXMatrixTranslation(&matTransSky,0.0f,-23000.0f,0.0f);
D3DXMatrixRotationY(&matRotSky, -0.00002f*timeGetTime()); //旋转天空网格, 简单模拟云彩运动效果
matSky=matTransSky*matRotSky;
g_pSkyBox->RenderSkyBox(&matSky);
//绘制地形
D3DXMATRIX matWorld;
D3DXMatrixIdentity(&matWorld);
g_pTerrain->RenderTerrain(&matWorld);
//设置公告板矩阵
D3DXMATRIX viewMat;
g_pCamera->GetViewMatrix(&viewMat);
D3DXMATRIX billboardMat;
D3DXMatrixIdentity(&billboardMat);
billboardMat._11 = viewMat._11;
billboardMat._12 = viewMat._12;
billboardMat._13 = viewMat._13;
billboardMat._21 = viewMat._21;
billboardMat._22 = viewMat._22;
billboardMat._23 = viewMat._23;
billboardMat._31 = viewMat._31;
billboardMat._32 = viewMat._32;
billboardMat._33 = viewMat._33;
D3DXMatrixInverse(&billboardMat, NULL, &billboardMat);
//渲染游戏对象
for(int i = 0; i < Red.size(); ++i)
if(!Red[i]->isDead())
Red[i]->Render(fTimeDelta, &billboardMat);
for(int i = 0; i < Blue.size(); ++i)
if(!Blue[i]->isDead())
Blue[i]->Render(fTimeDelta, &billboardMat);
//渲染火球粒子系统
g_pFireParticle->RenderFireParticle(&billboardMat);
}
//绘制文字信息
HelpText_Render(hWnd);
//---------------------------------------------------------------------------------------------------------------
//【Direct3D渲染步骤四】:结束绘制
//---------------------------------------------------------------------- -----------------------------------------
g_pd3dDevice->EndScene(); //结束绘制
//---------------------------------------------------------------------------------------------------------------
//【Direct3D渲染步骤五】:显示翻转
//---------------------------------------------------------------------------------------------------------------
g_pd3dDevice->Present(NULL, NULL, NULL, NULL); //翻转与显示
}
//----------------------------------------【HelpText_Render()函数】--------------------------------------------
//描述:对相应的帮助文本进行绘制
//---------------------------------------------------------------------------------------------------------------
void HelpText_Render(HWND hWnd)
{
//定义一个矩形,用来获取主窗口矩形
if(g_currentGUI == GUI_START_SCREEN) //开始游戏界面文字的绘制
{
formatRect.left = 0;
formatRect.top = 50;
if(g_playerID == CHARACTER_WARCRAFT)
g_pTextCharacter->DrawText(NULL, L"狂暴战士:魔兽", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
else
g_pTextCharacter->DrawText(NULL, L"亡灵法师:提尼", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
}
else if(g_currentGUI == GUI_OVER_SCREEN) //结束游戏界面文字的绘制
{
formatRect.top = 50;
if(towerRed->isDead())
{
formatRect.left = 430;
g_pTextCharacter->DrawText(NULL, L"恭喜召唤师获得了游戏的胜利!", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
}
else
{
formatRect.left = 630;
g_pTextCharacter->DrawText(NULL, L"再接再厉!", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(60,100,255,255));
}
}
else if(g_currentGUI == GUI_GAME_SCREEN) //游戏进行界面文字的绘制
{
formatRect.top = 0;
//在窗口右上角处,显示每秒帧数
swprintf_s(g_strFPS, L"FPS:%.3f", Get_FPS());
g_pTextFPS->DrawText(0, g_strFPS, -1, &formatRect, DT_TOP | DT_RIGHT, D3DCOLOR_XRGB(255,255,255));
//显示显卡类型名
g_pTextAdapterName->DrawText(0, g_strAdapterName, -1, &formatRect, DT_TOP | DT_LEFT, D3DXCOLOR(1.0f, 0.5f, 0.0f, 1.0f));
// 输出帮助信息
formatRect.left = 0,formatRect.top = 500;
g_pTextInfor->DrawText(NULL, L"控制说明:", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235,123,230,255));
formatRect.top += 35;
g_pTextHelper->DrawText(NULL, L" A:左转向 D:右转向", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top += 25;
g_pTextHelper->DrawText(NULL, L" W:前进", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top += 25;
if(player->GetAttackTime() == player->GetAttackWait())
g_pTextHelper->DrawText(NULL, L" J: 攻击", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
else
{
swprintf_s(g_strHelpter, L" J: %.3f", player->GetAttackTime());
g_pTextHelper->DrawText(NULL, g_strHelpter, -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,0,0,255));
}
formatRect.top += 25;
g_pTextHelper->DrawText(NULL, L" ESC键 : 返回主菜单", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top = 20;
swprintf_s(g_strHelpter, L"等级: %d", player->GetLevel());
g_pTextHelper->DrawText(NULL, g_strHelpter, -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,255,255,255));
formatRect.top += 30;
swprintf_s(g_strHelpter, L"击杀: %d / 死亡: %d", player->GetKillNum(), player->GetDeadNum());
g_pTextHelper->DrawText(NULL, g_strHelpter, -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,255,255,255));
if(player->isDead())
{
formatRect.top += 30;
swprintf_s(g_strHelpter, L"复活时间:%d", player->GetReviveTime());
g_pTextHelper->DrawText(NULL, g_strHelpter, -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,0,0,255));
}
}
}
//-----------------------------------------【Get_FPS()函数】---------------------------------------------------
//描述:用于计算帧频率
//---------------------------------------------------------------------------------------------------------------
float Get_FPS()
{
//定义四个静态变量
static int frameCount = 0; //帧数
static float currentTime = 0; //当前时间
static float lastTime = 0; //上次计算帧频率的时间
static float fps = 0; //需要计算的fps值
++frameCount; //每调用一次此函数,帧数加一
//获取系统时间, timeGetTime() 返回系统时间,以毫秒为单位,乘以0.001得到秒
currentTime = timeGetTime() * 0.001f;
//如果当前时间减去之前计算帧频率的时间大于1秒钟,就进行帧频率的更新,并将帧数归零
if(currentTime - lastTime > 1.0f) //将时间控制在1秒钟
{
fps = frameCount / (currentTime - lastTime); //计算这一秒的fps值
frameCount = 0; //将本次帧数清零
lastTime = currentTime; //将当前时间赋给上次计算帧频率的时间,作为下一秒的基准时间
}
return fps;
}
//------------------------------------------------【 Direct3D_ClearUp函数】------------------------------------------
//描述:资源清理函数,在此函数中进行程序退出前资源的清理工作
//-------------------------------------------------------------------------------------------------------------------
void Direct3D_ClearUp()
{
//释放COM接口对象
SAFE_RELEASE(g_pd3dDevice);
SAFE_RELEASE(g_pTextFPS);
SAFE_RELEASE(g_pTextHelper);
SAFE_RELEASE(g_pTextAdapterName);
SAFE_RELEASE(g_pTextInfor);
SAFE_RELEASE(g_pTextCharacter);
SAFE_DELETE(g_pDInput);
SAFE_DELETE(g_pCamera);
SAFE_DELETE(g_pSkyBox);
SAFE_DELETE(g_pTerrain);
SAFE_DELETE(g_pWarcraftAnim);
SAFE_DELETE(g_pTowerAnim);
Clear();
SAFE_DELETE(g_mainGUI);
SAFE_DELETE(g_startGUI);
SAFE_DELETE(g_overGUI);
SAFE_DELETE(g_pFireParticle);
}
初始化的时候根据玩家选择的英雄进行相应的对象创建。而电脑则是随机产生的。死亡后可以通过键盘控制相机移动。
头一次写这么多,好累。游戏程序设计先告一段落了。等有时间学学Shader去。