c#生成2048游戏(1)

2048游戏

需求分析

  • 可以使用W、S、A、D键进行操作
  • 游戏开始时随机的产生2个数值为2/4的方格,位置随机
  • 每次按下移动键后,逐行计算移动后的方格值。每行移动的算法是:先把移动倒数第二个数,有3种情况,如果次数本身是0,则不移动;或者前面有数,则不移动,如果相等则合并;不然则移动。
  • 一次移动结束后,在所有值为0的方格中随机的分配一个2/4的值。
  • 所有方格值不为0且上下、左右相邻的方格都不相等,或者任意方格的值为2048,则游戏结束。
  • 4出现的概率为90%,2出现的概率为为10%。

分析

整个游戏过程有3个类,格子类网格类还有游戏管理类
格子类代表16个格子中的每一个格子,
成员变量:行下标、列下标,格子代表的数,是否是第一次合并,因为是控制台程序所以不用颜色了

运行结果:
这里写图片描述
这里写图片描述

    /// <summary>
    /// 格子类
    /// </summary>
    class Box
    {
       private int row = 0;
       private int cols = 0;
        int num  = 0;
        bool isFirst = false;//是否是第一次合并
        public int Num
        {
            get
            {
                return num;
            }
            set
            {
                num = value;
            }
        }

        /// <summary>
        /// 获取行数
        /// </summary>
        public int Row
        {
            get
            {
                return row;
            }
            set
            {
                row = value;
            }
        }
        /// <summary>
        /// 获取列数
        /// </summary>
        public int Cols
        {
            get
            {
                return cols;
            }
        }

        public bool IsFirst
        {
            get
            {
                return isFirst;
            }

            set
            {
                isFirst = value;
            }
        }

        public Box(int row,int cols)
        {
            this.row = row;
            this.cols = cols;
            this.Num = 0;
        }

    }
}

