zx2cwf 发表于 2015-7-18 22:51

.NET C#贪吃蛇游戏课程设计项目

这是写了三天的小游戏,大家下载玩玩,自己暂未发现任何bug



源码下载:




主要源码如下:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Media;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using 贪吃蛇.Entities;
using 贪吃蛇.Util;
using System.Runtime.InteropServices;// 使用MCI Command String多媒体设备程序接口

namespace 贪吃蛇.Controller
{
    /// <summary>
    /// 游戏控制器 用来控制整个游戏的逻辑
    /// </summary>
    class GameController
    {
      private Ground ground;//游戏控制器所控制的背景对象
      public Snake snake;//游戏控制器所控制的蛇对象

      private MainForm mForm;//主窗体类

      private Thread snakeMoveThread;//线程控制

      private Graphics graphics;//Gdi+对象


      /// <summary>
      /// 构造函数,初始化当前对象的背景字段和蛇字段
      /// </summary>
      public GameController(Graphics g, MainForm mForm)
      {
            this.mForm = mForm;
            this.graphics = g;
            this.ground = new Ground();
            this.snake = new Snake();
      }

      /// <summary>
      /// 初始化地图、蛇以及食物
      /// </summary>
      public void InitMap()
      {
            //绘制背景
            this.ground.DrawMe(graphics);

            //绘制蛇
            this.snake.DrawMe(graphics);

            //在地图上随机的产生一个食物
            this.ground.MakeFood(graphics, snake);
      }


      /// <summary>
      /// 开始新游戏的方法
      /// </summary>
      public void NewGame()
      {


            //让蛇动起来
            snakeMoveThread = new Thread(SnakeAutoMoveThread);//创建线程
            snakeMoveThread.IsBackground = true;//设置为后台线程
            snakeMoveThread.Start();//开启线程

      }


      #region 蛇移动的线程方法
      /// <summary>
      /// 蛇移动的线程方法
      /// </summary>
      private void SnakeAutoMoveThread()
      {

            //判断蛇头是否能继续移动
            //取出蛇头的坐标 判断蛇头的坐标是否越界

            while (ground.IsMoveable(snake))
            {
                if (snake.IsEatSelf())//判断蛇头是否吃到自己
                {
                  break;
                }

                if (ground.IsEatFood(snake))//判断一下蛇是否吃到了食物
                {
                  snake.AddBody();//如果吃到了食物 增加蛇的身体
                  ground.MakeFood(graphics, snake);//再次随机的产生一个食物
                  CommonHelper.Score++;//加分数
                  mForm.ShowScore();
                }
                this.snake.AutoMove(graphics);
                Thread.Sleep(CommonHelper.GetSpeed());
            }
            CommonHelper.SoundPlayer.Stop();
            SoundPlayer sp = new SoundPlayer();
            sp.SoundLocation = Directory.GetCurrentDirectory() + @"\sound\gameover.wav";
            sp.Play();
            graphics.DrawString("GameOver", new Font("宋体", 50), new SolidBrush(Color.Yellow), new Point(30, 30));
      }
      #endregion

      #region 处理用户传递过来的按键
      /// <summary>
      /// 处理用户传递过来的按键
      /// </summary>
      /// <param name="keyData"></param>
      public void ProcessDialogKey(Keys keyData)
      {
            switch (keyData)
            {
                case Keys.Up:
                  snake.SnakeHead.Dir = Direction.Up;
                  break;
                case Keys.Down:
                  snake.SnakeHead.Dir = Direction.Down;
                  break;
                case Keys.Right:
                  snake.SnakeHead.Dir = Direction.Right;
                  break;
                case Keys.Left:
                  snake.SnakeHead.Dir = Direction.Left;
                  break;
            }
      }
      #endregion

      #region 暂停线程 暂停游戏
      /// <summary>
      /// 暂停线程 暂停游戏
      /// </summary>
      public void PauseThread()
      {
            try
            {
                CommonHelper.SoundPlayer.Stop();
                snakeMoveThread.Suspend();
            }
            catch
            {
            }

      }
      #endregion

