0


lua 游戏架构 之 游戏 AI (五)ai_autofight_find_way

这段Lua脚本定义了一个名为 ai_autofight_find_way 的类,继承自 ai_base 类。

lua 游戏架构 之 游戏 AI (一)ai_base-CSDN博客文章浏览阅读238次。定义了一套接口和属性,可以基于这个基础类派生出具有特定行为的AI组件。例如,可以创建追逐敌人的AI、巡逻的AI或使用特定策略的AI等,都继承自这个基础类https://blog.csdn.net/heyuchang666/article/details/140624481?spm=1001.2014.3001.5502

这个类用于处理游戏中AI在自动战斗模式下寻找路径的逻辑。以下是对代码的具体解释:

  1. 引入基类

    • 使用 require 函数引入 ai_base 类,作为基础类。
  2. 定义 ai_autofight_find_way

    • 使用 class 关键字定义了 ai_autofight_find_way 类,并继承自 BASE(即 ai_base)。
  3. **构造函数 (ctor)**:

    • 构造函数接受一个 entity 参数,并设置 _type 属性为 eAType_AUTOFIGHT_FIND_WAY,表示自动战斗中寻找路径的行为。
    • 初始化 _targetnil,用于后续存储找到的目标。
  4. IsValid 方法

    • 这个方法用于验证AI是否应该寻找路径。它首先检查实体是否开启了自动战斗(_AutoFight),是否死亡或无法攻击。
    • 检查实体的行为,如果处于准备战斗或禁止攻击状态,则返回 false
    • 计算警报范围 radius,可能基于实体的属性或世界配置。
    • 根据不同的地图类型和条件,确定是否需要寻找路径。
  1. OnEnter 方法

    • 当AI组件进入激活状态时执行。根据当前地图类型和条件,计算目标位置并使实体移动到该位置。
  2. OnLeave 方法

    • 当AI组件离开激活状态时执行。当前实现中直接返回 true
  3. OnUpdate 方法

    • 每帧调用,用于更新AI状态。如果基类的 OnUpdate 方法返回 true,则当前方法也返回 true
  4. OnLogic 方法

    • 逻辑更新方法,如果基类的 OnLogic 方法返回 true,则当前方法返回 false,表示只执行一次。
  5. 创建组件函数

    • create_component 函数用于创建 ai_autofight_find_way 类的新实例,传入一个实体和一个优先级。

代码中的一些关键点:

    • IsDead():检查实体是否死亡。
    • CanAttack():检查实体是否可以攻击。
    • GetPropertyValue(ePropID_alertRange):获取实体的警报范围属性。
    • game_get_world():获取游戏世界配置。
    • Test(eEBPrepareFight)Test(eEBDisAttack):检查实体的行为状态。
    • MoveTo():移动到指定位置。

这个脚本为游戏中的AI提供了一个自动战斗中寻找路径的基础框架,可以根据具体游戏的需求进行扩展和修改。以下是一些具体的逻辑处理:

    • 根据不同的地图类型(如 g_BASE_DUNGEONg_ACTIVITY 等),AI的行为可能会有所不同。
    • 计算与目标的距离,并根据距离决定是否移动。
    • 考虑地图上的特定点(如物品掉落点、怪物刷新点)来决定移动路径。
    • 使用 vec3_dist 函数计算两个位置之间的距离,并根据距离决定是否移动到该位置。

整体而言,这个类的目的是在自动战斗模式下,根据游戏世界的当前状态和配置,为AI实体找到合适的移动路径。

