学 号:
课 程 设 计
2013——2014学年 第2学期
课程名称
可视化编程(VC) 学 院 计算机科学与技术学院
专 业
软件工程
班
级 姓 名 指导教师
岑 丽
目录
基于MFC的贪吃蛇游戏设计与实现 (1)
一.课设要求 (1)
二.简单操作及功能说明 (1)
三.模块功能说明 (2)
四.运行结果 (7)
五.设计过程中自己所遇到的问题及相应的解决方法和解决过程 (8)
六.心得体会 (10)
七.参考资料 (10)
八.附录(主要代码) (11)
基于MFC的贪吃蛇游戏设计与实现一.课设要求:
1.游戏界面设计
2.食物的初始化
3.游戏开始以及具体实现
二.简单操作及功能说明:
这是基于MFC的一个简单的贪吃蛇游戏的制作。他的具体实现在CView类中实现。上图为运行的结果。
(1)有两个简单的选项。
游戏的开始(start追寻荣耀吧);
暂停(歇一会儿呗。);
继续(继续圣战吧兔宝宝!);
离开(先撤了)。
由于这部分功能没什么用,就让他失效了。(2)能够实现简单的上下左右操作。
三.模块说明与介绍:
1.游戏开始功能
void CSnakeView::OnStart()
{
SetTimer(1,2500,NULL); AfxMessageBox("准备好游戏马上开始!"); }
2.游戏暂停功能
void CSnakeView::OnPause()
{
KillTimer(1);
AfxMessageBox("stop the game "); }
3.游戏继续功能
void CSnakeView::OnContinue() {
SetTimer(1,500,NULL);
}
4.游戏退出功能
void CSnakeView::OnExit()
{
AfxMessageBox("我会想念你的主人...");
exit(0);
}
5. 撞界判断
if(Snake[0].x*20<=37||Snake[0].y*20<=37||Snake[0].x*20>=462||Snake[ 0].y*20>=462)
{
KillTimer(1);
AfxMessageBox(soure);
// s=0;
}
6.蛇身相撞判断
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;
}
}
7.行走方向判断
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,192,203));
CBrush *Drawbrush=pDC->SelectObject(&DrawBrush);
pDC->Rectangle(Snake[0].x*20,Snake[0].y*20,(Snake[0].x+1)*20,(Snak e[0].y+1)*20);
pDC->SelectObject(DrawBrush);
8.判断吃豆的条件,撞到就吃
if(Snake[0].x*20==Food.x*20&&Snake[0].y*20==Food.y*20)
{
Snake[0].len++;
Food.isfood=1;
Snake[Snake[0].len-1].x=Snake[Snake[0].len-2].x;
Snake[Snake[0].len-1].y=Snake[Snake[0].len-2].y;
}
9.如果食物被吃了就生成
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<70||Food.y*20<70||Food.x*20>430||Food.y*20>430); pDC->Rectangle(Food.x*20,Food.y*20,(Food.x+1)*20,(Food.y+1)*20);
Food.isfood=0;
}
四.运行结果
开始游戏
食物的初始化
碰壁死显示得分
咬到自己死显示得分
五.设计过程中遇到的问题及相应的解决方法和解决过程。第一次做贪吃蛇,可以说是问题很多,在网上高人的指导和同学的帮助下,还是遇到过这些问题。
(1)蛇和食物的全局变量定义完后,由于对MFC的各个类不了解,一时不知道放在哪个代码中。后来意识到游戏的功能在cview中实现的,就把变量定义放入了csnakeview中。
(2)游戏的继续与退出功能。
void CSnakeView::OnExit()
{
AfxMessageBox("我会想念你的主人...");
exit(0);
}
void CSnakeView::OnContinue()
{
SetTimer(1,500,NULL);
}
之前定义两个功能的顺序刚好反一下,结果编译出来的结果一直错误。试着改了很多参数都没有用。后来才发现不是顺序的问题,是游戏继续功能的类向导忘记建立了。
(3)先前想把蛇身与食物的颜色区分开,但是发现运行之后,蛇身的初始颜色与之后的颜色不一样,最后还是把蛇身与食物改成了相同的颜色。
(4)修改窗口左上角图标。先前不知道如何修改图标,就在IDR_MAINFRAME中手画图标,看了网上的教程之后,就用ico修改了一个图标引入Icon中,并且在IDD_ABOUTBOX中也一并修改了图标,但是执行之后发现图标变是变了,变成可执行文件的标准图标了。后来把Icon中原有的图标删除后,重命名新的图标,把他改成原来图标的名字,就成功了。
六.心得体会
由于平时上课不够认真,自己课下看书经常找不到重点,这导致我在做课程设计时磕磕盼盼,开始做的时候,一发现编译错误,又不知道错在哪里,就把类里面的代码挨个点开,漫无边际的检查错误,看了半天没发现错误在哪里,也不认识代码讲的是什么,经过慢慢的摸索和不断的错误,不懂就问同学,上网查资料,终于完成了。
我觉得课程设计是一个很好的学习契机,他是从功能和应用出发的,从功能和应用我们可以知道我们需要掌握哪些知识,让我们直接从实践中学习,发现错误,并针对应用去学习,并改正错误,而且这样会让我们对知识有更深的印象和记忆,这也是对上课知识的补充和强化,更贴近应用领域,提高了我们动手实践的能力。
在这次课程设计中,我完成了贪吃蛇这一个小游戏,但是更多的,我知道了如何从功能和应用出发去完成MFC小游戏,也知道发现问题后,解决一类问题的方法,而不是一个问题,我觉得这是别的地方很难学来的,在这次课程设计学习后,我感觉真的收获很大。七.参考资料:
1.Visual c++ 面向对象与可视化程序设计(第2版)清华大学出版社黄维通编著
2.https://www.doczj.com/doc/451869153.html,/renyhui/article/details/21463517(MFC对话框贪吃蛇小游戏)
3.https://www.doczj.com/doc/451869153.html,/s/blog_6cbbf04b0100m49k.html(手把手教MFC贪吃蛇)
附录:程序的主要代码
// snakeView.cpp : implementation of the CSnakeView class #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
struct Snake
{
int x,y;
int len;
int direct;
}Snake[50];
struct Food
{
int x;
int y;
int isfood;
}Food;
// CSnakeView
IMPLEMENT_DYNCREATE(CSnakeView, CView) BEGIN_MESSAGE_MAP(CSnakeView, CView) //{{AFX_MSG_MAP(CSnakeView)
ON_WM_KEYDOWN()
ON_WM_TIMER()
ON_WM_RBUTTONDOWN()
ON_COMMAND(IDM_START, OnStart)
ON_COMMAND(IDM_PAUSE, OnPause)
ON_COMMAND(IDM_CONTINUE, OnContinue)
ON_COMMAND(IDM_EXIT, OnExit)
//}}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_V ALID(pDoc);
// TODO: add draw code for native data here
CBrush backBrush(RGB(123,104,238));
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(19,19,501,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*/) {
}
// 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) {
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);
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CSnakeView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CDC *pDC=GetDC();
CString soure;
if(Snake[0].len==2)SetTimer(1,370,NULL);
if(Snake[0].len==3)SetTimer(1,270,NULL);
if(Snake[0].len==6)SetTimer(1,200,NULL);
if(Snake[0].len==9)SetTimer(1,100,NULL);
soure.Format("bravo!score:%d!",(Snake[0].len-3)*10);
//撞界判断
if(Snake[0].x*20<=37||Snake[0].y*20<=37||Snake[0].x*20>=462||Snake[0].y*20>=46 2)
{
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[Sn ake[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,192,203));
CBrush *Drawbrush=pDC->SelectObject(&DrawBrush);
pDC->Rectangle(Snake[0].x*20,Snake[0].y*20,(Snake[0].x+1)*20,(Snake[0].y+1)*2 0);
pDC->SelectObject(DrawBrush);
//判断吃豆的条件,撞到就吃
if(Snake[0].x*20==Food.x*20&&Snake[0].y*20==Food.y*20)
{
Snake[0].len++;
Food.isfood=1;
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<70||Food.y*20<70||Food.x*20>430||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::OnRButtonDown(UINT nFlags, CPoint point)
{
CString str;
str.Format("%d,%d",point.x,point.y);
AfxMessageBox(str);
CView::OnRButtonDown(nFlags, point);
CView::OnRButtonDown(nFlags, point);
CView::OnRButtonDown(nFlags, point);
}
void CSnakeView::oninit()
{
CDC *pDC=GetDC();
CBrush DrawBrush=(RGB(255,192,203));
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::OnInitialUpdate()
{
CView::OnInitialUpdate();
Snake[0].x=10;
Snake[0].y=10;
Snake[1].x=11;
Snake[1].y=10;
Snake[2].x=12;
Snake[2].y=10;
Snake[0].direct=3;
Snake[0].len=3;
Food.isfood=1;
}
void CSnakeView::OnStart()
{
SetTimer(1,2500,NULL);
AfxMessageBox("准备好游戏马上开始!");
}
void CSnakeView::OnPause()
{
KillTimer(1);
AfxMessageBox("stop the game ");
}
void CSnakeView::OnExit()
{
AfxMessageBox("我会想念你的主人..."); exit(0);
}
void CSnakeView::OnContinue()
{
SetTimer(1,500,NULL);
}
本科课程论文评分标准
班级学号姓名
论文题目基于MFC的贪吃蛇游戏设计与实现
评阅点评分标准(细则)分值给分
功能及算
法(40分)正确实现本程序所需全部功能,算法设
计正确合理且有一定创意
40分实现所需功能,算法正确30分基本实现所需功能15分有明显重大错误5分无法实现程序功能0分
界面和操
作性(20分)界面美观、合理,可操作性强20分界面合理,可操作15分界面尚可,基本可操作10分可操作较差5分
程序可读、可维护性(15分)程序可读性好、逻辑清晰,程序完整,
可维护性好,
15分程序可读、可维护10分基本可读可维护5分逻辑混乱、不可读0分
论文质量(25分)论文规范,行文流畅,层次清晰25分
论文书写基本规范,文理较通畅20分
结构较合理,层次较清楚,基本符合要
求
15分
结构混乱,文不对题目,或者有明显抄
袭现象
5分
总分
教师签名: