计算机软件实习

贪吃蛇的游戏开发

这个实验要求是实现贪吃蛇游戏的基本功能,屏幕上随机出现一个食物,键盘上下左右控制蛇的移动,吃到食物后蛇的身体长一点,得分增加,蛇碰到边界或者咬到自己的尾巴,蛇死亡,游戏结束。

实验准备

整个过程都是在Cview类中完成的,所以查阅了一些相关的内容。

本次实验主要涉及到的知识点有:
(1)CView类中的消息响应

(2)控件的消息响应

(3)基于CView类内的具体游戏实现

(4)游戏图形的实现用CDC类实现。

接下来我会介绍一下主要步骤

主要步骤

交互页面的设计

先添加“游戏”和“帮助两个标题”,再在两个标题下分别添加“开始”,“暂停”,“继续”,“结束”,“关于贪吃蛇”控件,如图所示:
在这里插入图片描述
在这里插入图片描述
接下来最关键的是画贪吃蛇游戏的页面,设计颜色,大小,形状
利用windows给我们提供的CDC来进行画图

用灰色将页面进行填充,然后画一个801*501的矩形,就是贪吃蛇活动的界面
在这里插入图片描述
分别对蛇和出现的事物进行颜色填充
这里我设计的是粉色的
在这里插入图片描述
在这里插入图片描述
初始化蛇有三个节点
要写出每个节点的坐标

在这里插入图片描述
这就是设计好的界面了

在这里插入图片描述

函数

首先为刚才添加的“开始”,“暂停”,“继续”,“退出”,“关于贪吃蛇”添加消息响应函数
在这里插入图片描述
这里使用的是自带的AfxMessageBox函数的默认格式,有一个文本和一个确定按钮还有一个警告标识符
比如这是设置好的“关于贪吃蛇”的效果
按“确定”或者“X”都是一样的可以关闭弹出的框

在这里插入图片描述
OnKeyDown函数对玩家的键盘输入进行判断,当蛇是向上移动时,你按“上”,“下”都是无效的

在这里插入图片描述
OnTimer函数是最主要的函数,因为我们判断蛇移动,暂停,继续都是根据时间来的

设置不同长度下蛇的速度
在这里插入图片描述

判断蛇是否死亡

在这里插入图片描述
判断是否具有吃掉食物的条件

在这里插入图片描述

判断食物是否被蛇吃掉,如果吃掉了就生成,注意食物的生成不能出界,也不能生成在蛇身上

在这里插入图片描述
判断蛇的行走方向

在这里插入图片描述
判断得分情况

在这里插入图片描述
最后是添加音效,这里我添加了一个音效,使得蛇吃掉食物的时候会发出声音
添加音乐主要就是用到了playSound函数
在这里插入图片描述
这样贪吃蛇的游戏开发就算完成了

完整代码

#include "stdafx.h"
#include "snake.h"

#include "snakeDoc.h"
#include "snakeView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#include "Mmsystem.h"
#pragma comment(lib,"Winmm.lib")

BOOL playSound(LPCSTR pasSound,HMODULE hmod,DWORD fdwSound);
// CSnakeView
struct Snake
{
	int x;
	int y;
	int len;
	int direct;
}Snake[50];

struct Food
{
	int x;
	int y;
	int isfood;
}Food;

IMPLEMENT_DYNCREATE(CSnakeView, CView)

BEGIN_MESSAGE_MAP(CSnakeView, CView)
	//{{AFX_MSG_MAP(CSnakeView)
	ON_WM_KEYDOWN()
	ON_WM_RBUTTONDOWN()
	ON_WM_TIMER()
	ON_COMMAND(IDM_START, OnStart)
	ON_COMMAND(IDM_PAUSE, OnPause)
	ON_COMMAND(IDM_EXIT, OnExit)
	ON_COMMAND(IDM_CONTINUE, OnContinue)
	ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()

// CSnakeView construction/destruction

CSnakeView::CSnakeView()
{
	// TODO: add construction code here

}

CSnakeView::~CSnakeView()
{
}

BOOL CSnakeView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

return CView::PreCreateWindow(cs);
}

// CSnakeView drawing

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

CBrush backBrush(RGB(100,100,100));
    CBrush* pOldBrush = pDC->SelectObject(&backBrush);
    CRect rect;
    pDC->GetClipBox(&rect);
    pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),PATCOPY);
    pDC->SelectObject(pOldBrush);
	pDC->Rectangle(100,100,801,501);
	oninit();
}

// CSnakeView printing

BOOL CSnakeView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CSnakeView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CSnakeView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}


// CSnakeView diagnostics

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

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

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

// CSnakeView message handlers

void CSnakeView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	switch(nChar)
	{//对玩家的按键进行判断,你如蛇往左的时候,玩家按右或左是无效的
    case VK_UP:if(Snake[0].direct!=2)Snake[0].direct=1;break; 
    case VK_DOWN:if(Snake[0].direct!=1)Snake[0].direct=2;break;
    case VK_LEFT:if(Snake[0].direct!=4)Snake[0].direct=3;break;  
    case VK_RIGHT:if(Snake[0].direct!=3)Snake[0].direct=4;break; 
	}
	CView::OnKeyDown(nChar, nRepCnt, nFlags);
}

void CSnakeView::OnRButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	CString str;
    str.Format("%d,%d",point.x,point.y);
    AfxMessageBox(str);
	CView::OnRButtonDown(nFlags, point);
}

