欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

飞机大战游戏源码

程序员文章站 2022-06-21 10:46:41
...

大家好,我是业余写来玩玩的,写不好的地方不要取笑哦!

自定义头文件WinMain.h源码

#include <Windows.h>
#include<list>
#include<time.h>
#include<ctime>
#include "resource.h"
#include "resource1.h"
#include <gdiplus.h>
#include <mmsystem.h>
#pragma comment(lib,"gdiplus.lib")
#pragma comment(lib,"Msimg32.lib")
#pragma comment(lib,"Winmm.lib")
using namespace Gdiplus;
using namespace std;


#define CLIENTWIDTH 400
#define CLIENTHEIGHT 600
#define TIMERID_1 10			 //定时器ID
#define TIMERID_2 20			 //定时器ID
#define GAMEFRAME 180         //游戏帧
#define VE_NPCONE 1          //一号敌机速度
#define VE_NPCTWO 1          //二号敌机速度
#define VE_NPCTRE 1          //三号敌机速度
#define MENU_ITEM_WIDTH 120	 //菜单宽度
#define MENU_ITEM_HEIGHT 40  //菜单高度
#define RATIO 0.1			 //碰撞矩形系数

enum GAMESCENE//游戏场景
{
	SCENE_START,
	SCENE_PLAY,
	SCENE_OVER
};

enum ENEMYTYPE//敌机类型
{
	NPCONE,
	NPCTWO,
	NPCTRE,
	SUPNPCONE
};

enum BULLETTYPE//子弹类型
{
	BULLETONE,
	BULLETTWO
};

enum MENUTYPE
{
	SETFOCUS,
	KILLFOCUS
};

enum AWARD
{
	AWARDONE,
	AWARDTWO
};

HBITMAP hBitmap_start, hBitmap_play, hBitmap_over;
HBITMAP hBitmap_npc1, hBitmap_npc2, hBitmap_npc3, hBitmap_player, hBitmap_bullet1, hBitmap_bullet2, hBitmap_supnpc1, hBitmap_award1, hBitmap_award2, hBitmap_bomb;
GAMESCENE curScene;//游戏场景
Point point;//记录玩家飞机轨迹
Rect PlayerCollisionRect;

int player_xPos, player_yPos;//玩家位置
int collision_maxY, collision_minY, collision_maxX, collision_minX;//玩家碰撞检测
int index;//玩家爆炸动画
bool death;//玩家死亡
bool isdeath;//玩家被撞击
int flag, flag_bullet;//指向生成敌机类型
bool upgrade;//子弹升级
int upgrade_num;//二级子弹数量
bool Bomb;//炸弹
int Bomb_num;//炸弹数量
clock_t tmp;



void GameInit();//初始化
void LoadImg();//加载位图
void GamePaint(HDC hdc);//游戏界面重绘
void ReleaseRes();//释放资源
void DelImage();//删除位图资源
void MouseClick(int x,int y,HWND hwnd);//鼠标点击事件
void DrawStartOver(HDC hdc, HBITMAP hBmp);//重绘开始结束场景
void DrawPlay(HDC hdc);//重绘玩游戏场景
void GameLogic();//游戏逻辑帧
void DrawMenu(HDC hdc, RectF rect, MENUTYPE type, PTCHAR text);//输出菜单
void CreateNpc(HBITMAP hbmp);//生成敌机
void CreateBullet(HBITMAP hbmp);//生成敌机
void IsHit();//子弹是否击中敌机
void IsFocus(int x, int y);//是否获得焦点
void CreateAward(HBITMAP hbmp);//生成奖励
bool isCollsionWithRect(Rect rect1, Rect rect2);//碰撞检测
void CreateBomb(HBITMAP hbmp);//生成炸弹
void BigBang();//飞机爆炸声
void LoadSound();//加载音频
void CloseSound();//关闭音频
void Update(HDC hdc, HDC hdcMem, HDC hdcMemTemp, BLENDFUNCTION dc_bf);//游戏画面帧

class EnemyPlane //敌机类
{
private:

public:

	double PosX;
	double PosY;
	int Blood;
	int collision_maxY, collision_minY, collision_maxX, collision_minX;
	int index;
	bool isdeath;
	bool death;
	Rect ColRect;
	HBITMAP Type;
	ENEMYTYPE enemyType;
	EnemyPlane(HBITMAP h)
	{
		Type = h;
		if (h == hBitmap_npc1)
		{
			enemyType = NPCONE;
			Blood = 2;
			index = 0;
			isdeath = death = false;
		}
		if (h == hBitmap_npc2)
		{
			enemyType = NPCTWO;
			Blood = 6;
			index = 0;
			isdeath = death = false;
		}
		if (h == hBitmap_npc3)
		{
			enemyType = NPCTRE;
			PosY = -245;
			Blood = 20;
			index = 0;
			isdeath = death = false;
		}
		if (h == hBitmap_supnpc1)
		{
			enemyType = SUPNPCONE;
			Blood = 3;
			index = 0;
			isdeath = death = false;
		}
	}

	void CollsionRect(HBITMAP Type, Rect &ColRect)//碰撞矩形
	{
		BITMAP bmp;
		GetObject(Type, sizeof(BITMAP), &bmp);
		ColRect.X = PosX + bmp.bmWidth/4*RATIO;
		ColRect.Y = PosY + bmp.bmHeight*RATIO;
		ColRect.Width = bmp.bmWidth/4 - bmp.bmWidth/4*RATIO*2;
		ColRect.Height = bmp.bmHeight - bmp.bmHeight*RATIO*2;
	}

