欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#贪吃蛇游戏实现分析

程序员文章站 2024-02-08 19:50:46
今天无聊突发奇想做个贪吃蛇,虽然网上很多这东西了,不过自己写的感觉还行吧 贪吃蛇分析 游戏规则: 1、蛇起始长度5,每吃一个食物增加1,最大15过关 2、蛇用蓝...

今天无聊突发奇想做个贪吃蛇,虽然网上很多这东西了,不过自己写的感觉还行吧

贪吃蛇分析

游戏规则:

1、蛇起始长度5,每吃一个食物增加1,最大15过关

2、蛇用蓝色表示,食物用绿色,障碍物用黑色

3、当蛇碰到自己、墙壁、障碍物则游戏失败

4、方向键控制蛇的移动方向,蛇不可反方向移动,如正在向上移动,不能马上向下,只能向左、右、上运动

5、每过关一次速度提升一次

大概思路:

1、地图用网格的形式表示,蛇由方格组成,保存在list中

2、1中提到了方格,方格保存的内容有,颜色,坐标,是否可以通过,是否是食物

3、向前移动一次,将前面方格添加进蛇列表中,将列表最后一个移除,若为前方格子为食物,则不移除最后一个

4、使用while死循环来做整个移动

5、空格键为加速键,通过修改while循环sleep时间来实现加速

包括了3个类一个主窗体,分别是node(用来表示方格)、map(用来表示地图)、serpent(用来表示蛇),另外一个主窗体。下面依次把代码贴上,基本上每个方法都有注释

代码1:

using system;
using system.collections.generic;
using system.text;
using system.drawing;

namespace engorgeserpent
{
 /// <summary>
 /// 节点
 /// </summary>
 class node
 {
 #region 字段
 private int x;
 private int y;
 private int width = 10;
 private bool isfood = false;
 private bool ispass = true;//是否可通过
 private color bgcolor = color.fromargb(224, 224, 224);
 private color foodcolor = color.green;
 private color hindercolor = color.black;
 private color thiscolor;
 private color serpentcolor = color.chocolate;

 #endregion
 /// <summary>
 /// 设置食物参数
 /// </summary>
 /// <param name="_isfood"></param>
 public void setfood(bool _isfood)
 {
  isfood = _isfood;
  if (_isfood)
  {
  thiscolor = foodcolor;

  }
  else
  {
  thiscolor = bgcolor;
  }
 }

 /// <summary>
 /// 设置障碍物参数
 /// </summary>
 /// <param name="_ishinder">是否为障碍物</param>
 public void sethinder(bool _ishinder)
 {
  ispass =! _ishinder;
  if (_ishinder)
  {
  thiscolor = hindercolor;
  }
  else
  {
  thiscolor = bgcolor;
  }
 }

 /// <summary>
 /// 设置蛇颜色
 /// </summary>
 /// <param name="_isserpent"></param>
 public void setserpent(bool _isserpent)
 {
  ispass = !_isserpent;
  if (_isserpent)
  {
  thiscolor = serpentcolor;
  }
  else
  {
  thiscolor = bgcolor;
  }
 }
 #region 构造函数
 public node()
 {
  thiscolor = bgcolor;
 }

 /// <summary>
 /// 有参构造方法
 /// </summary>
 /// <param name="_x">相对x坐标</param>
 /// <param name="_y">相对y坐标</param>
 /// <param name="_width">边长</param>
 /// <param name="_isfood">是否是食物</param>
 /// <param name="_ispass">是否可通过</param>
 public node(int _x, int _y, int _width, bool _isfood, bool _ispass)
 {
  thiscolor = bgcolor;
  x = _x;
  y = _y;
  width = _width;
  isfood = _isfood;
  ispass = _ispass;
 }

 /// <summary>
 /// 有参构造方法
 /// </summary>
 /// <param name="_x">相对x坐标</param>
 /// <param name="_y">相对y坐标</param>
 /// <param name="_width">边长</param>
 public node(int _x, int _y, int _width)
 {
  x = _x;
  y = _y;
  width = _width;
 }

