c++基于游戏壳的飞机大战游戏----开发(第二部分)

news2025/1/19 14:38:28

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++;
		}
	}

	}
	

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/829018.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【汇总】解决Ajax请求后端接口,返回ModelAndView页面不跳转

【汇总】解决Ajax请求后端接口&#xff0c;返回ModelAndView不跳转 问题发现问题解决方法一&#xff1a;直接跳转到指定URL&#xff08;推荐&#xff09;方法二&#xff1a;将返回的html内容&#xff0c;插入到页面某个元素中方法三&#xff1a;操作文档流方法四&#xff1a;使…

【雕爷学编程】MicroPython动手做(28)——物联网之Yeelight 2

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

KubeSphere 3.4.0 发布:支持 K8s v1.26

2023 年 07 月 26 日&#xff0c;KubeSphere 开源社区激动地向大家宣布&#xff0c;KubeSphere 3.4.0 正式发布&#xff01; 让我们先简单回顾下之前三个大版本的主要变化&#xff1a; KubeSphere 3.1.0 新增了“边缘计算”、“计量计费” 等功能&#xff0c;将 Kubernetes 从…

【uniapp】【Vue3】 超简单全局自定义弹窗组件Modal

Element-Plus 自动引入&#xff0c;Icon图标不显示 //这样写是不会显示的 <el-icon size"20"><view /> </el-icon>// 应该这样写 <el-icon size"20"><i-ep-view/> </el-icon>// 或 <i-ep-view/>这个名字怎么去…

SpringBoot+ruoyi框架图片上传和文件下载

第一次接触ruoyi框架&#xff0c;碰到文件上传和下载问题&#xff0c;今天来总结一下。 使用若依框架文件上传下载首先配置文件路径要配好。 文件下载&#xff1a; application.yml若依配置 # 项目相关配置 ruoyi:# 名称name: RuoYi# 版本version: 3.6.0# 版权年份copyright…

《向量数据库指南》——向量数据库Milvus Cloud、Pinecone、Vespa、Weaviate、Vald、GSI 、 Qdrant选哪个?

1、Milvus Cloud(https://milvuscloud.com) Milvus是一个开源的向量数据库,支持高效的向量搜索和相似度匹配。它针对大规模向量数据集的性能进行了优化,并提供了Python、Java、Go和C++等多种语言的客户端接口。Milvus在图像、音频、文本和推荐等领域都有广泛的应用。 2…

Gorm 单表操作 查询数据

单表记录查询 //单表记录的查询&#xff0c;var s Studentdb.Debug().Take(&Student{})fmt.Println(s)[1.034ms] [rows:1] SELECT * FROM students LIMIT 1 {0 0 false <nil>} first就是按照主键排序&#xff0c;last就是按照主键倒排。 /…

了解垃圾回收算法

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ 垃圾回收&#xff08;Garbage Collect&#xff09;是Java语言中的一种自动内存管理机制&#xff0c;用于自动回收不再使用的对象所占用的内存空间。Java虚拟机会自动追踪和…

python中数据可视化

1.掷一个D6和一个D10 50000次的结果 die.py from random import randintclass Die:def __init__(self, num_sides6):self.num_sides num_sidesdef roll(self):return randint(1, self.num_sides) die_visual.py from die import Die from plotly.graph_objs import Bar, L…

宝塔Linux面板Java项目一键部署(springboot)

部署项目之前请安装相关软件: jdk1.8、redis、nginx 、mysql 等等(项目中用到的) 1. 网站 2. 创建项目文件夹 文件 - /www/wwwroot - 新建项目文件夹 - 存放jar文件 3. 上传jar文件 (直接拖进来) 4. 添加Java项目 5. jar包路径 - 项目端口, 提交(启动项目) 6. 成功运行 7. 浏览…

nodejs VM沙箱绕过

文章目录 nodejs vm沙箱绕过1.基本概念——什么是沙箱&#xff08;sandbox&#xff09;2.nodejs的作用域3.vm模块的运行原理4.沙箱绕过5.沙箱绕过的一些问题 nodejs vm沙箱绕过 1.基本概念——什么是沙箱&#xff08;sandbox&#xff09; 当我们运行一些可能会产生危害的程序…

2023 电赛 E 题 K210方案--K210实现矩形识别

相关库介绍 sensor&#xff08;摄像头&#xff09; sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.skip_frames(10) reset()&#xff1a;重置并初始化单目摄像头 set_pixformat()&#xff1a;设置摄像头输出格式&#xff0c…

云上 Index:看「简墨」如何为云原生打造全新索引

拓数派首款数据计算引擎 PieCloudDB 是一款全新的云原生虚拟数仓。为了提升用户使用体验&#xff0c;提高查询效率&#xff0c;在实现存算分离的同时&#xff0c;PieCloudDB 设计与打造了全新的存储引擎「简墨」等模块&#xff0c;并针对云场景和分析型场景设计了高效的「Data …

长相思追剧小游戏

看效果图 Vue长相思 刚学Vue&#xff0c;正好在追剧&#xff0c;看到这个小案例觉得挺好玩的&#xff0c;第一天学&#xff0c;代码太简陋了 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name&qu…

LLM大模型——langchain相关知识总结

目录 一、简介LangChain的主要价值支柱简单安装 二、 LangChain的主要模块1.Model I/Oprompt模版定义调用语言模型 2. 数据连接3. chains4. Agents5. MemoryCallbacks 三、其他记录多进程调用 主要参考以下开源文档 文档地址&#xff1a;https://python.langchain.com/en/lates…

无人机管控平台,推动电力巡检管理水平提升

各地区无人机作业水平和管理水平存在参差不齐&#xff0c;电力巡检管理要求与业务发展水平不匹配的问题。同时&#xff0c;巡检数据的存储和管理分散&#xff0c;缺乏有效的整合与共享手段&#xff0c;使得内外业脱节&#xff0c;没有形成统一应用和闭环管理。这就导致巡检数据…

【云原生】K8S二进制搭建上篇

目录 一、环境部署1.1操作系统初始化 二、部署etcd集群2.1 准备签发证书环境在 master01 节点上操作在 node01与02 节点上操作 三、部署docker引擎四、部署 Master 组件4.1在 master01 节点上操 五、部署Worker Node组件 一、环境部署 集群IP组件k8s集群master01192.168.243.1…

Vc - Qt - QPainter translate

QPainter的translate()函数是用来对绘制坐标系统进行平移操作的方法。它可以将绘制的原点&#xff08;坐标轴的起始点&#xff09;在水平和垂直方向上进行平移。以下是一个使用QPainter的translate()方法进行坐标平移的示例代码&#xff1a; QPainter painter(this);// 绘制一个…

Day12-1-Webpack前端工程化开发

Webpack前端工程化 1 案例-webpack打包js文件 1 在index.html中编写代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><me…

Vue3_03_拉开序幕的setup

1.理解&#xff1a;Vue3.0 中的一个新的配置项&#xff0c;值为一个函数。 2.setup是所有组合式 API 表演的舞台。 3.组件中所用到的&#xff1a;数据、方法等等&#xff0c;均要配置在setup中。 4.setup函数的两种返回值&#xff1a; 若返回一个对象&#xff0c;则对象中的…