定义`ai_mgr`的类,用于管理游戏中实体的AI组件。
先定义 AI行为枚举和优先级:
lua 游戏架构 之 游戏 AI (八)ai_tbl 行为和优先级-CSDN博客https://blog.csdn.net/heyuchang666/article/details/140712839?spm=1001.2014.3001.5501lua 游戏架构 之 游戏 AI (一)ai_base-CSDN博客
https://blog.csdn.net/heyuchang666/article/details/140624481?spm=1001.2014.3001.5501
以下是对代码的具体解释:
1. **引入依赖**: 使用`require`函数引入全局定义和AI定义。
2. **关闭JIT编译**: 如果启用了JIT编译,则关闭它,以确保AI逻辑的一致性。
3. **定义`ai_mgr`类**: `ai_mgr`类用于管理实体的AI组件。
4. **构造函数 (`ctor`)**:
5. **`AddComponent`方法**:
6. **`RmvComponent`方法**:移除指定类型的AI组件,并调用其`OnDetach`方法。
7. **`GetActiveComp`方法**:返回当前激活的AI组件。
8. **`BuildIdx`方法**: 构建子组件索引列表,并按优先级排序。
9. **`SwitchComp`方法**:
self._activeComp
)不是新切换的组件,则先检查当前激活的组件是否开启(IsTurnOn
)。如果是,则调用其OnLeave
方法,使其离开当前状态。OnEnter
方法,使其进入激活状态。self._activeComp = comp
)。10. **`OnUpdate`方法**:
- 调用当前激活的AI组件的`OnUpdate`方法,更新AI状态。
11. **`OnLogic`方法**:
- 调用当前激活的AI组件的`OnLogic`方法,执行逻辑更新。如果逻辑更新失败,则将组件从激活状态移除。
12. **`OnStopAction`方法**:
- 调用当前激活的AI组件的`OnStopAction`方法,停止当前动作。
13. **`OnAttackAction`方法**:
- 调用当前激活的AI组件的`OnAttackAction`方法,处理攻击动作。
14. **`create_mgr`函数**:
- 创建并返回一个新的`ai_mgr`实例。
代码逻辑流程:
关键点:
整体而言,这段代码为游戏中的AI组件提供了一个灵活的管理框架,根据不同的游戏场景和实体状态动态地切换和控制AI行为。
local require = require require("global"); require("logic/entity/ai/ai_def"); ------------------------------------------------------ if jit then jit.off(true, true) end ------------------------------------------------------ ai_mgr = class("ai_mgr"); function ai_mgr:ctor(entity) self._entity = entity; self._childs = { }; self._child_idx = { }; self._activeComp = nil; -- add default ai component self:AddComponent(eAType_BASE); -- get default ai component self:SwitchComp(); end function ai_mgr:AddComponent(atype) local ai = ai_tbl[atype]; if ai then local comp = require("logic/entity/ai/" .. ai.script); if comp then local c = comp.create_component(self._entity, ai.priority); if c then c:SetName(ai.script); c:OnAttach(); end self._childs[atype] = c; self:BuildIdx(); end end end function ai_mgr:RmvComponent(atype) local c = self._childs[atype]; if c then c:OnDetach(); end self._childs[atype] = nil; self:BuildIdx(); end function ai_mgr:GetActiveComp() return self._activeComp; end function ai_mgr:BuildIdx() self._child_idx = { }; for k ,_ in pairs(self._childs) do table.insert(self._child_idx, k); end local _cmp = function(d1, d2) if d1 > d2 then return true; end return false; end table.sort(self._child_idx, _cmp); end function ai_mgr:SwitchComp() if jit then jit.off(true, true) end if self._entity and self._entity:IsPlayer() and g_game_context:IsInPingMode() then return false; end for k, v in ipairs(self._child_idx) do local comp = self._childs[v]; if self._entity:IsRenderable() or (comp._priority == eAI_Priority_High) then if comp:Switch() then if self._activeComp ~= comp then if self._activeComp and self._activeComp:IsTurnOn() then self._activeComp:OnLeave(); end if not comp:IsTurnOn() then --if self._entity:GetEntityType()==eET_Mercenary then --log("entity enter ai " .. comp:GetName()); -- end comp:OnEnter(); end self._activeComp = comp; end return true; end end end return false; end function ai_mgr:OnUpdate(dTime) if self._activeComp then if self._entity and self._entity:IsPlayer() and g_game_context:IsInPingMode() then return ; end self._activeComp:OnUpdate(dTime); end end function ai_mgr:OnLogic(dTick) if self._activeComp then if self._entity and self._entity:IsPlayer() and g_game_context:IsInPingMode() then return ; end if not self._activeComp:OnLogic(dTick) then self._activeComp:OnLeave(); self._activeComp = nil; return false; end end return true; end function ai_mgr:OnStopAction(action) if self._activeComp then self._activeComp:OnStopAction(action); end end function ai_mgr:OnAttackAction(id) if self._activeComp then self._activeComp:OnAttackAction(id); end end function create_mgr(entity) return ai_mgr.new(entity); end