📄 shootview.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 + -