C#做贪吃蛇(含窗体)——可穿墙

设置贪吃蛇的步骤:

step1:设置贪吃蛇的界面,包含一个menustrip,timer,panel和两个label,如下图所示。

menustrip的属性中有item,设置为  如下图所示

         

 setp2:Form1窗体的代码为:

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 贪吃蛇
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public static bool ifStart = false;//判断是否开始
        public static int career = 400;//移动的速度
        Snake snake = new Snake();//实例化Snake类
        int snake_W = 20;//骨节的宽度
        int snake_H = 20;//骨节的高度
        public static bool pause = false;//是否暂停游戏

        /// <summary>
        /// 绘制游戏场景
        /// </summary>
        /// <param g="Graphics">封装一个GDI+绘图图面</param>
        public void ProtractTable(Graphics g)
        {
            for (int i = 0; i <= panel1.Width / snake_W; i++)//绘制单元格的纵向线
            {
                g.DrawLine(new Pen(Color.Black, 1), new Point(i * snake_W, 0), new Point(i * snake_W, panel1.Height));
            }
            for (int i = 0; i <= panel1.Height / snake_H; i++)//绘制单元格的横向线
            {
                g.DrawLine(new Pen(Color.Black, 1), new Point(0, i * snake_H), new Point(panel1.Width, i * snake_H));
            }
        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = panel1.CreateGraphics();//创建panel1控件的Graphics类
            ProtractTable(g);//绘制游戏场景
            if (!ifStart)//如是没有开始游戏
            {
                Snake.timer = timer1;
                Snake.label = label2;
                snake.Ophidian(panel1, snake_W);//初始化场地及贪吃蛇信息
            }
            else
            {
                for (int i = 0; i < Snake.List.Count; i++)//绘制蛇身
                {
                    e.Graphics.FillRectangle(Snake.SolidB, ((Point)Snake.List[i]).X + 1, ((Point)Snake.List[i]).Y + 1, snake_W - 1, snake_H - 1);
                }
                e.Graphics.FillRectangle(Snake.SolidF, Snake.Food.X + 1, Snake.Food.Y + 1, snake_W - 1, snake_H - 1);//绘制食物
                if (Snake.ifGame)//如果游戏结束
                    //绘制提示文本
                    e.Graphics.DrawString("Game Over", new Font("宋体", 30, FontStyle.Bold), new SolidBrush(Color.DarkSlateGray), new PointF(150, 130));
            }
        }

        private void 开始ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            NoviceCortrol(Convert.ToInt32(((ToolStripMenuItem)sender).Tag.ToString()));
            snake.BuildFood();
            textBox1.Focus();
        }

        /// <summary>
        /// 控制游戏的开始、暂停和结束
        /// </summary>
        /// <param n="int">标识</param>
        public void NoviceCortrol(int n)
        {
            switch (n)
            {
                case 1://开始游戏
                    {
                        ifStart = false;
                        Graphics g = panel1.CreateGraphics();//创建panel1控件的Graphics类
                        g.FillRectangle(Snake.SolidD, 0, 0, panel1.Width, panel1.Height);//刷新游戏场地
                        ProtractTable(g);//绘制游戏场地
                        ifStart = true;//开始游戏
                        snake.Ophidian(panel1, snake_W);//初始化场地及贪吃蛇信息
                        timer1.Interval = career;//设置贪吃蛇移动的速度
                        timer1.Start();//启动计时器
                        pause = true;//是否暂停游戏
                        label2.Text = "0";//显示当前分数
                        break;
                    }
                case 2://暂停游戏
                    {
                        if (pause)//如果游戏正在运行
                        {
                            ifStart = true;//游戏正在开始
                            timer1.Stop();//停止计时器
                            pause = false;//当前已暂停游戏
                        }
                        else
                        {
                            ifStart = true;//游戏正在开始
                            timer1.Start();//启动计时器
                            pause = true;//开始游戏
                        }

                        break;
                    }
                case 3://退出游戏
                    {
                        timer1.Stop();//停止计时器
                        Application.Exit();//半闭工程
                        break;
                    }
            }
        }

        private void 初级ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (timer1.Enabled == false)//如果游戏没有开始
            {
                初级ToolStripMenuItem.Checked = false;//设置该项没有被选中
                中级ToolStripMenuItem.Checked = false;//设置该项没有被选中
                高级ToolStripMenuItem.Checked = false;//设置该项没有被选中
                ((ToolStripMenuItem)sender).Checked = true;//设置当前项被选中
                switch (Convert.ToInt32(((ToolStripMenuItem)sender).Tag.ToString()))
                {
                    case 1://高级
                        {
                            career = 400;//设置移动的速度
                            break;
                        }

                    case 2://中级
                        {
                            career = 200;
                            break;
                        }
                    case 3://初
                        {
                            career = 50;
                            break;
                        }
                }
            }
            textBox1.Focus();//获得焦点
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            int tem_n = -1;//记录移动键值
            if (e.KeyCode == Keys.Right)//如果按→键
                tem_n = 0;//向右移
            if (e.KeyCode == Keys.Left)//如果按←键
                tem_n = 1;//向左移
            if (e.KeyCode == Keys.Up)//如果按↑键
                tem_n = 2;//向上移
            if (e.KeyCode == Keys.Down)//如果按↓键
                tem_n = 3;//向下移
            if (tem_n != -1 && tem_n != Snake.Aspect)//如果移动的方向不是相同方向
            {
                if (Snake.ifGame == false)
                {
                    //如果移动的方向不是相反的方向
                    if (!((tem_n == 0 && Snake.Aspect == 1 || tem_n == 1 && Snake.Aspect == 0) || (tem_n == 2 && Snake.Aspect == 3 || tem_n == 3 && Snake.Aspect == 2)))
                    {
                        Snake.Aspect = tem_n;//记录移动的方向
                        snake.SnakeMove(tem_n);//移动贪吃蛇
                    }
                }
            }
            int tem_p = -1;//记录控制键值
            if (e.KeyCode == Keys.F2)//如果按F2键
                tem_p = 1;//开始游戏
            if (e.KeyCode == Keys.F3)//如果按F3键
                tem_p = 2;//暂停或继续游戏
            if (e.KeyCode == Keys.F4)//如果按F4键
                tem_p = 3;//关闭游戏
            if (tem_p != -1)//如果当前是操作标识
                NoviceCortrol(tem_p);//控制游戏的开始、暂止和关闭
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            snake.SnakeMove(Snake.Aspect);//移动贪吃蛇
          
        }

       
    }
}

