当前位置: 移动技术网 > IT编程>开发语言>c# > C#贪吃蛇游戏实现分析

C#贪吃蛇游戏实现分析

2019年07月18日  | 移动技术网IT编程  | 我要评论

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

贪吃蛇分析

游戏规则:

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
 }
}

主界面

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网