⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shootview.cpp

📁 射击小游戏
💻 CPP
字号:
// ShootView.cpp : implementation of the CShootView class
//

#include "stdafx.h"
#include "Shoot.h"

#include "ShootDoc.h"
#include "ShootView.h"

#include "MyDefine.h"
#include<windows.h>
#include<mmsystem.h>

#include "EnemySystem.h"
#include "HeroDlg.h"
//#include <fstream.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CShootView

IMPLEMENT_DYNCREATE(CShootView, CView)

BEGIN_MESSAGE_MAP(CShootView, CView)
	//{{AFX_MSG_MAP(CShootView)
	ON_WM_CREATE()
	ON_WM_TIMER()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	ON_COMMAND(IDM_RESET, OnReset)
	ON_COMMAND(ID_PAUSE, OnPause)
	ON_UPDATE_COMMAND_UI(ID_PAUSE, OnUpdatePause)
	ON_COMMAND(IDM_LASTINFOR, OnLastinfor)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CShootView construction/destruction

CShootView::CShootView()
{
	// TODO: add construction code here
	m_iClientWidth = 800;
	m_iClientHeight = 600;

}

CShootView::~CShootView()
{
}

BOOL CShootView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs
	return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CShootView drawing

void CShootView::OnDraw(CDC* pDC)
{
	CShootDoc* pDoc  =  GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here	
}

/////////////////////////////////////////////////////////////////////////////
// CShootView diagnostics

#ifdef _DEBUG
void CShootView::AssertValid() const
{
	CView::AssertValid();
}