step3:另外还要写一个Snake类:

using System;
using System.Collections;
using System.Drawing;
using System.Windows.Forms;

namespace 贪吃蛇
{
    class Snake
    {
        public static int Condyle = 0;//设置骨节的大小
        public static int Aspect = 0;//设置方向
        public static Point[] Place = { new Point(-1, -1), new Point(-1, -1), new Point(-1, -1), new Point(-1, -1), new Point(-1, -1), new Point(-1, -1) };//设置个骨节的位置
        public static Point Food = new Point(-1, -1);//设置食物的所在点
        public static bool ifFood = false;//是否有食物
        public static bool ifGame = false;//游戏是否结束
        public static int Field_width = 0;//场地的宽度
        public static int Field_Height = 0;//场地的高度
        public static Control control;//记录绘制贪吃蛇的控件
        public static Timer timer;//记录Timer组件
        public static SolidBrush SolidB = new SolidBrush(Color.Red);//设置贪吃蛇身体的颜色
        public static SolidBrush SolidD = new SolidBrush(Color.White);//设置背景颜色
        public static SolidBrush SolidF = new SolidBrush(Color.Blue);//设置食物的颜色
        //public static SolidBrush Solid = new SolidBrush(TextBox.DefaultBackColor);           
        //public static SolidBrush SolidE = new SolidBrush(Text."#");//设置食物的xingzhuang
        public static Label label;//记录Label控件
        public static ArrayList List = new ArrayList();//实例化ArrayList数组
        Graphics g;//实例化Graphics类

        /// <summary>
        /// 初始化场地及贪吃蛇的信息
        /// </summary>
        /// <param Con="Control">控件</param>
        /// <param condyle="int">骨节大小</param>
        public void Ophidian(Control Con, int condyle)
        {
            Field_width = Con.Width;//获取场地的宽度
            Field_Height = Con.Height;//获取场地的高度
            Condyle = condyle;//记录骨节的大小
            control = Con;//记录背景控件
            g = control.CreateGraphics();//创建背景控件的Graphics类
            SolidD = new SolidBrush(Con.BackColor);//设置画刷颜色
            for (int i = 0; i < Place.Length; i++)//绘制贪吃蛇
            {
                Place[i].X = (Place.Length - i - 1) * Condyle;//设置骨节的横坐标位置
                Place[i].Y = (Field_Height / 2) - Condyle;//设置骨节的纵坐标位置
                g.FillRectangle(SolidB, Place[i].X + 1, Place[i].Y + 1, Condyle - 1, Condyle - 1);//绘制骨节
            }
            List = new ArrayList(Place);//记录每个骨节的位置
            ifGame = false;//停止游戏
            Aspect = 0;//设置方向为右
        }

