[C# Project Actual Combat] Console game Dragon Quest (2) - game scene setting and player battle logic

insert image description here

Junxi_'s personal homepage

No matter how far you go, don't forget the original intention when you set off

C/C++ game development

Hello, Mina-san, this is Jun Xi_, who has recently started to officially enter the right track of learning game development, and wants to share the knowledge and experience he has learned by writing a blog. This is the purpose of creating this column. I hope these small independent C# projects can be helpful to you who are making games. After all, the best way to learn game development is to make a game yourself! !

foreword

  • Today we will continue to talk about the second part of Dragon Quest. Last time we talked about the implementation of the start interface and the initialization of the console. This time we will talk about the core content of this small game. The initialization of the game scene and the player’s Realization of movement and battle related codes with BOSS
  • Let's put the overall flow chart of our game here first
    insert image description here

1. Initialization of the game scene

  • Last time we said that to realize the conversion between interfaces, only one while+switch is needed. At this time, we change the nowSceneID (game scene number) to 2, and start editing our game scene.
  • First of all, we have to set up the most basic things that don't need to change every time

1. Initialization of the constant scene

  • In this game scene, it is undoubtedly the red walls around that we don’t need to change every time. Let’s set these red walls first.
    insert image description here
 Console.Clear();
 #region 4 不变的红墙
 //设置颜色为红色
 Console.ForegroundColor = ConsoleColor.Red;
 //画墙
 //上方墙
 for (int i = 0; i < w; i += 2)
 {
    
    
     //上方墙
     Console.SetCursorPosition(i, 0);
     Console.Write("■");
     //下方墙
     Console.SetCursorPosition(i, h - 1);
     Console.Write("■");
     //中间墙
     Console.SetCursorPosition(i, h - 6);
     Console.Write("■");
 }
 //左边的墙
 for (int i = 0; i < h; i++)
 {
    
    
     //左边的墙
     Console.SetCursorPosition(0, i);
     Console.Write("■");
     //右边的墙
     Console.SetCursorPosition(w - 2, i);
     Console.Write("■");
 }
#endregion
  • It's very simple. It is to print the wall with the set position and color on the console interface through a loop, so I won't go into details here.
  • The only thing to note is that for the console, the vertical axis of one unit is equal to the horizontal axis of two units, so every time the horizontal axis wants to correspond to the vertical axis, two grids are skipped at a time. At the same time, we have to consider the boundary problem , Note here that if the red wall is not specifically set to the upper left corner of the position (0, 0), so the rightmost boundary of our horizontal axis setting is w-2, and the bottommost boundary is h-1. (If you don't understand this passage, try changing the boundary to other parameters when typing the code yourself, and you will be able to clearly understand the reason for doing this here)

2. Player and BOSS attributes related settings

  • Before starting to explain the relevant game logic, let's initialize the players and BOSS in the game, set the position, and the icons corresponding to the characters
  • At the same time, our players and BOSS need to fight. We also need to set the blood volume and the attack power of the two during initialization to facilitate the writing of the battle logic later ()
#region 5 boss属性相关
//boss坐标
int bossX = 24;
int bossY = 15;
//boss攻击力的最大最小值
int bossAtkMin = 7;
int bossAtkMax = 13;
//boss血量
int bossHp = 100;
string bossIcon = "■";
//申明一个 颜色变量
ConsoleColor bossColor = ConsoleColor.Green;
#endregion

#region 6 玩家属性相关
int playerX = 4;
int playerY = 5;
//玩家攻击力的最大最小值
int playerAtkMin = 8;
int playerAtkMax = 12;
//玩家血量
int playerHp = 100;
string playerIcon = "●";
ConsoleColor playerColor = ConsoleColor.Yellow;
//玩家输入的内容 外面申明 节约性能
//检测玩家的输入 方便之后的移动和攻击逻辑
char playerInput;
#endregion

#region 7 玩家战斗相关
//战斗状态
bool isFight = false;//在玩家与boss战斗或者未进行战斗时应该有不同的逻辑,通过一个bool变量来判断应该走哪种逻辑
#endregion

2. Player movement and battle logic

1. Player movement

  • Like a normal game, we hope that our players can hold down "WASD" to move up, down, left, and right. What is the basic principle of movement? It is to change the coordinates of the player displayed on the game screen, that is, on our console. At the same time, we have to erase the icon of a player on the console.
  • There is another problem here. Our player cannot move at will. We must add a certain range limit to his movement. Otherwise, is it difficult to move your player out of our screen? So here is another problem that is after all complicated, that is, the boundary discussion

Boundary issues with player movement

  • Just now we mentioned the boundary problem of player movement, so what is the boundary problem? Let's analyze it in combination with the specific screen of our game.
    insert image description here
  • First of all, there are currently three objects in our game screen, the first is the constant wall, the second is the player, and the third is our BOSS. What we can control is the movement of the player in the game interface .
  • The movement of our players must be within the specified range, which is the red wall. This is the game area we set. At the same time, our players cannot coincide with the coordinates of the red wall. As we said before, the red wall is unchanged The object does not change with the player's control, so we don't need to print it repeatedly in each loop of executing the game, it is enough to print it when switching to the game scene, so if the player and If the red wall coincides, the red wall at this coordinate will disappear and will not be printed again when the game is not over, and the same is true for the BOSS. We also cannot allow the coordinates of the player to coincide with the BOSS, although the BOSS will be in every loop Both are printed, but we allow the player and the BOSS to overlap, so it is difficult to deal with the logic of the player and the BOSS battle.
  • Through the above analysis, we can get the following player movement code
    #region 6 玩家移动相关
    //擦除之前位置的玩家图标
    Console.SetCursorPosition(playerX, playerY);
    Console.Write("  ");
    //改位置
    switch (playerInput)
    {
    
    
        case 'W':
        case 'w':
            --playerY;//往上移动
            if (playerY < 1)//边界检查 如果玩家到红墙上边缘就把玩家坐标拉回去
            {
    
    
                playerY = 1;
            }
            //位置如果和boss重合了 并且boss没有死
            else if (playerX == bossX && playerY == bossY && bossHp > 0)
            {
    
    
                //拉回去
                ++playerY;
            }
            break;
        case 'A':
        case 'a':
            playerX -= 2;//向左移动
            if (playerX < 2)边界检查 如果玩家到红墙左边缘就把玩家坐标拉回去
            {
    
    
                playerX = 2;
            }
            else if (playerX == bossX && playerY == bossY && bossHp > 0)
            {
    
    
                //拉回去
                playerX += 2;
            }
            break;
        case 'S':
        case 's':
            ++playerY;//向下移动
            if (playerY > h - 7) 边界检查 如果玩家到红墙下边缘就把玩家坐标拉回去
            {
    
    
                playerY = h - 7;
            }
            else if (playerX == bossX && playerY == bossY && bossHp > 0)
            {
    
    
                //拉回去
                --playerY;
            }
            break;
        case 'D':
        case 'd':
            playerX += 2;  //向右移动
            if (playerX > w - 4)//边界检查 如果玩家到红墙右边缘就把玩家坐标拉回去
            {
    
    
                playerX = w - 4;
            }
            else if (playerX == bossX && playerY == bossY && bossHp > 0)
            {
    
    
                //拉回去
                playerX -= 2;
            }
            break;
       
    }
    #endregion

insert image description here

  • As shown in the picture, now we can move freely on the map, and then we will make battle-related settings

2. Combat-related code logic

how to enter the battle

  • So how to fight the BOSS? First of all, we have to move our player to the side of the BOSS, then press a key to enter the battle, and at the same time switch the player's state to the combat state. At this time, we also have to print some information in the box below to Remind players that they can attack BOSS when they enter the battle
  case 'J':
  case 'j':
      //开始战斗
      if ((playerX == bossX && playerY == bossY - 1 ||
          playerX == bossX && playerY == bossY + 1 ||
          playerX == bossX - 2 && playerY == bossY ||
          playerX == bossX + 2 && playerY == bossY) && bossHp > 0)//玩家处于BOSS周围
      {
    
    
          isFight = true;//玩家状态切换至战斗状态
          //可以开始战斗,提醒一下玩家应该做什么,以及玩家和BOSS此时的血量
          Console.SetCursorPosition(2, h - 5);
          Console.ForegroundColor = ConsoleColor.White;
          Console.Write("开始和Boss战斗了,按J键继续");
          Console.SetCursorPosition(2, h - 4);
          Console.Write("玩家当前血量为{0}", playerHp);
          Console.SetCursorPosition(2, h - 3);
          Console.Write("boss当前血量为{0}", bossHp);
      }
      //进入战斗状态就要让玩家不能再移动
      //同时下方能够显示信息,提示双方造成的伤害和此时剩下的血量

      break;

battle logic

  • We defined a bool type of IsFight above to judge whether the player enters the battle at this time. After entering the battle, we have to enter the battle logic instead of the movement logic. What kind of logic should be in the battle?
  • First of all, every time we enter the combat state, we have to judge the blood volume of both sides at this time. No matter whose blood volume drops to 0, we must enter the next link or the game fails or enters the link of rescuing the princess.
  • Then, we use the attack power of both sides to attack each other in turn. We have given the maximum and minimum attack power when setting the player and the BOSS, so that each time we attack, both sides should cause the maximum attack and the minimum attack. Random damage between attacks, the opponent deducts the corresponding blood volume, so that the basic idea is clear, and then enters a game branch
  • When the blood of the BOSS is first reduced to 0, the BOSS should be destroyed on the map and the location of the princess should be marked, and the player's action should be restored at the same time so that the player can go to the princess to rescue the princess
  • When the player's blood volume first decreases to 0, it means that the player has failed to defeat the BOSS at this time. At this time, the scene ID should be changed to enter the game end interface
 //游戏场景的死循环 专门用来 检测 玩家输入相关循环
 while (true)
 {
    
    
   
     //boss活着时才绘制
     if (bossHp > 0)
     {
    
    
         //绘制boss图标
         Console.SetCursorPosition(bossX, bossY);
         Console.ForegroundColor = bossColor;
         Console.Write(bossIcon);
     }
    
     //画出玩家
     Console.SetCursorPosition(playerX, playerY);
     Console.ForegroundColor = playerColor;
     Console.Write(playerIcon);
     //得到玩家输入
     playerInput = Console.ReadKey(true).KeyChar;
   

     //战斗状态处理什么逻辑
     if (isFight)
     {
    
    
         #region 7 玩家战斗相关
         //如果是战斗状态 你做什么
         //只会处理J键 
         if (playerInput == 'J' || playerInput == 'j')
         {
    
    
             //在这判断 玩家或者怪物 是否死亡 如果死亡了 继续之后的流程
             if (playerHp <= 0)
             {
    
    
                 //游戏结束
                 //输掉了 应该直接显示 我们的 游戏结束界面
                 nowSceneID = 3;
                 break;
             }
             else if (bossHp <= 0)
             {
    
    
                 //去营救公主
                 //boss擦除
                 Console.SetCursorPosition(bossX, bossY);
                 Console.Write("  ");
                 isFight = false;//重新让玩家能够按wasd键移动
             }
             else
             {
    
    
                 //去处理按J键打架
                 // 玩家打怪物
                 Random r = new Random();
                 //得到随机攻击了
                 int atk = r.Next(playerAtkMin, playerAtkMax);
                 //血量减对应的攻击力
                 bossHp -= atk;
                 //打印信息
                 Console.ForegroundColor = ConsoleColor.Green;
                 //先擦除这一行 上次显示的内容
                 Console.SetCursorPosition(2, h - 4);
                 Console.Write("                                           ");
                 //再来写新的信息
                 Console.SetCursorPosition(2, h - 4);
                 Console.Write("你对恶龙造成了{0}点伤害,boss剩余血量为{1}", atk, bossHp);
                 // 怪物打玩家
                 if (bossHp > 0)
                 {
    
    
                     //得到随机攻击了
                     atk = r.Next(bossAtkMin, bossAtkMax);
                     playerHp -= atk;

                     //打印信息
                     Console.ForegroundColor = ConsoleColor.Yellow;
                     //先擦除这一行 上次显示的内容
                     Console.SetCursorPosition(2, h - 3);
                     Console.Write("                                           ");
                     //再来写新的信息
                     //boss如果把玩家打死了 做什么
                     if (playerHp <= 0)
                     {
    
    
                         Console.SetCursorPosition(2, h - 3);
                         Console.Write("很遗憾,你未能通过boss的试炼,战败了");
                     }
                     else
                     {
    
    
                         Console.SetCursorPosition(2, h - 3);
                         Console.Write("恶龙对你造成了{0}点伤害,你的剩余血量为{1}", atk, playerHp);
                     }
                 }
                 else
                 {
    
    
                     //擦除之前的战斗信息
                     Console.SetCursorPosition(2, h - 5);
                     Console.Write("                                           ");
                     Console.SetCursorPosition(2, h - 4);
                     Console.Write("                                           ");
                     Console.SetCursorPosition(2, h - 3);
                     Console.Write("                                           ");
                     //显示恭喜胜利的信息
                     Console.SetCursorPosition(2, h - 5);
                     Console.Write("你战胜了boss,快去营救公主");
                     Console.SetCursorPosition(2, h - 4);
                     Console.Write("前往公主身边按J键继续");
                 }
             }
         }
  • I think I have made the above logic clear. The only thing that needs to be mentioned now is that we need to erase the last printed information every time we print new information, and because we will clear the screen if we use Clear All the content on the screen is eliminated, so here we choose to blank the corresponding line before printing new information, so that we can achieve the effect we want
    insert image description here
  • Well, speaking of this, today’s knowledge about the game scene is almost the same, and then put the source code here for your reference and self-modification

3. Game source code

 //游戏场景
 case 2:
     Console.Clear();
     #region 4 不变的红墙
     //设置颜色为红色
     Console.ForegroundColor = ConsoleColor.Red;
     //画墙
     //上方墙
     for (int i = 0; i < w; i += 2)
     {
    
    
         //上方墙
         Console.SetCursorPosition(i, 0);
         Console.Write("■");
         //下方墙
         Console.SetCursorPosition(i, h - 1);
         Console.Write("■");
         //中间墙
         Console.SetCursorPosition(i, h - 6);
         Console.Write("■");
     }
     //左边的墙
     for (int i = 0; i < h; i++)
     {
    
    
         //左边的墙
         Console.SetCursorPosition(0, i);
         Console.Write("■");
         //右边的墙
         Console.SetCursorPosition(w - 2, i);
         Console.Write("■");
     }
     #endregion

     #region 5 boss属性相关
     int bossX = 24;
     int bossY = 15;
     int bossAtkMin = 7;
     int bossAtkMax = 13;
     int bossHp = 100;
     string bossIcon = "■";
     //申明一个 颜色变量
     ConsoleColor bossColor = ConsoleColor.Green;
     #endregion

     #region 6 玩家属性相关
     int playerX = 4;
     int playerY = 5;
     int playerAtkMin = 8;
     int playerAtkMax = 12;
     int playerHp = 100;
     string playerIcon = "●";
     ConsoleColor playerColor = ConsoleColor.Yellow;
     //玩家输入的内容 外面申明 节约性能
     char playerInput;
     #endregion

     #region 7 玩家战斗相关
     //战斗状态
     bool isFight = false;
     #endregion

     //游戏场景的死循环 专门用来 检测 玩家输入相关循环
     while (true)
     {
    
    
         #region 5 boss属性相关
         //boss活着时才绘制
         if (bossHp > 0)
         {
    
    
             //绘制boss图标
             Console.SetCursorPosition(bossX, bossY);
             Console.ForegroundColor = bossColor;
             Console.Write(bossIcon);
         }
         #endregion

         #region 6 玩家移动相关
         //画出玩家
         Console.SetCursorPosition(playerX, playerY);
         Console.ForegroundColor = playerColor;
         Console.Write(playerIcon);
         //得到玩家输入
         playerInput = Console.ReadKey(true).KeyChar;
         #endregion

         //战斗状态处理什么逻辑
         if (isFight)
         {
    
    
             #region 7 玩家战斗相关
             //如果是战斗状态 你做什么
             //只会处理J键 
             if (playerInput == 'J' || playerInput == 'j')
             {
    
    
                 //在这判断 玩家或者怪物 是否死亡 如果死亡了 继续之后的流程
                 if (playerHp <= 0)
                 {
    
    
                     //游戏结束
                     //输掉了 应该直接显示 我们的 游戏结束界面
                     nowSceneID = 3;
                     break;
                 }
                 else if (bossHp <= 0)
                 {
    
    
                     //去营救公主
                     //boss擦除
                     Console.SetCursorPosition(bossX, bossY);
                     Console.Write("  ");
                     isFight = false;
                 }
                 else
                 {
    
    
                     //去处理按J键打架
                     // 玩家打怪物
                     Random r = new Random();
                     //得到随机攻击了
                     int atk = r.Next(playerAtkMin, playerAtkMax);
                     //血量减对应的攻击力
                     bossHp -= atk;
                     //打印信息
                     Console.ForegroundColor = ConsoleColor.Green;
                     //先擦除这一行 上次显示的内容
                     Console.SetCursorPosition(2, h - 4);
                     Console.Write("                                           ");
                     //再来写新的信息
                     Console.SetCursorPosition(2, h - 4);
                     Console.Write("你对boss造成了{0}点伤害,boss剩余血量为{1}", atk, bossHp);
                     // 怪物打玩家
                     if (bossHp > 0)
                     {
    
    
                         //得到随机攻击了
                         atk = r.Next(bossAtkMin, bossAtkMax);
                         playerHp -= atk;

                         //打印信息
                         Console.ForegroundColor = ConsoleColor.Yellow;
                         //先擦除这一行 上次显示的内容
                         Console.SetCursorPosition(2, h - 3);
                         Console.Write("                                           ");
                         //再来写新的信息
                         //boss如果把玩家打死了 做什么
                         if (playerHp <= 0)
                         {
    
    
                             Console.SetCursorPosition(2, h - 3);
                             Console.Write("很遗憾,你未能通过boss的试炼,战败了");
                         }
                         else
                         {
    
    
                             Console.SetCursorPosition(2, h - 3);
                             Console.Write("boss对你造成了{0}点伤害,你的剩余血量为{1}", atk, playerHp);
                         }
                     }
                     else
                     {
    
    
                         //擦除之前的战斗信息
                         Console.SetCursorPosition(2, h - 5);
                         Console.Write("                                           ");
                         Console.SetCursorPosition(2, h - 4);
                         Console.Write("                                           ");
                         Console.SetCursorPosition(2, h - 3);
                         Console.Write("                                           ");
                         //显示恭喜胜利的信息
                         Console.SetCursorPosition(2, h - 5);
                         Console.Write("你战胜了boss,快去营救公主");
                         Console.SetCursorPosition(2, h - 4);
                         Console.Write("前往公主身边按J键继续");
                     }
                 }
             }
             #endregion
         }
         //非战斗状态处理什么逻辑
         else
         {
    
    
             #region 6 玩家移动相关
             //擦除
             Console.SetCursorPosition(playerX, playerY);
             Console.Write("  ");
             //改位置
             switch (playerInput)
             {
    
    
                 case 'W':
                 case 'w':
                     --playerY;
                     if (playerY < 1)
                     {
    
    
                         playerY = 1;
                     }
                     //位置如果和boss重合了 并且boss没有死
                     else if (playerX == bossX && playerY == bossY && bossHp > 0)
                     {
    
    
                         //拉回去
                         ++playerY;
                     }
                     break;
                 case 'A':
                 case 'a':
                     playerX -= 2;
                     if (playerX < 2)
                     {
    
    
                         playerX = 2;
                     }
                     else if (playerX == bossX && playerY == bossY && bossHp > 0)
                     {
    
    
                         //拉回去
                         playerX += 2;
                     }
                     break;
                 case 'S':
                 case 's':
                     ++playerY;
                     if (playerY > h - 7)
                     {
    
    
                         playerY = h - 7;
                     }
                     else if (playerX == bossX && playerY == bossY && bossHp > 0)
                     {
    
    
                         //拉回去
                         --playerY;
                     }
                     break;
                 case 'D':
                 case 'd':
                     playerX += 2;
                     if (playerX > w - 4)
                     {
    
    
                         playerX = w - 4;
                     }
                     else if (playerX == bossX && playerY == bossY && bossHp > 0)
                     {
    
    
                         //拉回去
                         playerX -= 2;
                     }
                     break;
                 case 'J':
                 case 'j':
                     //开始战斗
                     if ((playerX == bossX && playerY == bossY - 1 ||
                         playerX == bossX && playerY == bossY + 1 ||
                         playerX == bossX - 2 && playerY == bossY ||
                         playerX == bossX + 2 && playerY == bossY) && bossHp > 0)
                     {
    
    
                         isFight = true;
                         //可以开始战斗
                         Console.SetCursorPosition(2, h - 5);
                         Console.ForegroundColor = ConsoleColor.White;
                         Console.Write("开始和Boss战斗了,按J键继续");
                         Console.SetCursorPosition(2, h - 4);
                         Console.Write("玩家当前血量为{0}", playerHp);
                         Console.SetCursorPosition(2, h - 3);
                         Console.Write("boss当前血量为{0}", bossHp);
                     }
                     //要让玩家不能再移动
                     //下方能够显示信息

                     break;
             }
             #endregion
         }
         }
         break;

Summarize

  • Today's content is over here. The relevant settings of the game scene are the core and difficult points of this game. If you really want to learn this content well, you may wish to follow the blogger and try it yourself. After all, many problems can only be tried by yourself. You can only find out after a while. If you encounter any problems during the implementation process, please point them out in the comment area or send me a private message! !
  • The following content will be updated soon, if you are interested, you may wish to pay attention to the following content if you miss it! !

It is not easy for new bloggers to create. If you feel that the content of the article is helpful to you, you may wish to read it three times before leaving. Your support is my motivation to update! ! !

**(Ke Li asks you to support the blogger three times in a row!!! Click the comment below to like and collect to help Ke Li)**

insert image description here

Guess you like

Origin blog.csdn.net/syf666250/article/details/132708996