主页 > 编程 > c语言 >

C语言小游戏 流星阻击战 代码分析

2019-07-18 00:24 阅读:73 来源:智宇SEO自媒体
#pragma once   //防止多次包含

#include <windows.h>                                 
#include "resource.h"      //资源文件
#include "GameEngine.h"    //游戏引擎
#include "Bitmap.h"        //位图类
#include "Sprite.h"        //精灵类
#include "Background.h"    //背景

HINSTANCE	g_hInstance;    //实例句柄
GameEngine*	g_pGame;        //游戏引擎
HDC			g_hOffscreenDC;   //屏幕外绘图
HBITMAP		g_hOffscreenBitmap; //屏幕外绘图
Bitmap*		g_pGroundBitmap;  //沙漠和导弹发射塔
Bitmap*		g_pTargetBitmap; //瞄准器
Bitmap*		g_pCityBitmap;  //城市
Bitmap*		g_pMeteorBitmap;  //流星陨石
Bitmap*		g_pMissileBitmap; //导弹
Bitmap*		g_pExplosionBitmap; //爆炸
Bitmap*		g_pGameOverBitmap; //游戏结束
StarryBackground*	g_pBackground; //背景
Sprite*		g_pTargetSprite; //瞄准器精灵
int			g_iNumCities, g_iScore, g_iDifficulty;   //城市个数,等分,难度系数 
BOOL		g_bGameOver; //游戏是否结束

void NewGame();  // 新游戏开始
void AddMeteor(); //流星陨石下落


#include "MyMeteorDefense.h"
//游戏初始化
BOOL GameInitialize(HINSTANCE hInstance)
{
	// 创建游戏引擎                       //窗口类名称          //窗口标题          //大图标           //小图标          //窗口大小
	g_pGame = new GameEngine(hInstance,TEXT("Meteor Defense"),TEXT("Meteor Defense"),IDI_METEORDEFENSE,IDI_METEORDEFENSE_SM,600,450);
	 //创建游戏引擎失败
	if(g_pGame==NULL)
		return FALSE;
	//帧频 30/秒 ,设置游戏速度
	g_pGame->SetFrameRate(30);
	//保存实例句柄
	g_hInstance = hInstance;
	return TRUE;
}