        /// <summary>
        /// 移动贪吃蛇
        /// </summary>
        /// <param n="int">标识,判断的移动的方向</param>
        public void SnakeMove(int n)
        {
            Point tem_Point = new Point(-1, -1);//定义坐标结构
            switch (n)
            {
                case 0://右移
                    {
                        tem_Point.X = ((Point)List[0]).X + Condyle;//蛇头向右移
                        tem_Point.Y = ((Point)List[0]).Y;
                        break;
                    }
                case 1://左移
                    {
                        tem_Point.X = ((Point)List[0]).X - Condyle;//蛇头向左移
                        tem_Point.Y = ((Point)List[0]).Y;
                        break;
                    }
                case 2://上移
                    {
                        tem_Point.Y = ((Point)List[0]).Y - Condyle;//蛇头向上移
                        tem_Point.X = ((Point)List[0]).X;
                        break;
                    }
                case 3://下移
                    {
                        tem_Point.Y = ((Point)List[0]).Y + Condyle;//蛇头向下移
                        tem_Point.X = ((Point)List[0]).X;
                        break;
                    }
            }
            BuildFood();//生成食物
            if (!EstimateMove(tem_Point))//如果没有向相反的方向移动
            {
                Aspect = n;//改变贪吃蛇的移动方向
                bool aa = false;
                tem_Point = GameAborted(tem_Point, ref aa);
                if (!aa)//如果游戏没有结束
                {
                    ProtractSnake(tem_Point);//重新绘制蛇身
                    EatFood();//吃食
                }
                g.FillRectangle(SolidF, Food.X + 1, Food.Y + 1, Condyle - 1, Condyle - 1);//绘制食物

                Console.WriteLine("                   " + ((Point)List[0]).X);
            }
        }

        /// <summary>
        /// 吃食
        /// </summary>
        public void EatFood()
        {
            if (((Point)List[0]) == Food)//如果蛇头吃到了食物
            {
                List.Add(List[List.Count - 1]);//在蛇的尾部添加蛇身
                ifFood = false;//没有食物
                BuildFood();//生成食物
                label.Text = Convert.ToString(Convert.ToInt32(label.Text) + 5);//显示当前分数
            }
        }

        /// <summary>
        /// 游戏是否失败
        /// </summary>
        /// <param GameP="Point">设置文本的显示位置</param>
        public Point GameAborted(Point GameP, ref bool isGameOver)
        {
            Point temp = GameP;
            //bool tem_b = false;//游戏是否结束
            bool tem_body = false;//记录蛇身是否重叠
            for (int i = 1; i < List.Count; i++)//遍历所有骨节
            {
                if (((Point)List[0]) == ((Point)List[i]))//如是骨节重叠
                {
                    tem_body = true;//游戏失败
                    break;
                }
            }

            if (tem_body)
            {
                //绘制游戏结束的提示文本
                g.DrawString("Game Over", new Font("宋体", 35, FontStyle.Bold), new SolidBrush(Color.DarkSlateGray), new PointF(150, 130));
                ifGame = true;//游戏结束
                isGameOver = true;
                timer.Stop();//停止记时器
            }

            //判断蛇头是否超出游戏场地
            if (GameP.X <= -20)
            {
                temp = new Point(((Point)List[0]).Y,0 ); ;
                //Point temp = new Point(control.Width - 1, ((Point)List[0]).Y);
                //List[0] = temp;//panel1.Width
            }
            else if (GameP.X >= control.Width - 1)
            {
                temp = new Point(0, ((Point)List[0]).Y);
                //((Point)List[0]).X = -20;
                //绘制游戏结束的提示文本
                //g.DrawString("Game Over", new Font("宋体", 35, FontStyle.Bold), new SolidBrush(Color.DarkSlateGray), new PointF(150, 130));
                //ifGame = true;//游戏结束
                //timer.Stop();//停止记时器
                //tem_b = true;
                //tem_b = false;
            }
            else if (GameP.Y <= -20)
            {
                temp = new Point(0,((Point)List[0]).X);
                //temp = new Point(control.Width - 1, ((Point)List[0]).Y);
                //List[0] = temp;//panel1.Width
                //((Point)List[0]).Y = ccontrol.Height - 1;
            }
            else if (GameP.Y >= control.Height - 1)
            {
                temp = new Point(((Point)List[0]).X, 0);
                //temp = new Point(control.Width - 1, ((Point)List[0]).X);
                //List[0] = temp;//panel1.Width
                //((Point)List[0]).Y = -20;       
            }
            return temp;
        }