网格类,负责接收用户的上下左右操作,然后让网格内的格子进行相应的移动。然后判断游戏的输赢.(主要操作)
成员变量有:行数,列数,所有格子数(二维数组储存),布尔型判断是否第一次产生随机数,产生随机数的数量,储存上一次生成的随机数的值,当前生成随机数的个数,游戏进行开关,合并开关集合

 /// <summary>
    /// 网格类
    /// </summary>
    public class Grid
    {
        int row = 4;//行数
        int cols = 4;//列数
        Box[,] boxList;//数组,储存
        bool isFirst = true; //判断是否是第一次生成随机数
        int count = 0; //选择产生每一次随机生成数字的数量,1or2
        int num = 2; //储存上次随机生成数
        int countNum = 0; //储存生成了的数字的数量,一到16个以便进行游戏输赢判断
        bool gameBegin; //游戏开关
        Queue<Box> isMerage;//判断是是否已经合并集合
        Random r;


        public Grid(int row, int cols)
        {
            this.row = row < 0 ? this.row : row;
            this.cols = cols < 0 ? this.cols : cols;
            boxList = new Box[row, cols];
            r = new Random();
            isMerage = new Queue<Box>();
            gameBegin = true; //初始化游戏开始
        }
        /// <summary>
        /// 返回游戏开关
        /// </summary>
        public bool GameBegin
        {
            get
            {
                return gameBegin;
            }
        }

        /// <summary>
        /// 初始化布局
        /// </summary>
        public void Init()
        {
            for (int i = 0; i < boxList.GetLength(0); i++)
            {
                for (int j = 0; j < boxList.GetLength(1); j++)
                {
                    Box box = new Box(i, j);
                    boxList[i, j] = box;
                }
            }
            RandomNum();
            Test();
        }

        /// <summary>
        /// 随机生成数字
        /// </summary>
        public void RandomNum()
        {
            //第一次生成两个数字
            if (isFirst)
            {
                count = 2;
                isFirst = false;
            }
            //后面每一次只生成一个数字
            else
            {
                count = 1;
            }
            countNum += count;//生成一个随机数字,个数加一,以便胜负的判断
            for (int i = 0; i < count;)//容易形成死循环,万一没有位置初始化随机数字容易陷入死循环
            {
                //随机生成下标
                int rObj = r.Next(0, row);
                int cObj = r.Next(0, cols);
                if (boxList[rObj, cObj].Num != 0) {
                    continue;

                }
                //避免出现两个4
                if (num == 4)
                {
                    num = 2;
                }
                else
                {
                    //随机生成2,4的概率 ,90%2,20%4
                    int chance = r.Next(1, 11);
                    if (chance > 10) num = 2;
                    else num = 4;
                }
                Console.WriteLine("生成的数:" + num);
                boxList[rObj, cObj].Num = num;
                i++;
            }
        }

        /// <summary>
        /// 用户输入了按键,根据按键选择移动方向的方法
        /// </summary>
        /// <param name="keyValue"></param>
        public void move(ConsoleKey keyValue)
        {
            switch (keyValue)
            {
                //W 向上
                case ConsoleKey.W: GoUp(); break;
                //S 向下
                case ConsoleKey.S: GoDown(); break;
                //A 向左
                case ConsoleKey.A: GoLetf(); break;
                //D 向右
                case ConsoleKey.D: GoRight(); break;

                default: Console.WriteLine("输入了错误的选择"); break;
            }
            ReSet();//做完一次操作后重置一下开关
        }

        /// <summary>
        /// 向右运动
        /// </summary>
        private void GoRight()
        {
                //行下标循环
                for (int r = 0; r < boxList.GetLength(0); r++)
                {
                    //列下标循环
                    for (int c = boxList.GetLength(1) - 2; c >= 0; c--) //按照每行有多少列来循环,从右边到左边
                    {
                        Box box = boxList[r, c];
                        if (box.Num == 0) continue;
                        for (int nc = c + 1; nc < boxList.GetLength(1); nc++)//数字移动的3种情况
                        {
                            Box nextBox = boxList[r, nc];
                            if (nextBox.Num == 0) //如果前面格子里没有数,就往前移
                            {
                                nextBox.Num = box.Num;
                                box.Num = 0;
                                box = nextBox;
                                continue;
                            }
                            if (box.Num == nextBox.Num && !nextBox.IsFirst)//如果格子里的数和要往前移的格子里的数是相同的,就可以合并
                            {
                                nextBox.IsFirst = true;
                                nextBox.Num *= 2;
                                box.Num = 0;
                                countNum--;//合并后网格上的格子数减一
                                isMerage.Enqueue(nextBox);//添加了已经合并的数,便于修改合并开关
                            }
                            break;//不能移动格子,也不能合并,格子本身不做任何操作
                        }
                }
            }
            GameSwitch();//判断游戏输赢

        }

        /// <summary>
        /// 向左移动
        /// </summary>
        private void GoLetf()
        {
                //循环行下标
                for (int r = 0; r < boxList.GetLength(0); r++)
                {
                    //循环列下表
                    for (int c = boxList.GetLength(1) - 3; c < boxList.GetLength(1); c++)//按照每行有多少列来循环,从左边到右边
                    {
                        Box box = boxList[r, c];
                        if (box.Num == 0) continue;
                        for (int nc = c - 1; nc >= 0; nc--)
                        {
                        Box nextBox = boxList[r, nc];
                        if (box.Num == 0) continue;//检测当前盒子是否需要往下移动
                        if (nextBox.Num == 0)
                            {
                                nextBox.Num = box.Num;
                                box.Num = 0;
                                box = nextBox;
                                continue;
                            }
                            if (nextBox.Num == box.Num && !nextBox.IsFirst)//合并操作
                            {
                                nextBox.Num *= 2;
                                nextBox.IsFirst = true;
                                box.Num = 0;
                                countNum--;//合并网格的元素减一
                                isMerage.Enqueue(nextBox);//添加已经合并的数,以便重置合并开关
                            }
                            break;
                        }
                }

            }
            GameSwitch();//判断游戏输赢

        }

        /// <summary>
        /// 向上移动
        /// </summary>
        private void GoUp()
        {
                //循环列下标 
                for (int c = 0; c < boxList.GetLength(1); c++)
                {
                    //循环行下标
                    for (int r = boxList.GetLength(0) - 3; r < boxList.GetLength(0); r++)  //从下到上
                    {
                        Box box = boxList[r, c];
                        if (box.Num == 0) continue;//检测当前盒子是否需要往下移动
                        for (int k = r - 1; k >= 0; k--)
                        {
                            Box nextBox = boxList[k, c];
                            if (nextBox.Num == 0)//如果上一格元素为空,则可以移动
                            {
                                nextBox.Num = box.Num; //把前面的元素移动到后面的元素
                                box.Num = 0;
                                box = nextBox;
                                continue;
                            }
                            if (box.Num == nextBox.Num && !nextBox.IsFirst)
                            {
                                nextBox.Num *= 2;
                                nextBox.IsFirst = true;
                                box.Num = 0;
                                countNum--;//合并网格,随机数的个数元素减一
                                isMerage.Enqueue(nextBox);//添加已经合并的数,以便修改开关
                            }
                            break;
                        }
                    }
            }

            GameSwitch();//判断游戏输赢
        }

        /// <summary>
        /// 向下的方法
        /// </summary>
        private void GoDown()
        {
                //循环列的下标
                for (var c = 0; c < boxList.GetLength(1); c++)
                {
                    for (var r = boxList.GetLength(0) - 2; r >= 0; r--)
                    {
                        Box box = boxList[r, c];//当前进行检测判断是否可以往下移动或者合并的格子
                        if (box.Num == 0) continue;
                        for (var k = r + 1; k < boxList.GetLength(0); k++)
                        {
                            Box nextBox = boxList[k, c];
                            //进行空白格子判断
                            if (nextBox.Num == 0)
                            {
                                //找到一个就往下移一个
                                nextBox.Num = box.Num;
                                box.Num = 0;
                                box = nextBox;
                                continue;
                            }
                            //进行格子合并的判断
                            if (nextBox.Num == box.Num && !nextBox.IsFirst)
                            {
                                nextBox.Num *= 2;
                                nextBox.IsFirst = true;
                                box.Num = 0;
                                isMerage.Enqueue(nextBox);//添加已经合并的数,以便重置开关
                                countNum--;//合并网格的元素减一
                            }
                            break;
                        }
                }

            }
            GameSwitch();//判断游戏输赢

        }

        /// <summary>
        /// 打印布局
        /// </summary>
        private void Test()
        {

            Console.WriteLine("-------------------------------");
            for (int i = 0; i < boxList.GetLength(0); i++)
            {
                for (int j = 0; j < boxList.GetLength(1); j++)
                {
                    if (boxList[i, j].Num==2048) //游戏胜利
                    {
                        Console.WriteLine("游戏胜利");
                        gameBegin = false;

                    }
                    Console.Write(boxList[i, j].Num + "\t");
                }
                Console.Write("\n");
            }
            Console.WriteLine("-------------------------------");
        }

        /// <summary>
        /// 重置开关
        /// </summary>
        private void ReSet()
        {
            while (isMerage.Count > 0)
            {
                isMerage.Dequeue().IsFirst = false;
            }
        }

        /// <summary>
        /// 选择实现随机数的的生成
        /// </summary>
        private void GameSwitch()
        {

            if (countNum < 16)//数的个数小于等于16时才能随机生成
            {
                RandomNum();

            }
            if (countNum == 16)//该判断一下输赢了
            {
                IsGameOver();
            }
            Console.WriteLine("网格上的元素:" + countNum);
            Test();
        }
        /// <summary>
        /// 判断游戏是否进行
        /// </summary>
        public void IsGameOver()
        {

            for (int r = 0; r < row; r++)
            {
                for (int c = 0; c < cols; c++)
                {
                    if (c + 1 < row)//如果该元素列相邻元素存在,就比较
                    {
                        if (boxList[r, c].Num == boxList[r, c+1].Num)
                        {
                            return;
                        }
                    }
                    if (r + 1 < cols)//如果该元素的行相邻元素存在,就比较
                    {
                        if (boxList[r, c].Num == boxList[r+1, c].Num)
                        {
                             return;//如果该数与行相邻相等,游戏还可以进行
                        }
                    }
                }
            }
            gameBegin = false;
        }

    }

