C# 有限状态机问题
使用Unity3D游戏引擎中的C#为我的游戏AI类构建FSM。我现在有两个简单的游戏对象,一个立方体(AI)和一个子弹(在调用函数时实例化,代码如下)。只是为更复杂的FSM搭建基础,但在学期初,所以我要学习它。p> 我的AI射出子弹,一次射出5颗子弹,当bulletCount为5时,它会改变状态。所以基本上我只想让它射5发子弹,等待我选择的时间,重新装弹,再射5发,然后继续同样的过程。基本上,所发生的事情完全是我希望它首先做的,一旦它退出我的IEnumerator,它就会射出无限量的子弹,即使它第一次做了我想要的 艾格拉斯C# 有限状态机问题,c#,unity3d,state-machine,C#,Unity3d,State Machine,使用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次重新装弹。在屈服之前。屈服前惊呆了。(从顶部重复)当它点击waitTimeStartRoutine
时,它不会停止FSM的其余部分,因为它不是阻塞调用(也不是收益返回),所以Update()
中的所有StartRoutine(WaitMethod())
调用都会被重复发送。我敢打赌,在发射前5颗子弹后,您将运行5个WaitMethods
,这意味着您的子弹计数将连续重置5次。哈,是的,我知道您所做的。这正是我想要的。因此,作为将来的参考,我是否应该将大多数更改/方法调用的内容放在IEnumerator中?@user3308129由您决定。我在coroutine
中更改了状态,因为您需要10秒的等待,我不想在switch语句中添加凌乱的if(bulletCount>0)
代码。理想情况下,我喜欢将状态逻辑和转换封装在单个类/函数中(每个状态)。