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 } }
主界面
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Oracle 外连接实现代码
下一篇: oracle 删除重复数据