 /// <summary>
 /// 有参构造方法
 /// </summary>
 /// <param name="_x">相对x坐标</param>
 /// <param name="_y">相对y坐标</param>
 public node(int _x, int _y)
 {
  x = _x;
  y = _y;
 }
 #endregion

 #region 属性
 /// <summary>
 /// 蛇颜色
 /// </summary>
 public color serpentcolor
 {
  get { return serpentcolor; }
 }

 /// <summary>
 /// 背景色
 /// </summary>
 public color bgcolor
 {
  get { return bgcolor; }
 }

 /// <summary>
 /// 食物颜色
 /// </summary>
 public color foodcolor
 {
  get { return foodcolor; }
 }

 /// <summary>
 /// 障碍物颜色
 /// </summary>
 public color hindercolor
 {
  get { return hindercolor; }
 }

 /// <summary>
 /// 当前颜色
 /// </summary>
 public color thiscolor
 {
  get { return thiscolor; }
  set { thiscolor = value; }
 }

 /// <summary>
 /// 获取或设置相对横坐标
 /// </summary>
 public int x
 {
  get { return x; }
  set { x = value; }
 }

 /// <summary>
 /// 获取或设置相对纵坐标
 /// </summary>
 public int y
 {
  get { return y; }
  set { y = value; }
 }

 /// <summary>
 /// 获取或设置节点边长
 /// </summary>
 public int width
 {
  get { return width; }
  set { width = value; }
 }

 /// <summary>
 /// 获取或设置是否为食物
 /// </summary>
 public bool isfood
 {
  get { return isfood; }
  set { isfood = value; }
 }

 /// <summary>
 /// 获取或设置是否可以通过
 /// </summary>
 public bool ispass
 {
  get { return ispass; }
  set { ispass = value; }
 }
 #endregion
 }
}

代码2:

using system;
using system.collections.generic;
using system.text;
using system.drawing;

namespace engorgeserpent
{
 /// <summary>
 /// 地图
 /// </summary>
 class map
 {
 /// <summary>
 /// 节点数组
 /// </summary>
 private list<list<node>> _nodes;
 private int rowcount;
 private int comscount;
 private color bgcolor = color.fromargb(224, 224, 224);
 private system.windows.forms.control mappanel;
 graphics g;
 /// <summary>
 /// 地图背景色 和node中背景色一致
 /// </summary>
 public color bgcolor
 {
  get { return bgcolor; }
 }
 /// <summary>
 /// 构造方法
 /// </summary>
 /// <param name="rows">行数</param>
 /// <param name="coms">列数</param>
 public map(int rows, int coms, system.windows.forms.control c)
 {
  rowcount = rows;
  comscount = coms;
  mappanel = c;
  g = c.creategraphics();
  _nodes = new list<list<node>>();
  for (int i = 0; i < rows; i++)//行
  {
  list<node> index = new list<node>();
  for (int j = 0; j < coms; j++)
  {
   node node = new node(j, i);
   index.add(node);
  }
  _nodes.add(index);
  }
 }

 /// <summary>
 /// 构造方法
 /// </summary>
 /// <param name="rows">行数</param>
 /// <param name="coms">列数</param>
 /// <param name="width">节点宽度</param> 
 public map(int rows, int coms, int width, system.windows.forms.control c)
 {
  rowcount = rows;
  comscount = coms;
  mappanel = c;
  g = c.creategraphics();
  _nodes = new list<list<node>>();
  for (int i = 0; i < coms; i++)//行
  {
  list<node> index = new list<node>();
  for (int j = 0; j < rows; j++)
  {
   node node = new node(j, i, width);
   index.add(node);
  }
  _nodes.add(index);
  }
 }

 /// <summary>
 /// 重新加载地图
 /// </summary>
 public void resetmap()
 {
  for (int i = 0; i < comscount; i++)//行
  {
  for (int j = 0; j < rowcount; j++)
  {
   node node = getnode(i, j);
   node.ispass = true;
   node.isfood = false;  
  }
  }
 }
 /// <summary>
 /// 获得节点
 /// </summary>
 /// <param name="x"></param>
 /// <param name="y"></param>
 /// <returns></returns>
 public node getnode(int x, int y)
 {
  return _nodes[y][x];
 }

