C# 有限状态机问题

C# 有限状态机问题,c#,unity3d,state-machine,C#,Unity3d,State Machine,使用Unity3D游戏引擎中的C#为我的游戏AI类构建FSM。我现在有两个简单的游戏对象,一个立方体(AI)和一个子弹(在调用函数时实例化,代码如下)。只是为更复杂的FSM搭建基础,但在学期初,所以我要学习它。p> 我的AI射出子弹,一次射出5颗子弹,当bulletCount为5时,它会改变状态。所以基本上我只想让它射5发子弹,等待我选择的时间,重新装弹,再射5发,然后继续同样的过程。基本上,所发生的事情完全是我希望它首先做的,一旦它退出我的IEnumerator,它就会射出无限量的子弹,即使它

使用Unity3D游戏引擎中的C#为我的游戏AI类构建FSM。我现在有两个简单的游戏对象,一个立方体(AI)和一个子弹(在调用函数时实例化,代码如下)。只是为更复杂的FSM搭建基础,但在学期初,所以我要学习它。p> 我的AI射出子弹,一次射出5颗子弹,当bulletCount为5时,它会改变状态。所以基本上我只想让它射5发子弹,等待我选择的时间,重新装弹,再射5发,然后继续同样的过程。基本上,所发生的事情完全是我希望它首先做的,一旦它退出我的IEnumerator,它就会射出无限量的子弹,即使它第一次做了我想要的

艾格拉斯

using UnityEngine;
using System.Collections;

public class AIClass : MonoBehaviour
{

public GameObject bullet;
int bulletCount;
float stunned;

public enum CombatAIStates
{
    Firing = 0,
    Stunned = 1,
    Reloading = 2,
    Following = 3,
    Idle = 4
}

public CombatAIStates currentState = CombatAIStates.Firing;

void Update()
{

    switch (currentState) 
    {
    case CombatAIStates.Firing:
        StartCoroutine (WaitMethod ());

        if(bulletCount <= 5)
        {
            spawnBullets ();
            Debug.Log ("Firing. ");
            Debug.Log ("Bullet: ");
            Debug.Log (bulletCount);
            StartCoroutine (WaitMethod ());
            ++bulletCount;
        }

        if(bulletCount > 5)
        {
            currentState = CombatAIStates.Reloading;

        }
        break;

    case CombatAIStates.Stunned:
            Debug.Log ("Stunned.");
        StartCoroutine(WaitMethod());
        currentState = CombatAIStates.Firing;
        //currentState = CombatAIStates.Firing;
        break;

    case CombatAIStates.Reloading:
        Debug.Log ("Reloading.");
        StartCoroutine (WaitMethod ());
        currentState = CombatAIStates.Stunned;
        break;
    }



}

IEnumerator WaitMethod()
{
    float waitTime = 10;
    Debug.Log ("Before yield.");
    yield return new WaitForSeconds (waitTime);
    Debug.Log ("After yield.");
    bulletCount = 0;

}

void spawnBullets()
{
    Instantiate(bullet, transform.position, transform.rotation);
}
}
使用UnityEngine;
使用系统集合;
公共类:单行为
{
公共游戏对象子弹;
国际弹头计数;
浮子惊呆了;
公共战斗人员
{
点火=0,
震惊=1,
重新加载=2,
以下=3,
怠速=4
}
公共战斗人员当前状态=战斗人员开火;
无效更新()
{
开关(当前状态)
{
案例战斗人员。开火:
start例程(WaitMethod());
如果(第5项)
{
当前状态=战斗状态。重新加载;
}
打破
案例战斗人员。惊呆了:
Log(“目瞪口呆”);
start例程(WaitMethod());
当前状态=战斗人员。开火;
//当前状态=战斗人员。开火;
打破
案例战斗人员。重新加载:
Log(“重新加载”);
start例程(WaitMethod());
当前状态=战斗人员。晕眩;
打破
}
}
IEnumerator WaitMethod()
{
浮动等待时间=10;
Log(“屈服前”);
返回新的WaitForSeconds(waitTime);
Log(“屈服后”);
bulletCount=0;
}
无效项目符号()
{
实例化(bullet、transform.position、transform.rotation);
}
}