        /// <summary>
        /// 判断蛇是否向相反的方向移动
        /// </summary>
        /// <param Ep="Point">移动的下一步位置</param>
        public bool EstimateMove(Point Ep)
        {
            bool tem_bool = false;//记录蛇头是否向相反的方向移动
            if (Ep.X == ((Point)List[0]).X && Ep.Y == ((Point)List[0]).Y)//如果蛇头向相反的方向移动
                tem_bool = true;
            return tem_bool;
        }

        /// <summary>
        /// 重新绘制蛇身
        /// </summary>
        public void ProtractSnake(Point Ep)
        {
            bool tem_bool = false;//是否清除移动后的蛇身
            List.Insert(0, Ep);//根据蛇头的移动方向,设置蛇头的位置
            Point tem_point = ((Point)List[List.Count-1]);//记录蛇尾的位置
            List.RemoveAt(List.Count - 1);//移除蛇的尾部
            //使骨节向前移动一位
            for (int i = 0; i < List.Count - 1; i++)
            {
                if (tem_point == ((Point)List[i]))
                    tem_bool = true;
            }
            if (!tem_bool)//清除贪吃蛇移动前的蛇尾部份
                g.FillRectangle(SolidD, tem_point.X + 1, tem_point.Y + 1, Condyle - 1, Condyle - 1);
            for (int i = 0; i < List.Count; i++)//重新绘制蛇身
            {
                g.FillRectangle(SolidB, ((Point)List[0]).X + 1, ((Point)List[0]).Y + 1, Condyle - 1, Condyle - 1);
            }
        } 

        /// <summary>
        /// 生成食物
        /// </summary>
        public void BuildFood()
        {
            if (ifFood == false)//如果没有食物
            {
                Point tem_p = new Point(-1, -1);//定义坐标结构
                bool tem_bool = true;//是否计算出食物的合位置
                bool tem_b = false;//判断食物是否和蛇身重叠
                while (tem_bool)//计算食物的显示位置
                {
                    tem_b = false;
                    tem_p = RectFood();//随机生成食物的位置
                    for (int i = 0; i < List.Count; i++)//遍历整个蛇身的位置
                    {
                        if (((Point)List[i]) == tem_p)//如果食物是否和蛇身重叠
                        {
                            tem_b = true;//记录重叠
                            break;
                        }
                    }
                    if (tem_b == false)//如果没有重叠
                        tem_bool = false;//退出循环
                }
                Food = tem_p;//记录食物的显示位置
            }
            ifFood = true;//有食物
        }

        /// <summary>
        /// 随机生成食物的节点
        /// </summary>
        public Point RectFood()
        {
            int tem_W = Field_width / 20;//获取场地的行数
            int tem_H = Field_Height / 20;//获取场地的列数
            Random RandW = new Random();//实例化Random类
            tem_W=RandW.Next(0, tem_W - 1);//生成食物的横向坐标
            Random RandH = new Random();//实例化Random类
            tem_H = RandH.Next(0, tem_H - 1);//生成食物的纵向坐标
            Point tme_P = new Point(tem_W * Condyle, tem_H * Condyle);//生成食物的显示位置
            return tme_P;
        }

    }
}

