飞机躲避模型
一、设计要求
屏幕中有很多粒子,飞行速度和方向各不相同(可以用随机数产生每个粒子的飞行速度和方向),用户可以用上下左右键控制一个飞机,躲避所有粒子不被击中,坚持时间越长得分越多。
二、设计步骤
1、新建一个MFC单文档应用程序,如下图所示。
2、新建一个类,如下图所示。
3、定义粒子结构体并添加一些成员变量,如下图所示。
4、然后在构造函数里对部分成员变量初始化,代码如下。
CFeiJiDuoBi::CFeiJiDuoBi()
{
m_YD.x = 50;
m_YD.y = 850;
m_kx = 800.0/10000;
m_ky = -800.0/10000;//单位“米”
m_FJYD.x = m_YD.x + 5000*m_kx;
m_FJYD.y = m_YD.y + 5000*m_ky;
m_fjh = 700;
m_fjw = 400;
m_fjl = 200;
m_nLZ = 20;
m_lzr = 100;
dt = 0.1;
m_FS = 0;
CreateLiZi();//创建随机20个粒子
}
5、添加Draw函数,并调用后面我们需要用到的如下图所示。
代码如下:
void CFeiJiDuoBi::Draw(CDC *p)
{
CString str;
CFont ft;
pDC = p;
DrawArea();//画区域边界
DrawFeiJi();//画飞机
DrawLiZi();//画粒子
str.Format("得分:%d 分",m_FS);
ft.CreatePointFont(400,_T("隶书"),NULL);
pDC->SelectObject(&ft);
pDC->SetTextColor(RGB(0,0,0));
pDC->TextOut(900,150,str);
}
6、首先将游戏区域、粒子、飞机画出来,如下图所示。
(1)画游戏区域
代码如下:
//画游戏区域
void CFeiJiDuoBi::DrawArea()
{
int x,y,r;
x = m_YD.x;
y = m_YD.y;
r = 10000*m_kx;
pDC->Rectangle(x,y,x+r,y-r);//左下角为矩形起点
}
(2)画粒子
代码如下:
//画粒子
void CFeiJiDuoBi::DrawLiZi()
{
int i;
int x,y,r;
for (i = 0; i < m_nLZ; i++)
{
x = m_LZ[i].pt.x;
y = m_LZ[i].pt.y;
r = m_lzr*m_kx;
CBrush brush,*pOldBrush;
brush.CreateSolidBrush(RGB(0,0,0));
pOldBrush = pDC->SelectObject(&brush);
pDC->Ellipse(x-r,y-r,x+r,y+r);
brush.DeleteObject();
pDC->SelectObject(pOldBrush);
}
}
(3)画飞机
代码如下:
//画飞机
void CFeiJiDuoBi::DrawFeiJi()
{
int x,y,r;
CPoint p1,p2,p3;//画飞机头的3个点(当三角形处理)
x = m_FJYD.x + m_fjw*m_kx;
y = m_FJYD.y + m_fjh*m_ky;
CBrush brush,*pOldBrush;
brush.CreateSolidBrush(RGB(255,0,0));
pOldBrush = pDC->SelectObject(&brush);
pDC->MoveTo(m_FJYD);
pDC->Rectangle(m_FJYD.x,m_FJYD.y,x,y);//画飞机身(当矩形处理)
brush.DeleteObject();
pDC->SelectObject(pOldBrush);
p1.x = m_FJYD.x - m_lzr*m_kx;
p1.y = m_FJYD.y + m_fjh*m_ky;
p2.x = m_FJYD.x + m_fjw*m_kx/2;
p2.y = m_FJYD.y + m_fjh*m_ky + m_fjw*m_ky/2 + m_lzr*m_ky;
p3.x = m_FJYD.x + m_fjw*m_kx + m_lzr*m_kx;
p3.y = m_FJYD.y + m_fjh*m_ky;
pDC->MoveTo(p1);
pDC->LineTo(p2);
pDC->LineTo(p3);
pDC->LineTo(p1);//画飞机头(三角形)
pDC->MoveTo(m_FJYD);
x = m_FJYD.x - m_fjl*m_kx;
y = m_FJYD.y - m_fjl*m_ky;
pDC->LineTo(x,y);//画飞机左翼
x = m_FJYD.x + m_fjw*m_kx;
y = m_FJYD.y;
pDC->MoveTo(x,y);
x += m_fjl*m_kx;
y -= m_fjl*m_ky;
pDC->LineTo(x,y);//画飞机右翼
}
7、然后创建粒子,如下图所示。
代码如下:
//创建粒子
void CFeiJiDuoBi::CreateLiZi()
{
int i;
int x,y;
for(i = 0; i < m_nLZ; i++)
{
x = rand()%(10000 - 2*m_lzr);
y = rand()%(10000 - 2*m_lzr);
m_LZ[i].pt.x = m_YD.x + (x + m_lzr)*m_kx;
m_LZ[i].pt.y = m_YD.y + (y + m_lzr)*m_ky;
m_LZ[i].vx = rand()%200;//速度设在-300到-200和200到300之间
m_LZ[i].vy = rand()%200;
if(m_LZ[i].vx < 100)
m_LZ[i].vx -= 300;
else
m_LZ[i].vx += 100;
if(m_LZ[i].vy < 100)
m_LZ[i].vy -= 300;
else
m_LZ[i].vy += 100;
}
}
8、为了让飞机和粒子动起来,我们再添加两个函数,如下图所示。
(1)通过键盘上下左右键控制飞机的运动。
代码如下:
//移动飞机
void CFeiJiDuoBi::MoveFeiJi(int n)
{
switch(n)
{
case 37:
if(m_FJYD.x > m_YD.x + m_lzr*m_kx)
m_FJYD.x -= 2*m_lzr*m_kx;
break;
case 38:
if(m_FJYD.y > m_YD.y + 10000*m_ky - m_fjh*m_ky - m_fjw*m_ky/2 - m_lzr*m_ky)
m_FJYD.y += 2*m_lzr*m_ky;
break;
case 39:
if(m_FJYD.x < m_YD.x + 10000*m_kx - m_lzr*m_kx - m_fjw*m_kx)
m_FJYD.x += 2*m_lzr*m_kx;
break;
case 40:
if(m_FJYD.y < m_YD.y + m_lzr*m_ky)
m_FJYD.y -= 2*m_lzr*m_ky;
break;
}
}
(2)移动粒子(遇边界反弹),在OnTimer中调用,如下图所示。
代码如下:
//移动粒子
void CFeiJiDuoBi::MoveLiZi()
{
int i;
for(i = 0; i < m_nLZ; i++)
{
m_LZ[i].pt.x += m_LZ[i].vx*dt*m_kx;
m_LZ[i].pt.y += m_LZ[i].vy*dt*m_ky;
}
}
9、碰撞函数,如下图所示。
(1)碰撞粒子、飞机——游戏结束
代码如下:
//碰撞粒子、飞机—游戏结束
int CFeiJiDuoBi::PengZhuangLiZiFeiJi()
{
int i;
int x,y,x1,y1;
CPoint p;
x = m_FJYD.x;
y = m_FJYD.y;
x1 = m_FJYD.x + m_fjw*m_kx;
y1 = m_FJYD.y + m_fjh*m_ky + m_fjw*m_ky/2;
for(i = 0; i < m_nLZ; i++)
{
p.x = m_LZ[i].pt.x;
p.y = m_LZ[i].pt.y;
if( ((p.x >= x && p.x <= x1) ||(p.x >= x1 && p.x <= x)) && ((p.y >= y && p.y <= y1)||(p.y >= y1 && p.y <= y)) )
return 1;//待会儿在OnTimer中调用并判断
}
return 0;
}
(2)碰撞粒子、边界——粒子反弹
代码如下:
//碰撞粒子、边界—粒子反弹
void CFeiJiDuoBi::PengZhuangLiZiBianJie()
{
int i;
int x,y,r;
for(i = 0; i < m_nLZ; i++)
{
x = m_LZ[i].pt.x;
y = m_LZ[i].pt.y;
r = m_lzr*m_kx;
if(x <= m_YD.x + r)
m_LZ[i].vx = fabs(m_LZ[i].vx);
if( x >= m_YD.y - r)
m_LZ[i].vx = -fabs(m_LZ[i].vx);
if(y <= m_YD.x + r)
m_LZ[i].vy = -fabs(m_LZ[i].vy);
if(y >= m_YD.y - r)
m_LZ[i].vy = fabs(m_LZ[i].vy);
}
}
10、上面代码已经写好了,现在只需添加一个菜单并在CPlaneView里调用即可实现本设计的要求。
11、添加菜单并建立类向导,如下图所示。
代码如下:
void CPlaneView::OnMStart()
{
// TODO: Add your command handler code here
SetTimer(1,500,NULL);
}
void CPlaneView::OnMStop()
{
// TODO: Add your command handler code here
KillTimer(1);
}
12、在CPlaneView里将“FeiJiDuoBi.h”头文件嵌入进来,并添加成员对象,如下图所示。
13、在OnDraw函数里调用,代码如下。
void CPlaneView::OnDraw(CDC* pDC)
{
CPlaneDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
m_FJDB.Draw(pDC);
}
14、添加键盘消息响应函数和时钟函数,如下图所示。
代码如下:
void CPlaneView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
m_FJDB.MoveFeiJi(nChar);
Invalidate(TRUE);
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CPlaneView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
m_FJDB.MoveLiZi();
m_FJDB.PengZhuangLiZiBianJie();
if(1 == m_FJDB.PengZhuangLiZiFeiJi())
{
KillTimer(1);
CString str;
str.Format("游戏结束!");
AfxMessageBox(str);
}
else
m_FJDB.m_FS++;
Invalidate(true);
CView::OnTimer(nIDEvent);
}
三、界面截图