 /// <summary>
 /// 设置食物
 /// </summary>
 public void setfood()
 {
  solidbrush brush = null;
  int _x, _y;
  random r = new random();
  while (true)
  {
  _x = r.next(0, rowcount);
  _y = r.next(0, comscount);
  if (_nodes[_x][_y].ispass)
  {
   break;
  }
  }
  node nodeindex = _nodes[_x][_y];
  nodeindex.setfood(true);
  brush = new solidbrush(nodeindex.foodcolor);
  rectanglef[] rects = { new rectanglef(nodeindex.x * nodeindex.width, nodeindex.y * nodeindex.width, nodeindex.width, nodeindex.width) };
  g.fillrectangles(brush, rects);
 }

 /// <summary>
 /// 设置障碍物
 /// </summary>
 /// <param name="list"></param>
 public void sethinder(list<node> list)
 {
  solidbrush brush = null;
  rectanglef[] rects = new rectanglef[list.count];
  for (int i = 0; i < list.count; i++)
  {
  node _node = list[i];
  _node.sethinder(true);
  _node.ispass = false;
  if (brush == null)
  {
   brush = new solidbrush(_node.hindercolor);
  }
  rectanglef r = new rectanglef(_node.x * _node.width, _node.y * _node.width, _node.width, _node.width);
  rects[i] = r;
  }
  g.fillrectangles(brush, rects);
 }

 /// <summary>
 /// 设置边界
 /// </summary>
 public void setborder()
 {
  //通过计算得出边界的个数是2(x+y-2)个方格

  solidbrush brush = null;
  int borders = 2 * (comscount + rowcount - 2);
  rectanglef[] rects = new rectanglef[borders];
  int indexcount = 0;
  //添加顶部方格进rects列表中
  for (int i = 0; i < rowcount; i++)
  {
  node _node = _nodes[i][0];
  _node.sethinder(true);
  if (brush == null)
  {
   brush = new solidbrush(_node.hindercolor);
  }
  rectanglef r = new rectanglef(_node.x * _node.width, _node.y * _node.width, _node.width, _node.width);
  rects[indexcount] = r;
  indexcount++;
  }
  //添加底部方格进rects列表中
  for (int i = 0; i < rowcount; i++)
  {
  node _node = _nodes[i][comscount - 1];
  _node.sethinder(true);

  rectanglef r = new rectanglef(_node.x * _node.width, _node.y * _node.width, _node.width, _node.width);
  rects[indexcount] = r;
  indexcount++;
  }
  //添加左侧方格进列表,因为左侧最上面以及最下面的两个方格已经添加进去,这里不需要重复添加
  for (int i = 1; i < comscount - 1; i++)
  {
  node _node = _nodes[0][i];
  _node.sethinder(true);
  rectanglef r = new rectanglef(_node.x * _node.width, _node.y * _node.width, _node.width, _node.width);
  rects[indexcount] = r;
  indexcount++;
  }
  //添加右侧方格进列表,因为右侧最上面以及最下面两个方格已经添加进去,这里不需要重复添加
  for (int i = 1; i < comscount - 1; i++)
  {
  node _node = _nodes[rowcount - 1][i];
  _node.sethinder(true);
  rectanglef r = new rectanglef(_node.x * _node.width, _node.y * _node.width, _node.width, _node.width);
  rects[indexcount] = r;
  indexcount++;
  }
  g.fillrectangles(brush, rects);
 }
 }
}

代码3:

using system;
using system.collections.generic;
using system.text;
using system.drawing;

namespace engorgeserpent
{
 /// <summary>
 /// 蛇
 /// </summary>
 class serpent
 {
 private list<node> serpentlist = new list<node>();
 private direction direction = direction.right;//运动方向
 private int maxcount = 15;
 private int mincount = 5;
 private system.windows.forms.control mappanel;
 graphics g;
 /// <summary>
 /// 设置蛇长度数据
 /// </summary>
 /// <param name="maxlength">最大长度</param>
 /// <param name="minlength">最小长度</param>
 public serpent(int maxlength, int minlength, system.windows.forms.control c)
 {
  maxcount = maxlength;
  mincount = minlength;
  mappanel = c;
  g = mappanel.creategraphics();
 }

