【全栈计划 —— 编程语言之C#】 C# 实现双人飞行棋小游戏

简介: 【全栈计划 —— 编程语言之C#】 C# 实现双人飞行棋小游戏

项目结构流程图


首先要清楚项目的整体实现流程,跟着项目流程图走有助于思路上更加清晰。

微信图片_20221020131634.png项目实现


一、游戏开始界面


在编写游戏的开始界环节中,值得积累的知识点是控制台字体的背景颜色和字体颜色修改

利用枚举类 ConsoleColor来调取已经存储在其中的颜色字段。

同时使用: Console.ResetColor();来控制颜色的修改

微信图片_20221020131929.png

在利用Console类调用BackgroundColor来修改控制台中字体的背景颜色

微信图片_20221020132118.png

在利用Console类调用ForegroundColor来修改控制台中字体文本的颜色

微信图片_20221020132148.png

public static void GameShow()
        #region 画游戏头
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("*****************************");
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("*****************************");
            Console.ForegroundColor = ConsoleColor.Blue;
            Console.WriteLine("*******飞行棋游戏模拟********");
            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine("*****************************");
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.WriteLine("*****************************");
        }
        #endregion

二、初始化游戏地图


初始化游戏地图的目的主要是考虑到一些固定的位置要放置一些固定的关卡。

微信图片_20221020132237.png

这个环节就没有什么值得注意的点了,常规的数组的操作,假如想玩得花一点,可以考虑用随机数来表示关卡的位置。

        public static void InitMap()
        #region 初始化游戏地图
        {
            //1 幸运轮盘
            int[] lucky = { 6, 23, 40, 55, 69, 83 };
            for(int i = 0; i < lucky.Length; i++)
                Maps[lucky[i]] = 1;
            //2 地雷
            int[] landMine = { 5, 13, 17, 33, 38, 50, 64, 80, 94 };
            for (int i = 0; i < landMine.Length; i++)
                Maps[landMine[i]] = 2;
            //3 暂停
            int[] puase = { 9, 27, 60, 93 };
            for (int i = 0; i < puase.Length; i++)
                Maps[puase[i]] = 3;
            //4 时空隧道
            int[] timeTunnel = { 20, 25, 45, 63, 72, 88, 90 };
            for (int i = 0; i < timeTunnel.Length; i++)
                Maps[timeTunnel[i]] = 4;
        }
        #endregion

三、绘制飞行棋地图


绘制飞行棋地图这里技术含量不高,主要是for循环和switch语句的使用。只是有一个需要注意的点:

在绘制每一个关卡的时候,一定要先打印出玩家的位置,再在其他位置打印地图中各个关卡。

这种才能看起来玩家确实是在玩这个游戏。

 //环节三:切实的画游戏地图  —— 总共是100个关卡,画每个关卡之前,一定要先画玩家的位置
        public static void DrawMap()
        {
            Console.WriteLine("图例:幸运轮盘:◎ 地雷:☆ 暂停:△ 时空隧道:◆");
            //第一横行 0 ~ 30
            //绘制具体的每一个关卡 因为要重复使用绘制的逻辑,因此加载为方法
            for (int i = 0; i < 30; i++)
            {
                Console.Write(DrawEveryGrid(i));
            }
            //换行
            Console.WriteLine();
            //绘制第一竖行
            for(int i = 30;i < 35; i++)
            {
                //每行的0到29绘制空格,第30个方格绘制具体关卡
                for (int j = 0; j < 29; j++) Console.Write("  ");
                Console.Write(DrawEveryGrid(i));
                //小细节,画完每个竖行,都应该换行
                Console.WriteLine();
            }
            //绘制第二横行
            for(int i = 64;i >= 35;i--)
            {
                Console.Write(DrawEveryGrid(i));
            }
            Console.WriteLine();
            //绘制第二竖行
            for(int i = 65;i < 70;i++)
            {
                Console.WriteLine(DrawEveryGrid(i));
            }
            //绘制第三横行
            for (int i = 70; i < 100; i++)
                Console.Write(DrawEveryGrid(i));
            Console.WriteLine();
        }
        //绘制走到每个关卡的逻辑
        public static string DrawEveryGrid(int i)
        #region 绘制每个关卡的逻辑
        {
            string str = "";
            //如果玩家在同一个位置,使用<>表示
            //之前只是放了一个if ,就错了
            if (PlayPos[0] == PlayPos[1] && PlayPos[0] == i)
                str = "<>";
            //其他就单独绘制玩家A和玩家B的位置信息
            else if (PlayPos[0] == i)
                str = "A";
            else if (PlayPos[1] == i)
                str = "B";
            //获取当前位置的信息,switch匹配打印出相应的关卡
            else
            {
                switch (Maps[i])
                {
                    case 0:
                        Console.ForegroundColor = ConsoleColor.DarkYellow;
                        str = "□";
                        break;
                    case 1:
                        Console.ForegroundColor = ConsoleColor.Green;
                        str = "◎";
                        break;
                    case 2:
                        Console.ForegroundColor = ConsoleColor.Red;
                        str = "☆";
                        break;
                    case 3:
                        Console.ForegroundColor = ConsoleColor.Blue;
                        str = "△";
                        break;
                    case 4:
                        Console.ForegroundColor = ConsoleColor.Cyan;
                        str = "◆";
                        break;
                }//switch
            }
            return str;
        }//方法
        #endregion 

