我正在为一个多人游戏开发服务器,需要控制几千个在世界中奔跑的生物。每个生物都有一个AI和心跳方法,如果有玩家附近,每隔几毫秒/秒就会调用一次,以便它们做出反应。
目前,该AI使用枚举器作为“例程”,例如:
这些方法被称为“状态方法”,在foreach循环中调用,在心跳中产生yield,因此您可以在每个时刻回到相同的位置。
当然,这些例程也必须在循环中调用,否则它们不会执行。但由于编写这些AI的不是我,而是那些并非程序员的新手,因此我在服务器启动前预编译这些AI(简单的.cs文件)以进行编译。这给我提供了像这样的AI脚本:
“Do”被替换为一个foreach循环,该循环迭代调用例程。
我真的很喜欢这个设计,因为人工智能很容易理解,但又非常强大。它不仅仅是简单的状态,也不像行为树那样难以理解和编写。
现在到了我的实际“问题”,我不喜欢“Do”包装器,也不喜欢预编译我的脚本。但我就是想不出其他实现方式,而我想隐藏循环,因为它们过于冗长,而且撰写这些脚本的人的技能水平有限。
我希望有一种方法可以在没有显式循环的情况下调用例程,但这是不可能的,因为我必须从状态方法中进行yield。
我无法使用async/await,因为它不适合我所依赖的tick设计(AI可能非常复杂,而且我真的不知道如何使用async来实现它)。此外,我只会将Do()与await交换,改进并不大。
所以我的问题是:有人能想到一种摆脱循环包装器的方法吗?如果有一种支持这种方式的其他.NET语言可用作脚本(在服务器启动时编译),我也愿意使用。
目前,该AI使用枚举器作为“例程”,例如:
IEnumerable WanderAround(int radius)
{
// Do something
}
这些方法被称为“状态方法”,在foreach循环中调用,在心跳中产生yield,因此您可以在每个时刻回到相同的位置。
void OnHeartbeat()
{
// Do checks, maybe select a new state method...
// Then continue the current sequence
currentState.MoveNext();
}
当然,这些例程也必须在循环中调用,否则它们不会执行。但由于编写这些AI的不是我,而是那些并非程序员的新手,因此我在服务器启动前预编译这些AI(简单的.cs文件)以进行编译。这给我提供了像这样的AI脚本:
override IEnumerable Idle()
{
Do(WanderAround(400));
Do(Wait(3000));
}
override IEnumerable Aggro()
{
Do(Attack());
Do(Wait(3000));
}
“Do”被替换为一个foreach循环,该循环迭代调用例程。
我真的很喜欢这个设计,因为人工智能很容易理解,但又非常强大。它不仅仅是简单的状态,也不像行为树那样难以理解和编写。
现在到了我的实际“问题”,我不喜欢“Do”包装器,也不喜欢预编译我的脚本。但我就是想不出其他实现方式,而我想隐藏循环,因为它们过于冗长,而且撰写这些脚本的人的技能水平有限。
foreach(var r in Attack()) yield return r;
我希望有一种方法可以在没有显式循环的情况下调用例程,但这是不可能的,因为我必须从状态方法中进行yield。
我无法使用async/await,因为它不适合我所依赖的tick设计(AI可能非常复杂,而且我真的不知道如何使用async来实现它)。此外,我只会将Do()与await交换,改进并不大。
所以我的问题是:有人能想到一种摆脱循环包装器的方法吗?如果有一种支持这种方式的其他.NET语言可用作脚本(在服务器启动时编译),我也愿意使用。
event
(事件),并让每个AI实现一个事件处理程序呢?那么你所要做的就是触发事件(Idle,Aggro等),每个AI都会按照脚本进行响应。.NET框架将处理循环遍历所有已订阅AI的事件处理程序。 - Evil Dog Pie