      #region 恢复线程 恢复游戏
      /// <summary>
      /// 恢复线程 恢复游戏
      /// </summary>
      public void RecoverThread()
      {
            try
            {
                CommonHelper.SoundPlayer.PlayLooping();
                snakeMoveThread.Resume();
            }
            catch
            {


            }
      }
      #endregion

    }
}


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.Util;

namespace 贪吃蛇.Entities
{
    /// <summary>
    /// 贪吃蛇类 表示一条贪吃蛇
    /// </summary>
    class Snake
    {
      //蛇的身体单元集合,使用链表集合可以最快得到蛇头以及蛇尾
      public LinkedList<SnakeUnit> body = new LinkedList<SnakeUnit>();

      /// <summary>
      /// 蛇头属性 取到body集合中的第一个元素
      /// </summary>
      public SnakeUnit SnakeHead
      {
            get
            {
                return this.body.First.Value;
            }
      }
      /// <summary>
      /// 构造函数,为body链表集合中新增3个身体单元
      /// </summary>
      public Snake()
      {
            //蛇头:
            //1.创建一个身体单元对象
            SnakeUnit unit = new SnakeUnit(CommonHelper.ColCount / 2, CommonHelper.RowCount / 2);
            //2.将这个身体单元对象添加到链表集合中去,当做蛇头
            body.AddFirst(unit);
            AddBody();
            AddBody();
      }

      /// <summary>
      /// 为当前蛇对象新增一个身体单元
      /// </summary>
      public void AddBody()
      {
            //创建一个身体单元对象,这个身体单元对象的坐标应在最后1个身体单元的基础上行不变
            //列加1
            Position pos = body.Last.Value.Pos;//取到最后一个节点的坐标

            //行不变,列+1 对pos的修改不会影响最后一个节点的位置,因为pos为结构体(值类型)
            pos.colIndex++;

            //创建身体1个单元对象,坐标就是pos
            SnakeUnit unit = new SnakeUnit(pos,RandomMaker.GetRandomColor());
            body.AddLast(unit);

      }

      /// <summary>
      /// 蛇自己画自己的方法
      /// </summary>
      /// <param name="g"></param>
      public void DrawMe(Graphics g)
      {
            //蛇自己画自己的方法,只需要遍历body链表集合中的每个元素
            //调用每个元素的DrawMe方法
            foreach (SnakeUnit u in body)
            {
                u.DrawMe(g);
            }
      }

      /// <summary>
      /// 蛇自动移动的方法
      /// </summary>
      public void AutoMove(Graphics g)
      {
            //擦除整条蛇
            this.WipeMe(g);

            //根据每一个单元的前进方法 改变身体单元的坐标
            LinkedListNode<SnakeUnit> node = body.First;
            while (node!=null)
            {
                //先将遍历出来的元素按照现在的方向更改坐标
                switch (node.Value.Dir)
                {
                  case Direction.Left:
                        node.Value.MoveToLeft();
                        break;
                  case Direction.Right:
                        node.Value.MoveToRight();
                        break;
                  case Direction.Down:
                        node.Value.MovetoDown();
                        break;
                  case Direction.Up:
                        node.Value.MoveToUp();
                        break;
                  default:
                        break;
                }
                //将刚才移动的方向保存起来
                node.Value.OldDir = node.Value.Dir;

                //设置下一次前进的方向
                if (node.Previous!=null)
                {
                  node.Value.Dir = node.Previous.Value.OldDir;
                }

                node = node.Next;
            }
            


            //根据坐标绘制整条蛇
            this.DrawMe(g);

      }

      /// <summary>
      /// 蛇自己擦除自己的方法
      /// </summary>
      /// <param name="g"></param>
      private void WipeMe(Graphics g)
      {
            //遍历链表集合,调用每一个身体单元自己擦除自己的方法
            foreach (SnakeUnit u in body)
            {
                u.WipeMe(g);
            }
      }
      /// <summary>
      /// 判断蛇头是否吃到了自己
      /// </summary>
      /// <returns></returns>
      public bool IsEatSelf()
      {
            //取出蛇头的坐标
            Position pos = this.SnakeHead.Pos;

            //将其他身体单元遍历出来 做对比
            LinkedListNode<SnakeUnit> node = body.First.Next;
            
            while (node!=null)
            {
                if (node.Value.Pos.colIndex==pos.colIndex&&node.Value.Pos.rowIndex==pos.rowIndex)
                {
                  return true;
                }
                node = node.Next;
            }
            return false;

      }
    }

}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.Util;


