贪吃蛇游戏开发
一、需求分析
1、该贪吃蛇设计主要具有吃食、暂停、开始以及重新开始游戏。
2、主要目标:本游戏实现贪吃蛇在制定空间去吃随机出现的方块。游戏可以暂停,如不满意这一次游戏的成果还能重新开始游戏。
二、项目设计
1、流程设计
程序流程图
2、游戏具体设计:
(1) 蛇移动的实现
蛇的移动方向主要受头结点控制,所以每次画蛇时只要把前一结点的值赋给后 一节点即可。 当蛇头的移动方向向右时,y 值不变 x 的值不断增加。 当蛇头的移动方向向左时,y 值不变 x 的值不断减少。 当蛇头的移动方向向下时,y 值增加 x 的值不变。 当蛇头的移动方向向上时,y 值减小 x 的值不变。
(2) 蛇死亡的判断 当蛇头的值与蛇身或与墙的值相等时,蛇即算死亡.
(3)蛇到达边框时从另一端出现和传送的实现 当蛇头的 x 或 y 值达到边框的最大或最小位置时相应的给 x 或 y 赋以边框的最 小或最大值以实现当蛇到达边框时能从另一端出来,同理当蛇头的 x,y 值等于传 送点位置的值时将蛇头 x,y 的值赋以被传送到位置的值,这样将实现蛇的传送功 能。
三、项目实现
①蛇身颜色、最大长度及速度
int speed;//设置蛇的速度
int maxLen;//设置蛇的最大长度
②随机生成食物
产生随机种子:
qsrand(QTime().currentTime().msec());
定义食物的坐标、形状及颜色:
int mx = (qrand()%(w/20))*20;
int my = (qrand()%(h/20))*20;
food = new QLabel(this);
food->move(mx,my);
food->resize(20,20);//食物大小
food->setAutoFillBackground(true);//设置食物自动填充背景颜色
food->setFrameShape(QFrame::Box);//设置形状
food->setFrameShadow(QFrame::Sunken);
food->setPalette(QPalette(
QColor(qrand()%255,qrand()%110,qrand()%255)));//改变调色板的颜色
return food;
③方向控制及按键事件处理
方向控制:
switch(d)
{
case d_up:
nheady-=speed;break;
case d_down:
nheady+=speed;break;
case d_left:
nheadx-=speed;break;
case d_right:
nheadx+=speed;break;
}
按键事件处理:
void snake::keyPressEvent(QKeyEvent *f)
{
if(f->key()==Qt::Key_Up)
{
d=d_up;
}
else if(f->key()==Qt::Key_Down)
{
d=d_down;
}
else if(f->key()==Qt::Key_Left)
{
d=d_left;
}
else if(f->key()==Qt::Key_Right)
{
d=d_right;
}
}
④食物的显示与蛇吃食物
食物显示:
data.push_back(getFood());//将吃到的食物添加在蛇身之后
timer = new QTimer();//初始化时钟
timer->setInterval(400);//设置时钟周期
timer->start();
connect(timer,SIGNAL(timeout()),this,SLOT(move()));//传递信号
food = getFood();
food->show();
蛇吃食物:
if((nheadx==foodx)&&(nheady==foody))
{
data.push_back(food);
food = getFood();
food->show();
}
游戏截图1
游戏截图2
游戏截图3
游戏截图4
⑤游戏结束条件
if(data.size()>=10)
{
QMessageBox msg(this);
msg.setText("game over!");
msg.setStandardButtons(QMessageBox::Yes|QMessageBox::No);
msg.show();
if(msg.exec()==QMessageBox::Yes)
{
this->close();
}
}
四、总结
经过10天的培训,让我进一步熟悉了Linux系统下命令的使用、文件的编写与调试,更熟悉了以前所学的C++语言,让我对我所学习的计算机更加了解喜欢,也更加希望自己能学好计算机方面的设计,去设计更多有意思的游戏。
也非常感谢培训老师这些天对我们的悉心教导,让我们学到了很多东西。
五、附录
1、主函数代码
#include <QtGui/QApplication>
#include "snake.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
snake w;
w.show();
return a.exec();
}
2、头文件代码
#ifndef SNAKE_H
#define SNAKE_H
#include <QDialog>
#include <QLabel>
#include <QList>
//枚举四个方向
enum Direction{d_up,d_down,d_left,d_right};
namespace Ui {
class snake;
}
class snake : public QDialog {
Q_OBJECT
private:
QLabel* food;//食物
QList<QLabel*> data;//列表
int speed;//设置蛇的速度
int maxLen;//设置蛇的最大长度
Direction d;//方向
QTimer* timer;//定时器计时
public:
snake(QWidget *parent = 0);
~snake();//虚构函数
QLabel* getFood();
public slots:
void move();
protected:
void changeEvent(QEvent *e);
void keyPressEvent(QKeyEvent *);//按键事件处理
void TimerEvent(QTimerEvent *);//定时器事件处理
private:
Ui::snake *ui;
};
#endif // SNAKE_H
3、功能实现代码
#include "snake.h"
#include "ui_snake.h"
#include <QMessageBox>
#include <QTimer>
#include <QTime>
#include <QKeyEvent>
#include <time.h>
#include <QColor>
#include <QPalette>
#include <QApplication>
#include <QFrame>
snake::snake(QWidget *parent) :
QDialog(parent),
ui(new Ui::snake)
{
ui->setupUi(this);
speed =20;//速度
qsrand(QTime().currentTime().msec());//产生随机种子
this->resize(400,400);//窗口大小
d = d_right;//默认方向
data.push_back(getFood());//将吃到的食物添加在蛇身之后
timer = new QTimer();//初始化时钟
timer->setInterval(400);//设置时钟周期
timer->start();
connect(timer,SIGNAL(timeout()),this,SLOT(move()));//传递信号
food = getFood();
food->show();
maxLen = 10;//蛇身最大长度
}
snake::~snake()
{
delete ui;
//从集合中移除位于指定索引位置的对象
while(data.size()>0)
{
delete data[0];
data.removeAt(0);
}
}
QLabel* snake::getFood()
{
//定义窗口的高度和宽度
int w = this->width();
int h = this->height();
//定义食物的坐标
int mx = (qrand()%(w/20))*20;
int my = (qrand()%(h/20))*20;
food = new QLabel(this);
food->move(mx,my);
food->resize(20,20);//食物大小
food->setAutoFillBackground(true);//设置食物自动填充背景颜色
food->setFrameShape(QFrame::Box);//设置形状
food->setFrameShadow(QFrame::Sunken);
food->setPalette(QPalette(
QColor(qrand()%255,qrand()%110,qrand()%255)));//改变调色板的颜色
return food;
}
void snake::move(){
//获取蛇头坐标
int nheadx = data[0]->x();
int nheady = data[0]->y();
//获取食物坐标
int foodx = food->x();
int foody = food->y();
//吃食物
if((nheadx==foodx)&&(nheady==foody))
{
data.push_back(food);
food = getFood();
food->show();
}
//设置结束条件
if(data.size()>=10)
{
QMessageBox msg(this);
msg.setText("game over!");
msg.setStandardButtons(QMessageBox::Yes|QMessageBox::No);
msg.show();
if(msg.exec()==QMessageBox::Yes)
{
this->close();
}
}
//按键事件
switch(d)
{
case d_up:
nheady-=speed;break;
case d_down:
nheady+=speed;break;
case d_left:
nheadx-=speed;break;
case d_right:
nheadx+=speed;break;
}
for(int i=data.size()-1;i>0;i--)
{
data[i]->move(data[i-1]->x(),data[i-1]->y());
}
data[0]->move(nheadx,nheady);
}
//按键事件处理
void snake::keyPressEvent(QKeyEvent *f)
{
if(f->key()==Qt::Key_Up)
{
d=d_up;
}
else if(f->key()==Qt::Key_Down)
{
d=d_down;
}
else if(f->key()==Qt::Key_Left)
{
d=d_left;
}
else if(f->key()==Qt::Key_Right)
{
d=d_right;
}
}
//时钟事件处理
void snake::TimerEvent(QTimerEvent *)
{
move();
}
void snake::changeEvent(QEvent *e)
{
QDialog::changeEvent(e);
switch (e->type())
{
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
第二篇:贪吃蛇计算机实习报告 北京邮电大学
年计算机实习报告
计算机实习报告
姓名: xxx
班级: xxx
学号: xxx
小班序号:xxx
指导老师:xxx
题目:MFC简易贪吃蛇程序 邮箱:xxx
20xx年9月9日1 2012
20xx年计算机实习报告
MFC简易贪吃蛇程序实验报告
一.功能说明
1.1总体功能说明
主要功能为实现MFC简易贪吃蛇游戏的运行。具体功能:1、能够实现游戏的开始、暂停、继续和结束;2、能够显示游戏成绩;3、在贪吃蛇蛇身的加长过程中,通过改变蛇爬行的速度来改变游戏难度。4、游戏结束可重新开始游戏;5、能够显示贪吃蛇和食物所处的坐标。
主要特色为运用MFC编程,游戏界面友好,简洁、操作简单易懂,快捷键操作使游戏的暂停和继续更为方便,使得玩家在操作过程中感到轻松愉快。
1.2用户界面
游戏运行时:
游戏结束时:
20xx年9月9日 2
20xx年计算机实习报告
显示鼠标处坐标:
游戏主界面如上图。实现游戏的所有功能:游戏的开始、运行、暂停、继续和退出。
显示鼠标点击处坐标
1.3使用方法
单击“开始游戏”,弹出对话框“3秒之后开始游戏”,点按确定之后蛇开始移动。通过键盘的“↑”“↓”“←”“→”可控制蛇的移动,每吃一个食物增加一节蛇身长度。游戏过程中可通过“游戏”下拉菜单中选择“暂停”暂停游戏并继续游戏。若撞到边界或撞到蛇身游戏结束,弹出对话框提示得分情况,游戏结束。可通过点击“开始游戏”重新开始游戏。
游戏难度通过控制蛇的移动速度来实现,随蛇身长度的增加而增加。蛇身长度每增加三节到五节,速度增加一次。
20xx年9月9日 3
20xx年计算机实习报告
二.程序设计说明
具体模块划分:
1 定义蛇类和食物类,初始化贪吃蛇各项成员变量,包括图像的出现在屏幕的初始位置,长度,以及蛇头的行走方向。食物类的定义包括出现的初始位置,以及食物是否被吃掉的判断。
2 用数组初始化长度为3的贪吃蛇,并且默认食物未出现 3 在CView类上运用MFC提供的Windows消息中WM_TIMER消息,运用OnTimer()函数让系统提供一个时钟节拍,更新游戏
4 具体游戏实现,包括蛇撞到自己和围墙都将使游戏结束,判断吃豆等,其中还包括根据蛇的长度来进行游戏难度的改变。
5 具体键盘游戏操作运用到Windows消息响应中的WM_KEYDOWN,用OnKeyDown()来响应玩家的实际操作。
20xx年9月9日 4
20xx年计算机实习报告
2.2 关键算法描述
//根据蛇的长度设计游戏难度
CString soure;
if(Snake[0].len==3)SetTimer(1,300,NULL);
if(Snake[0].len==8)SetTimer(1,250,NULL);
if(Snake[0].len==13)SetTimer(1,200,NULL);
if(Snake[0].len==18)SetTimer(1,150,NULL);
if(Snake[0].len==23)SetTimer(1,100,NULL);
if(Snake[0].len==28)SetTimer(1,95,NULL);
if(Snake[0].len==33)SetTimer(1,90,NULL);
if(Snake[0].len==38)SetTimer(1,80,NULL);
if(Snake[0].len==45)SetTimer(1,60,NULL);
if(Snake[0].len==50)SetTimer(1,55,NULL);
if(Snake[0].len==55)SetTimer(1,50,NULL);
if(Snake[0].len==60)SetTimer(1,45,NULL);
if(Snake[0].len==65)SetTimer(1,40,NULL);
if(Snake[0].len==75)SetTimer(1,35,NULL);
if(Snake[0].len==100)SetTimer(1,25,NULL);
if(Snake[0].len==400)SetTimer(1,10,NULL);
soure.Format("Game over得分:%d!",(Snake[0].len-3)*10); //游戏结束时输出文本
//撞界判断
if(Snake[0].x*20<=45||Snake[0].y*20<=45||Snake[0].x*20>=630||Snake[0].y*20>=630)
20xx年9月9日 5
20xx年计算机实习报告
{
KillTimer(1);
AfxMessageBox(soure);
}
//蛇身相撞判断
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);
}
}
//
pDC->SelectStockObject(WHITE_PEN); //把白色的“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;
} //贪吃蛇移动的实现
//行走方向判断(1:上 2:下 3:左 4:右)
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); //把黑色的“PEN”选入设备进行画图
CBrush DrawBrush=(RGB(153,51,250)); //定义画刷
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)
{
20xx年9月9日 6
20xx年计算机实习报告
Snake[0].len++;
Food.isfood=0;
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==0)
{
srand((unsigned)time(NULL));
do
{
Food.x=rand()%50;
Food.y=rand()%50;
}
while(Food.x*20<65||Food.y*20<65||Food.x*20>630||Food.y*20>630);
pDC->Rectangle(Food.x*20,Food.y*20,(Food.x+1)*20,(Food.y+1)*20);
Food.isfood=1;
}
//生成蛇身之外的食物
for(int k=0;k<=(Snake[0].len+1);k++)
{
if(Food.x*20==Snake[k].x*20&&Food.y*20==Snake[k].y*20)
Food.isfood=0;
}
…..
2.3 程序设计的难点和关键点
1、贪吃蛇蛇身的移动的表现;
2、贪吃蛇身的加长的表现;
3、食物在游戏区域的随机产生;
4、蛇身速度的控制;
5、游戏背景的填充以及使用画刷画出贪吃蛇以及食物。
2.4 调试的方法
游戏过程中会某些时候会出现食物无法出现的情况。经反复测试发现原因如下:蛇移动是通过将蛇尾扫过区域用画刷画成白色实现
20xx年9月9日 7
20xx年计算机实习报告
的,而食物的随机坐标若恰好出现在蛇身覆盖区域,则蛇尾扫过之后就会变成背景的白色,造成食物看不见的现象。
解决办法:增加一个if条件语句,判断食物坐标是否与蛇身坐标重合,若重合则重新产生食物坐标。
另外,游戏过程中有时会出现食物出现在游戏地图外围的情况,经测试原因为:在编程过程中,未能正确确定食物出现是横纵坐标的限制。
解决办法:严密计算食物横纵坐标与地图外围坐标的关系,正确设立食物出现的限制。
2.5 程序性能评价
[从运行效果上进行分析,找出程序的优点和不足]
优点:由于MFC操作的简易性以及界面的简洁性,友好型,程序的操作简单易懂,快捷键的加入更是方便了用户操作。计分系统和重难度模式的加入增加了游戏的可玩性。
不足:鉴于对MFC了解的程度,该游戏功能过于简单,不能选择游戏难度、也没有英雄榜、背景音乐等,游戏界面不美观。
[从程序设计上进行分析,找出程序的优点和不足]
优点:用于实现主要功能的代码简洁易懂,条理清晰,注释部分讲解详细
缺点:鉴于对MFC的了解程度,还存在很多非必需的代码;产生蛇身之外食物的算法虽然简单易懂,但是在实际游戏操作中会有延迟现象,仍需改进。
20xx年9月9日 8
20xx年计算机实习报告
三.心得体会
在这次小学期中,最大的感受是——知识来源于实践。这个小学期之前,我对MFC一无所知,但在一步一步摸索着应用MFC编写程序的过程中,我慢慢了解了控件、消息,学会为按键设置快捷键、设计菜单…..每一次的实践都教会我许多,而每一次探索之后得到的快乐,是比从书上获得知识更快乐的。
通过运用MFC编程,我真切地感受到了它的便捷。它自动生成的代码省去的很多繁琐的初始化代码,自动生成一个运行程序框架,大大简化了编程。它提供的有关图形绘制的函数以及对消息的响应都为贪吃蛇一类的图形化游戏提供了良好的编程环境。
除去MFC强大的图形绘制功能、计时器功能,程序的主体部分很多都是运用C++课堂上教授的基础知识实现的。这也让我懂得了基础知识的重要性。在今后学习C++的过程中,不仅要学会运用图形化编程,更要研究其中的函数原型等知识,充分运用和实践C++的基础知识,从而达到温故知新。
2012.9.9
20xx年9月9日 9