四、玩游戏具体逻辑


到了玩家具体开始在地图上掷骰子,玩这个飞行棋的游戏的时候,整体稍微变得有点复杂了,但是跟着咱们之前梳理的流程图走下去,不会出现越写越凌乱的情况的。

① 创建两个玩家角色

既然是双人游戏,那么创建两个游戏对象是必要的环节了。

这里主要是积累程序设计的思想。

程序源于生活,也用于生活。那么玩家取名为空、玩家名字重复等情况,应该避免

        public static void CreatePlayer()
        {
            Console.WriteLine("请输入第一个玩家的姓名(按回车键继续):");
            PlayNames[0] = Console.ReadLine();
            while(Enumerable.SequenceEqual(PlayNames[0]," ")) 
            {
                Console.WriteLine("玩家姓名不可以为空,请重新输入");
                PlayNames[0] = Console.ReadLine();
            }
            Console.WriteLine();
            Console.WriteLine("请输入第二个玩家的姓名(按回车键继续):");
            PlayNames[1] = Console.ReadLine();
            while (PlayNames[1] == " ")
            {
                    Console.WriteLine("玩家姓名不可以为空,请重新输入");
                    PlayNames[1] = Console.ReadLine();
            }
            while(PlayNames[1] == PlayNames[0])
            {
                Console.WriteLine("玩家2姓名不可以和玩家1姓名重复,请重新输入");
                PlayNames[1] = Console.ReadLine();
            }
        }

② 具体走到每个关卡触发的结果

这个环节是具体的去落实游戏规则。


图例:幸运轮盘:◎ 地雷:☆ 暂停:△ 时空隧道:◆

游戏规则:

如果玩家A踩到玩家B,玩家B退6格

如果玩家踩中地雷。退6格

如果玩家踩进时空隧道,进10格

如果玩家踩到幸运轮盘, 1 交换位置,2 轰炸对方(使对方退6格)

如果玩家踩到了暂停,暂停一个回合

如果玩家踩到了方块,走到当前位置,什么都不发生


值得积累的知识点

1、按下任意键继续时,要在ReadKey中加入参数true

 Console.ReadKey(true);

倘若不加参数true,在按下任意键之后,是这种效果

微信图片_20221020132548.png

