辽 宁 科 技 大 学
课程设计说明书
设计题目: 基于C#的贪吃蛇游戏
学院、系: 装备制造学院
专业班级: 计算机科学与技术
学生姓名: 叶佳佳
指导教师: 丁宁
成 绩:
2015年 12月 12日
首先应该了解设计要求,然后按照功能设计出实际模块,每个模块都要完成特定的功能,要实现模块间的高内聚,低耦合。设计模块是一个相当重要的环节,模块的数量不宜太多,也不宜太少,要是每个模块都能比较简单的转换成流程图。模块设计完成后,就该给每个模块绘制流程图。流程图要尽可能的简单且容易理解,多使用中文,补一些过长的代码,增加理解难度。此外,流程图应容易转换成代码。
根据流程图编写好代码后在WindowsXP操作系统,VS.NET2008开发环境下进行运行测试,检查错误,最终设计出可行的程序。
游戏操作要尽可能的简单,界面要尽可能的美观。
编写程序实现贪吃蛇游戏,贪吃蛇游戏是一个深受人们喜欢的游戏:一条蛇在密闭的围墙内,在围墙内随机出现一个食物,通过键盘上的四个光标键控制蛇向上下左右四个方向移动,蛇头撞到食物,则表示食物被吃掉,这时蛇的身体长一节,同时计10分;接着又出现食物,等待被蛇吃掉,如果蛇在移动过程中,撞到墙壁、障碍物或身体交叉(蛇头撞到自己的身体),则游戏结束。游戏结束时输出相应得分。
具体要求有以下几点:
(1)对系统进行功能模块分析、控制模块分析正确,符合课题要求,实现相应功能;可以加以其他功能或修饰,使程序更加完善、合理;
(2)系统设计要实用,采用模块化程序设计方法,编程简练、可用,功能全面;
(3)说明书、流程图要清楚;
.NET课程设计是教学实践环节中一项重要内容,进行此课程设计旨在掌握基础知识的基础上,进一步加深对VC#.NET技术的理解和掌握;
提高和加强学生的计算机应用及软件开发能力,使学生具备初级程序员的基本素质;
培养学生独立分析问题、解决问题、查阅资料以及自学能力,以适应信息管理行业日新月异的发展形势;
本次课程设计是以学生独立思考解决问题为主,教师指导为辅,结合上机操作,完成指定的任务,做出设计报告。
利用Microsoft Visual Studio 2008 平台设计制作一个贪吃蛇小游戏,要求如下:
(1) 能够记录游戏成绩(计分按照每吃一块食物增加20累计)
(2) 可以暂停/继续游戏(通过按钮实现)
(3) 蛇的身体能够随着吃到食物的数量逐渐变长
(4) 可以自己添加障碍物,要求设计成红色墙壁
(5) 积分每增加50分要求蛇相应的加快速度
(6) 要求在游戏的过程中添加背景音乐和随机炸弹
程序关键在于表示蛇的图形及蛇的移动。用一个小矩形快表示蛇的一节身体,身体每长一节,增加一个矩形块,蛇头(绿色)用三节表示。移动时必须从蛇头开始,所以蛇不可以向相反的方向移动,如果不按任意键,蛇自行在当前方向右前移,但按下有效方向键后,蛇头朝该方向移动,一步移动一节身体,所以按下有效方向键后,先确定蛇头的位置,而后蛇的身体随蛇头移动,图形的实现是从蛇头新位置开始画出蛇,这时,由于未清屏的原因,原来的蛇的位置和新的位置差一个单位,所以看起来蛇多一节身体,所以将蛇的最后节用背景色覆盖。食物的出现与消失也是画矩形块和覆盖矩形块。为了便于理解,定义两个结构体:食物与蛇,同时还定义了一个随意的墙。然后利用图形驱动,,制作美观的游戏界面,通过随机函数产生随机的食物,控制游戏过程食物的出现。定义键盘操作控制游戏过程蛇的移动方向,画出边界,并判断游戏是否结束,统计游戏过程中蛇吃的食物数量,计算并输出游戏成绩。
1.snake的设计模块
2. Form 的设计模块
1.3、主函数流程图
首先进入VS2008打开文件新建一个项目,点击windows窗体应用程序,名字设为Snakes 。进入Form的设计界面,首先我们都知道游戏最基本的功能有开始,暂停,继续,退出,所以首先要先加4个button键来控制游戏,再加一个TextBox文本框来显示成绩。在窗体中加入Panel来实现贪吃蛇的运动空间,设置有一个游戏的界面运动空间。之后就要定义一个sakes类,来实现蛇的一些属性与方法,首先明白这个游戏实现的是贪吃蛇吃食物,所以还需要定义食物,食物被吃后要实现食物的重建。玩游戏时还需要有控制键的设置,这一模块可以选用Switch语句来实现。实现基本的功能后要注意怎样的情况会造成蛇的死亡,可以想到的有越界线,咬到自己都会死亡。随着思想的成熟,觉得只吃食物好像太简单,所以在这个贪吃蛇游戏的基础上又设置了一些障碍,加了几堵墙,还设置了随机的炸弹,这样游戏就更有意思了,加上以前玩俄罗斯方块的一些感觉,还设置了游戏的不断加速的模块。
1、snake 属性定义
2、Form 属性定义
3、创建蛇的模块
创建蛇的模块和创建障碍物的思路想法是一致的,都是通过label实现:
4、创建食物模块
创建食物模块和创建随机炸弹思路是一致的,都是在一定范围内随机出现。
通过坐标点的方法来实现食物,食物是随机出现的,而且一旦被吃掉就会立刻创建新的食物。而且还需要判断食物出现的地方时是否与墙壁重合。
5、蛇吃食物的模块
通过Timer 控件来设置时间,,吃到食物之后身体增长,蛇的身体颜色是三色交替出现,每吃到一个食物积分加10,身体加长对应增长。而且还要判断是否需要更改蛇的运行速度。
7、是否撞到自己模块
当贪吃蛇自己碰到自己的身体时游戏结束
8、游戏结束模块
9、初始化panel
10、初始化Form并添加背景音乐(Kalimba.wav)
11、控制蛇的运动方向
(1)在实现撞障碍物的过程中,刚刚开始的时候墙不能起作用,贪吃蛇总是能穿过障碍物,后来才发现时障碍物的设置范围出现了错误。经过不停的尝试与计算才算出正确的范围。
(2)在实现固定墙的过程中是通过使用Label来实现的,跟创建贪吃蛇的思想是一样的,但是在运行过程中刚刚开始的时候不出现障碍物,后来在老师的帮助下发现原来少一句话,需要在NowStar()函数中增加障碍物的显示
for (int i = 0; i
{ this.panel1.Controls.Add((Label)sk.Wall[i]);}
(3)在玩游戏的过程中发现食物会与墙壁还有炸弹重合的情况,然后通过分析原因,这与构造食物时判断食物与身体是否接触的道理是一样的,这里需要加一个循环语句来判断,如果不是墙的话才在这里创造食物。
(4)在创造炸弹的实现过程中,总是在炸弹的右半边任何位置都爆炸,通过一步一步的调试检查是在判断语句时右侧的范围太大,导致有半侧没有炸弹也爆炸。通过调试找到正确的范围。
(1) 游戏运行主界面
(2)帮助界面
(3)结束界面
这次的课设对我来说有很大的收获,我学到了许多课本上没有学到的知识,这次我将将课本上的理论知识充分的转化成了一些实用技能。通过这次自己制作的软件,丰富了自己的实践技能,扩展课本专业的知识面。在这次设计的同时,我又从中学到了许多东西。但由于我对这样的软件开发还只是一个开始,了解的不多,这其中或许还有很多的不足,有些模块做的不是很好,界面的设计及整体的布局还是比较简单。
此外,在这一次的课程设计过程中,我上网查阅了大量的资料,对C#有了更深的理解,对于软件工程这些辅助性的教材也巩固了不少,为我这次的课设提供了很大的帮助,锻炼了我的能力。更重要的是,它还让我认识到了自己的不足之处,在编程方面,我还是比较欠缺,以后的路任重道远,我需要的事不断地丰富自己,充实自己,这样才能在程序设计方面有所收获。
最后感谢老师在这次课程设计中对我们的悉心教导,通过这次学习,让我们掌握了很多有关C#.NET的应用知识。
[1] 陈俊荣. ASP与网络数据库技术[M]. 北京:中国铁道出版社,2005.
[2] 张绣兰. ASP网站建设实录[M]. 北京:北京希望电子出版社. 2008.
[3] 李华. DreamWeaver8网页设计程序教程[M]. 北京:清华大学出版社. 2004.
[4] 江开耀. 软件工程[M]. 西安:西安电子科技大学出版社.
snake源代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Drawing;
using System.ComponentModel;
using System.Data;
namespace Snake
{
class snake
{
public Point food_p;//定义食物的位置
private Label food; //定义食物
public Label Food //食物属性
{
get { return food; }
set { food = value; }
}
private List body = new List(); //定义食物定义食物链表
public List Body //食物链表属性
{
get { return body; }
set { body = value; }
}
//定义障碍物 上下左右各面墙 蛇撞墙即死
private List wall = new List();
public List Wall
{
get{ return wall; }
set { wall = value; }
}
private List wall1 = new List();
public List Wall1
{
get { return wall1; }
set { wall1 = value; }
}
private List wall2 = new List();
public List Wall2
{
get { return wall2; }
set { wall2 = value; }
}
private List wall3 = new List();
public List Wall3
{
get { return wall3; }
set { wall3 = value; }
}
public void CreateSnake()//使用Label进行创建一个蛇
{
int left = 20;
Label lb;
for (int i = 0; i < 2; i++)
{
lb = new Label();
lb.Name = "label" + i.ToString();
lb.BackColor = Color.Green;
lb.Width = 10;
lb.Height = 10;
lb.Top = 0;
lb.Left = left;
body.Add(lb);
left -= 10;
}
}
public void CreateWall()//使用Label进行创建障碍物
{
int left = 200;
Label lb0;
for (int i = 0; i < 10; i++ )
{
lb0 = new Label();
lb0.Name = "label" + i.ToString();
lb0.BackColor = Color.Red;
lb0.Width = 10;
lb0.Height = 10;
lb0.Top = 50;
lb0.Left = left;
wall.Add(lb0);
left -= 10;
}
}
public void CreateWall1()
{
int left = 200;
Label lb1;
for (int i = 0; i < 10; i++)
{
lb1 = new Label();
lb1.Name = "label" + i.ToString();
lb1.BackColor = Color.Red;
lb1.Width = 10;
lb1.Height = 10;
lb1.Top = 310;
lb1.Left = left;
wall1.Add(lb1);
left -= 10;
}
}
public void CreateWall2()
{
int top = 200;
Label lb2;
for (int i = 0; i < 10; i++)
{
lb2 = new Label();
lb2.Name = "label" + i.ToString();
lb2.BackColor = Color.Red;
lb2.Width = 10;
lb2.Height = 10;
lb2.Left = 50;
lb2.Top = top;
wall2.Add(lb2);
top -= 10;
}
}
public void CreateWall3()
{
int top = 200;
Label lb3;
for (int i = 0; i < 10; i++)
{
lb3 = new Label();
lb3.Name = "label" + i.ToString();
lb3.BackColor = Color.Red;
lb3.Width = 10;
lb3.Height = 10;
lb3.Left = 260;
lb3.Top = top;
wall3.Add(lb3);
top -= 10;
}
}
//创建食物
public void CreateFood()
{
Random rand = new Random();
food_p.X = rand.Next(36) * 10;//限定食物物所能出现的横坐标
food_p.Y = rand.Next(36) * 10;//限定食物物所能出现的横坐标
for (int i = 0; i < body.Count; i++)
{
if (food_p.Y == ((Label)body[i]).Top && food_p.X == ((Label)body[i]).Left)
{
this.CreateFood();
break;
}
}
//判断食物和所见障碍物是否重合
for (int i = 0; i < wall.Count; i++)
{
if (food_p.Y == ((Label)this.Wall[i]).Top && food_p.X == ((Label)this.Wall[i]).Left)
{
this.CreateFood();
}
else if (food_p.Y == ((Label)this.Wall1[i]).Top && food_p.X == ((Label)this.Wall1[i]).Left)
{
this.CreateFood();
}
else if (food_p.X == ((Label)this.Wall2[i]).Left && food_p.Y == ((Label)this.Wall2[i]).Top)
{
this.CreateFood();
}
else if (food_p.X == ((Label)this.Wall3[i]).Left && food_p.Y == ((Label)this.Wall3[i]).Top)
{
this.CreateFood();
}
}
food = new Label();
food.Width = 10;
food.Height = 10;
food.Top = food_p.Y;
food.Left = food_p.X;
//加载食物图片
food.Image = Snake.Properties.Resources.food;
}
//蛇吃食物 通过timer进行速度的设置
public Panel EatFood(Panel panel1, Timer timer1, TextBox textBox1, TextBox textBox2)
{
if (((Label)body[0]).Top == food_p.Y && ((Label)body[0]).Left == food_p.X)
{
panel1 = this.DeFood(panel1);
Label lb = new Label();//增加蛇身
lb.Name = "label" + body.Count.ToString();
int i=body.Count%3;
if(i==0)
lb.BackColor = Color.DimGray;
else if(i==1)
lb.BackColor = Color.DeepPink;
else
lb.BackColor = Color.DeepSkyBlue;
lb.Width = 10;
lb.Height = 10;
lb.Top = ((Label)body[body.Count - 1]).Top;
lb.Left = ((Label)body[body.Count - 1]).Left;
body.Add(lb);
textBox1.Text = Convert.ToString(Convert.ToInt32(textBox1.Text) + 10);
textBox2.Text = textBox1.Text;
if (Convert.ToInt32(textBox2.Text) < Convert.ToInt32(textBox1.Text))
textBox2.Text = textBox1.Text;
//修改速度
if (textBox1.Text == "50")
timer1.Interval = 150;
else if (textBox1.Text == "100")
timer1.Interval = 100;
else if (textBox1.Text == "150")
timer1.Interval = 80;
else if (textBox1.Text == "200")
timer1.Interval = 50;
else if (textBox1.Text == "250")
timer1.Interval = 20;
}
return panel1;
}
//吃过后销毁再创建食物
public Panel DeFood(Panel panel1)
{
panel1.Controls.Remove(food);
this.CreateFood();
panel1.Controls.Add(food);
return panel1;
}
}
}
//Form 源代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Media;
namespace Snake
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private snake sk = new snake(); //构造一个蛇的对象
private int dir = 3; //初始时要运动的方向(向右)
private Point bomb_b; //定义炸弹
private Label bomb;
public void CreatBomb()//创建炸弹
{
Random rand = new Random();
bomb_b.X = rand.Next(20) * 10;
bomb_b.Y = rand.Next(20) * 10;
bomb = new Label();
bomb.Width = 10;
bomb.Height = 10;
bomb.Top = bomb_b.Y;
bomb.Left = bomb_b.X;
bomb.Image = Snake.Properties.Resources.b2;
//判断随机炸弹是否与随机食物重合
if (bomb_b.X == sk.food_p.X && bomb_b.Y == sk.food_p.Y)
{
CreatBomb();
}
}
//清除炸弹
public Panel DeBomb(Panel panel1)
{
panel1.Controls.Remove(bomb);
return panel1;
}
private int diring = -1; //正在运动的方向
private void button1_Click(object sender, EventArgs e) //开始
{
textBox1.Text = "0";
button3.Enabled = true;
timer1.Start();
panel1 = sk.DeFood(panel1);
this.CreatBomb();
panel1.Controls.Add(bomb);
}
private void button2_Click(object sender, EventArgs e) //暂停
{
timer1.Stop();
}
private void button3_Click(object sender, EventArgs e) //新游戏
{
textBox1.Text = "0";
timer1.Interval = 200;
button3.Enabled = false;
panel1.Controls.Clear();
sk.Body.Clear();
sk.CreateSnake();
NowStart();
dir = 3;
diring = -1;
timer1.Stop();
}
private void NowStart()//初始化
{
//再panel中添加蛇的身体
for (int i = 0; i < sk.Body.Count; i++)
{
this.panel1.Controls.Add((Label)sk.Body[i]);
}
//再panel中添加障碍物
for (int i = 0; i < sk.Wall.Count; i++)
{
this.panel1.Controls.Add((Label)sk.Wall[i]);
}
for (int i = 0; i < sk.Wall1.Count; i++)
{
this.panel1.Controls.Add((Label)sk.Wall1[i]);
}
for (int i = 0; i < sk.Wall2.Count; i++)
{
this.panel1.Controls.Add((Label)sk.Wall2[i]);
}
for (int i = 0; i < sk.Wall3.Count; i++)
{
this.panel1.Controls.Add((Label)sk.Wall3[i]);
}
}
private void GameOver() //结束游戏
{
panel1.Controls.Remove(sk.Food);
PictureBox over = new PictureBox();
over.Image = Snake.Properties.Resources.the_end;
over.Width = 360;
over.Height = 360;
this.panel1.Controls.Add(over);
timer1.Stop();
panel1 = this.DeBomb(panel1);
MessageBox.Show("你本次的得分为:" + textBox1.Text+",历史最高分为:"+textBox2.Text);
}
private void panel1_Paint(object sender, PaintEventArgs e) //初始化panel
{
NowStart();
}
private void Form1_Load(object sender, EventArgs e) //初始化Form创建蛇的对象
{
sk.CreateSnake();
sk.CreateWall();
sk.CreateWall1();
sk.CreateWall2();
sk.CreateWall3();
this.CreatBomb();
SoundPlayer music = new SoundPlayer(@"H:\Kalimba.wav");
music.Play();
//this.Draws();
}
private void HitSelf() //撞击自己
{
for (int i = 1; i < sk.Body.Count; i++)
{
if (((Label)sk.Body[0]).Top == ((Label)sk.Body[i]).Top && ((Label)sk.Body[0]).Left == ((Label)sk.Body[i]).Left)
{
GameOver();
break;
}
}
}
public void move()//控制蛇的前进
{
for (int i = sk.Body.Count - 1; i > 0; i--)
{
//判断是否撞墙(所建的障碍物)
if (((Label)sk.Body[0]).Top == ((Label)sk.Wall[i]).Top && (((Label)sk.Wall[i]).Left - 90 <= ((Label)sk.Body[0]).Left && ((Label)sk.Body[0]).Left <= ((Label)sk.Wall[i]).Left + 20))
{
GameOver();
break;
}
else if (((Label)sk.Body[0]).Top == ((Label)sk.Wall1[i]).Top && (((Label)sk.Wall1[i]).Left - 90 <= ((Label)sk.Body[0]).Left && ((Label)sk.Body[0]).Left <= ((Label)sk.Wall1[i]).Left + 20))
{
GameOver();
break;
}
else if (((Label)sk.Body[0]).Left == ((Label)sk.Wall2[i]).Left && (((Label)sk.Wall2[i]).Top -90 <= ((Label)sk.Body[0]).Top && ((Label)sk.Body[0]).Top<= ((Label)sk.Wall2[i]).Top + 20))
{
GameOver();
break;
}
else if (((Label)sk.Body[0]).Left == ((Label)sk.Wall3[i]).Left && (((Label)sk.Wall3[i]).Top - 90 <= ((Label)sk.Body[0]).Top && ((Label)sk.Body[0]).Top <= ((Label)sk.Wall3[i]).Top + 20))
{
GameOver();
break;
}
//判断是否撞上炸弹
else if (bomb_b.Y == ((Label)sk.Body[0]).Top && bomb_b.X == ((Label)sk.Body[0]).Left)
{
GameOver();
break;
}
else if (dir == 0 && diring != 1)//Up//运动方向
{
((Label)sk.Body[i]).Top = ((Label)sk.Body[i - 1]).Top;
((Label)sk.Body[i]).Left = ((Label)sk.Body[i - 1]).Left;
if (i == 1)
{
((Label)sk.Body[0]).Top -= 10;
panel1 = sk.EatFood(panel1, timer1, textBox1, textBox2);
HitSelf();
}
if (((Label)sk.Body[0]).Top < 0)
{
GameOver();
break;
}
}
else if (dir == 1 && diring != 0)//Down
{
((Label)sk.Body[i]).Top = ((Label)sk.Body[i - 1]).Top;
((Label)sk.Body[i]).Left = ((Label)sk.Body[i - 1]).Left;
if (i == 1)
{
((Label)sk.Body[0]).Top += 10;
panel1 = sk.EatFood(panel1, timer1, textBox1, textBox2);
HitSelf();
}
if (((Label)sk.Body[0]).Top > 360)
{
GameOver();
break;
}
}
else if (dir == 2 && diring != 3)//Left
{
((Label)sk.Body[i]).Top = ((Label)sk.Body[i - 1]).Top;
((Label)sk.Body[i]).Left = ((Label)sk.Body[i - 1]).Left;
if (i == 1)
{
((Label)sk.Body[0]).Left -= 10;
panel1 = sk.EatFood(panel1, timer1, textBox1, textBox2);
HitSelf();
}
if (((Label)sk.Body[0]).Left< 0)
{
GameOver();
break;
}
}
else if (dir == 3 && diring != 2)//Right
{
((Label)sk.Body[i]).Top = ((Label)sk.Body[i - 1]).Top;
((Label)sk.Body[i]).Left = ((Label)sk.Body[i - 1]).Left;
if (i == 1)
{
((Label)sk.Body[0]).Left += 10;
panel1 = sk.EatFood(panel1, timer1, textBox1, textBox2);
HitSelf();
}
if (((Label)sk.Body[0]).Left > 360)
{
GameOver();
break;
}
}
else//逆向
{
GameOver();
break;
}
}
}
//timer控件具体实现
private void timer1_Tick(object sender, EventArgs e)
{
move();
}
//控制蛇的移动方向
protected override bool ProcessDialogKey(Keys keyData)
{
switch (keyData)
{
case Keys.Up:
dir = 0; break;
case Keys.Down:
dir = 1; break;
case Keys.Left:
dir = 2; break;
case Keys.Right:
dir = 3; break;
}
if (keyData == Keys.Up || keyData == Keys.Down || keyData == Keys.Left || keyData == Keys.Right)
{
return false;
}
else
{
return base.ProcessDialogKey(keyData);
}
}
private void button4_Click(object sender, EventArgs e) //退出
{
this.Close();
}
private void button5_Click(object sender, EventArgs e) //继续
{
timer1.Start();
}
private void button6_Click(object sender, EventArgs e) //帮助
{
MessageBox.Show("游戏介绍:\n" + "\n1、通过上下左右键控制蛇的移动。" + "\n2、蛇每吃一个食物伸长一节,积分加10。" + "\n3、每次积分增加50分时蛇的速度会相应的变快。" + "\n4、在运动的过程中蛇碰到墙壁或撞到自己时死亡。" + "\n5、黑色小块为炸弹,小心哦!!\n" + "\n。。。。。祝您好运。。。。。");
}
}
}
¥29.8
¥9.9
¥59.8