1.飞机大战
1.完成FoePlaneBox类
1.与子弹盒子类似,需要一个用来存放所有飞机的链表:list<CFoePlane*> m_lstFoePlane。
2.需要有三个成员函数:CreateFoePlane、AllFoePlaneShow、AllFoePlaneShow。
1)CreateFoePlane 函数用来创建敌人飞机,在创建敌人飞机的时候,我们需要产生不同类型飞机的频率不同(意思是每产生一架大飞机能产生三架中飞机或六架小飞机),一个简单的办法是通过随机数产生一个int值,然后按照不同的区间进行划分;
2)创建飞机并初始化,注意:这里创建的飞机是父类型 FoePlane 型的指针,指向子类型 new 出来的对象;
3)调用各自的InitFoePlane函数初始化,并将飞机加入到链表中;
4)显示所有飞机,需要 AllFoePlaneShow 函数遍历 m_lstFoePlane 链表来实现;
5)所有飞机进行移动,需要先判断该机是否已经不在窗口内部显示(即判断y的值),若是则删除该飞机,否则调用其自己的show函数;
6)主要代码:
#include "FoePlaneBox.h"
CFoePlaneBox::CFoePlaneBox(void)
{
}
CFoePlaneBox::~CFoePlaneBox(void)
{
list<CFoePlane*>::iterator ite = m_lstFoePlane.begin();
while (ite != m_lstFoePlane.end())
{
delete(*ite);
ite = m_lstFoePlane.erase(ite);
}
}
void CFoePlaneBox::AllFoePlaneMove()
{
list<CFoePlane*>::iterator ite = m_lstFoePlane.begin();
while (ite != m_lstFoePlane.end())
{
if((*ite)->y > 550)
{
delete(*ite);
ite = m_lstFoePlane.erase(ite);
}
else
{
(*ite)->FoePlaneMove();
ite++;
}
}
}
void CFoePlaneBox::AllFoePlaneShow(HDC dc)
{
list<CFoePlane*>::iterator ite = m_lstFoePlane.begin();
while (ite != m_lstFoePlane.end())
{
(*ite)->FoePlaneShow(dc);
ite++;
}
}
void CFoePlaneBox::CreateFoePlane(HINSTANCE hIns)
{
CFoePlane *new_foe = 0;
int flag = rand()%12;
if(flag >=0 && flag <= 2)
{
new_foe = new CBigFoePlane;
}
if(flag >=3 && flag <= 6)
{
new_foe = new CMidFoePlane;
}
if(flag >=6 && flag <= 12)
{
new_foe = new CSmallFoePlane;
}
new_foe->InitFoePlane(hIns);
m_lstFoePlane.push_back(new_foe);
}
3.当我们完成上述步骤之后,我们就已经完成了敌人飞机的大部分代码,剩下的就是将敌人飞机进行调用,那么该如何进行调用呢?
1)我们需要在 PlaneApp 的成员中加入 FoePlaneBox 类对象来记录敌人飞机;
2)需要在 PlaneApp 的成员函数 OnCreateGame 中设置敌人飞机生成的定时器 FOE_PLANE_CREATE_TIMER_ID、敌人飞机移动的定时器 FOE_PLANE_MOVE_TIMER_ID;
3)需要在 PalneApp 的成员函数 OnGameRun 中设置当上述 FOE_PLANE_CREATE_TIMER_ID 定时器消息来临时,我们调用敌人飞机盒子的 CreateFoePlane 函数;
4)在 PalneApp 的成员函数 OnGameRun 中设置当上述 FOE_PLANE_MOVE_TIMER_ID 定时器消息来临时,我们调用敌人飞机盒子的 AllFoePlaneMove 函数;
5)完成上述代码之后就可以看到移动的敌人飞机了!!!
2.判断敌人飞机是否被击中
1.判断敌人飞机是否被击中就是通过子弹的x、y和敌人飞机的x、y以及宽高来比较得到是否击中。
2.对于不同类型的敌人飞机,不同之处在于每个飞机的宽和高不同,其他基本相同。
1)对于大飞机:
bool CBigFoePlane::IsGunnerHitForPlane(const CGunner* pGunner)
{
if(pGunner->x > this->x && pGunner->x < this->x+108
&& pGunner->y > this->y && pGunner->y < this->y+128)
{
return TRUE;
}
return FALSE;
}
2)对于中等飞机:
bool CMidFoePlane::IsGunnerHitForPlane(const CGunner* pGunner)
{
if(pGunner->x > this->x && pGunner->x < this->x+70
&& pGunner->y > this->y && pGunner->y < this->y+90)
{
return TRUE;
}
return FALSE;
}
3)对于小型飞机:
bool CSmallFoePlane::IsGunnerHitForPlane(const CGunner* pGunner)
{
if(pGunner->x > this->x && pGunner->x < this->x+32
&& pGunner->y > this->y && pGunner->y < this->y+28)
{
return TRUE;
}
return FALSE;
}
3.设计一个存储爆炸飞机的类
1.我们可以将所有的飞机分为两类,一类是有血的飞机,另一类是没血了的飞机,没血了的飞机我们要播放(虽然很高大上,但实质上也是贴图…)爆炸效果,那么对于没血了的飞机,我们也需要一个类似于 FoePlaneBox 的类来存储。
2.将这个类命名为 BlastFoePlaneBox 类,该类有一个成员:list<CFoePlane*> m_lstBlastFoePlane,成员方法包括显示飞机 AllBlastFoePlaneShow 和 改变显示的飞机的ID ChangeShowID。
1)对于 ChangeShowID 函数,我们想要做的就是将 foeplane 的 showid 进行–,若减到零则删除飞机;
2)对于 AllBlastFoePlaneShow 函数,遍历 m_lstBlastFoePlane 链表,对于每个飞机调用其自身的 FoePlaneShow 函数即可;
3)主要代码:
#include "BlastFoePlaneBox.h"
CBlastFoePlaneBox::CBlastFoePlaneBox(void)
{
}
CBlastFoePlaneBox::~CBlastFoePlaneBox(void)
{
list<CFoePlane*>::iterator ite = m_lstBlastFoePlane.begin();
while (ite != m_lstBlastFoePlane.end())
{
delete(*ite);
ite = m_lstBlastFoePlane.erase(ite);
}
}
void CBlastFoePlaneBox::AllBlastFoePlaneShow(HDC dc)
{
list<CFoePlane*>::iterator ite = m_lstBlastFoePlane.begin();
while (ite != m_lstBlastFoePlane.end())
{
(*ite)->FoePlaneShow(dc);
++ite;
}
}
void CBlastFoePlaneBox::ChangeShowID()
{
list<CFoePlane*>::iterator ite = m_lstBlastFoePlane.begin();
while (ite != m_lstBlastFoePlane.end())
{
if((*ite)->m_nShowID == 0)
{
delete(*ite);
ite = m_lstBlastFoePlane.erase(ite);
}
else
{
((*ite)->m_nShowID)--;
ite++;
}
}
}
4.判断子弹是否击中飞机
1.对于子弹是否能击中飞机,我们如何判断?
1)由于我们将所有的子弹和所有的敌人飞机都放入了链表中,因此首先需要进行遍历子弹链表;
2)在遍历子弹链表的循环中,需要嵌套一个遍历敌人飞机的循环(即每一个子弹都与所有飞机进行判断,尽管这种方法很笨,但到目前为止我还不会其他好一点方法);
3)对于每一个敌人飞机,都调用它的 IsGunnerHitForPlane 函数,若是,则删除子弹,并让敌人飞机掉血,若敌人飞机没血了(IsBoom 函数返回true),则将该飞机添加到新的 blast_foeplane_box 对象中去,并删除这个敌人飞机;
4)在以上过程当中,我们会有一次删除子弹的操作,当击中飞机后,我们删除该子弹,但是遍历子弹链表仍会向后移动一个节点,这将会导致我们少遍历了一个子弹,因此我们用一个 bool 型变量 flag_of_hit 来记录子弹是否击中飞机,若是,则置为 true,并不进行子弹链表自增的操作,若否,则让子弹链表的迭代器自增;
5)主要代码:
void CPlaneApp::GunnerHitFoePlane()
{
bool flag_of_hit = false;
list<CGunner*>::iterator ite_gunner = gun_box.m_lstGunner.begin();
// 遍历所有子弹
while (ite_gunner != gun_box.m_lstGunner.end())
{
// 每一个子弹是否击中飞机
list<CFoePlane*>::iterator ite_foe_plane = foe_plane_box.m_lstFoePlane.begin();
while (ite_foe_plane != foe_plane_box.m_lstFoePlane.end())
{
if((*ite_foe_plane)->IsGunnerHitForPlane(*ite_gunner) == true) // 当前子弹击中了飞机
{
flag_of_hit = true; // 击中了就标记为true
// 删除炮弹
delete(*ite_gunner);
ite_gunner = gun_box.m_lstGunner.erase(ite_gunner);
(*ite_foe_plane)->DownBlood();
if((*ite_foe_plane)->IsBoom() == true) // 如果飞机没血了
{
blast_foeplane_box.m_lstBlastFoePlane.push_back(*ite_foe_plane);
ite_foe_plane = foe_plane_box.m_lstFoePlane.erase(ite_foe_plane);
}
break;
}
++ite_foe_plane;
}
if(flag_of_hit)
flag_of_hit = false;
else
++ite_gunner;
}
}
5.显示爆炸效果
1.在上面我们完成了 BlastFoePlane 类,可以通过设置定时器来显示爆炸效果了。
1)在 PlaneApp 的 OnGameRun 函数中设置一个 CHANGE_PLANE_SHOWID_TIMER_ID 的定时器,当这个定时器消息来到时,我们就调用 blast_foeplane_box.ChangeShowID();
2)增加一个小功能:按下空格键,所有的敌人飞机都爆炸(是不是外挂啊喂~);
3)主要代码:
void CPlaneApp::OnGameRun(WPARAM w_param)
{
if(w_param == PLAYER_MOVE_TIMER_ID)
{
if(::GetAsyncKeyState(VK_LEFT))
player.MovePlayer(VK_LEFT);
if(::GetAsyncKeyState(VK_RIGHT))
player.MovePlayer(VK_RIGHT);
if(::GetAsyncKeyState(VK_DOWN))
player.MovePlayer(VK_DOWN);
if(::GetAsyncKeyState(VK_UP))
player.MovePlayer(VK_UP);
}
if(w_param == BACK_MOVE_TIMER_ID)
{
back.MoveBack();
}
if(w_param == SEND_GUNNER_TIMER_ID)
{
player.SendGunner(gun_box, m_h_ins);
}
if (w_param == GUNNER_MOVE_TIMER_ID) // 每次炮弹移动都需要进行判断是否击中了飞机
{
gun_box.AllGunnerMove();
this->GunnerHitFoePlane();
}
// 敌方飞机生成
if(w_param == FOE_PLANE_CREATE_TIMER_ID)
{
foe_plane_box.CreateFoePlane(m_h_ins);
}
// 敌方飞机移动
if(w_param == FOE_PLANE_MOVE_TIMER_ID)
{
foe_plane_box.AllFoePlaneMove();
}
// 飞机爆炸显示图
if(w_param == CHANGE_PLANE_SHOWID_TIMER_ID)
{
blast_foeplane_box.ChangeShowID();
}
this->OnGameShow();
}
void CPlaneApp::OnGameKeyDown(WPARAM w_param) // 外挂函数
{
// 按下空格键将所有敌人飞机销毁
if(w_param == VK_SPACE)
{
blast_foeplane_box.m_lstBlastFoePlane.splice(blast_foeplane_box.m_lstBlastFoePlane.end(), foe_plane_box.m_lstFoePlane);
}
}
-------------------------------------------未完待续-------------------------------