 /// <summary>
 /// 初始化蛇
 /// </summary>
 public void initializeserpent()
 {
  solidbrush brush = null;
  rectanglef[] rects = new rectanglef[mincount];
  for (int i = 1; i < mincount; i++)
  {
  node indexnode = new node(i, 1);
  indexnode.setserpent(true);//设置蛇颜色
  serpentlist.insert(0, indexnode);
  if (brush == null)
  {
   brush = new solidbrush(indexnode.serpentcolor);
  }
  rects[i] = new rectanglef(indexnode.x * indexnode.width, indexnode.y * indexnode.width, indexnode.width, indexnode.width);
  }
  g.fillrectangles(brush, rects);
 }



 /// <summary>
 /// 插入一个
 /// </summary>
 /// <param name="node"></param>
 public void insertnode(node node)
 {
  serpentlist.insert(0, node);
  node.setserpent(true);
  solidbrush brush = new solidbrush(node.serpentcolor);
  rectanglef rect = new rectanglef(node.x * node.width, node.y * node.width, node.width, node.width);
  g.fillrectangle(brush, rect);
 }

 /// <summary>
 /// 移除尾巴
 /// </summary>
 /// <param name="node"></param>
 public void removenode()
 {
  node node = serpentlist[serpentlist.count - 1];
  serpentlist.remove(node);
  node.setserpent(false);
  solidbrush brush = new solidbrush(node.bgcolor);
  rectanglef rect = new rectanglef(node.x * node.width, node.y * node.width, node.width, node.width);
  g.fillrectangle(brush, rect);
 }

 /// <summary>
 /// 获取蛇头
 /// </summary>
 /// <returns>蛇头方格</returns>
 public node getserpenthead()
 {
  return serpentlist[0];
 }

 /// <summary>
 /// 蛇是否最长
 /// </summary>
 /// <returns></returns>
 public bool ismax()
 {
  if (serpentlist.count == maxcount)
  return true;
  else
  return false;
 }

 /// <summary>
 /// 蛇运动方向
 /// </summary>
 public direction direction
 {
  get { return direction; }
  set { direction = value; }
 }

 }
 /// <summary>
 /// 运动方向
 /// </summary>
 public enum direction
 {
 left,
 up,
 right,
 down
 }
}

代码4:

using system;
using system.collections.generic;
using system.componentmodel;
using system.data;
using system.drawing;
using system.text;
using system.windows.forms;
using system.threading;

namespace engorgeserpent
{
 public partial class mainform : form
 {
 public mainform()
 {
  initializecomponent();

 }
 list<list<node>> maplist = new list<list<node>>();
 map map;
 serpent serpent;
 graphics g;
 int level = 1;
 /// <summary>
 /// 运行线程
 /// </summary>
 thread work_thread = null;
 /// <summary>
 /// 运行线程监控值
 /// </summary>
 bool iswork = false;
 int sleeptime = 1000;
 int thissleeptime;

 private void mainform_load(object sender, eventargs e)
 {
  g = this.panel1.creategraphics();
  map = new map(40, 30, this.panel1);//这里可以对画布进行下大小设置 此处偷懒省略 
  loadmaplist();//加载障碍物列表  
 }

 /// <summary>
 /// 默认将地图设置为30*40
 /// </summary>
 private void setmap()
 {
  map.resetmap();
  g.clear(map.bgcolor);
  map.setborder();//设置边界
  list<node> hiderlist = gethider();//获取障碍物列表
  map.sethinder(hiderlist);//设置障碍物
  setserpent();//初始化蛇 
 }

 /// <summary>
 /// 设置蛇
 /// </summary>
 private void setserpent()
 {
  serpent = new serpent(15, 5, this.panel1);
  serpent.initializeserpent();//初始化蛇
 }