	double Vel()//返回敌机速度
	{
		switch (enemyType)
		{
		case NPCONE:
			return 4;
			break;
		case NPCTWO:
			return 1;
			break;
		case NPCTRE:
			return 0.5;
			break;
		case SUPNPCONE:
			return 2;
			break;
		default:
			break;
		}
	}
};
list <EnemyPlane> npcList;//储存敌机实例链表
list <EnemyPlane>::iterator iter_npc;//迭代器访问链表

class Bullet //子弹类
{
private:

public:
	int PosX;
	int PosY;
	int velocity = 20;
	int tmp;//子弹碰撞点偏移距离
	Rect ColRect;
	HBITMAP Type;
	BULLETTYPE bulletType;
	Bullet(HBITMAP h)
	{
		Type = h;
		if (h == hBitmap_bullet1)
		{
			bulletType = BULLETONE;
		}
		if (h == hBitmap_bullet2)
		{
			bulletType = BULLETTWO;
		}
	}

	void CollsionRect(HBITMAP Type, Rect &ColRect)
	{
		BITMAP bmp;
		GetObject(Type, sizeof(BITMAP), &bmp);
		ColRect.X = PosX + bmp.bmWidth*RATIO;
		ColRect.Y = PosY + bmp.bmHeight*RATIO;
		ColRect.Width = bmp.bmWidth - bmp.bmWidth*RATIO*2;
		ColRect.Height = bmp.bmHeight - bmp.bmHeight*RATIO*2;
	}
};
list <Bullet> bulletList;//储存子弹实例链表
list <Bullet>::iterator iter_bullet;

class Menu//菜单类
{
public:
	RectF rect;
	MENUTYPE menuType = KILLFOCUS;
	PTCHAR menuText;
	Menu(int x, int y, PTCHAR text)
	{
		rect.X = x;
		rect.Y = y;
		rect.Width = MENU_ITEM_WIDTH;
		rect.Height = MENU_ITEM_HEIGHT;
		menuText = text;
	};
private:

};
list <Menu> menuList_Start;
list <Menu> menuList_End;
list <Menu>::iterator iter_menu;

class Award//奖励类
{
public:
	double PosX;
	double PosY;
	double velocity = 0.8;
	Rect ColRect;
	HBITMAP Type;
	AWARD awardType;
	Award(HBITMAP h)
	{
		Type = h;
		if (h == hBitmap_award1)
		{
			awardType = AWARDONE;
		}
		if (h == hBitmap_award2)
		{
			awardType = AWARDTWO;
		}
	}

	void CollsionRect(HBITMAP Type, Rect &ColRect)
	{
		BITMAP bmp;
		GetObject(Type, sizeof(BITMAP), &bmp);
		ColRect.X = PosX + bmp.bmWidth*RATIO;
		ColRect.Y = PosY + bmp.bmHeight*RATIO;
		ColRect.Width = bmp.bmWidth - bmp.bmWidth*RATIO*2;
		ColRect.Height = bmp.bmHeight - bmp.bmHeight*RATIO*2;
	}
private:

};
list <Award> awardList;//储存奖励实例链表
list <Award>::iterator iter_award;

class Bomb_//炸弹类
{
public:
	int PosX;
	int PosY;
	HBITMAP Type;

	Bomb_(HBITMAP h)
	{
		PosX = 0;
		PosY = CLIENTHEIGHT - 36;
		Type = h;
	}
private:

};
list <Bomb_> bombList;//储存炸弹实例链表
list <Bomb_>::iterator iter_bomb;

主程序源文件WinMain.cpp源码

#include"WinMain.h"


LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);//第1个参数,是消息要传递的窗口,参数2是消息的id(也就是这是个什么样的消息,比如鼠标左键按下对应的消息是WM_LBUTTONDOWN),参数3和参数4是消息的具体内容

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szWndClassName[] = TEXT("hellowin");
	HWND hwnd;//窗口句柄
	MSG msg;//消息类型
	WNDCLASS wndclass;//窗口类

	//GDI+初始化
	GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR           gdiplusToken;
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

	wndclass.style = CS_HREDRAW | CS_VREDRAW;//窗口的风格,这里两个参数的意思是水平和垂直方向改变时重绘窗口
	wndclass.lpfnWndProc = WndProc;//窗口过程
	wndclass.cbClsExtra = 0;//额外分配的内存
	wndclass.cbWndExtra = 0;//额外分配的内存
	wndclass.hInstance = hInstance;//实例句柄
	wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));//设置图标,使用自定义图标第一个参数为实例句柄,第二个参数调用MAKEINTRESOURCE(图标ID)
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);//设置鼠标样式
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//设置背景
	wndclass.lpszMenuName = NULL;//设置菜单
	wndclass.lpszClassName = szWndClassName;//窗口类名

	if (!RegisterClass(&wndclass))//注册窗口类
	{
		MessageBox(NULL, L"注册失败", L"错误", MB_ICONERROR);
		return 0;
	}

	int cxScreen = GetSystemMetrics(SM_CXSCREEN);//获取屏幕宽度
	int cyScreen = GetSystemMetrics(SM_CYSCREEN);//获取屏幕高度
	RECT rc;//定义工作区域矩形
	rc.left = (cxScreen - CLIENTWIDTH) / 2;//工作区左上点x坐标
	rc.top = (cyScreen - CLIENTHEIGHT) / 2;//工作区左上点y坐标
	rc.right = rc.left + CLIENTWIDTH;//工作区右下点x坐标
	rc.bottom = rc.top + CLIENTHEIGHT;//工作区右下点y坐标
	//执行完此函数后rc返回的是整个窗口矩形
	AdjustWindowRect(&rc, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, FALSE);

	hwnd = CreateWindow(
		szWndClassName,//窗口类名,指定基于哪个窗口类
		L"飞机大战",//窗口标题
		WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,//窗口样式
		rc.left,//设置窗口左上相对屏幕的x坐标
		rc.top,//设置窗口左上相对屏幕的y坐标
		rc.right - rc.left,//设置窗口大小
		rc.bottom - rc.top,//设置窗口大小
		NULL,//父窗口句柄
		NULL,//菜单句柄
		hInstance,//实例句柄
		NULL//分配的额外参数
	);

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))//消息队列
	{
		TranslateMessage(&msg);//转向消息
		DispatchMessage(&msg);//传递消息
	}

	GdiplusShutdown(gdiplusToken);//关闭GDI+

	return msg.wParam;//此语句将发送WM_QUIT消息,接收此消息窗口关闭
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)//窗口过程函数
{
	HDC hdc;
	PAINTSTRUCT ps;

	switch (message)
	{
	case WM_CREATE://窗口加载时执行此case
		GameInit();
		return 0;
	case WM_LBUTTONDOWN:
		point.X = LOWORD(lParam);
		point.Y = HIWORD(lParam);
		MouseClick(point.X, point.Y, hwnd);
		return 0;
	case WM_MOUSEMOVE:
		if (curScene == SCENE_START)
		{
			IsFocus(LOWORD(lParam), HIWORD(lParam));
		}
		else if (curScene == SCENE_PLAY)
		{
			if (WM_LBUTTONDOWN&wParam)
			{
				int dx = LOWORD(lParam) - point.X;
				int dy = HIWORD(lParam) - point.Y;
				player_xPos += dx;
				player_yPos += dy;
				point.X = LOWORD(lParam);
				point.Y = HIWORD(lParam);

				PlayerCollisionRect.X = player_xPos + 20;
				PlayerCollisionRect.Width = 60;
				PlayerCollisionRect.Y = player_yPos + 20;
				PlayerCollisionRect.Height = 80;
			}
		}
		else if (curScene == SCENE_OVER)
		{
			IsFocus(LOWORD(lParam), HIWORD(lParam));
		}
		return 0;
	case WM_TIMER://定时器周期事件
		switch (wParam)
		{
		case TIMERID_1:
			GameLogic();
			InvalidateRect(hwnd, NULL, FALSE);//-------------------使得界面重绘-------------------
			break;
		case TIMERID_2:
			if (curScene == SCENE_PLAY)
			{
				flag++;
				if (flag % 6 == 0)
				{
					CreateNpc(hBitmap_npc2);
				}
				else if (flag % 15 == 0)
				{
					CreateNpc(hBitmap_npc3);
					mciSendString(L"play big_spaceship_flying from 0", NULL, 0, NULL);
				}
				else if (flag % 11 == 0)
				{
					CreateAward(hBitmap_award2);
				}
				else if (flag % 23 == 0 && Bomb == false)
				{
					CreateAward(hBitmap_award1);
				}
				else
				{
					CreateNpc(hBitmap_npc1);
				}
				if (clock() - tmp > 3000)//3秒生成一架supnpc1
				{
					tmp = clock();
					CreateNpc(hBitmap_supnpc1);
				}
			}
			if (flag == 500)
			{
				flag = 0;
			}
			break;
		default:
			break;
		}
		return 0;
	case WM_PAINT://窗口必须重绘时执行此case
		hdc = BeginPaint(hwnd, &ps);//返回设备描述表句柄
		GamePaint(hdc);
		EndPaint(hwnd, &ps);
		return 0;
	case WM_ERASEBKGND:

		return 0;
	case WM_SETFOCUS://程序获得焦点
		SetTimer(hwnd, TIMERID_1, 1000 / GAMEFRAME, NULL);//设置定时器,游戏主要逻辑执行间隔
		SetTimer(hwnd, TIMERID_2, 1000, NULL);//设置定时器,敌机生成间隔	
		return 0;
	case WM_KILLFOCUS://程序失去焦点
		KillTimer(hwnd, TIMERID_1);//关闭定时器
		KillTimer(hwnd, TIMERID_2);//关闭定时器
		return 0;
	case WM_SYSCOMMAND:
		if (wParam == SC_CLOSE) //劫持关闭按钮消息
		{
			if (IDCANCEL == MessageBox(hwnd, L"你确定要退出吗?",
				L"", MB_OKCANCEL | MB_ICONQUESTION))
			{
				return 0;
			}
		}
		break;
	case WM_DESTROY://窗口关闭时执行此case
		ReleaseRes();
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

void GameInit()
{
	srand(time(NULL));
	LoadImg();
	LoadSound();
	curScene = SCENE_START;
	Menu menu_Start = Menu((CLIENTWIDTH - MENU_ITEM_WIDTH) / 2, (CLIENTHEIGHT - MENU_ITEM_HEIGHT) / 2, L"开始游戏");
	menuList_Start.push_front(menu_Start);
	Menu menu_Exit = Menu((CLIENTWIDTH - MENU_ITEM_WIDTH) / 2, (CLIENTHEIGHT - MENU_ITEM_HEIGHT) / 2 + 40, L"退出游戏");
	menuList_Start.push_front(menu_Exit);
	Menu menu_RePlay = Menu((CLIENTWIDTH - MENU_ITEM_WIDTH) / 2, (CLIENTHEIGHT - MENU_ITEM_HEIGHT) / 2, L"重新开始");
	menuList_End.push_front(menu_RePlay);
	Menu menu_End = Menu((CLIENTWIDTH - MENU_ITEM_WIDTH) / 2, (CLIENTHEIGHT - MENU_ITEM_HEIGHT) / 2 + 40, L"结束游戏");
	menuList_End.push_front(menu_End);

	player_xPos = 150;
	player_yPos = 400;
	death = false;
	upgrade = false;
	upgrade_num = 0;
	Bomb = false;
	Bomb_num = 0;
	flag = 0;
	index = 0;
}

void LoadImg()
{
	//Bitmap* pBmp = Bitmap::FromResource(GetModuleHandle(NULL), (const WCHAR*)MAKEINTRESOURCE(IDB_BITMAP1));

	Bitmap* pBmp = Bitmap::FromFile(L".\\image\\img\\first.png");
	pBmp->GetHBITMAP(NULL, &hBitmap_start);
	pBmp = Bitmap::FromFile(L".\\image\\img\\back.png");
	pBmp->GetHBITMAP(NULL, &hBitmap_play);
	pBmp = Bitmap::FromFile(L".\\image\\img\\over.png");
	pBmp->GetHBITMAP(NULL, &hBitmap_over);
	pBmp = Bitmap::FromFile(L".\\image\\img\\npc1.png");
	pBmp->GetHBITMAP(NULL, &hBitmap_npc1);
	pBmp = Bitmap::FromFile(L".\\image\\img\\npc2.png");
	pBmp->GetHBITMAP(NULL, &hBitmap_npc2);
	pBmp = Bitmap::FromFile(L".\\image\\img\\npc3.png");
	pBmp->GetHBITMAP(NULL, &hBitmap_npc3);
	pBmp = Bitmap::FromFile(L".\\image\\img\\player.png");
	pBmp->GetHBITMAP(NULL, &hBitmap_player);
	pBmp = Bitmap::FromFile(L".\\image\\img\\bullet1.png");
	pBmp->GetHBITMAP(NULL, &hBitmap_bullet1);
	pBmp = Bitmap::FromFile(L".\\image\\img\\bullet2.png");
	pBmp->GetHBITMAP(NULL, &hBitmap_bullet2);
	pBmp = Bitmap::FromFile(L".\\image\\img\\npc1.png");
	pBmp->GetHBITMAP(NULL, &hBitmap_supnpc1);
	pBmp = Bitmap::FromFile(L".\\image\\img\\award1.png");
	pBmp->GetHBITMAP(NULL, &hBitmap_award1);
	pBmp = Bitmap::FromFile(L".\\image\\img\\award2.png");
	pBmp->GetHBITMAP(NULL, &hBitmap_award2);
	pBmp = Bitmap::FromFile(L".\\image\\img\\bomb.png");
	pBmp->GetHBITMAP(NULL, &hBitmap_bomb);
	delete pBmp;
	pBmp = NULL;

	//hBitmap = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP1));
}

void LoadSound()
{
	mciSendString(L"open .\\image\\sound\\backmusic.wav alias backmusic", NULL, 0, NULL);
	mciSendString(L"open .\\image\\sound\\get_double_laser.wav alias get_double_laser", NULL, 0, NULL);
	mciSendString(L"open .\\image\\sound\\get_bomb.wav alias get_bomb", NULL, 0, NULL);
	mciSendString(L"open .\\image\\sound\\use_bomb.wav alias use_bomb", NULL, 0, NULL);
	mciSendString(L"open .\\image\\sound\\enemy1_down.wav alias enemy1_down", NULL, 0, NULL);
	mciSendString(L"open .\\image\\sound\\enemy2_down.wav alias enemy2_down", NULL, 0, NULL);
	mciSendString(L"open .\\image\\sound\\enemy3_down.wav alias enemy3_down", NULL, 0, NULL);
	mciSendString(L"open .\\image\\sound\\game_over.wav alias game_over", NULL, 0, NULL);
	mciSendString(L"open .\\image\\sound\\big_spaceship_flying.wav alias big_spaceship_flying", NULL, 0, NULL);
	mciSendString(L"open .\\image\\sound\\bullet.wav alias bulletmusic", NULL, 0, NULL);
}

void GamePaint(HDC hdc)
{
	switch (curScene)
	{
	case SCENE_START:
		DrawStartOver(hdc, hBitmap_start);
		break;
	case SCENE_PLAY:
		DrawPlay(hdc);
		break;
	case SCENE_OVER:
		DrawStartOver(hdc, hBitmap_over);
		break;
	default:
		break;
	}
}

void DrawStartOver(HDC hdc, HBITMAP h)
{
	//双缓冲贴图会增加几个步骤
	//1.1、创建与设备DC兼容的内存DC
	HDC hdcMem = CreateCompatibleDC(hdc);
	//1.1、创建与设备DC兼容的内存DC并关联画布
	HBITMAP hBmp = CreateCompatibleBitmap(hdc, CLIENTWIDTH, CLIENTHEIGHT);
	SelectObject(hdcMem, hBmp);
	//1.2、创建与DC兼容的临时内存DC
	HDC hdcMemTemp = CreateCompatibleDC(hdc);
	//2、将位图对象选进临时内存DC中
	SelectObject(hdcMemTemp, h);
	//3.1、将临时内存中的位图贴到内存上
	BitBlt(hdcMem, 0, 0, CLIENTWIDTH, CLIENTHEIGHT, hdcMemTemp, 0, 0, SRCCOPY);

	switch (curScene)
	{
	case SCENE_START:
		for (iter_menu = menuList_Start.begin(); iter_menu != menuList_Start.end(); iter_menu++)
		{
			DrawMenu(hdcMem, iter_menu->rect, iter_menu->menuType, iter_menu->menuText);//画菜单
		}
		break;
	case SCENE_PLAY:
		break;
	case SCENE_OVER:
		for (iter_menu = menuList_End.begin();iter_menu != menuList_End.end();iter_menu++)
		{
			DrawMenu(hdcMem, iter_menu->rect, iter_menu->menuType, iter_menu->menuText);//画菜单
		}
		break;
	default:
		break;
	}

	//3.2、将内存中的位图贴到屏幕上
	BitBlt(hdc, 0, 0, CLIENTWIDTH, CLIENTHEIGHT, hdcMem, 0, 0, SRCCOPY);
	//4、释放内存DC
	DeleteObject(hBmp);//删除位图对象,即释放资源。
	DeleteDC(hdcMemTemp);
	DeleteDC(hdcMem);
	//5、删除位图对象,即释放资源。放在程序结尾,关闭gdi+前
}

void Update(HDC hdc, HDC hdcMem, HDC hdcMemTemp, BLENDFUNCTION dc_bf)
{
	for (iter_npc = npcList.begin(); iter_npc != npcList.end(); iter_npc++)
	{
		////2、将位图对象选进临时内存DC中
		SelectObject(hdcMemTemp, iter_npc->Type);
		switch (iter_npc->enemyType)
		{
		case NPCONE:
			////3.1、将临时内存中的位图贴到内存上
			AlphaBlend(hdcMem, iter_npc->PosX, iter_npc->PosY, 50, 40, hdcMemTemp, iter_npc->index * 50, 0, 50, 40, dc_bf);
			break;
		case NPCTWO:
			AlphaBlend(hdcMem, iter_npc->PosX, iter_npc->PosY, 75, 95, hdcMemTemp, iter_npc->index * 75, 0, 75, 95, dc_bf);
			break;
		case NPCTRE:
			AlphaBlend(hdcMem, iter_npc->PosX, iter_npc->PosY, 170, 245, hdcMemTemp, iter_npc->index * 170, 0, 170, 245, dc_bf);
			break;
		case SUPNPCONE:
			AlphaBlend(hdcMem, iter_npc->PosX, iter_npc->PosY, 50, 40, hdcMemTemp, iter_npc->index * 50, 0, 50, 40, dc_bf);
			break;
		default:
			break;
		}
	}

	SelectObject(hdcMemTemp, hBitmap_player);
	AlphaBlend(hdcMem, player_xPos, player_yPos, 100, 120, hdcMemTemp, index * 100, 0, 100, 120, dc_bf);

	for (iter_bullet = bulletList.begin(); iter_bullet != bulletList.end(); iter_bullet++)
	{
		SelectObject(hdcMemTemp, iter_bullet->Type);
		switch (iter_bullet->bulletType)
		{
		case BULLETONE:
			AlphaBlend(hdcMem, iter_bullet->PosX, iter_bullet->PosY, 6, 14, hdcMemTemp, 0, 0, 6, 14, dc_bf);
			break;
		case BULLETTWO:
			AlphaBlend(hdcMem, iter_bullet->PosX, iter_bullet->PosY, 24, 14, hdcMemTemp, 0, 0, 24, 14, dc_bf);
			break;
		default:
			break;
		}
	}

	for (iter_award = awardList.begin(); iter_award != awardList.end(); iter_award++)
	{
		SelectObject(hdcMemTemp, iter_award->Type);
		AlphaBlend(hdcMem, iter_award->PosX, iter_award->PosY, 65, 90, hdcMemTemp, 0, 0, 65, 90, dc_bf);
	}

	for (iter_bomb = bombList.begin(); iter_bomb != bombList.end(); iter_bomb++)
	{
		SelectObject(hdcMemTemp, iter_bomb->Type);
		AlphaBlend(hdcMem, iter_bomb->PosX, iter_bomb->PosY, 42, 36, hdcMemTemp, 0, 0, 42, 36, dc_bf);
	}

	//3.2、将内存中的位图贴到屏幕上
	BitBlt(hdc, 0, 0, CLIENTWIDTH, CLIENTHEIGHT, hdcMem, 0, 0, SRCCOPY);
}

/*1.只在WM_ERASEBKGND消息里处理画图部分, 不要在wm_pain中, 窗口刷新快点
2.用双缓冲, 且内存DC不要释放, 下次接着用, 真没办法再重建立内存DC
3.改变画图策略, 不要什么都在画图部分实现.*/

void DrawPlay(HDC hdc)
{
	//双缓冲贴图会增加几个步骤
	//1.1、创建与设备DC兼容的内存DC
	HDC hdcMem = CreateCompatibleDC(hdc);
	//1.1、创建与设备DC兼容的内存DC并关联画布
	HBITMAP hBmp = CreateCompatibleBitmap(hdc, CLIENTWIDTH, CLIENTHEIGHT);
	SelectObject(hdcMem, hBmp);
	//1.2、创建与DC兼容的临时内存DC
	HDC hdcMemTemp = CreateCompatibleDC(hdc);
	//2、将位图对象选进临时内存DC中
	SelectObject(hdcMemTemp, hBitmap_play);
	//3.1、将临时内存中的位图贴到内存上
	BitBlt(hdcMem, 0, 0, CLIENTWIDTH, CLIENTHEIGHT, hdcMemTemp, 0, 0, SRCCOPY);

	//此方法贴png透明度图片
	BLENDFUNCTION dc_bf = { AC_SRC_OVER ,0,250,AC_SRC_ALPHA };
	//dc_bf.BlendOp = AC_SRC_OVER;
	//dc_bf.BlendFlags = 0;
	//dc_bf.SourceConstantAlpha = 250; //0全透明,255不透明
	//dc_bf.AlphaFormat = AC_SRC_ALPHA;

	//Update(hdc, hdcMem, hdcMemTemp,dc_bf);
	for (iter_npc = npcList.begin(); iter_npc != npcList.end(); iter_npc++)
	{
		////2、将位图对象选进临时内存DC中
		SelectObject(hdcMemTemp, iter_npc->Type);
		switch (iter_npc->enemyType)
		{
		case NPCONE:
			////3.1、将临时内存中的位图贴到内存上
			AlphaBlend(hdcMem, iter_npc->PosX, iter_npc->PosY, 50, 40, hdcMemTemp, iter_npc->index * 50, 0, 50, 40, dc_bf);
			break;
		case NPCTWO:
			AlphaBlend(hdcMem, iter_npc->PosX, iter_npc->PosY, 75, 95, hdcMemTemp, iter_npc->index * 75, 0, 75, 95, dc_bf);
			break;
		case NPCTRE:
			AlphaBlend(hdcMem, iter_npc->PosX, iter_npc->PosY, 170, 245, hdcMemTemp, iter_npc->index * 170, 0, 170, 245, dc_bf);
			break;
		case SUPNPCONE:
			AlphaBlend(hdcMem, iter_npc->PosX, iter_npc->PosY, 50, 40, hdcMemTemp, iter_npc->index * 50, 0, 50, 40, dc_bf);
			break;
		default:
			break;
		}
	}

	SelectObject(hdcMemTemp, hBitmap_player);
	AlphaBlend(hdcMem, player_xPos, player_yPos, 100, 120, hdcMemTemp, index * 100, 0, 100, 120, dc_bf);

	for (iter_bullet = bulletList.begin(); iter_bullet != bulletList.end(); iter_bullet++)
	{
		SelectObject(hdcMemTemp, iter_bullet->Type);
		switch (iter_bullet->bulletType)
		{
		case BULLETONE:
			AlphaBlend(hdcMem, iter_bullet->PosX, iter_bullet->PosY, 6, 14, hdcMemTemp, 0, 0, 6, 14, dc_bf);
			break;
		case BULLETTWO:
			AlphaBlend(hdcMem, iter_bullet->PosX, iter_bullet->PosY, 24, 14, hdcMemTemp, 0, 0, 24, 14, dc_bf);
			break;
		default:
			break;
		}
	}

	for (iter_award = awardList.begin(); iter_award != awardList.end(); iter_award++)
	{
		SelectObject(hdcMemTemp, iter_award->Type);
		AlphaBlend(hdcMem, iter_award->PosX, iter_award->PosY, 65, 90, hdcMemTemp, 0, 0, 65, 90, dc_bf);
	}

	for (iter_bomb = bombList.begin(); iter_bomb != bombList.end(); iter_bomb++)
	{
		SelectObject(hdcMemTemp, iter_bomb->Type);
		AlphaBlend(hdcMem, iter_bomb->PosX, iter_bomb->PosY, 42, 36, hdcMemTemp, 0, 0, 42, 36, dc_bf);
	}
	//3.2、将内存中的位图贴到屏幕上
	BitBlt(hdc, 0, 0, CLIENTWIDTH, CLIENTHEIGHT, hdcMem, 0, 0, SRCCOPY);
	//4、释放内存DC
	DeleteObject(hBmp);//删除位图对象,即释放资源。
	DeleteDC(hdcMemTemp);
	DeleteDC(hdcMem);
	//5、删除位图对象,即释放资源。放在程序结尾,关闭gdi+前
}

void DrawMenu(HDC hdc, RectF rect, MENUTYPE type, PTCHAR text)
{
	Color fontColor;
	switch (type)
	{
	case SETFOCUS:
		fontColor = Color::Red;
		break;
	case KILLFOCUS:
		fontColor = Color::White;
	default:
		break;
	}
	Graphics graph(hdc);
	FontFamily fontFamily(L"黑体");
	Font font(&fontFamily, 17, FontStyleBold, UnitPoint);
	StringFormat format;
	format.SetAlignment(StringAlignmentCenter);
	format.SetLineAlignment(StringAlignmentCenter);
	SolidBrush brush(fontColor);
	graph.SetTextRenderingHint(TextRenderingHintAntiAlias);
	graph.DrawString(text, (INT)wcslen(text), &font, rect, &format, &brush);
	graph.ReleaseHDC(hdc);
}

void CreateNpc(HBITMAP hbmp)
{
	BITMAP bmp;
	GetObject(hbmp, sizeof(BITMAP), &bmp);

	EnemyPlane npc = EnemyPlane(hbmp);
	npc.PosX = rand() % (CLIENTWIDTH - bmp.bmWidth / 4);
	npcList.push_front(npc);
}

void CreateBullet(HBITMAP hbmp)
{
	BITMAP bmp;
	GetObject(hbmp, sizeof(BITMAP), &bmp);

	Bullet bullet = Bullet(hbmp);
	bullet.PosX = player_xPos + ((100 - bmp.bmWidth) / 2);
	bullet.PosY = player_yPos - bmp.bmHeight;
	bulletList.push_front(bullet);
	mciSendString(L"play bulletmusic from 0", NULL, 0, NULL);
}

void CreateAward(HBITMAP hbmp)
{
	BITMAP bmp;
	GetObject(hbmp, sizeof(BITMAP), &bmp);

	Award award = Award(hbmp);
	award.PosX = rand() % (CLIENTWIDTH - bmp.bmWidth);
	awardList.push_front(award);
}

void CreateBomb(HBITMAP hbmp)
{
	Bomb_ bomb = Bomb_(hbmp);
	bombList.push_front(bomb);
}

void IsHit()
{
	for (iter_npc = npcList.begin();iter_npc != npcList.end();iter_npc++)
	{
		for (iter_bullet = bulletList.begin();iter_bullet != bulletList.end();)
		{
			if (isCollsionWithRect(iter_npc->ColRect, iter_bullet->ColRect))
			{
				iter_npc->Blood--;
				iter_bullet = bulletList.erase(iter_bullet);
				if (iter_npc->Blood <= 0)
				{
					iter_npc->isdeath = true;
					mciSendString(L"play enemy3_down from 0", NULL, 0, NULL);
				}
			}
			else
			{
				iter_bullet++;
			}
		}
		if (isCollsionWithRect(iter_npc->ColRect, PlayerCollisionRect))
		{
			isdeath = true;
			mciSendString(L"play game_over from 0", NULL, 0, NULL);
		}
	}
	for (iter_award = awardList.begin();iter_award != awardList.end();)
	{
		iter_award->CollsionRect(hBitmap_award1, iter_award->ColRect);

		if (iter_award->PosY >= CLIENTHEIGHT)
		{
			iter_award = awardList.erase(iter_award);
		}
		else if (upgrade == true && iter_award->awardType == AWARDTWO)
		{
			iter_award = awardList.erase(iter_award);
		}
		else if (Bomb == true && iter_award->awardType == AWARDONE)
		{
			iter_award = awardList.erase(iter_award);
		}
		else if (isCollsionWithRect(iter_award->ColRect, PlayerCollisionRect))
		{
			switch (iter_award->awardType)
			{
			case AWARDONE:
				mciSendString(L"play get_bomb from 0", NULL, 0, NULL);
				Bomb = true;
				Bomb_num++;
				iter_award++;
				break;
			case AWARDTWO:
				mciSendString(L"play get_double_laser from 0", NULL, 0, NULL);
				upgrade = true;
				iter_award++;
				break;
			default:
				break;
			}
		}
		else
		{
			iter_award->PosY += iter_award->velocity;
			iter_award++;
		}
	}
}

bool isCollsionWithRect(Rect rect1, Rect rect2)
{
	if (rect1.X >= rect2.X && rect1.X >= rect2.X + rect2.Width) {
		return FALSE;
	}
	else if (rect1.X <= rect2.X && rect1.X + rect1.Width <= rect2.X) {
		return FALSE;
	}
	else if (rect1.Y >= rect2.Y && rect1.Y >= rect2.Y + rect2.Height) {
		return FALSE;
	}
	else if (rect1.Y <= rect2.Y && rect1.Y + rect1.Height <= rect2.Y) {
		return FALSE;
	}
	return TRUE;
}

void GameLogic()
{
	if (curScene == SCENE_PLAY)
	{
		flag_bullet++;
		if (flag_bullet == 8)
		{
			flag_bullet = 0;
			if (upgrade)
			{
				upgrade_num++;
				CreateBullet(hBitmap_bullet2);
				if (upgrade_num == 50)
				{
					upgrade_num = 0;
					upgrade = false;
				}
			}
			else
			{
				CreateBullet(hBitmap_bullet1);
			}
			if (Bomb)
			{
				CreateBomb(hBitmap_bomb);
			}
		}

		for (iter_npc = npcList.begin();iter_npc != npcList.end();)
		{
			switch (iter_npc->enemyType)
			{
			case NPCONE:
			case SUPNPCONE:
				iter_npc->CollsionRect(hBitmap_npc1, iter_npc->ColRect);
				break;
			case NPCTWO:
				iter_npc->CollsionRect(hBitmap_npc2, iter_npc->ColRect);
				break;
			case NPCTRE:
				iter_npc->CollsionRect(hBitmap_npc3, iter_npc->ColRect);
				break;
			default:
				break;
			}
			if (iter_npc->isdeath)
			{
				iter_npc->index++;
				if (iter_npc->index > 3)
				{
					iter_npc->death = true;
				}
			}
			if (iter_npc->PosY >= CLIENTHEIGHT || iter_npc->death)
			{
				iter_npc = npcList.erase(iter_npc);
			}
			else
			{
				iter_npc->PosY += iter_npc->Vel();
				iter_npc++;
			}
		}

		for (iter_bullet = bulletList.begin();iter_bullet != bulletList.end();)
		{
			switch (iter_bullet->bulletType)
			{
			case BULLETONE:
				iter_bullet->CollsionRect(hBitmap_bullet1, iter_bullet->ColRect);
				break;
			case BULLETTWO:
				iter_bullet->CollsionRect(hBitmap_bullet2, iter_bullet->ColRect);
				break;
			default:
				break;
			}
			if (iter_bullet->PosY <= 0)
			{
				iter_bullet = bulletList.erase(iter_bullet);
			}
			else
			{
				iter_bullet->PosY -= iter_bullet->velocity;
				iter_bullet++;
			}
		}

		IsHit();
	
		if (isdeath)
		{
			index++;
			if (index >= 4)
			{
				death = true;
				mciSendString(L"stop backmusic", NULL, 0, NULL);
			}
		}
		if (death)
		{
			bulletList.clear();
			npcList.clear();
			curScene = SCENE_OVER;
		}
	}
}

void ReleaseRes()
{
	DelImage();
	CloseSound();
}

void DelImage()//删除位图对象
{
	DeleteObject(hBitmap_start);
	DeleteObject(hBitmap_play);
	DeleteObject(hBitmap_over);
	DeleteObject(hBitmap_npc1);
	DeleteObject(hBitmap_npc2);
	DeleteObject(hBitmap_npc3);
	DeleteObject(hBitmap_supnpc1);
	DeleteObject(hBitmap_player);
	DeleteObject(hBitmap_bullet1);
	DeleteObject(hBitmap_bullet2);
	DeleteObject(hBitmap_award1);
	DeleteObject(hBitmap_award2);
	DeleteObject(hBitmap_bomb);
}

void CloseSound()
{
	mciSendString(L"close bulletmusic", NULL, 0, NULL);
	mciSendString(L"close backmusic", NULL, 0, NULL);
	mciSendString(L"close get_double_laser", NULL, 0, NULL);
	mciSendString(L"close get_bomb", NULL, 0, NULL);
	mciSendString(L"close use_bomb", NULL, 0, NULL);
	mciSendString(L"close enemy1_down", NULL, 0, NULL);
	mciSendString(L"close enemy2_down", NULL, 0, NULL);
	mciSendString(L"close enemy3_down", NULL, 0, NULL);
	mciSendString(L"close game_over", NULL, 0, NULL);
	mciSendString(L"close big_spaceship_flying", NULL, 0, NULL);
}

void MouseClick(int x, int y, HWND hwnd)
{
	switch (curScene)
	{
	case SCENE_START:
		for (iter_menu = menuList_Start.begin();iter_menu != menuList_Start.end();iter_menu++)
		{
			if (iter_menu->menuText == L"开始游戏"&&iter_menu->menuType == SETFOCUS)
			{
				curScene = SCENE_PLAY;
				tmp = clock();
				mciSendString(L"play backmusic from 0", NULL, 0, NULL);
			}
			else if (iter_menu->menuText == L"退出游戏"&&iter_menu->menuType == SETFOCUS)
			{
				SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
			}
		}
	case SCENE_OVER:
		for (iter_menu = menuList_End.begin();iter_menu != menuList_End.end();iter_menu++)
		{
			if (iter_menu->menuText == L"重新开始"&&iter_menu->menuType == SETFOCUS)
			{
				curScene = SCENE_PLAY;
				tmp = clock();
				mciSendString(L"play backmusic from 0", NULL, 0, NULL);
				player_xPos = 150;
				player_yPos = 400;
				death = false;
				isdeath = false;
				upgrade = false;
				upgrade_num = 0;
				Bomb = false;
				Bomb_num = 0;
				flag = 0;
				index = 0;
				bombList.clear();
			}
			else if (iter_menu->menuText == L"结束游戏"&&iter_menu->menuType == SETFOCUS)
			{
				SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
			}
		}
		break;
	case SCENE_PLAY:
		if (x < 42 && y > 564 && Bomb == true)
		{
			bombList.clear();
			Bomb = false;
			BigBang();
		}
		break;
	default:
		break;
	}
}

void BigBang()
{
	for (iter_npc = npcList.begin();iter_npc != npcList.end();iter_npc++)
	{
		iter_npc->isdeath = true;
	}
	mciSendString(L"play use_bomb from 0", NULL, 0, NULL);
}

void IsFocus(int x, int y)
{
	switch (curScene)
	{
	case SCENE_START:
		for (iter_menu = menuList_Start.begin();iter_menu != menuList_Start.end();iter_menu++)
		{
			if (x > iter_menu->rect.X && x < iter_menu->rect.X + MENU_ITEM_WIDTH
				&& iter_menu->rect.Y < y && iter_menu->rect.Y + MENU_ITEM_HEIGHT > y)
			{
				iter_menu->menuType = SETFOCUS;
			}
			else
			{
				iter_menu->menuType = KILLFOCUS;
			}
		}
	case SCENE_OVER:
		for (iter_menu = menuList_End.begin();iter_menu != menuList_End.end();iter_menu++)
		{
			if (x > iter_menu->rect.X && x < iter_menu->rect.X + MENU_ITEM_WIDTH
				&& iter_menu->rect.Y < y && iter_menu->rect.Y + MENU_ITEM_HEIGHT > y)
			{
				iter_menu->menuType = SETFOCUS;
			}
			else
			{
				iter_menu->menuType = KILLFOCUS;
			}
		}
	}
}

至此完啦,希望各位大牛指点

相关标签: 源代码