void CShootView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CShootDoc* CShootView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CShootDoc)));
	return (CShootDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CShootView message handlers
//***************************************************************************
//这个函数做游戏的初始化
//***************************************************************************
int CShootView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// TODO: Add your specialized creation code here
	srand(time(0));
	CClientDC dc(this);

	m_iFPS = 1;//初始化每秒中的祯数
	//加载位图
	m_pbmpbg = new Bitmap("bground.bmp",0,RGB(0,0,0));
	m_pbmppic = new Bitmap("picture.bmp",1,RGB(255,0,255));
//	over = new Bitmap("picture2.bmp",0,RGB(255,0,255));
	m_pbmpwelcome = new Bitmap("welcome.bmp",0,RGB(0,0,0));
	//初始化mdc二级缓冲
	mdc = new CDC;
	mdc->CreateCompatibleDC(&dc);
	CBitmap bmp;
	bmp.CreateCompatibleBitmap(&dc,m_iClientWidth,m_iClientHeight);
	mdc->SelectObject(&bmp);
	//初始化定时器
	SetTimer(EVENT_BKSCROLL,m_iFPS,NULL);
	SetTimer(EVENT_BAO,BAO_TICK,NULL);
	//初始化滚动背景的变量
	m_iScroll_X=0;
	m_iScroll_V = 2;
	//初始化玩家战斗机
	m_pPlayer = new Player(m_iClientWidth / 2, m_iClientHeight / 2 );
	//	pPlayer2 = new Player(ClientWidth / 2-10, ClientHeight / 2-10 );///////////////
	//初始化敌机子弹系统
	m_pEnermyBulletSystem = new BulletSystem();
	//初始化玩家子弹系统
	m_pPlayerBulletSystem = new BulletSystem();
	//初始化敌机系统
	m_pEnermySystem = new EnermySystem();
	//初始化碰撞系统
	m_pCollisionSystem = new CollisionSystem();
	//初始化宝箱系统
	m_pBaoSys = new BaoSystem();
	//初始化一些游戏状态
	m_bIsPause = FALSE;//是否暂停:否
	m_iLevel = 1;//游戏级别:1
	m_iBufKey = 0;//按键缓冲区:控
	m_iCurKey = 0;//当前按键:空

	m_b_GAME_STATE = true;//欢迎界面是否显示:是
	m_bFirstTime=TRUE;

	return 0;
}
//*******************************************************************
//这相当于游戏的主循环,游戏的整个流程在这个函数实现
//*******************************************************************
void CShootView::OnTimer(UINT nIDEvent) 
{
	
	// TODO: Add your message handler code here and/or call default
	CClientDC pDC(this);	
	if(m_b_GAME_STATE == true)//是否启动欢迎界面
	{
		m_pbmpwelcome->Draw(mdc->m_hDC,0,0,m_iClientWidth,m_iClientHeight,0,0);
		DrawAllToScreen();
//		Sleep(3000);//延时
		m_b_GAME_STATE = false;//将启动欢迎界面状态置为:否
	}
	if((nIDEvent == EVENT_BKSCROLL)&&(!m_bIsPause))//游戏的主循化
	{
	
		if(m_pPlayer->m_iChances<0)//如果玩家没有复活的机会则宣告游戏结束,打出“GameOver”字样
		{
		//	CDialog*dlg = new CDialog();
		//	dlg->DoModal();
			Over();
			DrawAllToScreen();	
			return;
		}
		//否则说明游戏在继续
		// 如果打够了一定的分数就进行难度升级
		if(m_pPlayer->m_iScore >= m_iLevel*700)
		{
			m_pEnermySystem->AddDifficulty();
			m_iLevel++;
		}
		//每次画面更新都需要清屏函数
		Clear();
		//下面更新每个实体系统
		m_pPlayerBulletSystem->Update();
		m_pPlayer->Update();
//		pPlayer2->Update();/////////////////
		m_pEnermyBulletSystem->Update();
		m_pEnermySystem->Update();
		m_pCollisionSystem->Update();
		m_pBaoSys->Update();////////////////////
		//将游戏信息输出到设备缓冲区
		ShowInformation();
		//将更新结果完全显示到屏幕上
		DrawAllToScreen();	
	}
	//如果是暂停状态就只调用清屏函数让背景不断滚动,并显示“Pause”字样
	if((nIDEvent == EVENT_BKSCROLL)&&(m_bIsPause))
	{
		//设定字体样式
		CFont font;
		LOGFONT lf;
		memset(&lf, 0, sizeof(LOGFONT));       // zero out structure
		lf.lfHeight = 40;                      // request a 12-pixel-height font
		strcpy(lf.lfFaceName, "Arial");        // request a face name "Arial"
		VERIFY(font.CreateFontIndirect(&lf));  // create the font
		CFont* def_font = mdc->SelectObject(&font);
		//作滚动贴图
		m_pbmpbg->Draw(mdc->m_hDC,0,0,m_pbmpbg->GetWidth(),m_iScroll_X,0,m_pbmpbg->GetHeight()-m_iScroll_X);
		m_pbmpbg->Draw(mdc->m_hDC,0,m_iScroll_X,m_pbmpbg->GetWidth(),m_pbmpbg->GetHeight()-m_iScroll_X,0,0);
		//输出文字“Pause”到缓冲区设备
		mdc->TextOut(m_iClientWidth/2-90,m_iClientHeight/2-20,"Pause");
		m_iScroll_X+=m_iScroll_V;
		if(m_iScroll_X>m_iClientHeight)
			m_iScroll_X = 0;
		mdc->SelectObject(def_font);
		font.DeleteObject();
		//将更新结果完全显示到屏幕上
		DrawAllToScreen();	

	}
	//宝箱系统使用第二个定时器
	if(nIDEvent == EVENT_BAO)
	{
		int temp = rand()%5;//随即产生宝箱
		if((temp == 4)&&(!m_bIsPause))
			m_pBaoSys->BaoHappened(Bao::BAO_BLOOD,rand()%m_iClientWidth,0,1,1);
		if((temp<=1)&&(!m_bIsPause))
			m_pBaoSys->BaoHappened(Bao::BAO_WEAPON,rand()%m_iClientWidth,0,1,1);
	}
	//文件读写部分
	if((m_pPlayer->m_iChances<0)&&(m_bFirstTime))
	{
		m_bFirstTime=FALSE;
		ifstream f("text.txt",ios::in|ios::binary);		
		CHeroDlg dlg;
		int is;
		char* str = new char[20];
		f>>is;
		f>>str;
		if(m_pPlayer->m_iScore>is)
		{
			dlg.SetLastName(str);
			dlg.SetLastScore(is);
			dlg.SetScore(m_pPlayer->m_iScore);
			dlg.DoModal();
		}		
	}
	CView::OnTimer(nIDEvent);
}
//这个函数负责将某个实体对象画到缓冲区中去
void CShootView::DrawObject(BaseObject*obj)
{
	m_pbmppic->Draw(mdc->m_hDC,obj->GetX(),obj->GetY(),obj->m_w,obj->m_h,obj->m_isx,obj->m_isy);
}
//将缓冲区的更新结果完全显示到屏幕上
void CShootView::DrawAllToScreen()
{
	CClientDC dc(this);
	dc.BitBlt(0,0,m_iClientWidth,m_iClientHeight,mdc,0,0,SRCCOPY);
}
//清屏函数
//只作滚动贴图
void CShootView::Clear()
{
	m_iScroll_V = m_iLevel;
	m_pbmpbg->Draw(mdc->m_hDC,0,0,m_pbmpbg->GetWidth(),m_iScroll_X,0,m_pbmpbg->GetHeight()-m_iScroll_X);
	m_pbmpbg->Draw(mdc->m_hDC,0,m_iScroll_X,m_pbmpbg->GetWidth(),m_pbmpbg->GetHeight()-m_iScroll_X,0,0);
	m_iScroll_X+=m_iScroll_V;
	if(m_iScroll_X>m_iClientHeight)
		m_iScroll_X = 0;
}
//响应键盘按下消息
void CShootView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default

	switch(nChar)
	{
	case VK_LEFT:
	case VK_RIGHT:
	case VK_UP:
	case VK_DOWN:
		if(nChar == m_iCurKey || nChar == m_iBufKey) return;		// 重复的键盘消息,忽略
		if(m_iBufKey && m_iCurKey) return;	// 同时按3个方向键,非法输入,忽略	
		//更新键盘缓冲变量的按键
		m_iBufKey = m_iCurKey;
		m_iCurKey = nChar;
		//根据按键缓冲区的值和当前按键的值来判断做出什么动作。双缓冲的思想可以使动作更为细腻
		if( m_iBufKey == VK_LEFT && m_iCurKey == VK_UP || m_iBufKey == VK_UP && m_iCurKey == VK_LEFT )
		{	
			m_pPlayer->Action( Player::GO_LEFT_UP );
//			pPlayer2->Action( Player::GO_LEFT_UP );
		}
		else if( m_iBufKey == VK_LEFT && m_iCurKey == VK_DOWN || m_iBufKey == VK_DOWN && m_iCurKey == VK_LEFT )
		{	m_pPlayer->Action( Player::GO_LEFT_DOWN );
//		pPlayer2->Action( Player::GO_LEFT_DOWN );
		}
		else if( m_iBufKey == VK_RIGHT && m_iCurKey == VK_UP || m_iBufKey == VK_UP && m_iCurKey == VK_RIGHT )
		{	m_pPlayer->Action( Player::GO_RIGHT_UP );
	//	pPlayer2->Action( Player::GO_RIGHT_UP );
		}
		else if( m_iBufKey == VK_RIGHT && m_iCurKey == VK_DOWN || m_iBufKey == VK_DOWN && m_iCurKey == VK_RIGHT )
		{	m_pPlayer->Action( Player::GO_RIGHT_DOWN );
//		pPlayer2->Action( Player::GO_RIGHT_DOWN );
		}
		else
		{	m_pPlayer->Action( (Player::ACTION) (Player::GO_LEFT + nChar - VK_LEFT) );//这个地方运用了一点小技巧
//		pPlayer2->Action( (Player::ACTION) (Player::GO_LEFT + nChar - VK_LEFT) );
		}
		break;
	case VK_SPACE://空格键按下代表开始发火,抬起代表停止发火
		m_pPlayer->Action(Player::START_FIRING);
//		pPlayer2->Action(Player::START_FIRING);
		break;
	case VK_F1://F1键代表暂停
		m_bIsPause=!m_bIsPause;
		break;
	}
	CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