 /// <summary>
 /// 获取地图障碍物列表 以增加不同级别难度
 /// </summary>
 private void loadmaplist()
 {
  //目前分为5个级别
  //第一级别
  list<node> hiderlist1 = new list<node>();
  for (int i = 15; i < 25; i++)
  {
  hiderlist1.add(map.getnode(i, 15));
  hiderlist1.add(map.getnode(15, i));
  }
  maplist.add(hiderlist1);

  //第二级别
  list<node> hiderlist2 = new list<node>();
  for (int i = 7; i < 25; i++)
  {
  hiderlist2.add(map.getnode(i, 15));
  hiderlist2.add(map.getnode(15, i));
  }
  maplist.add(hiderlist2);

  //第三级别
  list<node> hiderlist3 = new list<node>();
  for (int i = 7; i < 25; i++)
  {
  hiderlist3.add(map.getnode(i, 15));
  hiderlist3.add(map.getnode(15, i));
  hiderlist3.add(map.getnode(i, 25));
  }
  maplist.add(hiderlist3);

  //第四级别
  list<node> hiderlist4 = new list<node>();
  for (int i = 7; i < 25; i++)
  {
  hiderlist4.add(map.getnode(i, 25));
  hiderlist4.add(map.getnode(i, 15));
  hiderlist4.add(map.getnode(15, i));
  hiderlist4.add(map.getnode(i, 7));
  }
  maplist.add(hiderlist4);

  //第五级别
  list<node> hiderlist5 = new list<node>();
  for (int i = 7; i < 25; i++)
  {
  hiderlist5.add(map.getnode(i, 25));
  hiderlist5.add(map.getnode(i, 15));
  hiderlist5.add(map.getnode(15, i));
  hiderlist5.add(map.getnode(i, 7));
  hiderlist5.add(map.getnode(i, 35));
  }
  for (int i = 12; i < 20; i++)
  {
  hiderlist5.add(map.getnode(7, i));
  hiderlist5.add(map.getnode(25, i));
  }
  maplist.add(hiderlist5);
 }

 /// <summary>
 /// 获取障碍物列表
 /// </summary>
 /// <returns></returns>
 private list<node> gethider()
 {
  //这里可以添加多个地图,当级别改变时需要重新加载
  return maplist[level - 1];
 }

 /// <summary>
 /// 重置地图
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 private void btnresetmap_click(object sender, eventargs e)
 {
  iswork = false;
  btnstop.enabled = false;
  button3.enabled = false;
  button2.enabled = true;
  //map.resetmap();
  setmap();
 }

 /// <summary>
 /// 运行
 /// </summary>
 private void work()
 {
  map.setfood();//设置食物
  while (iswork)
  {
  node node_index;
  node serpenthead = serpent.getserpenthead();
  switch (serpent.direction)
  {
   case direction.left:
   node_index = map.getnode(serpenthead.x - 1, serpenthead.y);
   break;
   case direction.right:
   node_index = map.getnode(serpenthead.x + 1, serpenthead.y);
   break;
   case direction.up:
   node_index = map.getnode(serpenthead.x, serpenthead.y - 1); break;
   default:
   node_index = map.getnode(serpenthead.x, serpenthead.y + 1);
   break;
  }
  serpentstate index_move = serpentmove(node_index);
  if (index_move == serpentstate.error)//游戏结束
  {
   iswork = false;
   //map.resetmap();
   messagebox.show("游戏结束!", "提示", messageboxbuttons.ok, messageboxicon.information);
   sleeptime = 1000;
   level = 1;
   thissleeptime = sleeptime;
   lbllevel.begininvoke(new methodinvoker(delegate()
   {
   btnstop.enabled = false;
   button3.enabled = false;
   button2.enabled = true;
   lbllevel.text = "1";
   lblcount.text = "5";
   }));
  }
  else if (index_move == serpentstate.nextlevel)
  {
   iswork = false;
   this.lblcount.begininvoke(new methodinvoker(delegate()
   {
   level += 1;
   lbllevel.text = level.tostring();
   lblcount.text = "5";
   }));
   sleeptime = sleeptime / 2;
   thissleeptime = sleeptime;
   setmap();//重置地图
  }
  else
  {

   thread.sleep(thissleeptime);
  }
  }
  map.resetmap();
 }