void CSnakeView::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	CDC *pDC=GetDC();
 //设置不同长度下蛇的速度
 if(Snake[0].`len==3)SetTimer`(1,270,NULL);
 if(Snake[0].len==9)SetTimer(1,200,NULL);
 if(Snake[0].len==15)SetTimer(1,150,NULL);
 if(Snake[0].len==30)SetTimer(1,100,NULL);
 //判断得分
 CString soure;
 soure.Format("      得分: %d!    ",(Snake[0].len-3)*10); 
 //撞界判断
 if(Snake[0].x*20<=118||Snake[0].y*20<=118||Snake[0].x*20>=762||Snake[0].y*20>=462)
 {
  KillTimer(1);
  AfxMessageBox(soure);
 // s=0;
 }
   //蛇身相撞判断
 if(Snake[0].len>3)
  for(int sn=Snake[0].len-1;sn>0;sn--)
  {
   if(Snake[0].x*20==Snake[sn].x*20&&Snake[0].y*20==Snake[sn].y*20)
   {
    KillTimer(1);
    AfxMessageBox(soure);
  //  s=0;
   }
  }
  pDC->SelectStockObject(WHITE_PEN);
  pDC->Rectangle(Snake[Snake[0].len-1].x*20,Snake[Snake[0].len-1].y*20,(Snake[Snake[0].len-1].x+1)*20,(Snake[Snake[0].len-1].y+1)*20);
  for(int i=Snake[0].len-1;i>0;i--)
  {
   Snake[i].x=Snake[i-1].x;
   Snake[i].y=Snake[i-1].y;
  }

  //行走方向判断
  if(Snake[0].direct==1)Snake[0].y--;
  if(Snake[0].direct==2)Snake[0].y++;
  if(Snake[0].direct==3)Snake[0].x--;
  if(Snake[0].direct==4)Snake[0].x++;
  pDC->SelectStockObject(BLACK_PEN);
  CBrush DrawBrush=(RGB(255,217,255));
  CBrush *Drawbrush=pDC->SelectObject(&DrawBrush);
  pDC->Rectangle(Snake[0].x*20,Snake[0].y*20,(Snake[0].x+1)*20,(Snake[0].y+1)*20);
  pDC->SelectObject(DrawBrush);


  //判断吃食物的条件,撞到就吃
  if(Snake[0].x*20==Food.x*20&&Snake[0].y*20==Food.y*20)
  {
   Snake[0].len++;
   Food.isfood=1;
   sndPlaySound("D:\\按钮类7.wav", SND_ASYNC);
   Snake[Snake[0].len-1].x=Snake[Snake[0].len-2].x;
   Snake[Snake[0].len-1].y=Snake[Snake[0].len-2].y;
  }
  //如果食物被吃了 就生成
  if(Food.isfood==1)
  {
   srand((unsigned)time(NULL));
   do
   {
    for(int isfo=Snake[0].len-1;isfo>=0;isfo--)

   if(Snake[0].x*20==Snake[isfo].x*20&&Snake[0].y*20==Snake[isfo].y*20)
     {
      Food.x=rand()%25;
      Food.y=rand()%25;
     }
   }
   while(Food.x*20<150||Food.y*20<150||Food.x*20>730||Food.y*20>430);

   pDC->Rectangle(Food.x*20,Food.y*20,(Food.x+1)*20,(Food.y+1)*20);
   Food.isfood=0;
  }
 
CView::OnTimer(nIDEvent);
}

void CSnakeView::OnInitialUpdate() 
{  //初始化蛇有四个节点,每个节点的坐标
	CView::OnInitialUpdate();
    Snake[0].x=15;
    Snake[0].y=10;
    Snake[1].x=16;
    Snake[1].y=10;
    Snake[2].x=17;
    Snake[2].y=10;
    Snake[0].direct=3;
    Snake[0].len=3;
    Food.isfood=1;//食物默认1有
	// TODO: Add your specialized code here and/or call the base class
	
}

CSnakeView::oninit()
{//函数画一个矩形,用当前的画笔画矩形轮廓,用当前画刷进行填充
    CDC *pDC=GetDC();
    CBrush DrawBrush=(RGB(255,217,255));
    CBrush *Drawbrush=pDC->SelectObject(&DrawBrush);
    for(int i=0;i<=Snake[0].len-1;i++)
        pDC->Rectangle(Snake[i].x*20,Snake[i].y*20,(Snake[i].x+1)*20,(Snake[i].y+1)*20);
    pDC->SelectObject(DrawBrush);
}

void CSnakeView::OnStart() 
{
	SetTimer(1,3000,NULL);
	AfxMessageBox("             开始游戏              \n\n             3秒后开始游戏                ");

}

void CSnakeView::OnPause() 
{
	KillTimer(1);
    AfxMessageBox("           休息一下吧                 ");
}

void CSnakeView::OnExit() 
{
	AfxMessageBox("            退出咯                  ");
    exit (0);
}

void CSnakeView::OnContinue() 
{
	SetTimer(1,150,NULL);
}

void CSnakeView::OnAppAbout() 
{
	AfxMessageBox("        键盘控制蛇移动      \n\n        每吃到一个食物加10分          \n\n          吃得越多移动得越快             ");
}
最后

这个代码是我参考了一些网上的例子以及一些Cview编程的知识写出来的,可能会有一些bug,我会尽量的去完善它。
然后这个例子真的很有用,建议初学者都能自己动手尝试一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值