重点解释一下 OnEnter:

  1. function ai_autofight_find_way:OnEnter()
  2. if BASE.OnEnter(self) then
  3. local entity = self._entity;
  4. local radius = entity:GetPropertyValue(ePropID_alertRange);
  5. local logic = game_get_logic();
  6. local world = game_get_world();
  7. if world then
  8. -- 如果世界配置中有自动战斗半径,则使用该值
  9. if world._cfg.autofightradius then
  10. radius = world._cfg.autofightradius;
  11. end
  12. -- 根据不同的地图类型执行不同的逻辑
  13. if world._mapType == g_BASE_DUNGEON or world._mapType == g_ACTIVITY or ... then
  14. -- 检查所有掉落物品,如果物品处于激活状态,则移动到该物品位置
  15. for k,v in pairs(world._ItemDrops) do
  16. if v and v:GetStatus() == eSItemDropActive then
  17. local _pos = logic_pos_to_world_pos(v._curPos);
  18. entity:MoveTo(_pos);
  19. return false; -- 移动到物品位置后,退出函数
  20. end
  21. end
  22. -- 如果地图类型是开放区域,并且有怪物刷新点或当前活动区域
  23. if world._openType == g_FIELD then
  24. -- 寻找一个有活着的怪物的刷新点
  25. local _pos = nil;
  26. local isfind = false;
  27. for k1,v1 in pairs(world._curArea._spawns) do
  28. for k2,v2 in pairs(v1._monsters) do
  29. if not v2:IsDead() then
  30. isfind = true;
  31. break;
  32. end
  33. end
  34. if isfind then
  35. _pos = v1._cfg.pos;
  36. break;
  37. end
  38. end
  39. -- 如果没有找到有活着的怪物的刷新点,使用第一个刷新点的位置
  40. if not _pos then
  41. _pos = world._curArea._spawns[1]._cfg.pos;
  42. end
  43. -- 计算实体当前位置到刷新点或地图增益点的距离
  44. local dist = vec3_dist(entity._curPos,world_pos_to_logic_pos(_pos));
  45. local mindist = dist;
  46. -- 寻找最近的地图增益点
  47. for k,v in pairs(world._mapbuffs) do
  48. if v and v:GetStatus() == 1 then
  49. local distbuff = vec3_dist(v._curPos,entity._curPos);
  50. if distbuff < mindist and distbuff < db_common.droppick.AutoFightMapbuffAutoRange then
  51. mindist = distbuff;
  52. _pos = logic_pos_to_world_pos(v._curPos);
  53. end
  54. end
  55. end
  56. -- 移动实体到计算出的位置
  57. entity:MoveTo(_pos);
  58. end
  59. -- 其他地图类型的逻辑...
  60. elseif world._mapType == g_FIELD or world._mapType == g_Life then
  61. -- 对于其他地图类型,寻找最近的地图增益点并移动实体
  62. -- ...
  63. end
  64. end
  65. return false; -- 如果没有找到目标位置或执行了移动逻辑,则返回false
  66. end
  67. return false; -- 如果没有调用基类的OnEnter或基类返回false,则返回false
  68. end

  1. OnEnter

方法中,首先调用基类的

  1. OnEnter

方法,如果它返回

  1. false

,则直接返回

  1. false

。如果基类的

  1. OnEnter

方法返回

  1. true

,则继续执行以下逻辑:

  1. 获取实体的警报范围 radius
  2. 检查游戏世界配置,如果存在自动战斗半径配置,则使用该配置值覆盖实体的警报范围。
  3. 根据当前的地图类型,执行不同的逻辑来寻找目标位置。例如: - 如果是 g_BASE_DUNGEONg_ACTIVITY 等地图类型,会检查所有物品掉落点,寻找激活的物品并移动到该位置。- 如果是开放区域(g_FIELD),会寻找有活着的怪物的刷新点或最近的地图增益点,并移动实体到该位置。
  4. 使用 vec3_dist 函数计算实体当前位置到目标位置的距离,并根据这个距离来确定是否移动实体。
  5. 如果找到目标位置,则调用 entity:MoveTo(_pos) 方法移动实体到该位置,然后返回 false 退出函数。
  6. 如果没有找到目标位置或不满足移动条件,则返回 false

整体而言,

  1. OnEnter

方法的目的是确定AI在自动战斗模式下应该移动到哪个位置,并执行移动操作。