管理类,管理整个格局,游戏开始到游戏结束.
成员:格局类


 /// <summary>
    /// 管理游戏类
    /// </summary>
    class Maneger
    {
        Grid gird;

        public Maneger()
        {
            gird = new Grid(4,4);
        }

        public void InitGame()
        {

            gird.Init();
            Console.WriteLine("2048游戏开始,规则如下,通过aswd键滑动字符串");
            Console.WriteLine("每滑动一次,所有的数字就会想滑动的方向靠拢");
            Console.WriteLine("只要有一个格子出现2048,就取得游戏胜利");
        }
        /// <summary>
        /// 获取用户的输入
        /// </summary>
        public void choice()
        {
            ConsoleKeyInfo key = Console.ReadKey();
            while (key.Key != ConsoleKey.Escape){ //输出ESC退出
                gird.move(key.Key);
                //游戏是否结束
                if (!gird.GameBegin)
                {
                    IsOver();
                    break;
                }
                key = Console.ReadKey();
            }
        }
       private void IsOver()
        {
                Console.WriteLine("游戏结束");
        }
    }

开始程序


    class Program
    {
        static void Main(string[] args)
        {
            Maneger ma = new Maneger();
            ma.InitGame();
            ma.choice();

            Console.ReadLine();

        }

    }

目前2048还有BUG ,我已经修改了些许BUG,在下一篇c#生成2048游戏(2)

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C# WinForm 2048游戏实现可以分为以下几个步骤: 1. 创建WinForm项目 首先,你需要创建一个C# WinForm项目。在Visual Studio中,选择File -> New -> Project -> Windows Forms App (.NET Framework)。然后,给你的项目命名,选择保存位置,最后点击Create按钮创建项目。 2. 设计游戏界面 在WinForm应用程序中,你可以使用控件来设计游戏界面。在这个游戏中,我们需要一个网格来放置数字方块,所以你可以使用TableLayoutPanel控件来实现。你可以在设计视图下拖动TableLayoutPanel控件到窗体中,并设置它的行和列以及单元格大小。 3. 实现数字方块的生成与移动 在2048游戏中,每次移动会生成一个新的数字方块。因此,你需要在代码中实现数字方块的生成。你可以使用Random类生成随机数,然后将数字方块添加到网格中。 当用户按下上、下、左、右箭头键时,数字方块应该向相应的方向移动。你可以在代码中实现这些移动,并且在移动完成后生成新的数字方块。 4. 判断游戏是否结束 当数字方块无法再移动时,游戏结束。你可以通过判断数字方块的位置和数值来判断游戏是否结束。如果所有的单元格都被占据,并且相邻的数字方块数值不相等,那么游戏结束。 5. 实现分数统计 在2048游戏中,每次移动会得到相应的分数。你可以在代码中实现分数统计,并将分数显示在窗体上。 以上就是实现C# WinForm 2048游戏的基本步骤。你可以根据自己的需要进行扩展和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值