c++基于游戏壳的飞机大战游戏----开发(第二部分)
一.我们先将每个功能按文件夹进行分类(这样便于管理)
如下
每一个文件里都写出相应的头文件与源文件(GameFrame文件夹中的内容是上一篇博客中写好的游戏壳代码(写好的游戏壳的头文件和源文件)),这里拿back这个文件夹举例
在Visual Studio中 我们将头文件,源文件删掉,自己添加筛选器(文件夹),然后对其进行改名并在每一个筛选器(文件夹)中添加相应的头文件和源文件
二.进行代码实现
1.背景
头文件
#pragma once
#include<easyx.h>
class CBack {
public:
int m_x;
int m_y;
IMAGE m_imgBack;
CBack();
~CBack();
void InitBack();
void ShowBack();
void MoveBack();
};
源文件
#include"Cback.h"
#include"../config/config.h"
CBack::CBack():m_x(0),m_y(0) {
}
CBack::~CBack() {
}
void CBack::InitBack(){
::loadimage(&m_imgBack, L"./res/背景.jpg");
m_x = 0;
m_y = -BACK_HEIGHT;
}
void CBack::ShowBack(){
::putimage(m_x, m_y, &m_imgBack);
}
void CBack::MoveBack() {
m_y += BACK_MOVE_STEP;
if (m_y >= 0) {
m_y = -BACK_HEIGHT;
}
}
2.玩家飞机
头文件
#pragma once
#include<easyx.h>
#include"../gunnerlist/CGunList.h"
class CPlayer {
public:
int m_x;
int m_y;
IMAGE m_imgPlayer;
IMAGE m_imgMask;
CPlayer();
~CPlayer();
void InitPlayer();
void ShowPlayer();
void MovePlayer(unsigned dir);
CGunner* SendGunner();
};
源文件
#include"player.h"
#include"../config/config.h"
CPlayer::CPlayer():m_x(0),m_y(0){}
CPlayer::~CPlayer(){}
void CPlayer::InitPlayer(){
m_x = (BACK_WIDTH - PLAYER_WIDTH) / 2;
m_y = BACK_HEIGHT - PLAYER_HEIGHT;
::loadimage(&m_imgPlayer, L"./res/playerplane.jpg");//加载原图
::loadimage(&m_imgMask, L"./res/playerplane-mask.jpg");//加载屏蔽图
}
void CPlayer::ShowPlayer(){
::putimage(m_x, m_y, &m_imgMask, SRCPAINT);//屏蔽图 和目标做位或操作
::putimage(m_x, m_y, &m_imgPlayer, SRCAND);//原图 和上一次的结果 做位与操作
}
void CPlayer::MovePlayer(unsigned dir){
if (dir == VK_UP) {
(m_y - PLAYER_MOVE_STEP) >= 0 ? m_y -= PLAYER_MOVE_STEP: m_y = 0;
}
if (dir == VK_DOWN) {
(m_y + PLAYER_MOVE_STEP) <= (BACK_HEIGHT - PLAYER_HEIGHT) ? m_y += PLAYER_MOVE_STEP : m_y = BACK_HEIGHT -PLAYER_HEIGHT;
}
if (dir == VK_LEFT) {
(m_x - PLAYER_MOVE_STEP) >= 0 ? m_x -= PLAYER_MOVE_STEP : m_x = 0;
}
if (dir == VK_RIGHT) {
(m_x + PLAYER_MOVE_STEP) <= (BACK_WIDTH - PLAYER_WIDTH) ? m_x += PLAYER_MOVE_STEP : m_x = BACK_WIDTH - PLAYER_WIDTH;
}
}
CGunner* CPlayer::SendGunner() {//发射炮弹(创建炮弹)
CGunner* PGUN = new CGunner;
int x = m_x + (PLAYER_WIDTH - GUNNER_WIDTH) / 2;
int y = m_y - GUNNER_HEIGHT;
PGUN->InitGunner(x, y);//初始化
return PGUN;
}
3.炮弹
头文件
炮弹头文件
#pragma once
#include <easyx.h>
#include"../config/config.h"
class CGunner {
public:
int m_x;
int m_y;
IMAGE m_imgGunner;
public:
CGunner();
~CGunner();
public:
void InitGunner(int x, int y);
void ShowGunner();
void MoveGunner();
};
炮弹链表头文件
#pragma once
#include<list>
#include"CGunner.h"
using namespace std;
class CGunList {
public:
list<CGunner*> gumlist;
public:
CGunList();
~CGunList();
public:
void ShowAllGun();
void MoveAllGun();
};
源文件
炮弹源文件
#include"CGunner.h"
CGunner::CGunner():m_x(0),m_y(0){}
CGunner::~CGunner(){}
void CGunner::InitGunner(int x, int y){
m_x = x;
m_y = y;
::loadimage(&m_imgGunner,L"./res/gunner.jpg");
}
void CGunner::ShowGunner(){
::putimage(m_x, m_y/*目标的位置*/, GUNNER_WIDTH, GUNNER_HEIGHT/*显示图片的大小*/
, &m_imgGunner/*要显示哪张图*/, GUNNER_WIDTH, 0/*从图片的哪个位置开始显示*/, SRCPAINT/*传输方式*/);
::putimage(m_x, m_y, GUNNER_WIDTH, GUNNER_HEIGHT, &m_imgGunner, 0, 0, SRCAND);
}
void CGunner::MoveGunner(){
m_y -= GUNNER_MOVE_STEP;
}
炮弹链表源文件
#include"CGunList.h"
CGunList::CGunList(){}
CGunList::~CGunList(){//回收炮弹
list<CGunner*>::iterator ite = gumlist.begin();
while (ite != gumlist.end()) {
if (*ite) {
delete (*ite);
}
ite++;
}
gumlist.clear();
}
void CGunList::ShowAllGun(){
for (CGunner* PGUN: gumlist) {
PGUN->ShowGunner();
}
}
void CGunList::MoveAllGun(){
list<CGunner*>::iterator ite = gumlist.begin();
while (ite != gumlist.end()) {
if (*ite) {
(*ite)->MoveGunner();
if ((*ite)->m_y <= -GUNNER_HEIGHT) {
delete (*ite);
(*ite) = nullptr;
ite = gumlist.erase(ite);
continue;
}
ite++;
}
}
}
4.敌人飞机
父类敌人飞机头文件及源文件
#pragma once
#include <random>
#include <easyx.h>
#include"../player/player.h"
#include"../gunnerlist/CGunList.h"
class CFoe {
public:
int m_x;
int m_y;
IMAGE m_imgFoe;
int m_blood;
int m_showid;
static random_device rd;
public:
CFoe();
~CFoe();
public:
virtual void InitFoe() = 0;
virtual void ShowFoe() = 0;
void MoveFoe(int step);
virtual bool IsHitPlayer(CPlayer& player) = 0;
virtual bool IsHitGun(CGunner* gun) = 0;
};
#include "CFoe.h"
CFoe::CFoe():m_x(0), m_y(0), m_blood(0), m_showid(0){}
CFoe::~CFoe(){}
void CFoe::MoveFoe(int step) {
m_y += step;
}
random_device CFoe::rd;
子类敌人飞机头文件及源文件
大型飞机
#pragma once
#include"CFoe.h"
class CFoeBig:public CFoe{
public:
void InitFoe() override;//可以用于校验当前的虚函数是否重写父类的虚函数,如果不是,则报错
void ShowFoe() override;
bool IsHitPlayer(CPlayer& player) override;
bool IsHitGun(CGunner* gun) override;
};
#include "CFoeBig.h"
void CFoeBig::InitFoe() {
m_x = (rd()) % (BACK_WIDTH - FOEBIG_WIDTH + 1);
m_y = -FOEBIG_HEIGHT;
::loadimage(&m_imgFoe, L"./res/foeplanebig.jpg");
m_blood = FOEBIG_BLOOD;
m_showid = FOEBIG_SHOWID_INIT;
}
void CFoeBig::ShowFoe(){
::putimage(m_x, m_y, FOEBIG_WIDTH, FOEBIG_HEIGHT, &m_imgFoe, FOEBIG_WIDTH, (FOEBIG_SHOWID_INIT- m_showid)*FOEBIG_HEIGHT, SRCPAINT);
::putimage(m_x, m_y, FOEBIG_WIDTH, FOEBIG_HEIGHT, &m_imgFoe, 0, (FOEBIG_SHOWID_INIT - m_showid) * FOEBIG_HEIGHT, SRCAND);
}
bool CFoeBig::IsHitPlayer(CPlayer& player){
int x1 = player.m_x + PLAYER_WIDTH / 2;
if ((x1 >= m_x && x1 <= m_x + FOEBIG_WIDTH) && (player.m_y >= m_y && player.m_y <= m_y + FOEBIG_HEIGHT)) {
return true;
}
int y1 = player.m_y + PLAYER_HEIGHT / 2;
if ((player.m_x >= m_x && player.m_x <= m_x + FOEBIG_WIDTH) && (y1 >= m_y && y1 <= m_y + FOEBIG_HEIGHT)) {
return true;
}
int x2= player.m_x + PLAYER_WIDTH;
if ((x2 >= m_x && x2 <= m_x + FOEBIG_WIDTH) && (y1 >= m_y && y1 <= m_y + FOEBIG_HEIGHT)) {
return true;
}
return false;
}
bool CFoeBig::IsHitGun(CGunner* gun){
int x1 = gun->m_x + GUNNER_WIDTH / 2;
if ((x1 >= m_x && x1 <= m_x + FOEBIG_WIDTH) && (gun->m_y >= m_y && gun->m_y <= m_y + FOEBIG_HEIGHT)) {
return true;
}
return false;
}
中型飞机
#pragma once
#include"CFoe.h"
class CFoeMid :public CFoe {
public:
void InitFoe() override;//可以用于校验当前的虚函数是否重写父类的虚函数,如果不是,则报错
void ShowFoe() override;
bool IsHitPlayer(CPlayer& player) override;
bool IsHitGun(CGunner* gun) override;
};
#include "CFoeMid.h"
void CFoeMid::InitFoe() {
m_x = (rd()) % (BACK_WIDTH - FOEMID_WIDTH + 1);
m_y = -FOEMID_HEIGHT;
::loadimage(&m_imgFoe, L"./res/foeplanemid.jpg");
m_blood = FOEMID_BLOOD;
m_showid = FOEMID_SHOWID_INIT;
}
void CFoeMid::ShowFoe() {
::putimage(m_x, m_y, FOEMID_WIDTH, FOEMID_HEIGHT, &m_imgFoe, FOEMID_WIDTH, (FOEMID_SHOWID_INIT - m_showid) * FOEBIG_HEIGHT, SRCPAINT);
::putimage(m_x, m_y, FOEMID_WIDTH, FOEMID_HEIGHT, &m_imgFoe, 0, (FOEMID_SHOWID_INIT - m_showid) * FOEBIG_HEIGHT, SRCAND);
}
bool CFoeMid::IsHitPlayer(CPlayer& player) {
int x1 = player.m_x + PLAYER_WIDTH / 2;
if ((x1 >= m_x && x1 <= m_x + FOEMID_WIDTH) && (player.m_y >= m_y && player.m_y <= m_y + FOEMID_HEIGHT)) {
return true;
}
int y1 = player.m_y + PLAYER_HEIGHT / 2;
if ((player.m_x >= m_x && player.m_x <= m_x + FOEMID_WIDTH) && (y1 >= m_y && y1 <= m_y + FOEMID_HEIGHT)) {
return true;
}
int x2 = player.m_x + PLAYER_WIDTH;
if ((x2 >= m_x && x2 <= m_x + FOEMID_WIDTH) && (y1 >= m_y && y1 <= m_y + FOEMID_HEIGHT)) {
return true;
}
return false;
}
bool CFoeMid::IsHitGun(CGunner* gun) {
int x1 = gun->m_x + GUNNER_WIDTH / 2;
if ((x1 >= m_x && x1 <= m_x + FOEMID_WIDTH) && (gun->m_y >= m_y && gun->m_y <= m_y + FOEMID_HEIGHT)) {
return true;
}
return false;
}
小型飞机
#pragma once
#include"CFoe.h"
class CFoeSma :public CFoe {
public:
void InitFoe() override;//可以用于校验当前的虚函数是否重写父类的虚函数,如果不是,则报错
void ShowFoe() override;
bool IsHitPlayer(CPlayer& player) override;
bool IsHitGun(CGunner* gun) override;
};
#include "CFoeSma.h"
void CFoeSma::InitFoe() {
m_x = (rd()) % (BACK_WIDTH - FOESMA_WIDTH + 1);
m_y = -FOESMA_HEIGHT;
::loadimage(&m_imgFoe, L"./res/foeplanesma.jpg");
m_blood = FOESMA_BLOOD;
m_showid = FOESMA_SHOWID_INIT;
}
void CFoeSma::ShowFoe() {
::putimage(m_x, m_y, FOESMA_WIDTH, FOESMA_HEIGHT, &m_imgFoe, FOESMA_WIDTH, (FOESMA_SHOWID_INIT - m_showid) * FOEBIG_HEIGHT, SRCPAINT);
::putimage(m_x, m_y, FOESMA_WIDTH, FOESMA_HEIGHT, &m_imgFoe, 0, (FOESMA_SHOWID_INIT - m_showid) * FOEBIG_HEIGHT, SRCAND);
}
bool CFoeSma::IsHitPlayer(CPlayer& player) {
int x1 = player.m_x + PLAYER_WIDTH / 2;
if ((x1 >= m_x && x1 <= m_x + FOESMA_WIDTH) && (player.m_y >= m_y && player.m_y <= m_y + FOESMA_HEIGHT)) {
return true;
}
int y1 = player.m_y + PLAYER_HEIGHT / 2;
if ((player.m_x >= m_x && player.m_x <= m_x + FOESMA_WIDTH) && (y1 >= m_y && y1 <= m_y + FOESMA_HEIGHT)) {
return true;
}
int x2 = player.m_x + PLAYER_WIDTH;
if ((x2 >= m_x && x2 <= m_x + FOESMA_WIDTH) && (y1 >= m_y && y1 <= m_y + FOESMA_HEIGHT)) {
return true;
}
return false;
}
bool CFoeSma::IsHitGun(CGunner* gun) {
int x1 = gun->m_x + GUNNER_WIDTH / 2;
if ((x1 >= m_x && x1 <= m_x + FOESMA_WIDTH) && (gun->m_y >= m_y && gun->m_y <= m_y + FOESMA_HEIGHT)) {
return true;
}
return false;
}
敌人飞机链表头文件及源文件
#pragma once
#include <list>
#include"CFoe.h"
using namespace std;
class CFoeList {
public:
list<CFoe*> m_IsFoe;
list<CFoe*> m_IsFoeBoom;
public:
CFoeList();
~CFoeList();
public:
void ShowAllFoe();
void MoveAllFoe();
};
#include "CFoeList.h"
#include<typeinfo>
#include"CFoeBig.h"
#include"CFoeMid.h"
#include"CFoeSma.h"
CFoeList::CFoeList(){}
CFoeList::~CFoeList(){
list<CFoe*>::iterator ite = m_IsFoe.begin();
while (ite != m_IsFoe.end()) {
if (*ite) {
delete* (ite);
ite++;
}
}
m_IsFoe.clear();
ite = m_IsFoeBoom.begin();
while (ite != m_IsFoeBoom.end()) {
if (*ite) {
delete (*ite);
(*ite) = nullptr;
}
ite++;
}
m_IsFoeBoom.clear();
}
void CFoeList::ShowAllFoe(){
list<CFoe*>::iterator ite = m_IsFoe.begin();
while (ite != m_IsFoe.end()) {
if (*ite) {
(*ite)->ShowFoe();
ite++;
}
}
ite = m_IsFoeBoom.begin();
while (ite != m_IsFoeBoom.end()) {
if (*ite) {
(*ite)->ShowFoe();
ite++;
}
}
}
void CFoeList::MoveAllFoe(){
list<CFoe*>::iterator ite= m_IsFoe.begin();
while (ite != m_IsFoe.end()) {
if (*ite) {
//RTTI 运行时类型识别 (RunTime Type Id)
//typeid('a')==typeid(char)
if (typeid(**ite) == typeid(CFoeBig)) {
(*ite)->MoveFoe(FOEBIG_MOVE_STEP);
}
if (typeid(**ite) == typeid(CFoeMid)) {
(*ite)->MoveFoe(FOEMID_MOVE_STEP);
}
if (typeid(**ite) == typeid(CFoeSma)) {
(*ite)->MoveFoe(FOESMA_MOVE_STEP);
}
if ((*ite)->m_y >= BACK_HEIGHT) {
delete (*ite);
ite = m_IsFoe.erase(ite);
continue;
}
ite++;
}
}
}
5.游戏壳
头文件
#pragma once
#include<easyx.h>
#include<map>
using namespace std;
#define ADD_MSG(MSGID,MSGTYPE,CLASS)\
m_msgMap[MSGID] = new MesTypefun{ MSGTYPE };\
m_msgMap[MSGID]->p_fun_##MSGTYPE = (PFUN_##MSGTYPE)&CLASS::On_##MSGID;
class CGameFrame {
public:
HWND m_hWnd; //窗口句柄,标识窗口
bool m_isQuit;//表示是否退出,true:退出 false:不退出
//#define EX_MOUSE 1
//#define EX_KEY 2
//#define EX_CHAR 4
//#define EX_WINDOW 8
typedef void(CGameFrame::* PFUN_EX_MOUSE)(int, int);//鼠标类型
typedef void(CGameFrame::* PFUN_EX_KEY)(BYTE);//键盘类型
typedef void(CGameFrame::* PFUN_EX_CHAR)(WPARAM);//字符类型
typedef void(CGameFrame::* PFUN_EX_WINDOW)(WPARAM, LPARAM);//窗口类型
struct MesTypefun {
int MsgType;
union {
PFUN_EX_MOUSE p_fun_EX_MOUSE;
PFUN_EX_KEY p_fun_EX_KEY;
PFUN_EX_CHAR p_fun_EX_CHAR;
PFUN_EX_WINDOW p_fun_EX_WINDOW;
};
};
map <UINT, MesTypefun*> m_msgMap; //消息映射表
CGameFrame() :m_hWnd(nullptr), m_isQuit(false) {
}
virtual ~CGameFrame() {
for (pair<UINT, MesTypefun*> pr : m_msgMap) {
if (pr.second) delete pr.second; //回收new出的空间
}
}
virtual void AddMsg();
//1.初始化游戏的函数 InitGame
void InitGame(int width, int height, int x, int y, LPCWSTR title);
//2.显示 重绘 PaintGame
void On_WM_PAINT(WPARAM w, LPARAM l);
//3.游戏运行 RunGame
//void RunGame();
static LRESULT RunGame(HWND hwnd, UINT msg, WPARAM w, LPARAM l);
//4.销毁 CloseGame
void On_WM_CLOSE(WPARAM w, LPARAM l);
/*------------------------------------------*/
virtual void Init() = 0;
virtual void Paint() = 0;
virtual void close() = 0;
};
#define CREATE_OBJECT(OBJ_CLASS)\
CGameFrame* CreateObject(){\
return new OBJ_CLASS;\
}
#define WND_PARAMWIDTHWND_PARAMWIDTH(WIDTH,HEIGHT,X,Y,TITLE)\
int wnd_width=WIDTH;\
int wnd_height=HEIGHT;\
int wnd_x=X;\
int wnd_y=Y;\
TCHAR* pTitle=(TCHAR*)TITLE;
/*
GameFrame.h ,GameFrame.cpp 添加到自己的工程中,需要自定义子类继承 游戏壳的父类(CGameFrame)
父类中的纯虚函数
virtual void Init();
virtual void Paint();
virtual void close();
必须要在具体的游戏中重写定义 ,实现
virtual void AddMsg(),虚函数根据自己的需求,可以根据自己的需求,选择性的重写,添加自己所需要的信息,最后要显示的调用父类的 CGameFrame::AddMsg();
最后要显示的调用父类的 CGameFrame::AddMsg();
并且在子类中添加消息对应的处理函数,根据消息所属的类型,函数定义的类型如下:
void(CGameFrame::* PFUN_EX_MOUSE)(int, int);//鼠标类型
void(CGameFrame::* PFUN_EX_KEY)(BYTE);//键盘类型
void(CGameFrame::* PFUN_EX_CHAR)(WPARAM);//字符类型
void(CGameFrame::* PFUN_EX_WINDOW)(WPARAM, LPARAM);
使用宏 CREATE_OBJECT ,WND_PARAM 传递对应的宏参数
*/
源文件
#include "GameFrame.h"
#include <Windowsx.h>
//1.初始化游戏的函数 InitGame
void CGameFrame::InitGame(int width, int height, int x, int y, LPCWSTR title) {
//创建窗口
m_hWnd = ::initgraph(width, height);
//设定窗口的背景色为白色
::setbkcolor(RGB(255, 255, 255));
::cleardevice(); //1.及时更新背景色
//移动窗口
::MoveWindow(m_hWnd, x, y, width, height, TRUE);
//设置窗口标题
::SetWindowText(m_hWnd, title);
//设置窗口的属性
::SetWindowLong(m_hWnd, GWL_WNDPROC/*32位下的宏*/, (LONG)&CGameFrame::RunGame);//设置窗口的回调函数
//添加消息
AddMsg();
//具体游戏初始化
Init();
}
void CGameFrame::AddMsg() {
/*m_msgMap[WM_LBUTTONDOWN] = new MesTypefun{ EX_MOUSE };
m_msgMap[WM_LBUTTONDOWN]->p_fun_EX_MOUSE = &CGameFrame::On_WM_LBUTTONDOWN;*/
/*m_msgMap[WM_KEYDOWN] = new MesTypefun{ EX_KEY };
m_msgMap[WM_KEYDOWN]->p_fun_EX_KEY = &CGameFrame::On_WM_KEYDOWN;*/
ADD_MSG(WM_CLOSE, EX_WINDOW, CGameFrame);
ADD_MSG(WM_PAINT, EX_WINDOW, CGameFrame);
}
//2.显示 重绘 PaintGame
void CGameFrame::On_WM_PAINT(WPARAM w, LPARAM l) {
::BeginBatchDraw();//开始批量绘图
::cleardevice();
//具体游戏的重绘
Paint();
::EndBatchDraw();//批量结束绘图
}
CGameFrame* pGame = nullptr;
CGameFrame* CreateObject();
extern int wnd_width;
extern int wnd_height;
extern int wnd_x;
extern int wnd_y;
extern TCHAR* pTitle;
LRESULT CGameFrame::RunGame(HWND hwnd, UINT msg, WPARAM w, LPARAM l) {
if (pGame->m_msgMap.count(msg)) {
switch (pGame->m_msgMap[msg]->MsgType) {
case EX_MOUSE: {
//(对象->*函数指针)();
(pGame->*pGame->m_msgMap[msg]->p_fun_EX_MOUSE)(GET_X_LPARAM(l), GET_Y_LPARAM(l));
break;
}
case EX_KEY: {
(pGame->*pGame->m_msgMap[msg]->p_fun_EX_KEY)(w);
break;
}
case EX_CHAR: {
(pGame->*pGame->m_msgMap[msg]->p_fun_EX_CHAR)(w);
break;
}
case EX_WINDOW: {
(pGame->*pGame->m_msgMap[msg]->p_fun_EX_WINDOW)(w, l);
break;
}
}
}
/*将整个窗口设置为无效,系统会判定其为过时了,会主动发送
WN_PAINT 来告诉程序 应当及时刷新,保证窗口最新*/
RECT rect{ wnd_width,wnd_height };
::InvalidateRect(hwnd, &rect, false);//设置窗口的无效区
return ::DefWindowProc(hwnd, msg, w, l);//默认的窗口回调,一般处理不太关心的消息
}
//4.销毁 CloseGame
void CGameFrame::On_WM_CLOSE(WPARAM w, LPARAM l) {
//具体游戏的关闭;
close();
::closegraph();//关闭窗口
m_isQuit = true;//告诉主函数的循环该退出了
}
int main() {
pGame = CreateObject();
pGame->InitGame(wnd_width, wnd_height, wnd_x, wnd_y, pTitle);
pGame->On_WM_PAINT(0, 0);
while (!pGame->m_isQuit) {
Sleep(2000);
}
delete pGame;
pGame = nullptr;
return 0;
}
6.宏定义
宏定义头文件
#define BACK_WIDTH 600
#define BACK_HEIGHT 800
#define PLAYER_WIDTH 60
#define PLAYER_HEIGHT 60
#define GUNNER_WIDTH 6
#define GUNNER_HEIGHT 20
#define FOEBIG_WIDTH 150
#define FOEBIG_HEIGHT 100
#define FOEMID_WIDTH 80
#define FOEMID_HEIGHT 60
#define FOESMA_WIDTH 60
#define FOESMA_HEIGHT 40
#define BACK_MOVE_STEP 3
#define BACK_MOVE_TIMERID 1
#define BACK_MOVE_INTERVAL 80
#define PLAYER_MOVE_STEP 3
#define PLAYER_MOVE_TIMERID 2
#define PLAYER_MOVE_INTERVAL 20
#define GUNNER_MOVE_STEP 10
#define GUNNER_MOVE_TIMERID 3
#define GUNNER_MOVE_INTERVAL 50
#define CREAT_GUNNER_TIMERID 4
#define CREAT_GUNNER_INTERVAL 1000
#define CREAT_FEO_TIMERID 5
#define CREAT_FEO_INTERVAL 3000
#define FEO_MOVE_TIMERID 6
#define FEO_MOVE_INTERVAL 70
#define CHECK_HIT_TIMERID 7
#define CHECK_HIT_INTERVAL 5
#define FOE_DESTRY_TIMERID 8
#define FOE_DESTRY_INTERVAL 100
#define GUNNER_HURT 1
#define FOEBIG_BLOOD 5
#define FOEMID_BLOOD 3
#define FOESMA_BLOOD 1
#define FOEBIG_SCORE 5
#define FOEMID_SCORE 3
#define FOESMA_SCORE 1
#define FOEBIG_SHOWID_INIT 4
#define FOEMID_SHOWID_INIT 3
#define FOESMA_SHOWID_INIT 2
#define FOEBIG_MOVE_STEP 4
#define FOEMID_MOVE_STEP 7
#define FOESMA_MOVE_STEP 9
7.飞机大战主体(具体游戏类)
头文件
#pragma once
#include"../GameFrame/GameFrame.h"
#include"../back/Cback.h"
#include"../player/player.h"
#include"../config/config.h"
#include"../gunnerlist/CGunList.h"
#include"../foelist/CFoeList.h"
class CPlaneApp :public CGameFrame {
public:
int m_score;
IMAGE m_imgBoard;
CBack m_back;
CPlayer m_player;
CGunList m_gunLst;
CFoeList m_foeLst;
public:
CPlaneApp();
~CPlaneApp();
public:
virtual void Init();
virtual void Paint();
virtual void close();
virtual void AddMsg();
virtual void On_WM_KEYDOWN(BYTE key);
virtual void On_WM_TIMER(WPARAM, LPARAM);
virtual void ShowScore();
virtual void SetTimer();
virtual void KillTimer();
};
源文件
#include"PlaneApp.h"
#include "../foelist/CFoe.h"
#include"../foelist/CFoeBig.h"
#include"../foelist/CFoeMid.h"
#include"../foelist/CFoeSma.h"
CREATE_OBJECT(CPlaneApp)
WND_PARAMWIDTHWND_PARAMWIDTH(616,839,400,50,L"飞机大战")
CPlaneApp::CPlaneApp():m_score(0){}
CPlaneApp::~CPlaneApp(){}
void CPlaneApp::Init(){
m_back.InitBack();
m_player.InitPlayer();
SetTimer();//初始的时候,设定所有的定时器
::loadimage(&m_imgBoard, L"./res/cardboard.png", 100, 60);
}
void CPlaneApp::Paint(){
m_back.ShowBack();
m_player.ShowPlayer();
m_gunLst.ShowAllGun();
m_foeLst.ShowAllFoe();
ShowScore();
}
void CPlaneApp::close(){
KillTimer();
}
void CPlaneApp::AddMsg(){
ADD_MSG(WM_TIMER, EX_WINDOW, CPlaneApp);
ADD_MSG(WM_KEYDOWN,EX_KEY, CPlaneApp);
CGameFrame::AddMsg();
}
void CPlaneApp::On_WM_KEYDOWN(BYTE key){
//m_player.MovePlayer(key);
}
void CPlaneApp::ShowScore(){
//先显示分数板
::putimage(0, 0, &m_imgBoard);
//显示分数
WCHAR arr[5] = { 0 };
_itow_s(m_score, arr, 10);
wstring str = L"分数为: ";
str += arr;
::settextcolor(RGB(45, 87, 96));
::setbkmode(TRANSPARENT);
RECT rect = { 0,0,100,60 };
//显示文字到指定位置,设置,水平、垂直居中
::drawtext(str.c_str(), &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
void CPlaneApp::SetTimer(){
//设置定时器
::SetTimer(m_hWnd, BACK_MOVE_TIMERID/*定时器ID*/, BACK_MOVE_INTERVAL, nullptr);//windows API
::SetTimer(m_hWnd, PLAYER_MOVE_TIMERID/*定时器ID*/, PLAYER_MOVE_INTERVAL, nullptr);//windows API
::SetTimer(m_hWnd, GUNNER_MOVE_TIMERID/*定时器ID*/, GUNNER_MOVE_INTERVAL, nullptr);//windows API
::SetTimer(m_hWnd, CREAT_GUNNER_TIMERID/*定时器ID*/, CREAT_GUNNER_INTERVAL, nullptr);//windows API
::SetTimer(m_hWnd, CREAT_FEO_TIMERID/*定时器ID*/, CREAT_FEO_INTERVAL, nullptr);//windows API
::SetTimer(m_hWnd, FEO_MOVE_TIMERID/*定时器ID*/, FEO_MOVE_INTERVAL, nullptr);//windows API
::SetTimer(m_hWnd, CHECK_HIT_TIMERID/*定时器ID*/, CHECK_HIT_INTERVAL, nullptr);//windows API
::SetTimer(m_hWnd, FOE_DESTRY_TIMERID/*定时器ID*/, FOE_DESTRY_INTERVAL, nullptr);//windows API
}
void CPlaneApp::KillTimer(){
::KillTimer(m_hWnd, BACK_MOVE_TIMERID/*定时器ID*/);//windows API
::KillTimer(m_hWnd, PLAYER_MOVE_TIMERID/*定时器ID*/);//windows API
::KillTimer(m_hWnd, GUNNER_MOVE_TIMERID/*定时器ID*/);//windows API
::KillTimer(m_hWnd, CREAT_GUNNER_TIMERID/*定时器ID*/);//windows API
::KillTimer(m_hWnd, CREAT_FEO_TIMERID/*定时器ID*/);//windows API
::KillTimer(m_hWnd, FEO_MOVE_TIMERID/*定时器ID*/);//windows API
::KillTimer(m_hWnd, CHECK_HIT_TIMERID/*定时器ID*/);//windows API
::KillTimer(m_hWnd, FOE_DESTRY_TIMERID/*定时器ID*/);//windows API
}
void CPlaneApp::On_WM_TIMER(WPARAM w/*这里包含了定时器的ID*/, LPARAM l) {
switch (w) {
case BACK_MOVE_TIMERID: //如果背景移动的定时器触发了
{
m_back.MoveBack();
break;
}
case PLAYER_MOVE_TIMERID: //定时检测是否按下方向键
{
if (::GetAsyncKeyState(VK_UP)) {//如果方向键上按下了 返回为非零
m_player.MovePlayer(VK_UP);
}
if (::GetAsyncKeyState(VK_DOWN)) {//如果方向键上按下了 返回为非零
m_player.MovePlayer(VK_DOWN);
}
if (::GetAsyncKeyState(VK_RIGHT)) {//如果方向键上按下了 返回为非零
m_player.MovePlayer(VK_RIGHT);
}
if (::GetAsyncKeyState(VK_LEFT)) {//如果方向键上按下了 返回为非零
m_player.MovePlayer(VK_LEFT);
}
break;
}
case GUNNER_MOVE_TIMERID: {
m_gunLst.MoveAllGun();
break;
}
case CREAT_GUNNER_TIMERID: {
m_gunLst.gumlist.push_back(m_player.SendGunner());
break;
}
case CREAT_FEO_TIMERID: {
int n = CFoe::rd() % 11;
CFoe* PCFe = nullptr;
if (n >= 0 && n <= 5) {
PCFe = new CFoeBig;
}
else if (n >= 6 && n <= 8)
{
PCFe = new CFoeMid;
}
else if (n >= 9 && n <= 10)
{
PCFe = new CFoeSma;
}
PCFe->InitFoe();
m_foeLst.m_IsFoe.push_back(PCFe);
break;
}
case FEO_MOVE_TIMERID: {
m_foeLst.MoveAllFoe();
break;
}
case CHECK_HIT_TIMERID: {
bool isBoom = false;//是否爆炸,默认不爆炸
list<CFoe*>::iterator iteFoe = m_foeLst.m_IsFoe.begin();
while (iteFoe!=m_foeLst.m_IsFoe.end()) {
//1.是否碰撞玩家飞机
if ((*iteFoe)->IsHitPlayer(m_player)) {
//删除定时器
KillTimer();
::MessageBox(m_hWnd, L"游戏退出", L"提示", MB_OK);
//游戏退出
//投递一个消息,投递WM_CLOSE,最终回到回调函数处理
::PostMessage(m_hWnd, WM_CLOSE, 0, 0);
return;
}
//2.是否碰撞炮弹
list<CGunner*>::iterator iteGun = m_gunLst.gumlist.begin();
while (iteGun != m_gunLst.gumlist.end()) {
if (*iteFoe && *iteGun) {
if ((*iteFoe)->IsHitGun(*iteGun)) {
delete(*iteGun);
*iteGun = nullptr;
iteGun = m_gunLst.gumlist.erase(iteGun);//删除炮弹链表节点,自带++效果
//敌人飞机掉血,判断是否为0
if (((*iteFoe)->m_blood -= GUNNER_HURT) <= 0) {
//加分
if (typeid(**iteFoe) == typeid(CFoeBig)) {
m_score += FOEBIG_SCORE;
}
else if(typeid(**iteFoe) == typeid(CFoeMid)) {
m_score += FOEMID_SCORE;
}
else if (typeid(**iteFoe) == typeid(CFoeSma)) {
m_score += FOESMA_SCORE;
}
//飞机要爆炸
m_foeLst.m_IsFoeBoom.push_back(*iteFoe);//添加到爆炸链表
iteFoe = m_foeLst.m_IsFoe.erase(iteFoe);//删除正常敌人链表的节点
isBoom = true;
break;
}
continue;
}
iteGun++;
}
}
if (isBoom){
isBoom = false;
}
else {
iteFoe++;
}
}
break;
}
case FOE_DESTRY_TIMERID: {
list<CFoe*>::iterator ite = m_foeLst.m_IsFoeBoom.begin();
while (ite != m_foeLst.m_IsFoeBoom.end()) {
if (*ite) {
if(--(*ite)->m_showid < 0) {//飞机逐渐p
delete(*ite);
ite = m_foeLst.m_IsFoeBoom.erase(ite);
continue;
}
}
ite++;
}
}
}
}