主题
Thinker 系统
Thinker 系统管理需要每帧更新的游戏对象。提供两种接口:IThinker(每帧调用)和 IThinkerStaggered(分散调用,降低单帧负载)。
核心接口
| 接口 | 说明 |
|---|---|
IThinker | 每帧调用 Think(int delta) |
IThinkerStaggered | 每 N 帧调用一次 Think(),N 由 StaggeredCount 决定 |
IThinker
每帧更新接口,适用于需要实时处理的逻辑(游戏循环、动画、计时器等)。
csharp
public interface IThinker
{
void Think(int delta); // delta 为距上次 tick 的毫秒数
bool DoesThink { get; set; } // 启用/禁用
}- 服务端帧率:约 30 FPS(每帧 ~33ms)
- 客户端帧率:约 60-200 FPS(每帧 ~5-16ms)
使用示例
csharp
public class MyGameLoop : IThinker
{
public void Start()
{
(this as IThinker).DoesThink = true;
}
public void Stop()
{
(this as IThinker).DoesThink = false;
}
public void Think(int delta)
{
float deltaTime = delta / 1000f;
// 更新游戏逻辑
}
}框架中的 IThinker 使用
Simple2DMultiplayerGame<T>— 游戏模板的主循环Buff— Buff 的 Think 逻辑(OnThink回调)AIThinkTree— AI 行为树的定期决策
IThinkerStaggered
分散更新接口,将注册的对象分成 StaggeredCount 组,每帧只更新一组。适用于大量对象的低优先级更新(如 AI 扫描)。
csharp
public interface IThinkerStaggered
{
int StaggeredCount { get; } // 分组数(如 4 表示每 4 帧执行一次)
void Think(); // 无 delta 参数
bool DoesThink { get; set; }
}工作原理
帧 0: 执行 Group[0] 的所有 Thinker
帧 1: 执行 Group[1] 的所有 Thinker
帧 2: 执行 Group[2] 的所有 Thinker
帧 3: 执行 Group[3] 的所有 Thinker (StaggeredCount=4)
帧 4: 执行 Group[0](循环)
...对象在注册时被随机分配到某一组,确保负载均匀分布。
使用示例
csharp
public class AIScanner : IThinkerStaggered
{
public int StaggeredCount => 4; // 每 4 帧执行一次
public void Start()
{
(this as IThinkerStaggered).DoesThink = true;
}
public void Think()
{
// 扫描周围敌人、更新 AI 状态
}
}框架中的 IThinkerStaggered 使用
WaveAI— AI 波次管理器的定期扫描(StaggeredCount = 4)- 大量单位的周期性状态检查
IThinker vs IThinkerStaggered
| 特性 | IThinker | IThinkerStaggered |
|---|---|---|
| 调用频率 | 每帧 | 每 N 帧 |
| delta 参数 | 有(毫秒) | 无 |
| 适用场景 | 实时逻辑 | 低优先级批量处理 |
| 性能影响 | 高频 | 均匀分散 |
注意事项
DoesThink设为true时自动注册到引擎更新循环,false时注销IThinkerStaggered在 Think 执行期间的注册/注销会被延迟到当帧结束处理- 不要在
Think()中使用Task.Delay(),应使用Game.Delay() - 日志使用参数化模板:
Game.Logger.LogInformation("{Name} thinking", name)