namespace 贪吃蛇.Entities
{
    /// <summary>
    /// 身体单元类 用来表示组成蛇的每一个身体单元
    /// </summary>
    class SnakeUnit
    {
      #region 身体单元的颜色 默认为红色

      /// <summary>
      /// 颜色
      /// </summary>
      private Color color = Color.Red;

      public Color Color
      {
            get { return color; }
            set { color = value; }
      }

      #endregion

      #region 身体单元的坐标
      /// <summary>
      /// 坐标
      /// </summary>
      private Position pos;

      internal Position Pos
      {
            get { return pos; }
            set { pos = value; }
      }
      #endregion

      #region 构造函数 用于各种方式创建对象
      public SnakeUnit(int rowIndex, int colIndex)
      {
            this.pos.rowIndex = rowIndex;
            this.pos.colIndex = colIndex;
      }

      public SnakeUnit(int rowIndex, int colIndex, Color color)
            : this(rowIndex, colIndex)
      {
            this.color = color;
      }
      public SnakeUnit(Position pos)
      {
            this.pos = pos;
      }
      public SnakeUnit(Position pos, Color color)
            : this(pos)
      {
            this.color = color;
      }
      #endregion

      #region 将当前身体单元所在单元格的颜色填充为当前身体单元对象的颜色
      /// <summary>
      /// 当前身体单元根据自己的坐标和颜色将自己绘制出来
      /// </summary>
      /// <param name="g"></param>
      public void DrawMe(Graphics g)
      {
            //将当前身体单元所在单元格的颜色填充为当前身体单元对象的颜色
            Brush brush = new SolidBrush(this.color);
            g.FillRectangle(brush, new Rectangle(
                this.pos.colIndex * CommonHelper.SquLength + 1,
                this.pos.rowIndex * CommonHelper.SquLength + 1,
                CommonHelper.SquLength - 1,
                CommonHelper.SquLength - 1
                ));
      }
      #endregion

      #region 身体但单元的前进方向 默认向左
      private Direction dir = Direction.Left;

      internal Direction Dir
      {
            get { return dir; }
            set { dir = value; }
      }
      #endregion

      #region 身体单元向左移动
      /// <summary>
      /// 身体单元方向向走移动 其实就是身体单元的列坐标-1
      /// </summary>
      public void MoveToLeft()
      {
            this.pos.colIndex--;
      }
      #endregion
      #region 身体单元向上移动
      /// <summary>
      /// 身体单元方向向上移动 其实就是身体单元的行坐标-1
      /// </summary>
      public void MoveToUp()
      {
            this.pos.rowIndex--;
      }
      #endregion
      #region 身体单元向右移动
      /// <summary>
      /// 身体单元方向向右移动的方法 其实就是身体单元的列坐标+1
      /// </summary>
      public void MoveToRight()
      {
            this.pos.colIndex++;
      }
      #endregion
      #region 身体单元向下移动
      /// <summary>
      /// 身体单元方向向下移动的方向 其实就是身体单元的行坐标+1
      /// </summary>
      public void MovetoDown()
      {
            this.pos.rowIndex++;
      }
      #endregion

      #region 身体单元擦除自己的方法
      /// <summary>
      /// 身体单元自己擦除自己方法
      /// </summary>
      /// <param name="g"></param>
      public void WipeMe(Graphics g)
      {
            //将当前身体单元所在的单元格的颜色填充为背景色
            Brush brush = new SolidBrush(CommonHelper.GroundColor);
            g.FillRectangle(brush, new Rectangle(
                this.pos.colIndex * CommonHelper.SquLength + 1,
                this.pos.rowIndex * CommonHelper.SquLength + 1,
                CommonHelper.SquLength - 1,
                CommonHelper.SquLength - 1
                ));
      }
      #endregion

      #region 身体单元移动的旧方向
      private Direction oldDir = Direction.Left;

      internal Direction OldDir
      {
            get { return oldDir; }
            set { oldDir = value; }
      }
      #endregion
    }
}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.Entities;
using System.Media;