//玩家开火
void  CShootView::PlayerFire(Player *pPlayer)
{
	m_pPlayerBulletSystem->FireHappened(pPlayer->BulletType, pPlayer->GetX()+pPlayer->m_w/2, pPlayer->GetY()+pPlayer->m_h/2, pPlayer->m_vx, pPlayer->m_vy);
}
//处理键盘弹起消息
void CShootView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default

	if(nChar == m_iCurKey)//如果抬起的键是这之前最后一个被按下的
	{
		m_iCurKey = 0;
		if(m_iBufKey)//如果缓冲区中有按键记录则按照这个记录动作
		{
			m_iCurKey = m_iBufKey;
			m_iBufKey = 0;
			m_pPlayer->Action( ( Player::ACTION )( m_iCurKey - VK_LEFT ) );	
		}
		else//如果缓冲区中没有记录说明现在没有键被按下,则停止运动
		{
			m_pPlayer->Action( Player::STOP_MOVING );
		}
	}
	else if(nChar == m_iBufKey)//如果抬起的键是缓冲区的按键
		m_iBufKey = 0;
	else if(nChar == VK_SPACE)//空格键抬起时停止发射子弹
		m_pPlayer->Action(Player::STOP_FIRING);
	CView::OnKeyUp(nChar, nRepCnt, nFlags);
}
//重置玩家信息为初始状态
void CShootView::ResetPlayer()
{
	delete m_pPlayer;
	m_pPlayer = new Player(m_iClientWidth / 2, m_iClientHeight / 2 );
	m_iLevel = 1;
	m_pEnermySystem->ResetDifficulty();
}
//敌人战机开火
void CShootView::EnermyFire(Enermy *pEnermy)
{
	m_pEnermyBulletSystem->FireHappened(pEnermy->BulletType, pEnermy->GetX()+pEnermy->m_w/2, pEnermy->GetY()+pEnermy->m_h/2, pEnermy->m_vx, pEnermy->m_vy);	

}
//显示游戏信息。就是一系列的坐标计算,文字输出
void CShootView::ShowInformation(){

	int HPStart_X,HPStart_Y;//血条的左上角坐标
	int HPWidth;//血条的宽度
	int HPText_Width;//血条与文字“HP”的间距
	int Blood_Score_Width;
	//初始化血条
	HPStart_X = 50,HPStart_Y = 10;
	HPWidth = 30;
	HPText_Width = 50;
	Blood_Score_Width = 25;
	//设置文字为背景透明,前景红色
	mdc->SetTextColor(RGB(255,0,0));
	mdc->SetBkMode(TRANSPARENT);
//	mdc->TextOut(HPStart_X-HPText_Width,HPStart_Y,"HP:");
	CBrush b1,b2;
	CPen p1;
	//实心绿画刷,实心红画笔
	p1.CreatePen(PS_SOLID,2,RGB(255,0,0));
	b2.CreateSolidBrush(RGB(0,255,0));
	mdc->SelectObject(&p1);
	mdc->SelectObject(&b2);
	//画出血条边框
	mdc->Rectangle(CRect(HPStart_X,HPStart_Y,HPStart_X+20*10,HPWidth));
	//实心红画刷
	b1.CreateSolidBrush(RGB(255,0,0));
	mdc->SelectObject(&b1);
	//画出血块儿
	if(m_pPlayer->m_iLife>=20)
		m_pPlayer->m_iLife=20;
	mdc->FillRect(CRect(HPStart_X+1,HPStart_Y+1,HPStart_X+m_pPlayer->m_iLife*10-1,HPWidth-2),&b1);
	//写出文字“HP”
	mdc->TextOut(HPStart_X-HPText_Width,HPStart_Y,"战斗力:");
	CString str_score;
	str_score.Format("得分:%d",m_pPlayer->m_iScore);
	mdc->TextOut(HPStart_X+20*10+Blood_Score_Width,HPStart_Y,str_score);
	CString str_Level;
	str_Level.Format("游戏难度:%d",m_iLevel);
	mdc->TextOut(HPStart_X+20*10+Blood_Score_Width+str_score.GetLength()+100,HPStart_Y,str_Level);
	CString str_Chances;
	m_pbmppic->Draw(mdc->m_hDC,HPStart_X+20*10+Blood_Score_Width+str_score.GetLength()+100+100,HPStart_Y-10,29,33,0,0);
	str_Chances.Format("X%d",m_pPlayer->m_iChances);
	mdc->TextOut(HPStart_X+20*10+Blood_Score_Width+str_score.GetLength()+240,HPStart_Y,str_Chances);
}
//游戏失败结束画面
void CShootView::Over()
{	
	CFont font;
	LOGFONT lf;
	memset(&lf, 0, sizeof(LOGFONT));       // zero out structure
	lf.lfHeight = 40;                      // request a 12-pixel-height font
	strcpy(lf.lfFaceName, "Arial");        // request a face name "Arial"
	VERIFY(font.CreateFontIndirect(&lf));  // create the font
	CFont* def_font = mdc->SelectObject(&font);
	m_pbmpbg->Draw(mdc->m_hDC,0,0,m_pbmpbg->GetWidth(),m_iScroll_X,0,m_pbmpbg->GetHeight()-m_iScroll_X);
	m_pbmpbg->Draw(mdc->m_hDC,0,m_iScroll_X,m_pbmpbg->GetWidth(),m_pbmpbg->GetHeight()-m_iScroll_X,0,0);
	mdc->TextOut(m_iClientWidth/2-90,m_iClientHeight/2-20,"Game Over");
	m_iScroll_X+=m_iScroll_V;
	if(m_iScroll_X>m_iClientHeight)
		m_iScroll_X = 0;
	mdc->SelectObject(def_font);
	font.DeleteObject();
}
//“重置游戏”菜单消息处理函数
void CShootView::OnReset() 
{
	// TODO: Add your command handler code here
	ResetPlayer();
	m_pEnermyBulletSystem->Clear();
	m_pEnermySystem->Clear();
	m_pPlayerBulletSystem->Clear();
	m_pBaoSys->Clear();
	m_bFirstTime = TRUE;
}
//暂停游戏
void CShootView::OnPause() 
{
	// TODO: Add your command handler code here
	m_bIsPause = !m_bIsPause;
}

void CShootView::OnUpdatePause(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	if(m_bIsPause)
	{
		pCmdUI->SetText("开始游戏(&s)");
	}
	else
	{
		pCmdUI->SetText("暂停游戏(&p)");
	}
}

void CShootView::OnLastinfor() 
{
	// TODO: Add your command handler code here
		
	ifstream f("text.txt",ios::in|ios::binary);		

	int is;
	char* str = new char[20];
	f>>is;
	f>>str;
	CString infor;
	infor.Format("最高分:%d,它是由%s创造的!",is,str);
	MessageBox(infor);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -