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

C#实现贪吃蛇小游戏

程序员文章站 2022-03-04 13:42:03
本文实例为大家分享了c#实现贪吃蛇小游戏的具体代码,供大家参考,具体内容如下之前一直想写一个贪吃蛇小游戏,上个周末终于有时间做了一个,现在和大家分享。界面界面比较简单,一个按钮和一个积分器组成。基本逻...

本文实例为大家分享了c#实现贪吃蛇小游戏的具体代码,供大家参考,具体内容如下

之前一直想写一个贪吃蛇小游戏,上个周末终于有时间做了一个,现在和大家分享。

界面

界面比较简单,一个按钮和一个积分器组成。
基本逻辑:每五个食物出现一次大食物,小食物1分,大食物5分。
控制:撞墙和缠绕时,游戏暂停。

C#实现贪吃蛇小游戏

代码详解

详细介绍下代码

一、代码分详解

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# 贪吃蛇