全部代码实现:

  1. ----------------------------------------------------------------
  2. module(..., package.seeall)
  3. local require = require
  4. local BASE = require("logic/entity/ai/ai_base").ai_base;
  5. ------------------------------------------------------
  6. ai_autofight_find_way = class("ai_autofight_find_way", BASE);
  7. function ai_autofight_find_way:ctor(entity)
  8. self._type = eAType_AUTOFIGHT_FIND_WAY;
  9. self._target = nil;
  10. end
  11. function ai_autofight_find_way:IsValid()
  12. local entity = self._entity;
  13. if not entity._AutoFight then
  14. return false;
  15. end
  16. if entity:IsDead() or not entity:CanAttack() then
  17. return false;
  18. end
  19. if entity._behavior:Test(eEBPrepareFight) then
  20. return false;
  21. end
  22. if entity._behavior:Test(eEBDisAttack) then
  23. return false;
  24. end
  25. local radius = entity:GetPropertyValue(ePropID_alertRange);
  26. local world = game_get_world();
  27. if world then
  28. if world._cfg.autofightradius then
  29. radius = world._cfg.autofightradius;
  30. end
  31. local target = entity._alives[2][1]; -- 敌方
  32. if entity._alives[3][1] then--中立
  33. local trap = entity._alives[3][1];
  34. if trap.entity and trap.entity._traptype == eSTrapActive then
  35. target = entity._alives[3][1];
  36. end
  37. end
  38. if target then
  39. if target.dist < radius then
  40. if target.entity._groupType == eGroupType_N and target.dist > db_common.droppick.AutoFightMapbuffAutoRange then
  41. else
  42. return false;
  43. end
  44. end
  45. else
  46. if world._mapType == g_TOURNAMENT then
  47. return false;
  48. end
  49. end
  50. if world._mapType == g_BASE_DUNGEON or world._mapType == g_ACTIVITY or world._mapType == g_FACTION_DUNGEON or world._mapType == g_TOWER or world._mapType == g_WEAPON_NPC or world._mapType == g_RIGHTHEART or world._mapType == g_ANNUNCIATE or world._mapType == g_FIGHT_NPC or world._mapType == g_Pet_Waken then
  51. if world._openType == g_FIELD then
  52. if #world._spawns == 0 and not world._curArea then
  53. return false
  54. end
  55. else
  56. local spawnID = math.abs(g_game_context:GetDungeonSpawnID())
  57. if spawnID == 0 then
  58. return false
  59. end
  60. local dist = nil;
  61. if spawnID ~= 0 then
  62. spawnPointID = db_spawn_area[spawnID].spawnPoints[1]
  63. _pos = db_spawn_point[spawnPointID].pos
  64. dist = vec3_dist(entity._curPos,world_pos_to_logic_pos(_pos))
  65. if dist and dist < 100 then
  66. return false
  67. end
  68. end
  69. end
  70. elseif world._mapType == g_FIELD or world._mapType == g_Life then
  71. if entity._PVPStatus ~= g_PeaceMode then
  72. return false;
  73. end
  74. local dist = vec3_dist(entity._curPos,entity._AutoFight_Point)
  75. if dist < radius then
  76. return false;
  77. end
  78. local value = g_game_context:getAutoFightRadius()
  79. if value and value == g_OneMap then
  80. return false;
  81. end
  82. else -- TODO
  83. return false;
  84. end
  85. end
  86. return true;
  87. end
  88. function ai_autofight_find_way:OnEnter()
  89. if BASE.OnEnter(self) then
  90. local entity = self._entity;
  91. local radius = entity:GetPropertyValue(ePropID_alertRange)
  92. local logic = game_get_logic();
  93. local world = game_get_world();
  94. if world then
  95. if world._cfg.autofightradius then
  96. radius = world._cfg.autofightradius
  97. end
  98. if world._mapType == g_BASE_DUNGEON or world._mapType == g_ACTIVITY or world._mapType == g_FACTION_DUNGEON or world._mapType == g_TOWER or world._mapType == g_WEAPON_NPC or world._mapType == g_RIGHTHEART or world._mapType == g_ANNUNCIATE or world._mapType == g_FIGHT_NPC or world._mapType == g_Pet_Waken then
  99. for k,v in pairs(world._ItemDrops) do
  100. if v and v:GetStatus() == eSItemDropActive then
  101. local _pos = logic_pos_to_world_pos(v._curPos)
  102. entity:MoveTo(_pos)
  103. return false;
  104. end
  105. end
  106. if world._openType == g_FIELD then
  107. if #world._spawns > 0 or world._curArea then
  108. local _pos = nil;
  109. local isfind = false
  110. for k1,v1 in pairs(world._curArea._spawns) do
  111. for k2,v2 in pairs(v1._monsters) do
  112. if not v2:IsDead() then
  113. isfind = true;
  114. break;
  115. end
  116. end
  117. if isfind then
  118. _pos = v1._cfg.pos;
  119. break;
  120. end
  121. end
  122. if not _pos then
  123. _pos = world._curArea._spawns[1]._cfg.pos
  124. end
  125. --local _pos = world._curArea._spawns[1]._cfg.pos
  126. local dist = vec3_dist(entity._curPos,world_pos_to_logic_pos(_pos))
  127. local mindist = dist
  128. for k,v in pairs(world._mapbuffs) do
  129. if v and v:GetStatus() == 1 then
  130. local distbuff = vec3_dist(v._curPos,entity._curPos)
  131. if distbuff < mindist and distbuff < db_common.droppick.AutoFightMapbuffAutoRange then
  132. mindist = distbuff
  133. _pos = logic_pos_to_world_pos(v._curPos)
  134. end
  135. end
  136. end
  137. entity:MoveTo(_pos)
  138. end
  139. else
  140. local _pos = nil
  141. local spawnID = math.abs(g_game_context:GetDungeonSpawnID())
  142. local dist = 99999999999;
  143. if spawnID ~= 0 then
  144. spawnPointID = db_spawn_area[spawnID].spawnPoints[1]
  145. _pos = db_spawn_point[spawnPointID].pos
  146. dist = vec3_dist(entity._curPos,world_pos_to_logic_pos(_pos))
  147. end
  148. local mindist = dist
  149. local isspawn = true
  150. for k,v in pairs(world._mapbuffs) do
  151. if v and v:GetStatus() == 1 then
  152. local distbuff = vec3_dist(v._curPos,entity._curPos)
  153. if distbuff < mindist and distbuff < db_common.droppick.AutoFightMapbuffAutoRange then
  154. mindist = distbuff
  155. isspawn = false;
  156. _pos = logic_pos_to_world_pos(v._curPos)
  157. end
  158. end
  159. end
  160. if mindist < 150 and isspawn and g_game_context:GetDungeonSpawnID() < 0 then
  161. g_game_context:SetDungeonSpawnID(0);
  162. _pos = nil;
  163. end
  164. if _pos then
  165. entity:MoveTo(_pos)
  166. end
  167. end
  168. elseif world._mapType == g_FIELD or world._mapType == g_Life then
  169. for k,v in pairs(world._mapbuffs) do
  170. if v and v:GetStatus() == 1 then
  171. local distbuff = vec3_dist(v._curPos,entity._AutoFight_Point)
  172. if distbuff < radius and distbuff < db_common.droppick.AutoFightMapbuffAutoRange then
  173. local _pos = logic_pos_to_world_pos(v._curPos)
  174. entity:MoveTo(_pos)
  175. return false;
  176. end
  177. end
  178. end
  179. end
  180. end
  181. return false;
  182. end
  183. return false;
  184. end
  185. function ai_autofight_find_way:OnLeave()
  186. if BASE.OnLeave(self) then
  187. return true;
  188. end
  189. return false;
  190. end
  191. function ai_autofight_find_way:OnUpdate(dTime)
  192. if BASE.OnUpdate(self, dTime) then
  193. return true;
  194. end
  195. return false;
  196. end
  197. function ai_autofight_find_way:OnLogic(dTick)
  198. if BASE.OnLogic(self, dTick) then
  199. return false; -- only one frame
  200. end
  201. return false;
  202. end
  203. function create_component(entity, priority)
  204. return ai_autofight_find_way.new(entity, priority);
  205. end
标签: lua 游戏 人工智能

本文转载自: https://blog.csdn.net/heyuchang666/article/details/140652299
版权归原作者 heyuchang666 所有, 如有侵权,请联系我们删除。

“lua 游戏架构 之 游戏 AI (五)ai_autofight_find_way”的评论:

还没有评论