//游戏开始
void GameStart(HWND hWindow)
{
	//设置随机数的种子
	srand(GetTickCount());
	//屏幕外绘图 和游戏窗口兼容
	g_hOffscreenDC = CreateCompatibleDC(GetDC(hWindow));
	//创建和游戏窗口一样宽高大小的位图
	g_hOffscreenBitmap = CreateCompatibleBitmap(GetDC(hWindow),g_pGame->GetWidth(), g_pGame->GetHeight());
	//把位图选入DC,可以用于屏幕外绘图
	SelectObject(g_hOffscreenDC,g_hOffscreenBitmap);

	//设备上下文环境
	HDC hDC = GetDC(hWindow);
	//创建位图
	g_pGroundBitmap = new Bitmap(hDC, IDB_GROUND, g_hInstance); //沙漠导弹发射器
	g_pTargetBitmap = new Bitmap(hDC, IDB_TARGET, g_hInstance); //瞄准器
	g_pCityBitmap = new Bitmap(hDC, IDB_CITY, g_hInstance);  //城市
	g_pMeteorBitmap = new Bitmap(hDC, IDB_METEOR, g_hInstance); //流星陨石
	g_pMissileBitmap = new Bitmap(hDC, IDB_MISSILE, g_hInstance); //导弹
	g_pExplosionBitmap = new Bitmap(hDC, IDB_EXPLOSION, g_hInstance);//爆炸
	g_pGameOverBitmap = new Bitmap(hDC, IDB_GAMEOVER, g_hInstance);//游戏结束

	g_pBackground= new StarryBackground(600,450);  //满天星背景

	g_pGame->PlayMIDISong(TEXT("Music.mid")); //播放音乐

	NewGame(); //游戏新开始
}
//游戏结束
void GameEnd()
{
	//停止播放背景音乐
	g_pGame->CloseMIDIPlayer();
	//屏幕外绘图删除
	DeleteObject(g_hOffscreenBitmap);
	DeleteDC(g_hOffscreenDC);
	//删除位图 有 new 的
	delete g_pGroundBitmap;
	delete g_pTargetBitmap;
	delete g_pCityBitmap;
	delete g_pMeteorBitmap;
	delete g_pMissileBitmap;
	delete g_pExplosionBitmap;
	delete g_pGameOverBitmap;
	//删除背景
	delete g_pBackground;
	//清除精灵
	g_pGame->CleanupSprites();
	//
	delete g_pGame;

}
//窗口激活
void GameActivate(HWND hWindow)
{   //音乐继续
	g_pGame->PlayMIDISong(TEXT(""),FALSE);
}
//窗口激死
void GameDeactivate(HWND hWindow)
{
	//音乐暂停
	g_pGame->PauseMIDISong();
}
//游戏绘制
void GamePaint(HDC hDC)
{ 
	//画满天星背景
	g_pBackground->Draw(hDC);
	//画出沙漠发射塔位图,ture表示透明
	g_pGroundBitmap->Draw(hDC,0,398,TRUE);
	//画出所有精灵
	g_pGame->DrawSprites(hDC);

	//绘制游戏得分
	TCHAR szText[64];
	//分数显示的位置
	RECT rect = {275, 0, 325, 50};
	wsprintf(szText, "%d", g_iScore);
	//背景模式透明
	SetBkMode(hDC, TRANSPARENT);
	//字体颜色白色
	SetTextColor(hDC,RGB(255,255,255));
	DrawText(hDC, szText, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

	//游戏结束画面
	if(g_bGameOver)
		g_pGameOverBitmap->Draw(hDC,170,150,TRUE);
}

//循环 
void GameCycle()  
{   //游戏没结束
	if(!g_bGameOver)
	{
		  //随机数 整除难度系数 
		if((rand() % g_iDifficulty) == 0)
			AddMeteor();
		//背景更新
		g_pBackground->Update();
		//精灵更新
		g_pGame->UpdateSprites();
		
		//游戏窗口句柄
		HWND hWindow = g_pGame->GetWindow();
		HDC	hDC = GetDC(hWindow);
		//屏幕外绘图 
		GamePaint(g_hOffscreenDC);
		//屏幕外画好的图,快速拷贝到游戏窗口的DC里
		BitBlt(hDC,0,0,g_pGame->GetWidth(), g_pGame->GetHeight(),g_hOffscreenDC,0,0,SRCCOPY);
		//释放DC
		ReleaseDC(hWindow,hDC);
	}
}
//键盘
void HandleKeys()
{
}
//鼠标按下
void MouseButtonDown(int x, int y, BOOL bLeft)
{
	//游戏没结束,左键按下.发射导弹
	if(!g_bGameOver && bLeft)
	{
		//导弹精灵活动范围
		RECT rcBounds = {0,0,600,450};
		//导弹精灵发射位置,两座发射塔,看鼠标的位置,x<300左边发射,>300右边发射
		int iXPos = (x < 300) ? 144 : 449;
		//导弹精灵                                              //碰边界消失
		Sprite* pSprite = new Sprite(g_pMissileBitmap, rcBounds, BA_DIE);
		//导弹起点位置
		pSprite->SetPosition(iXPos,365);
		//设置导弹速度 
		int iYVel = -6;

		int iXVel;
		//鼠标的位置太靠下,按300来算
		y = min(y,300);

		iXVel = iYVel * ((iXPos+8) - x) / (365 - y);
		//设置导弹速度
		pSprite->SetVelocity(iXVel, iYVel);
		//导弹精灵加到游戏引擎里
		g_pGame->AddSprite(pSprite);
		//添加声音
		PlaySound((LPCSTR)IDW_FIRE, g_hInstance, SND_ASYNC|SND_RESOURCE|SND_NOSTOP);
		//最小得分0
		g_iScore = max(--g_iScore,0);
	}
	//游戏结束,右键开始新游戏
	else if(g_bGameOver && !bLeft)
		NewGame();
}
//鼠标抬起
void MouseButtonUp(int x, int y, BOOL bLeft)
{
}
//鼠标移动
void MouseMove(int x, int y)
{
	//瞄准器精灵位置就是鼠标的位置,传入x,y跟着鼠标移动
	g_pTargetSprite->SetPosition(x-(g_pTargetSprite->GetWidth()/2),
		y-(g_pTargetSprite->GetHeight()/2));
}
//游戏手柄
void HandleJoystick(JOYSTATE jsJoystickState)
{
}
//精灵碰撞                   撞者                  被撞者
BOOL SpriteCollision(Sprite* pSpriteHitter, Sprite* pSpriteHittee)
{        //导弹碰撞流星或者流星碰撞导弹
	if((pSpriteHitter->GetBitmap() == g_pMissileBitmap 
		&& pSpriteHittee->GetBitmap() == g_pMeteorBitmap) ||
		(pSpriteHitter->GetBitmap() == g_pMeteorBitmap
		&& pSpriteHittee->GetBitmap() == g_pMissileBitmap))
	{
		//导弹和流星自杀消失
		pSpriteHitter->Kill();
		pSpriteHittee->Kill();

		//得分
		g_iScore += 6;
		//提高难度系数
		g_iDifficulty = max(50-(g_iScore/10),5);
	}
	     //流星碰撞城市
	if(pSpriteHitter->GetBitmap() == g_pMeteorBitmap &&
		pSpriteHittee->GetBitmap() == g_pCityBitmap)
	{
		//大爆炸声音
		PlaySound((LPCSTR)IDW_BIGEXPLODE,g_hInstance,SND_ASYNC | SND_RESOURCE);
		//流星和城市自杀消失
		pSpriteHitter->Kill();
		pSpriteHittee->Kill();
		//城市数量减掉为0 游戏结束
		if(--g_iNumCities == 0)
			g_bGameOver = TRUE;
	}

	return FALSE;
}
//精灵死亡
void SpriteDying(Sprite* pSpriteDying)
{
	//死掉的精灵是流星
	if(pSpriteDying->GetBitmap() == g_pMeteorBitmap)
	{
		//播放导弹击中流星的声音
		PlaySound((LPCSTR)IDW_EXPLODE,g_hInstance, SND_ASYNC|SND_RESOURCE|SND_NOSTOP);
		//爆炸精灵活动范围
		RECT rcBounds = {0,0,600,450};
		//死掉的精灵位置,播放爆炸画面
		RECT rcPos = pSpriteDying->GetPosition();
		//创建一个精灵
		Sprite* pSprite = new Sprite(g_pExplosionBitmap, rcBounds);
		//爆炸动画12帧,ture不循环播
		pSprite->SetNumFrames(12,TRUE);
		//精灵位置死掉精灵的位置
		pSprite->SetPosition(rcPos.left,rcPos.top);
		g_pGame->AddSprite(pSprite);
	}
}
//游戏重新开始
void NewGame()
{
	//清除原有精灵
	g_pGame->CleanupSprites();
	//矩形精灵窗口活动范围 和窗口一样大
	RECT rcBounds = {0,0,600,450};
	//创建精灵,
	g_pTargetSprite = new Sprite(g_pTargetBitmap,rcBounds, BA_STOP);
	//显示最前面 10越大越前面
	g_pTargetSprite->SetZOrder(10);
	//精灵添加到游戏引擎里
	g_pGame->AddSprite(g_pTargetSprite);
	//城市精灵
	Sprite* pSprite = new Sprite(g_pCityBitmap,rcBounds);
	//位置
	pSprite->SetPosition(2,370);
	//加到游戏引擎里
	g_pGame->AddSprite(pSprite);
	//第二座城市精灵
	pSprite = new Sprite(g_pCityBitmap, rcBounds);
	//位置
	pSprite->SetPosition(186,370);
	//精灵加到游戏引擎
	g_pGame->AddSprite(pSprite);
	//第三个城市精灵
	pSprite = new Sprite(g_pCityBitmap, rcBounds);
	//位置
	pSprite->SetPosition(302,370);
	//精灵加到游戏引擎里
	g_pGame->AddSprite(pSprite);
	//第四个城市精灵
	pSprite = new Sprite(g_pCityBitmap, rcBounds);
	pSprite->SetPosition(490,370);
	g_pGame->AddSprite(pSprite);
	//游戏得分 炸掉流星得分,发射一颗导弹减分
	g_iScore = 0;
	//城市数量4
	g_iNumCities = 4;
	//难度系数,流星下落的多和少
	g_iDifficulty = 50;
	g_bGameOver = FALSE;
}
//添加流星陨石下落
void AddMeteor()
{
	//精灵活动范围矩形
	RECT rcBounds = {0,0,600,390};
	//位置随机出现
	int iXPos = rand() % 600;
	//
	Sprite* pSprite = new Sprite(g_pMeteorBitmap, rcBounds, BA_DIE);
	//动画14帧
	pSprite->SetNumFrames(14);

	pSprite->SetPosition(iXPos,0);
	//流星速度
	int iXVel;
	int iYVel = (rand() % 4) + 3;

	switch(rand()%4)
	{
	case 0: //流星瞄准第1个城市
		iXVel = iYVel * (56 - (iXPos + 50)) / 400;
		break;
	case 1: //流星瞄准第2个城市
		iXVel = iYVel * (240 - (iXPos + 50)) / 400;
		break;
	case 2://流星瞄准第3个城市
		iXVel = iYVel * (360 - (iXPos + 50)) / 400;
		break;
	case 3://流星瞄准第4个城市
		iXVel = iYVel * (546 - (iXPos + 50)) / 400;
		break;
	}
	//流星速度
	pSprite->SetVelocity(iXVel, iYVel);
	//精灵加入游戏引擎
	g_pGame->AddSprite(pSprite);
}