【WinForm】WinForm应用C#语言实现贪吃蛇游戏

前言


一、游戏效果

初始界面:
在这里插入图片描述

开始游戏界面:
在这里插入图片描述

游戏失败界面:
在这里插入图片描述

游戏暂停界面:
在这里插入图片描述

二、界面设计

在这里插入图片描述
在这里插入图片描述

三、代码

Snake类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

namespace SnakeGame
{
    public class Snake
    {
        public int SnkWidth = 16;//蛇的每个点的宽度
        public const int SNAKE_MAX_LENGTH = 500;//最大长度
        public Point[] SnkLct=new Point[SNAKE_MAX_LENGTH];
        public int SnkLen;//蛇的长度
        public byte SnkDrt = 2;//方向 1上 2右 3下 4 左

        /// <summary>
        /// 蛇的属性初始化
        /// </summary>
        public void SnakeInit()
        {
            int start = 0;
            SnkLen = 5;
            for (int i = 5; i >= 1; i--)
            {
                SnkLct[i].X = start;
                SnkLct[i].Y = 32;
                start += SnkWidth;
                    
            }

            SnkDrt = 2;//初始方向
        }

        /// <summary>
        /// 判断蛇头是否撞到蛇尾
        /// </summary>
        /// <returns></returns>
        public bool CheckSnakeHeadInSnakeBody()
        {
            return CheckInSnakeBody(SnkLct[1].X, SnkLct[1].Y, 2);
        }