为了简单起见,我怀疑这就是您试图做的事情:

public int BulletCount = 0;
public enum CombatAIStates
{
    Firing = 0,
    Reloading = 1,
}
CombatAIStates currentState = CombatAIStates.Firing;

// Update is called once per frame
void Update () {
    switch (currentState) {
        case CombatAIStates.Firing:
            if (BulletCount < 5) {
                Debug.Log ("Firing: " + BulletCount);
                ++BulletCount;
            } else {
                currentState = CombatAIStates.Reloading;
                StartCoroutine(Reload ());
            }
            break;
        case CombatAIStates.Reloading:
            // Nothing to do here, Reload() coroutine is handling things.
            // Maybe play a 10 second animation here or twiddle thumbs
            break;
    }
}
IEnumerator Reload()
{
    yield return new WaitForSeconds (10.0f);
    BulletCount = 0;

    //Now update the current combat state
    currentState = CombatAIStates.Firing;       
}
public int bullettcount=0;
公共战斗人员
{
点火=0,
重新加载=1,
}
战斗人员当前状态=战斗人员开火;
//每帧调用一次更新
无效更新(){
开关(当前状态){
案例战斗人员。开火:
如果(BulletCount<5){
调试日志(“触发:+BulletCount”);
++子弹计数;
}否则{
当前状态=战斗状态。重新加载;
开始例行程序(重新加载());
}
打破
案例战斗人员。重新加载:
//这里没什么可做的,Reload()协同程序正在处理事情。
//也许在这里播放10秒的动画或是摆弄拇指
打破
}
}
IEnumerator重载()
{
收益率返回新的WaitForSeconds(10.0f);
BulletCount=0;
//现在更新当前的战斗状态
当前状态=战斗人员。开火;
}

我没有对原始代码做太多更改。我刚刚将一个状态更改移动到一个
重新加载
协同程序,该程序在10秒后切换回
触发
,并重置
子弹计数
。或者,您可以在交换机的重新加载情况下更改状态。但是,与其调用协同程序,只需检查
bulletCount>=5
,如果不检查,则完成重新加载,您可以切换回触发。

我不太了解Unity,或者什么是协同程序-但看起来您在错误的位置重置了bulletCount。尝试在重新加载/昏迷状态下重置它,而不是在枚举中。实际上,你是对的,除非当我这样做时,它不会在5个子弹处停止,即使第一次它只是吐出无限量。谢谢你的帮助!(你是对的,我只是在这里做错了什么。)看起来你也等得太久了——试着把等待从触发状态中去掉。这应该会让你火*5…暂停…火*5…暂停…好吧,我认为问题更多的是它没有等待。我查看了我的调试,它正在发送所有必要的消息,只是没有等待!这是它运行时的控制台:开火。子弹:0发。子弹:1发。子弹:2发。子弹:3发。子弹:4发。子弹:5次重新装弹。在屈服之前。屈服前惊呆了。(从顶部重复)当它点击waitTime
StartRoutine
时,它不会停止FSM的其余部分,因为它不是阻塞调用(也不是收益返回),所以
Update()
中的所有
StartRoutine(WaitMethod())
调用都会被重复发送。我敢打赌,在发射前5颗子弹后,您将运行5个
WaitMethods
,这意味着您的子弹计数将连续重置5次。哈,是的,我知道您所做的。这正是我想要的。因此,作为将来的参考,我是否应该将大多数更改/方法调用的内容放在IEnumerator中?@user3308129由您决定。我在
coroutine
中更改了状态,因为您需要10秒的等待,我不想在switch语句中添加凌乱的
if(bulletCount>0)
代码。理想情况下,我喜欢将状态逻辑和转换封装在单个类/函数中(每个状态)。