Unity学习之P&D 过河游戏智能帮助实现

本文详细介绍了一款基于Unity的游戏——过河游戏的AI实现过程。通过构建状态图和使用广度优先搜索算法,实现了游戏的智能帮助系统,能够根据当前游戏状态提供下一步的最佳操作建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Unity学习之P&D 过河游戏智能帮助实现

根据之前设计好的动作分离版过河游戏,我们进行一个简单的状态图AI实现。

转移状态图

状态图老师已经给出:
在这里插入图片描述

该状态图只记录了游戏过程中左岸的情况。P代表牧师,D代表魔鬼,B代表船。当船在右岸时不记录。双箭头代表两个状态可以相互转化。

构造状态图

next.boat = nowStatue;
    if (next.boat == Status.BLRING ||
        next.boat == Status.BRLING ||
        next.boat == Status.LOSE ||
        next.boat == Status.WIN || boatSize() != 0)
     {
          next.boat = Status.None;
          return next;
      }

      else
      {
           if (next.boat == Status.BLEFT &&
               leftPriests.Count == 3 && 
               leftDevils.Count == 3)
           {
                int turn = randomValue();
                if (turn == 1)
                    next.boataction = Boataction.PD;
                else
                    next.boataction = Boataction.DD;
            }

          else if (next.boat == Status.BRIGHT && 
               leftPriests.Count == 2 && 
               leftDevils.Count == 2)
           {
               next.boataction = Boataction.P;
           }

          else if (next.boat == Status.BRIGHT && 
               leftPriests.Count == 3 &&
               leftDevils.Count == 2)
           {
               next.boataction = Boataction.D;
            }

          else if (next.boat == Status.BRIGHT && 
               leftPriests.Count == 3 &&
               leftDevils.Count == 1)
           {
               next.boataction = Boataction.D;
           }

          else if (next.boat == Status.BLEFT && 
               leftPriests.Count == 3 &&
               leftDevils.Count == 2)
           {
               next.boataction = Boataction.DD;
            }

          else if (next.boat == Status.BRIGHT && 
               leftPriests.Count == 3 && 
               leftDevils.Count == 0)
            {
                next.boataction = Boataction.D;
            }

          else if (next.boat == Status.BLEFT &&
               leftPriests.Count == 3 &&
               leftDevils.Count == 1)
           {
               next.boataction = Boataction.PP;
           }

          else if (next.boat == Status.BRIGHT &&
              leftPriests.Count == 1 &&
              leftDevils.Count == 1)
          {
              next.boataction = Boataction.PD;
          }

         else if (next.boat == Status.BLEFT &&
             leftPriests.Count == 2 &&
             leftDevils.Count == 2)
         {
             next.boataction = Boataction.PP;
         }

         else if (next.boat == Status.BRIGHT &&
             leftPriests.Count == 0 &&
             leftDevils.Count == 2)
         {
             next.boataction = Boataction.D;
         }

        else if (next.boat == Status.BLEFT &&
            leftPriests.Count == 0 &&
            leftDevils.Count == 3)
        {
            next.boataction = Boataction.DD;
        }

       else if (next.boat == Status.BRIGHT &&
           leftPriests.Count == 0 &&
           leftDevils.Count == 1)
       {
           int turn = randomValue();
           if (turn == 1) next.boataction = Boataction.D;
           else next.boataction = Boataction.P;
        }

        else if (next.boat == Status.BLEFT &&
            leftPriests.Count == 2 &&
            leftDevils.Count == 1)
         {
              next.boataction = Boataction.P;
         }

         else if (next.boat == Status.BLEFT &&
             leftPriests.Count == 0 &&
             leftDevils.Count == 2)
         {
             next.boataction = Boataction.DD;
         }

         else if (next.boat == Status.BLEFT &&
             leftPriests.Count == 1 &&
                 leftDevils.Count == 1)
         {
             next.boataction = Boataction.PD;
         }

     }

搜索路径