        /// <summary>
        /// 检查输入的坐标是否在蛇的身上
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="snkHead"></param>
        /// <returns></returns>
        public bool CheckInSnakeBody(int x, int y, int snkHead)
        {
            for (int i = snkHead; i <= SnkLen; i++)
            {
                if (x == SnkLct[i].X && y == SnkLct[i].Y)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 判断是否撞墙
        /// </summary>
        /// <returns></returns>
        public bool CheckSnakeBodyInFrm()
        {
            if (SnkLct[1].X >= 560 || SnkLct[1].Y >= 512 || SnkLct[1].X < 0 || SnkLct[1].Y < 32)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 判断是否吃到食物
        /// </summary>
        /// <param name="FoodLct"></param>
        /// <returns></returns>
        public bool EatedFood(Point FoodLct)
        {
            if (SnkLct[1].X == FoodLct.X && SnkLct[1].Y == FoodLct.Y)
            {
                if (SnkLen < SNAKE_MAX_LENGTH)
                {
                    SnkLen++;
                    SnkLct[SnkLen].X=SnkLct[SnkLen - 1].X;
                    SnkLct[SnkLen].Y = SnkLct[SnkLen - 1].Y;
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 蛇的控制前进
        /// </summary>
        /// <param name="drc"></param>
        public void Forward(int drc)
        {
            Point tmp = new Point();
            tmp.X = SnkLct[1].X;
            tmp.Y = SnkLct[1].Y;
            for (int i = SnkLen; i > 1; i--)
            {
                //蛇头动,把蛇头的坐标逐个后移(蛇身往蛇头方向位移)
                SnkLct[i].X = SnkLct[i - 1].X;
                SnkLct[i].Y = SnkLct[i - 1].Y;   
            }
            switch (drc)
            {
                //根据设置的方向,计算蛇头的坐标
                case 1:
                    SnkLct[1].X = tmp.X;
                    SnkLct[1].Y = tmp.Y - SnkWidth;
                    break;//上
                case 2:
                    SnkLct[1].X = tmp.X + SnkWidth;
                    SnkLct[1].Y = tmp.Y;
                    break;//右
                case 3:
                    SnkLct[1].X = tmp.X;
                    SnkLct[1].Y = tmp.Y + SnkWidth;
                    break;//下
                case 4:
                    SnkLct[1].X = tmp.X - SnkWidth;
                    SnkLct[1].Y = tmp.Y;
                    break;//下
            }  
        }
    }
}

Game类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

namespace SnakeGame
{
    //经过了两层封装,先封装了蛇这个类,然后蛇以对象的形式在Game类中调用,在接口处只调用游戏类就行了。也是三层封装的思想。
    
    //三层封装为:表现层、逻辑层、实体层
    public class Game
    {
        public Point FoodLct = new Point();//缓存食物的坐标
        public int score = 0;//得分
        public bool pause;//暂停
        public Snake snake = new Snake();

        /// <summary>
        /// 游戏初始化
        /// </summary>
        public void GameInit()
        {
            pause = false;
            score = 0;
            snake.SnakeInit();//初始化蛇
        }

        /// <summary>
        /// 随即显示食物
        /// </summary>
        public void ShowFood()
        {
            Random rmd = new Random();
            int x, y;
            x = rmd.Next(0, 35) * snake.SnkWidth;
            y = 32 + rmd.Next(0,  30) * snake.SnkWidth;
            while (snake.CheckInSnakeBody(x, y, 1))
            {
                x = rmd.Next(0, 32) * snake.SnkWidth;
                y = 32 + rmd.Next(0, 30) * snake.SnkWidth;
            }
            FoodLct.X = x;
            FoodLct.Y = y;
        }

        /// <summary>
        /// 分数
        /// </summary>
        /// <returns></returns>
        public bool AddScore()
        {
            if (snake.EatedFood(FoodLct))
            {
                score += 10;
                return true;
            }
            return false;
        }

        /// <summary>
        /// 判断游戏是否结束
        /// </summary>
        /// <returns></returns>
        public bool Dead()
        {
            return snake.CheckSnakeBodyInFrm() || snake.CheckSnakeHeadInSnakeBody();
        }
    }
}

主程序:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SnakeGame
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        Game game = new Game();

        /// <summary>
        /// 绘制一个方块
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        private void DrawShape(int x, int y)
        {
            Graphics g = CreateGraphics();
            Pen pen = new Pen(Color.Green, 1);
            SolidBrush brush = new SolidBrush(Color.GreenYellow);
            g.DrawRectangle(pen, x, y, 15, 15);
            g.FillRectangle(brush, x, y, 15,15);
        }

        /// <summary>
        /// 开始
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsmiStart_Click(object sender, EventArgs e)
        {
            tsmiPause.Enabled = true;
            game.GameInit();
            timerMove.Start();
            game.ShowFood();
            lblFood.Location = game.FoodLct;
        }

        /// <summary>
        /// 暂停
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsmiPause_Click(object sender, EventArgs e)
        {
            if (game.pause == false)
            {
                game.pause = true;
                timerMove.Enabled = false;
            }
            else
            {
                game.pause = false;
                timerMove.Enabled = true;
            }
            tsmiPause.Checked = game.pause;
        }

        /// <summary>
        /// 退出
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsmiStop_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        /// <summary>
        /// 加载
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            timerMove.Interval = 150;
            tsmiPause.Enabled = false;
        }

        /// <summary>
        /// 时间事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timerMove_Tick(object sender, EventArgs e)
        {
            if (game.score < 100)
            {
                timerMove.Interval = 150;
            }
            else if (game.score < 150)
            {
                timerMove.Interval = 100;
            }
            else
            {
                timerMove.Interval = 50;
            }

            Graphics g = CreateGraphics();
            g.Clear(Color.DarkKhaki);//清除整个画面
            game.snake.Forward(game.snake.SnkDrt);

            for (int i = 1; i <= game.snake.SnkLen; i++)
            {
                DrawShape(game.snake.SnkLct[i].X, game.snake.SnkLct[i].Y);
            }

            if (game.AddScore())
            {
                game.ShowFood();
                lblFood.Location = game.FoodLct;
            }
            this.Text = this.Text.Substring(0, this.Text.IndexOf(": ") + 9) + this.game.score.ToString();
            if (game.Dead())
            {
                timerMove.Enabled = false;
                tsmiPause.Enabled = false;
                MessageBox.Show("游戏结束!\n" + "得分:" + game.score, "", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        /// <summary>
        /// 方向键
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (game.pause == false)
            {
                string key = e.KeyCode.ToString();
                switch (key)
                {
                    //按上方向键 或小键盘的8键时,向上移动一单元格
                    case "Up":
                        { 
                            //正在向下走时,不允许向上,下面相同
                            if (game.snake.SnkDrt != 3)
                            {
                                game.snake.SnkDrt = 1;
                            }
                            break;
                        }
                    case "Right":
                        {
                            if (game.snake.SnkDrt != 4)
                            {
                                game.snake.SnkDrt = 2;
                            }
                            break;
                        }
                    case "Down":
                        {
                            if (game.snake.SnkDrt != 1)
                            {
                                game.snake.SnkDrt = 3;
                            }
                            break;
                        }
                    case "Left":
                        {
                            if (game.snake.SnkDrt != 2)
                            {
                                game.snake.SnkDrt = 4; 
                            }
                            break;
                        }
                }
            }
        }


    }
}


总结

这个程序不仅实现了贪吃蛇游戏,也体现了面向对象封装的思想,即先封装“蛇”实体类,然后封装“游戏”逻辑类,最后在窗体中调用Game类,Game类调用Snake类,体现三层架构的思想:实体层、逻辑层、表现层。

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
游戏名称:贪吃蛇 游戏级别:10级 注意:因为文件太大,无法上传,所以将音乐和图片文件另外发布,请下载(免费),下载完解压缩后,将音乐和图片放在Debug根目录下即可。 游戏说明: 关于控制蛇运动方向: 用键盘上的↑、↓、←、→控制蛇的运动方向。 当蛇向一个方向运动时,它的反向键被锁定。 不能通过连续摁某个方向键而加快蛇的运动。 若在游戏中,蛇头碰了墙或是自己的身体,则游戏结束。 关于蛇吃食物: 蛇每吃一个食物增长一节,并且得分加10分,总共为100节。 蛇每增长10节游戏上升一个级别。 关于游戏结束: 如果在游戏过程中,蛇头碰墙或是碰到了自己的身体,则游戏结束。 如果在游戏过程中,用户选择退出游戏,则会提醒用户游戏正在进行中,是否要退出。 选择退出,则游戏结束。 选择取消,则游戏继续。 如果玩家成功过关,则游戏结束。 在上述任何一种情况下,系统都会询问用户:是否保存游戏成绩? 选择确定,如果姓名为空,则默认以“匿名玩家”记录。 选择取消,则不记录。 关于蛇运动的速度: 玩家可以通过:选项->速度 打开窗口。 系统默认的方式是变速游戏。 玩家可以自行选择变速游戏或是均速游戏。 变速游戏:速度分1-10个级别。 并且根据关卡的高低决定速度的快慢。 均速游戏:用户可以自行选择所要速度的快慢。 1表示最慢,10表示最快。 关于音乐的播放: 当打开游戏界面时,音乐会自动播放,默认的音乐是:Remeber。 若玩家要修改或关闭音乐,可以通过:选项->音乐 或是 F5快捷键 打开窗口。 若玩家不想播放音乐,请点击关闭。 若玩家要播放选中的音乐,请点击确定。 关于界面的选择: 玩家可以根据爱好选择想要的图片,总共有8张背景图片供选择。 玩家选择图片后,可以在对话框的右边预览到图片。 点击确定则显示选中的图片,点击取消则显示原先图片。 当游戏开始后,此功能键不能用。 关于查看记录: 玩家可以通过:关于->查看记录 或 F6快捷键 打开窗口。 窗口中显示了以往玩家的前三名成绩。 关于游戏说明: 玩家可以通过:关于->游戏说明 或 F7快捷键 打开窗口。 窗口中显示了本游戏的说明。 关于游戏的快捷键: 开始:F2 暂停:F3 退出:F4 音乐:F5 查看记录:F6 游戏说明:F7

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值