以上就是贪吃蛇的完整代码,可穿墙哦!!!

  • 5
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
实现穿墙模式需要对贪吃蛇的碰撞检测部分进行修改。以下是一个简单的穿墙模式实现示例: 1. 在贪吃蛇的移动函数中,添加判断蛇头是否碰到了边界。 2. 如果蛇头碰到了边界,根据蛇头的位置判断出对应的穿墙位置,并将其作为蛇头下一步要移动到的位置。 3. 如果蛇头没有碰到边界,按照原来的逻辑继续移动。 以下是示例代码: ``` #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <windows.h> #include <time.h> #define WIDTH 40 #define HEIGHT 20 #define MAX_LENGTH 100 int x, y, food_x, food_y, score, length; int snake_x[MAX_LENGTH], snake_y[MAX_LENGTH]; int direction; int wall_mode; // 穿墙模式开关 void init(); // 初始化函数 void draw_map(); // 绘制地图函数 void draw_snake(); // 绘制蛇函数 void generate_food(); // 生成食物函数 void move_snake(); // 移动蛇函数 void check_collision(); // 碰撞检测函数 void game_over(); // 游戏结束函数 int main() { init(); while (1) { if (_kbhit()) { // 检测是否有按键按下 switch (_getch()) { case 'w': // 上 if (direction != 2) // 防止蛇倒退 direction = 0; break; case 'd': // 右 if (direction != 3) direction = 1; break; case 's': // 下 if (direction != 0) direction = 2; break; case 'a': // 左 if (direction != 1) direction = 3; break; case 'q': // 切换穿墙模式 wall_mode = !wall_mode; break; } } move_snake(); check_collision(); if (score == WIDTH * HEIGHT) { // 游戏胜利 system("cls"); printf("Congratulations! You win!\n"); system("pause"); break; } Sleep(50); // 控制帧率 } return 0; } void init() { srand(time(NULL)); // 初始化随机种子 x = WIDTH / 2; y = HEIGHT / 2; food_x = rand() % WIDTH; food_y = rand() % HEIGHT; score = 0; length = 1; snake_x[0] = x; snake_y[0] = y; direction = 0; // 初始方向为上 wall_mode = 0; // 初始为非穿墙模式 } void draw_map() { system("cls"); printf("Score: %d\n", score); for (int i = 0; i < HEIGHT; i++) { for (int j = 0; j < WIDTH; j++) { if (i == 0 || i == HEIGHT - 1 || j == 0 || j == WIDTH - 1) { printf("#"); // 绘制边界 } else if (i == food_y && j == food_x) { printf("$"); // 绘制食物 } else { int flag = 0; for (int k = 0; k < length; k++) { if (i == snake_y[k] && j == snake_x[k]) { printf("*"); // 绘制蛇 flag = 1; break; } } if (!flag) { printf(" "); // 绘制空格 } } } printf("\n"); } } void draw_snake() { for (int i = 0; i < length; i++) { printf("(%d, %d) ", snake_x[i], snake_y[i]); } printf("\n"); } void generate_food() { food_x = rand() % WIDTH; food_y = rand() % HEIGHT; } void move_snake() { for (int i = length - 1; i > 0; i--) { snake_x[i] = snake_x[i - 1]; snake_y[i] = snake_y[i - 1]; } switch (direction) { case 0: // 上 y--; break; case 1: // 右 x++; break; case 2: // 下 y++; break; case 3: // 左 x--; break; } if (wall_mode) { // 穿墙模式 if (x < 0) x = WIDTH - 1; if (x >= WIDTH) x = 0; if (y < 0) y = HEIGHT - 1; if (y >= HEIGHT) y = 0; } else { // 非穿墙模式 if (x < 1) x = 1; if (x >= WIDTH - 1) x = WIDTH - 2; if (y < 1) y = 1; if (y >= HEIGHT - 1) y = HEIGHT - 2; } snake_x[0] = x; snake_y[0] = y; draw_map(); } void check_collision() { if (x == food_x && y == food_y) { // 吃到食物 score++; length++; generate_food(); } for (int i = 1; i < length; i++) { // 撞到自己 if (x == snake_x[i] && y == snake_y[i]) { game_over(); return; } } if (!wall_mode) { // 撞到边界 if (x == 0 || x == WIDTH - 1 || y == 0 || y == HEIGHT - 1) { game_over(); return; } } } void game_over() { system("cls"); printf("Game over! Your score is: %d\n", score); system("pause"); init(); } ``` 在上述代码中,我们新增了一个 `wall_mode` 变量来控制穿墙模式的开关,初始为非穿墙模式。在移动蛇时,如果开启了穿墙模式,则判断蛇头是否碰到了边界,如果碰到了,则根据蛇头位置判断出对应的穿墙位置,并将其作为蛇头下一步要移动到的位置。如果没有开启穿墙模式,则按照原来的逻辑继续移动。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值