2、获取随机数需要通过Random类造对象实例,随机数的范围用Next函数确定,其区间左闭右开

      Random random = new Random();
            int ResultNum = random.Next(1, 7);
 //具体玩游戏的逻辑
        public static void PlayGame(int PlayID)
        {
            Console.ResetColor();
            Console.WriteLine("玩家{0}按下任意键掷骰子:", PlayNames[PlayID]);
            Console.ReadKey(true);//加了这个参数之后,会不显示出任意键的值
            Random random = new Random();
            int ResultNum = random.Next(1, 7);
            Console.WriteLine("玩家{0}掷出的结果是{1}", PlayNames[PlayID], ResultNum);
            Console.WriteLine("按下任意键,玩家{0}开始在棋盘上移动",PlayNames[PlayID]);
            Console.ReadKey(true);
            //处理掷骰子后玩家的移动
            PlayPos[PlayID] += ResultNum;
            TurnRight();
            Console.WriteLine("玩家{0}移动完啦,按任意键继续游戏",PlayNames[PlayID]);
            //处理移动之后,在地图之后触发的关卡
            //玩家可以踩到 另一个玩家、普通方块、幸运轮盘、地雷、暂停、时空隧道
            //踩到另一个玩家,另一个玩家退后6格
            if(PlayPos[PlayID] == PlayPos[1 - PlayID])
            {
                Console.WriteLine("玩家{0}踩到了玩家{1},玩家{2}退回6格", PlayNames[0], PlayNames[1],PlayNames[1]);
                PlayPos[1] -= 6;
                //这里存在一步异常处理的矫正,玩家不能退出地图,也不能超出地图
                TurnRight();
                Console.ReadKey(true);
            }
            else //踩到关卡
            {
                switch (Maps[PlayPos[PlayID]])
                {
                    case 0://踩到普通方块
                        Console.WriteLine("玩家{0}猜中的普通方块,正常到达该位置",PlayNames[PlayID]);
                        Console.ReadKey(true);
                        break;
                    case 1://踩到幸运盘
                        Console.WriteLine("玩家{0}踩到了幸运轮盘,请选择:1 - 交换位置  2 - 轰炸对方(对手退回6格)",PlayNames[PlayID]);
                        Console.ReadKey(true);
                        string choice = Console.ReadLine();
                        if (choice == "1")
                        {
                            Console.WriteLine("玩家{0}选择与玩家{1}交换位置", PlayNames[PlayID], PlayNames[1 - PlayID]);
                            Console.WriteLine("按下任意键执行操作");
                            Console.ReadKey(true);
                            int temp = PlayPos[PlayID];
                            PlayPos[PlayID] = PlayPos[1 - PlayID];
                            PlayPos[1 - PlayID] = temp;
                            Console.WriteLine("操作执行完成,按任意键继续游戏");
                            Console.ReadKey(true);
                            break;
                        }
                        else if (choice == "2")
                        {
                            Console.WriteLine("玩家{0}选择轰炸玩家{1}", PlayNames[PlayID], PlayNames[1 - PlayID]);
                            Console.WriteLine("按下任意键执行操作");
                            PlayPos[1 - PlayID] -= 6;
                            TurnRight();
                            Console.WriteLine("操作执行完成,按任意键继续游戏");
                            Console.ReadKey(true);
                            break;
                        }
                        else
                        {
                            Console.WriteLine("请遵守游戏规则,在1和2之间进行选择");
                            Console.ReadKey(true);
                            break;
                        }
                    case 2://踩到地雷
                        Console.WriteLine("玩家{0}踩到地雷,倒退6格", PlayNames[PlayID]) ;
                        Console.ReadKey(true);
                        PlayPos[PlayID] -= 6;
                        TurnRight();
                        Console.WriteLine("玩家倒退完毕。按任意键继续游戏");
                        Console.ReadKey(true);
                        break;
                    case 3://踩到暂停
                        Console.WriteLine("玩家{0}踩到暂停,暂停一个回合", PlayNames[PlayID]);
                        Flags[PlayID] = true;
                        Console.ReadKey(true);
                        break;
                    case 4://踩到时空隧道
                        Console.WriteLine("玩家{0}踩到时空隧道,前进10格", PlayNames[PlayID]);
                        PlayPos[PlayID] += 10;
                        TurnRight();
                        Console.WriteLine("玩家前进完毕,按任意键继续游戏");
                        Console.ReadKey(true);
                        break;
                }//switch
            }//if - else
            //当前轮的关卡处理完成之后。清屏,重新打印
            Console.Clear();
            DrawMap();//重新画地图

③ 判断胜利

两个玩家是放在一个长度为100的数组表示的飞行棋棋盘进行游戏的。那么当有玩家的索引变成100的时候,TA就获得了最终的胜利。

需要注意的点是:因为关卡中有暂停关卡,当玩家踩到暂停了,他就不能够参与当前轮的掷骰子

      while(PlayPos[0] < 100 && PlayPos[1] < 100)
            {
                if (!Flags[0])PlayGame(0);
                else Flags[0] = false;
                //判断胜利的条件
                if (PlayPos[0] == 100)
                {
                    Console.WriteLine("恭喜玩家{0}获得胜利", PlayNames[0]);
                    break;
                }
                if (!Flags[1]) PlayGame(1);
                else Flags[1] = false;
                    if (PlayPos[1] == 100)
                {
                    Console.WriteLine("恭喜玩家{0}获得胜利", PlayNames[1]);
                    break;
                }
            }

④ 回首调优

无论如何,玩家在棋盘中移动的时候,是不能到棋盘之外的位置,因此在玩家进行位置移动的代码后方,都应该判断新出现的位置是否合法。

  //异常处理,矫正玩家位置
        public static void TurnRight()
        {
            if (PlayPos[0] < 0) PlayPos[0] = 0;
            if (PlayPos[0] >= 99) PlayPos[0] = 99;
            if(PlayPos[1] < 0) PlayPos[1] = 0;
            if (PlayPos[1] >= 99) PlayPos[1] = 99;
        }

总结


整个飞行棋项目的gitee地址

1、写项目流程图蛮重要的吧,跟着自己梳理好的流程板块去逐一落实代码,不会出现迷失在项目中的情况

2、积累修改字体背景颜色、字体文本颜色

3、按任意键后在控制台无显示依赖于ReadKey函数中传入参数true

相关文章
C#窗体连连看小游戏(超详细)(下)
C#窗体连连看小游戏(超详细)
282 0
|
算法 C#
C#窗体连连看小游戏(超详细)(上)
C#窗体连连看小游戏(超详细)
294 0
C#窗体连连看小游戏(超详细)(上)
C#小游戏之疯狂字母
C#小游戏之疯狂字母
68 0
C#小游戏之疯狂字母
儿童节教大家做一个C#图片匹配小游戏
儿童节教大家做一个C#图片匹配小游戏
124 0
儿童节教大家做一个C#图片匹配小游戏
|
10天前
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。
|
10天前
|
SQL 开发框架 安全
C#编程与多线程处理
【4月更文挑战第21天】探索C#多线程处理,提升程序性能与响应性。了解C#中的Thread、Task类及Async/Await关键字,掌握线程同步与安全,实践并发计算、网络服务及UI优化。跟随未来发展趋势,利用C#打造高效应用。
|
10天前
|
存储 安全 网络安全
C#编程的安全性与加密技术
【4月更文挑战第21天】C#在.NET框架支持下,以其面向对象和高级特性成为安全软件开发的利器。本文探讨C#在安全加密领域的应用,包括使用System.Security.Cryptography库实现加密算法,利用SSL/TLS保障网络传输安全,进行身份验证,并强调编写安全代码的重要性。实际案例涵盖在线支付、企业应用和文件加密,展示了C#在应对安全挑战的同时,不断拓展其在该领域的潜力和未来前景。
|
10天前
|
人工智能 C# 开发者
C#编程中的图形界面设计
【4月更文挑战第21天】本文探讨了C#在GUI设计中的应用,介绍了Windows Forms、WPF和UWP等常用框架,强调了简洁界面、响应式设计和数据绑定等最佳实践。通过实际案例,展示了C#在企业应用、游戏开发和移动应用中的GUI实现。随着技术发展,C#在GUI设计的未来将趋向于跨平台、更丰富的组件和AI集成,为开发者创造更多可能性。
|
10天前
|
存储 算法 C#
C#编程与数据结构的结合
【4月更文挑战第21天】本文探讨了C#如何结合数据结构以构建高效软件,强调数据结构在C#中的重要性。C#作为面向对象的编程语言,提供内置数据结构如List、Array和Dictionary,同时也支持自定义数据结构。文章列举了C#实现数组、链表、栈、队列等基础数据结构的示例,并讨论了它们在排序、图算法和数据库访问等场景的应用。掌握C#数据结构有助于编写高性能、可维护的代码。