 /// <summary>
 /// 开始
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 private void button2_click(object sender, eventargs e)
 {
  iswork = false;
  btnstop.enabled = false;
  button3.enabled = false;
  button2.enabled = true;
  //map.resetmap();
  setmap();
  thissleeptime = sleeptime;
  this.panel1.focus();
  iswork = true;
  this.btnstop.enabled = true;
  this.button3.enabled = true;
  button2.enabled = false;
  work_thread = new thread(new threadstart(work));
  work_thread.isbackground = true;
  work_thread.start();
 }

 private void mainform_keydown(object sender, keyeventargs e)
 {

  if (e.keycode == keys.right)
  {
  if (serpent.direction != direction.left)
   serpent.direction = direction.right;
  }
  else if (e.keycode == keys.left)
  {
  if (serpent.direction != direction.right)
   serpent.direction = direction.left;
  }
  else if (e.keycode == keys.up)
  {
  if (serpent.direction != direction.down)
   serpent.direction = direction.up;
  }
  else if (e.keycode == keys.down)
  {
  if (serpent.direction != direction.up)
   serpent.direction = direction.down;
  }
  else if (e.keycode == keys.space)
  {
  thissleeptime = sleeptime / 2;
  }
  else if (e.keycode == keys.escape)
  {
  if (iswork)
  {
   this.button3.text = "继续";
   iswork = false;
  }

  }
 }

 /// <summary>
 /// 暂停
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 private void button3_click(object sender, eventargs e)
 {
  if (!iswork)
  {
  this.button3.text = "暂停";
  iswork = true;
  work_thread = new thread(new threadstart(work));
  work_thread.isbackground = true;
  work_thread.start();
  }
  else
  {
  this.button3.text = "继续";
  iswork = false;
  }
 }
 /// <summary>
 /// 退出
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 private void button4_click(object sender, eventargs e)
 {
  this.close();
 }

 private void mainform_formclosing(object sender, formclosingeventargs e)
 {
  iswork = false;
  application.exit();
  system.diagnostics.process.getcurrentprocess().kill();
 }



 private void btnstop_click(object sender, eventargs e)
 {
  // map.resetmap();
  btnstop.enabled = false;
  button3.enabled = false;
  button2.enabled = true;
  iswork = false;
  work_thread.abort();
  setmap();
 }

 /// <summary>
 /// 移动
 /// </summary>
 /// <param name="node">将要移动到的节点</param>
 /// <returns>返回状态</returns>
 private serpentstate serpentmove(node node)
 {
  if (!node.ispass)
  {
  return serpentstate.error;
  }
  serpent.insertnode(node);
  if (!node.isfood)
  {
  //不是食物,则移除最后一个节点
  serpent.removenode();
  }
  else
  {
  lblcount.begininvoke(new methodinvoker(delegate()
  {
   this.lblcount.text = (convert.toint32(this.lblcount.text.trim()) + 1).tostring();
  }));
  map.setfood();//设置食物
  }

  if (serpent.ismax())
  {
  return serpentstate.nextlevel;
  }
  return serpentstate.moving;
 }

 private void mainform_keyup(object sender, keyeventargs e)
 {
  if (e.keycode == keys.space)
  {
  thissleeptime = sleeptime;
  }
 }

 private void combobox1_selectedindexchanged(object sender, eventargs e)
 {
  int index = 1;
  int index_count = convert.toint32(combobox1.text);
  for (int i = 1; i < index_count; i++)
  {
  index = index * 2;
  }
  level = index_count;
  sleeptime = 1000 / index;
  thissleeptime = sleeptime;
  btnstop.enabled = false;
  button3.enabled = false;
  button2.enabled = true;
  iswork = false;

  setmap();
  lblcount.text = "5";
  lbllevel.text = index_count.tostring();
  serpent.direction = direction.right;

 }

 private void checkbox1_click(object sender, eventargs e)
 {
  combobox1.enabled = this.checkbox1.checked;
 }

 }
 public enum serpentstate
 {
 moving,
 nextlevel,
 error
 }
}

主界面

C#贪吃蛇游戏实现分析

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。