while (queue.Count > 0)
        {
            temp = queue.Peek();

            if (temp == end)
            {
                while (temp.parent_state != start)
                {
                    temp = temp.parent_state;
                }
                return temp;
            }
            queue.Dequeue();

            if (temp.pos)
            {

                if (temp.lp > 0)
                {
                    GameState next = new GameState(temp);
                    next.parent_state = new GameState(temp);
                    next.pos = false;
                    next.lp--;
                    next.rp++;
                    if (next.isValid() && !queue.Contains(next))
                    {
                        queue.Enqueue(next);
                    }
                }
                if (temp.ld > 0)
                {
                    GameState next = new GameState(temp);
                    next.parent_state = new GameState(temp);
                    next.pos = false;
                    next.ld--;
                    next.rd++;
                    if (next.isValid() && !queue.Contains(next))
                    {
                        queue.Enqueue(next);
                    }
                }

                if (temp.ld > 0 && temp.lp > 0)
                {
                    GameState next = new GameState(temp);
                    next.parent_state = new GameState(temp);
                    next.pos = false;
                    next.ld--;
                    next.rd++;
                    next.lp--;
                    next.rp++;
                    if (next.isValid() && !queue.Contains(next))
                    {
                        queue.Enqueue(next);
                    }
                }

                if (temp.lp > 1)
                {
                    GameState next = new GameState(temp);
                    next.parent_state = new GameState(temp);
                    next.pos = false;
                    next.lp -= 2;
                    next.rp += 2;
                    if (next.isValid() && !queue.Contains(next))
                    {
                        queue.Enqueue(next);
                    }
                }

                if (temp.ld > 1)
                {
                    GameState next = new GameState(temp);
                    next.parent_state = new GameState(temp);
                    next.pos = false;
                    next.ld -= 2;
                    next.rd += 2;
                    if (next.isValid() && !queue.Contains(next))
                    {
                        queue.Enqueue(next);
                    }
                }
            }


            else

            {

                if (temp.rp > 0)
                {
                    GameState next = new GameState(temp);
                    next.parent_state = new GameState(temp);
                    next.pos = true;
                    next.rp--;
                    next.lp++;
                    if (next.isValid() && !queue.Contains(next))
                    {
                        queue.Enqueue(next);
                    }
                }

                if (temp.rd > 0)
                {
                    GameState next = new GameState(temp);
                    next.parent_state = new GameState(temp);
                    next.pos = true;
                    next.rd--;
                    next.ld++;
                    if (next.isValid() && !queue.Contains(next))
                    {
                        queue.Enqueue(next);
                    }
                }

                if (temp.rd > 0 && temp.rp > 0)
                {
                    GameState next = new GameState(temp);
                    next.parent_state = new GameState(temp);
                    next.pos = true;
                    next.rd--;
                    next.ld++;
                    next.rp--;
                    next.lp++;
                    if (next.isValid() && !queue.Contains(next))
                    {
                        queue.Enqueue(next);
                    }
                }

                if (temp.rd > 1)
                {
                    GameState next = new GameState(temp);
                    next.parent_state = new GameState(temp);
                    next.pos = true;
                    next.rd -= 2;
                    next.ld += 2;
                    if (next.isValid() && !queue.Contains(next))
                    {
                        queue.Enqueue(next);
                    }
                }

                if (temp.rp > 1)
                {
                    GameState next = new GameState(temp);
                    next.parent_state = new GameState(temp);
                    next.pos = true;
                    next.rp -= 2;
                    next.lp += 2;
                    if (next.isValid() && !queue.Contains(next))
                    {
                        queue.Enqueue(next);
                    }
                }
            }
        }
        return null;
    }

最后,更新GUI,以便正确提示输出即可

    void OnGUI()
    {
        GUIStyle fontstyle = new GUIStyle();
        fontstyle.normal.background = null;
        fontstyle.normal.textColor = new Color(255, 192, 203);
        fontstyle.fontSize = 50;

        style = new GUIStyle()
        {
            fontSize = 16
        };
        style.normal.textColor = new Color(0, 0, 0);
        buttonStyle = new GUIStyle("button")
        {
            fontSize = 16
        };

        if (GUI.Button(new Rect (Screen.width/2 - 50 , Screen.height- 50, 100, 40), "Reset", buttonStyle))
            {
                status = 0;
                userAction.Restart();
            }
        if (status == 1)
        {
            GUI.Label(new Rect (Screen.width/2- 50, 50, 100, 40), "Lose", style);
        }
        else if (status == 2)
        {
            GUI.Label(new Rect (Screen.width/2- 50, 50, 100, 40), "Win", style);
        }
        GUI.Button(new Rect(Screen.width/2 - 150 , 30, 400, 40), tips, style);

        if (GUI.Button(new Rect(Screen.width/2 - 300 , 30, 100, 40), "Tips", buttonStyle))
        {
            int[] arr = userAction.getStateInfo();
            leftPriests = arr[0];
            leftDevils = arr[1];
            rightPriests = arr[2];
            rightDevils = arr[3];

            if (arr[4] == 0) boat_pos = true;
            else boat_pos = false;
            start = new GameState(leftPriests, leftDevils, rightPriests, rightDevils, boat_pos, null);

            GameState temp = GameState.BFS(start, end);


            int p = leftPriests - temp.lp;
            int d = leftDevils - temp.ld;
            if (p < 0) p = -p;
            if (d < 0) d = -d;
            tips = "Move " + p + " priest(s)," + d
                + " devil(s) to another side.";
        }
    }

GUI更新

最后,我们更新GUI,从而能够正确提示即可

    void OnGUI()
    {
        GUIStyle fontstyle = new GUIStyle();
        fontstyle.normal.background = null;
        fontstyle.normal.textColor = new Color(255, 192, 203);
        fontstyle.fontSize = 50;

        style = new GUIStyle()
        {
            fontSize = 16
        };
        style.normal.textColor = new Color(0, 0, 0);
        buttonStyle = new GUIStyle("button")
        {
            fontSize = 16
        };

        if (GUI.Button(new Rect (Screen.width/2 - 50 , Screen.height- 50, 100, 40), "Reset", buttonStyle))
            {
                status = 0;
                userAction.Restart();
            }
        if (status == 1)
        {
            GUI.Label(new Rect (Screen.width/2- 50, 50, 100, 40), "Lose", style);
        }
        else if (status == 2)
        {
            GUI.Label(new Rect (Screen.width/2- 50, 50, 100, 40), "Win", style);
        }
        GUI.Button(new Rect(Screen.width/2 - 150 , 30, 400, 40), tips, style);

        if (GUI.Button(new Rect(Screen.width/2 - 300 , 30, 100, 40), "Tips", buttonStyle))
        {
            int[] arr = userAction.getStateInfo();
            leftPriests = arr[0];
            leftDevils = arr[1];
            rightPriests = arr[2];
            rightDevils = arr[3];

            if (arr[4] == 0) boat_pos = true;
            else boat_pos = false;
            start = new GameState(leftPriests, leftDevils, rightPriests, rightDevils, boat_pos, null);

            GameState temp = GameState.BFS(start, end);


            int p = leftPriests - temp.lp;
            int d = leftDevils - temp.ld;
            if (p < 0) p = -p;
            if (d < 0) d = -d;
            tips = "Move " + p + " priest(s)," + d
                + " devil(s) to another side.";
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值