namespace 贪吃蛇.Util
{
    /// <summary>
    /// 游戏帮助类 这个类中提供整个程序中需要被共享的数据
    /// </summary>
    static class CommonHelper
    {
      #region 初始化游戏环境

      /// <summary>
      /// 初始化游戏环境的方法
      /// </summary>
      /// <param name="panelWidth">游戏面板的宽度</param>
      /// <param name="panelHeight">游戏面板的高度</param>
      public static Size InitializeEnvironment(int panelWidth, int panelHeight)
      {
            //根据游戏面板的宽度和高度以及游戏面板的总行数和总列数为squLength赋值
            int width = panelWidth / colCount;//小方格的宽度
            int height = panelHeight / rowCount;//小方格的高度

            //取较短的一边作为小方格的边长
            squLength = width > height ? height : width;//取得小方格的边长

            Size size = new Size();
            size.Width = squLength * colCount+1;
            size.Height = squLength * rowCount+1;
            return size;
      }
      #endregion

      #region 游戏面板的总行数 默认14行
      private static int rowCount = 14;

      public static int RowCount
      {
            get { return CommonHelper.rowCount; }
            set { CommonHelper.rowCount = value; }
      }
      #endregion

      #region 游戏面板的总列数 默认12列
      private static int colCount = 12;

      public static int ColCount
      {
            get { return CommonHelper.colCount; }
            set { CommonHelper.colCount = value; }
      }
      #endregion

      #region 小方格的边长
      private static int squLength;

      public static int SquLength
      {
            get
            {
                return CommonHelper.squLength;
            }
      }
      #endregion

      #region 线条颜色 默认是黑色
      private static Color lineColor = Color.Black;

      public static Color LineColor
      {
            get { return CommonHelper.lineColor; }
            set { CommonHelper.lineColor = value; }
      }
      #endregion

      #region 背景颜色 默认是天蓝色
      private static Color groundColor = Color.SkyBlue;

      public static Color GroundColor
      {
            get { return CommonHelper.groundColor; }
            set { CommonHelper.groundColor = value; }
      }

      
      #endregion

      #region 食物的颜色 默认是白色
      private static Color foodColor = Color.White;

      public static Color FoodColor
      {
            get { return CommonHelper.foodColor; }
            set { CommonHelper.foodColor = value; }
      }
      #endregion

      #region 玩家的分数
      private static int score;

      public static int Score
      {
            get { return CommonHelper.score; }
            set { CommonHelper.score = value; }
      }
      #endregion

      #region 玩家的等级
      private static GameLevel level;

      internal static GameLevel Level
      {
            get { return CommonHelper.level; }
            set { CommonHelper.level = value; }
      }
      
      
      #endregion

      #region 游戏速度
      public static int GetSpeed()
      {
            int time=300;
            switch (level)
            {
                case GameLevel.初级:
                  time = 300;
                  break;
                case GameLevel.中级:
                  time = 200;
                  break;
                case GameLevel.高级:
                  time = 100;
                  break;
            
            }
            return time;
      }

      #endregion

      #region 存放多媒体播放对象
      /// <summary>
      /// 存放背景音乐多媒体播放对象
      /// </summary>
      private static SoundPlayer soundPlayer;
      public static SoundPlayer SoundPlayer
      {
            get { return CommonHelper.soundPlayer; }
            set { CommonHelper.soundPlayer = value; }
      }
      #endregion
    }
}




壮哥 发表于 2015-7-18 23:03

做个沙发,虽然不懂

able0 发表于 2015-7-18 23:05

学习学习 楼主好厉害

kangda666 发表于 2015-7-19 00:08

这个必须赞一个

学破处 发表于 2015-7-19 00:31

JuStkK 发表于 2015-7-19 02:13

感谢分享啊!这代码 我只看得懂中文{:6_224:}

xiaogui 发表于 2016-2-21 11:24

我要成品啊

阿軒同學 发表于 2017-7-24 03:19

下載來看看先~~~

a2655968658 发表于 2017-7-27 09:22

谢谢分享{:5_117:}

哨兵51号 发表于 2017-8-5 10:14

厉害了,可以学习学习。
页: [1] 2
查看完整版本: .NET C#贪吃蛇游戏课程设计项目