C#实现贪吃蛇小游戏
本文实例为大家分享了c#实现贪吃蛇小游戏的具体代码,供大家参考,具体内容如下
之前一直想写一个贪吃蛇小游戏,上个周末终于有时间做了一个,现在和大家分享。
界面
界面比较简单,一个按钮和一个积分器组成。
基本逻辑:每五个食物出现一次大食物,小食物1分,大食物5分。
控制:撞墙和缠绕时,游戏暂停。
代码详解
详细介绍下代码
一、代码分详解
1.界面是在pc上,所以移动以上下左右键来控制移动,为了及时响应,所以增加如下代码
protected override bool processdialogkey(keys keydata) { //遇到上下左右键 就自定义处理 if (keydata == keys.up || keydata == keys.down || keydata == keys.left || keydata == keys.right) return false; else return base.processdialogkey(keydata); }
2.做个枚举,来标记某个时间状态下蛇的移动方向,配合键盘按键
/// <summary> /// 方向枚举 /// </summary> public enum snakedirection { left, right, down, up } /// <summary> /// 键盘和鼠标按下时 处理 但必须有控件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void snakeform_keydown(object sender, keyeventargs e) { if (e.keycode == keys.up) { snake.sd = snakedirection.up; } else if (e.keycode == keys.down) { snake.sd = snakedirection.down; } else if (e.keycode == keys.left) { snake.sd = snakedirection.left; } else if (e.keycode == keys.right) { snake.sd = snakedirection.right; } }
3.声明一个蛇的类,存储所有蛇的相关信息,如所有蛇身体的节点位置
public class snake
主要变量如下
public static snakedirection sd;//蛇进行的方向 上下左右四个方向 public int location_x;//0为x,1为y 蛇的初始位置 public int location_y; public static list<snake> snakebody = new list<snake>();//蛇身子的具体位置,每次位移都刷新一次 整个蛇身子的所有位置 最后一位是蛇头 public static int width = 10, height = 10; public static int curscore = 1;//当前食物的分数 public static int allscore = -1;//总分数 public static int maxscore = 5;//大分出现频次
4.声明一个食物的类,同时增加一个方法,随机在界面上的一个位置显示食物
public class food { public int food_location_x; public int food_location_y; public food() { random x = new random(); random y = new random(); food_location_x = x.next(0, 49) * 10;//随机点出现食物 food_location_y = y.next(0, 49) * 10;//随机点出现食物 } }
5.点击开始按钮,触发开始相关方法,主要是启动刷新的时间器,初始化食物位置,初始化积分等
public void refreshscore() { snake.allscore = snake.allscore+ snake.curscore; this.snakescore.text = convert.tostring(snake.allscore); } private int foodx = 0;//食物x轴 private int foody = 0;//食物y轴 private void beginbtn_click(object sender, eventargs e) { snake.start();//创建蛇 createnewfood(); starttimer.start(); starttimer.interval = 100;//毫秒刷新一次 }
6.定时器启动后,定时刷新,我这边设置的是100毫秒,也可以做一个前端设置按钮,增加游戏趣味性,同时也可以设置根据不同的积分处理此设置
定时器中有画蛇身体的方法、随机一个食物位置的方法、蛇移动的方法、蛇是否吃到食物的方法、游戏有没有结束的方法
/// <summary> /// 开始的定时器 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void starttimer_tick(object sender, eventargs e) { drawsnake(); drawfood(); snake.move(snake.sd);//蛇移动 移动的方向键盘控制 eatfood(); isornotgameover(); }
7.画蛇的方法如下
/// <summary> /// 画蛇 /// </summary> public void drawsnake() { rectanglef[] rectangles = new rectanglef[snake.snakebody.count]; int num; for (num = 0; num < snake.snakebody.count; num++) { rectangles[num] = new rectanglef(snake.snakebody[num].location_x, snake.snakebody[num].location_y, snake.width, snake.height); } this.refresh(); graphics g = this.snake_panel.creategraphics(); solidbrush mybrush = new solidbrush(color.black); g.fillrectangles(mybrush, rectangles); }
8.食物显示的方法如下,其中maxscore表示小食物出现的次数,每出现一次此值减一,当为0时,食物变为大食物。
/// <summary> /// 食物的位置 /// </summary> public void drawfood() { graphics f = this.snake_panel.creategraphics(); solidbrush mybrush = new solidbrush(color.red); if (snake.maxscore==0) { f.fillrectangle(mybrush, foodx, foody, 20, 20);//随机了食物的位置 } else { f.fillrectangle(mybrush, foodx, foody, 10, 10);//随机了食物的位置 } }
9.当每次刷新时,蛇都会移动,相应的蛇整体的位置也会发生变化,但蛇身有痕迹,所以使用如下方式进行蛇体变化
//蛇的移动操作 每次移动 都需要改变蛇身体 public static void move(snakedirection sd) { int i = snakebody.count - 1;//根据不同的移动方向 需要对相对位置发生变化,这个操作保证蛇身按照蛇头的轨迹运转 switch (sd) { case snakedirection.up: changesnakeline(); snakebody[i].location_y -= 10; break; case snakedirection.left: changesnakeline(); snakebody[i].location_x -= 10; break; case snakedirection.down: changesnakeline(); snakebody[i].location_y += 10; break; case snakedirection.right: changesnakeline(); snakebody[i].location_x += 10; break; } } /// <summary> /// 每次移动一次 改变蛇身体的相对位置 /// </summary> public static void changesnakeline() { int j = 0; int x, y; int i = snakebody.count - 1; for (j = 0; j < i; j++)//蛇 1位置变为蛇0 2=》1 3=》2 { x = snakebody[j + 1].location_x; y = snakebody[j + 1].location_y; snakebody[j].location_y = y; snakebody[j].location_x = x; } }
10.刷新蛇身体后,要判断食物位置是否和蛇头碰撞,当发生碰撞时,表示蛇吃掉了食物,食物刷新,蛇身体增长
/// <summary> /// 吃掉食物 判断蛇头位置和食物位置相同时,食物重新刷新 /// </summary> public void eatfood() { if (snake.snakebody[snake.snakebody.count - 1].location_x == foodx && snake.snakebody[snake.snakebody.count - 1].location_y == foody) { snake.addbody();//增加 蛇身增加 //吃掉食物之后 随机创建一个新的食物 createnewfood(); } } //吃一个节点 变为新的蛇头 public static void addbody() { snake s_eat = new snake(); int xx = snakebody[snakebody.count - 1].location_x; int yy = snakebody[snakebody.count - 1].location_y; switch (sd) { case snakedirection.up: s_eat.location_y = yy - 10; s_eat.location_x = xx; snakebody.add(s_eat); break; case snakedirection.left: s_eat.location_x = xx - 10; s_eat.location_y = yy; snakebody.add(s_eat); break; case snakedirection.down: s_eat.location_y = yy + 10; s_eat.location_x = xx; snakebody.add(s_eat); break; case snakedirection.right: s_eat.location_y = yy; s_eat.location_x = xx + 10; snakebody.add(s_eat); break; } }
11.食物被吃掉后,食物刷新,同时判断小食物出现的次数
/// </summary> public void createnewfood() { refreshscore(); bool iscreate = false; while (!iscreate)//是否创建成功 { food newfood = new food(); foodx = newfood.food_location_x; foody = newfood.food_location_y; //判断这个不会出现在蛇身上 iscreate = true;//创建成功 for (int i = 0; i < snake.snakebody.count; i++) { if (snake.snakebody[i].location_x == foodx && snake.snakebody[i].location_y == foody)//当坐标相同 终止for 未创建成功 { iscreate = false; break; } } if (iscreate) { if (!(foodx <= this.snake_panel.width-10 && foodx >= 10 && foody <= this.snake_panel.height-10 && foody >= 10))//食物不在范围内 重新刷新 { iscreate = false; } } if (iscreate) { if (snake.snakebody.count != 4) { snake.maxscore--;//不是第一次创建食物时 } snake.curscore = 1;//当前小节点的分数 if (snake.maxscore == 0) { snake.curscore = 5;//当前小节点的分数 } else if (snake.maxscore<0) { snake.maxscore = 5;//初始化次数 } } } }
12.每次定时器刷新,蛇身会发生变化,同时就需要判断蛇是否触发终止规则
蛇身体缠绕,蛇头碰壁表示游戏终止
/// <summary> /// /// </summary> public void isornotgameover() { int x = snake.snakebody[snake.snakebody.count - 1].location_x; int y = snake.snakebody[snake.snakebody.count - 1].location_y; bool isgameover = false; if (!(x <= this.snake_panel.width && x >= 0 && y <= this.snake_panel.height && y >= 0))//蛇头碰触到边框 { isgameover = true; } //蛇头碰到自己蛇身 for(int i=0;i< snake.snakebody.count - 2; i++) { if(snake.snakebody[i].location_x==x&& snake.snakebody[i].location_y == y) { isgameover = true; break; } } if (isgameover) { gameover(); starttimer.stop(); } }
以上就是整个蛇运行的逻辑
二、完整代码
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; namespace project_snake { public partial class snakeform : form { public snakeform() { initializecomponent(); } //为了上下左右键起作用 需要重写这个操作 protected override bool processdialogkey(keys keydata) { //遇到上下左右键 就自定义处理 if (keydata == keys.up || keydata == keys.down || keydata == keys.left || keydata == keys.right) return false; else return base.processdialogkey(keydata); } /// <summary> /// 键盘和鼠标按下时 处理 但必须有控件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void snakeform_keydown(object sender, keyeventargs e) { if (e.keycode == keys.up) { snake.sd = snakedirection.up; } else if (e.keycode == keys.down) { snake.sd = snakedirection.down; } else if (e.keycode == keys.left) { snake.sd = snakedirection.left; } else if (e.keycode == keys.right) { snake.sd = snakedirection.right; } } /// <summary> /// 蛇的控件 记录蛇的基本方法 /// </summary> public class snake { public static snakedirection sd;//蛇进行的方向 上下左右四个方向 public int location_x;//0为x,1为y 蛇的初始位置 public int location_y; public static list<snake> snakebody = new list<snake>();//蛇身子的具体位置,每次位移都刷新一次 整个蛇身子的所有位置 最后一位是蛇头 public static int width = 10, height = 10; public static int curscore = 1;//当前食物的分数 public static int allscore = -1;//总分数 public static int maxscore = 5;//大分出现频次 //当前方向 public snake() { location_x = 300; location_y = 300; } /// <summary> /// 蛇初始化 朝向 初始长度等 /// </summary> public static void start() { maxscore = 5; allscore = -1; curscore = 1; sd = snakedirection.left;//默认往左跑 snakebody.clear();//每次操作舍身重置 //添加初始化的小蛇位置 snake s0 = new snake();//蛇1 snake s1 = new snake();//蛇2 snake s2 = new snake(); snake s3 = new snake(); //默认四个长度 蛇的位置 snakebody.add(s0);//默认蛇1位置 snakebody[0]是蛇头 s1.location_x = s0.location_x - 10; snakebody.add(s1); s2.location_x = s1.location_x - 10; snakebody.add(s2); s3.location_x = s2.location_x - 10; snakebody.add(s3); } //蛇的移动操作 每次移动 都需要改变蛇身体 public static void move(snakedirection sd) { int i = snakebody.count - 1;//根据不同的移动方向 需要对相对位置发生变化,这个操作保证蛇身按照蛇头的轨迹运转 switch (sd) { case snakedirection.up: changesnakeline(); snakebody[i].location_y -= 10; break; case snakedirection.left: changesnakeline(); snakebody[i].location_x -= 10; break; case snakedirection.down: changesnakeline(); snakebody[i].location_y += 10; break; case snakedirection.right: changesnakeline(); snakebody[i].location_x += 10; break; } } /// <summary> /// 每次移动一次 改变蛇身体的相对位置 /// </summary> public static void changesnakeline() { int j = 0; int x, y; int i = snakebody.count - 1; for (j = 0; j < i; j++)//蛇 1位置变为蛇0 2=》1 3=》2 { x = snakebody[j + 1].location_x; y = snakebody[j + 1].location_y; snakebody[j].location_y = y; snakebody[j].location_x = x; } } //吃一个节点 变为新的蛇头 public static void addbody() { snake s_eat = new snake(); int xx = snakebody[snakebody.count - 1].location_x; int yy = snakebody[snakebody.count - 1].location_y; switch (sd) { case snakedirection.up: s_eat.location_y = yy - 10; s_eat.location_x = xx; snakebody.add(s_eat); break; case snakedirection.left: s_eat.location_x = xx - 10; s_eat.location_y = yy; snakebody.add(s_eat); break; case snakedirection.down: s_eat.location_y = yy + 10; s_eat.location_x = xx; snakebody.add(s_eat); break; case snakedirection.right: s_eat.location_y = yy; s_eat.location_x = xx + 10; snakebody.add(s_eat); break; } } } public void refreshscore() { snake.allscore = snake.allscore+ snake.curscore; this.snakescore.text = convert.tostring(snake.allscore); } private int foodx = 0;//食物x轴 private int foody = 0;//食物y轴 private void beginbtn_click(object sender, eventargs e) { snake.start();//创建蛇 createnewfood(); starttimer.start(); starttimer.interval = 100;//毫秒刷新一次 } /// <summary> /// 开始的定时器 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void starttimer_tick(object sender, eventargs e) { drawsnake(); drawfood(); snake.move(snake.sd);//蛇移动 移动的方向键盘控制 eatfood(); isornotgameover(); } /// <summary> /// 画蛇 /// </summary> public void drawsnake() { rectanglef[] rectangles = new rectanglef[snake.snakebody.count]; int num; for (num = 0; num < snake.snakebody.count; num++) { rectangles[num] = new rectanglef(snake.snakebody[num].location_x, snake.snakebody[num].location_y, snake.width, snake.height); } this.refresh(); graphics g = this.snake_panel.creategraphics(); solidbrush mybrush = new solidbrush(color.black); g.fillrectangles(mybrush, rectangles); } /// <summary> /// 创建一个新的食物,也就是一个小点,红色 /// </summary> public void createnewfood() { refreshscore(); bool iscreate = false; while (!iscreate)//是否创建成功 { food newfood = new food(); foodx = newfood.food_location_x; foody = newfood.food_location_y; //判断这个不会出现在蛇身上 iscreate = true;//创建成功 for (int i = 0; i < snake.snakebody.count; i++) { if (snake.snakebody[i].location_x == foodx && snake.snakebody[i].location_y == foody)//当坐标相同 终止for 未创建成功 { iscreate = false; break; } } if (iscreate) { if (!(foodx <= this.snake_panel.width-10 && foodx >= 10 && foody <= this.snake_panel.height-10 && foody >= 10))//食物不在范围内 重新刷新 { iscreate = false; } } if (iscreate) { if (snake.snakebody.count != 4) { snake.maxscore--;//不是第一次创建食物时 } snake.curscore = 1;//当前小节点的分数 if (snake.maxscore == 0) { snake.curscore = 5;//当前小节点的分数 } else if (snake.maxscore<0) { snake.maxscore = 5;//初始化次数 } } } } /// <summary> /// 食物的位置 /// </summary> public void drawfood() { graphics f = this.snake_panel.creategraphics(); solidbrush mybrush = new solidbrush(color.red); if (snake.maxscore==0) { f.fillrectangle(mybrush, foodx, foody, 20, 20);//随机了食物的位置 } else { f.fillrectangle(mybrush, foodx, foody, 10, 10);//随机了食物的位置 } } /// <summary> /// 吃掉食物 判断蛇头位置和食物位置相同时,食物重新刷新 /// </summary> public void eatfood() { if (snake.snakebody[snake.snakebody.count - 1].location_x == foodx && snake.snakebody[snake.snakebody.count - 1].location_y == foody) { snake.addbody();//增加 蛇身增加 //吃掉食物之后 随机创建一个新的食物 createnewfood(); } } /// <summary> /// /// </summary> public void isornotgameover() { int x = snake.snakebody[snake.snakebody.count - 1].location_x; int y = snake.snakebody[snake.snakebody.count - 1].location_y; bool isgameover = false; if (!(x <= this.snake_panel.width && x >= 0 && y <= this.snake_panel.height && y >= 0))//蛇头碰触到边框 { isgameover = true; } //蛇头碰到自己蛇身 for(int i=0;i< snake.snakebody.count - 2; i++) { if(snake.snakebody[i].location_x==x&& snake.snakebody[i].location_y == y) { isgameover = true; break; } } if (isgameover) { gameover(); starttimer.stop(); } } /// <summary> /// 游戏结束 /// </summary> public void gameover() { } } /// <summary> /// 方向枚举 /// </summary> public enum snakedirection { left, right, down, up } //食物类 食物的纵轴横轴 public class food { public int food_location_x; public int food_location_y; public food() { random x = new random(); random y = new random(); food_location_x = x.next(0, 49) * 10;//随机点出现食物 food_location_y = y.next(0, 49) * 10;//随机点出现食物 } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: c++实现俄罗斯方块游戏代码