突然相遇:
然后死掉.
源代码以及实现方法:
首先定义一个Character类为角色的基类,然后英雄魔兽(战士)类Warcraft与托尼(法师)类Timy继承于它。分别实现对应的方法。
角色类有许多的方法,也有一些需要子类实现的虚函数方法。
Character.h:
//=============================================================================
//一个封装了游戏角色类的头文件
//=============================================================================#pragma once
#include <d3d9.h>
#include <d3dx9.h>
#include "AnimationClass.h"
#include "AnimInstanceClass.h"
#include "DirectInputClass.h"
#include <vector>//血条的顶点定义
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<Character *> &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<Character *> &enemy, std::vector<Character *> &friends) = 0; //AIvirtual void SetMatrix() = 0; //对骨骼动画进行矩阵变换virtual ~Character(void) = 0; //析构函数virtual int GetExp() = 0; //返回角色死亡后返回的经验值virtual void AddExp(int exp) = 0; //角色获得经验值virtual void UserControl(DirectInputClass *pInput, std::vector<Character *> &enemy, std::vector<Character *> &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<Character *> &enemy, std::vector<Character *> &friends); //前进void RotationLeft(); //左转void RotationRight(); //右转void Attack(std::vector<Character *> &enemy); //攻击void Ready(); //准备void PlayAnimation(); //播放动画void Update(float fDeltaTime); //更新void Dead(); //死亡void AI(std::vector<Character *> &enemy, std::vector<Character *> &friends); //AIbool isBlocked(D3DXVECTOR3 *position, std::vector<Character *> &enemy, std::vector<Character *> &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<Character *> &enemy, std::vector<Character *> &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<Character *> &enemy, std::vector<Character *> &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<Character *> &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<Character *> &enemy, std::vector<Character *> &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<Character *> &enemy, std::vector<Character *> &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<Character *> &enemy, std::vector<Character *> &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<Character *> &enemy, std::vector<Character *> &friends); //前进void RotationLeft(); //左转void RotationRight(); //右转void Attack(std::vector<Character *> &enemy); //攻击void Ready(); //准备void PlayAnimation(); //播放动画void Update(float fDeltaTime); //更新void Dead(); //死亡void AI(std::vector<Character *> &enemy, std::vector<Character *> &friends); //AIbool isBlocked(D3DXVECTOR3 *position, std::vector<Character *> &enemy, std::vector<Character *> &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<Character *> &enemy, std::vector<Character *> &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<Character *> &enemy, std::vector<Character *> &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<Character *> &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<Character *> &enemy, std::vector<Character *> &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<Character *> &enemy, std::vector<Character *> &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<Character *> &enemy, std::vector<Character *> &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 <d3d9.h>
#include <d3dx9.h>
#include <tchar.h>
#include <list>
#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<FIREPARTICLE> 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<Character *> &Red, std::vector<Character *> &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<FIREPARTICLE>::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); //源混合系数设为1m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); //目标融合系数设为1//设置剔除模式为不剔除任何面m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);//渲染火球std::list<FIREPARTICLE>::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<Character *> &Red, std::vector<Character *> &Blue, TerrainClass *pTerrain)
{std::list<FIREPARTICLE>::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 <d3d9.h>
#include <d3dx9.h>
#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<Character *> &enemy); //攻击void Ready(); //准备void PlayAnimation(); //播放动画void Update(float fDeltaTime); //更新void Dead(); //死亡 void AI(std::vector<Character *> &enemy, std::vector<Character *> &friends); //AIvoid SetMatrix(); //对骨骼动画进行矩阵变换int GetExp(); //返回角色死亡后返回的经验值,为当前经验值void Render(float fDeltaTime, D3DXMATRIX *billboardMat); //渲染游戏角色void UserControl(DirectInputClass *pInput, std::vector<Character *> &enemy, std::vector<Character *> &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<Character *> &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<Character *> &enemy, std::vector<Character *> &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<Character *> &enemy, std::vector<Character *> &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 <d3d9.h>
#include <d3dx9.h>
#include <tchar.h>
#include <time.h>
#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<Character *> 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; //支持硬件顶点运算,采用硬件顶点运算elsevp = 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);elsemciSendString(L"play defeat from 0", NULL, 0, NULL);//切换当前GUI为游戏结束GUIg_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为开始游戏GUIg_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为主界面GUIg_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));elseg_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去。