做網(wǎng)站怎么插音樂循環(huán)西安網(wǎng)站制作價(jià)格
這段Lua腳本定義了一個(gè)名為 `ai_autofight_find_way` 的類,繼承自 `ai_base` 類。
lua 游戲架構(gòu) 之 游戲 AI (一)ai_base-CSDN博客文章瀏覽閱讀238次。定義了一套接口和屬性,可以基于這個(gè)基礎(chǔ)類派生出具有特定行為的AI組件。例如,可以創(chuàng)建追逐敵人的AI、巡邏的AI或使用特定策略的AI等,都繼承自這個(gè)基礎(chǔ)類https://blog.csdn.net/heyuchang666/article/details/140624481?spm=1001.2014.3001.5502
這個(gè)類用于處理游戲中AI在自動戰(zhàn)斗模式下尋找路徑的邏輯。以下是對代碼的具體解釋:
1. **引入基類**:
? ?- 使用 `require` 函數(shù)引入 `ai_base` 類,作為基礎(chǔ)類。
2. **定義 `ai_autofight_find_way` 類**:
? ?- 使用 `class` 關(guān)鍵字定義了 `ai_autofight_find_way` 類,并繼承自 `BASE`(即 `ai_base`)。
3. **構(gòu)造函數(shù) (`ctor`)**:
? ?- 構(gòu)造函數(shù)接受一個(gè) `entity` 參數(shù),并設(shè)置 `_type` 屬性為 `eAType_AUTOFIGHT_FIND_WAY`,表示自動戰(zhàn)斗中尋找路徑的行為。
? ?- 初始化 `_target` 為 `nil`,用于后續(xù)存儲找到的目標(biāo)。
4. **`IsValid` 方法**:
- ? ?- 這個(gè)方法用于驗(yàn)證AI是否應(yīng)該尋找路徑。它首先檢查實(shí)體是否開啟了自動戰(zhàn)斗(`_AutoFight`),是否死亡或無法攻擊。
- ? ?- 檢查實(shí)體的行為,如果處于準(zhǔn)備戰(zhàn)斗或禁止攻擊狀態(tài),則返回 `false`。
- ? ?- 計(jì)算警報(bào)范圍 `radius`,可能基于實(shí)體的屬性或世界配置。
- ? ?- 根據(jù)不同的地圖類型和條件,確定是否需要尋找路徑。
5. **`OnEnter` 方法**:
? ?- 當(dāng)AI組件進(jìn)入激活狀態(tài)時(shí)執(zhí)行。根據(jù)當(dāng)前地圖類型和條件,計(jì)算目標(biāo)位置并使實(shí)體移動到該位置。
6. **`OnLeave` 方法**:
? ?- 當(dāng)AI組件離開激活狀態(tài)時(shí)執(zhí)行。當(dāng)前實(shí)現(xiàn)中直接返回 `true`。
7. **`OnUpdate` 方法**:
? ?- 每幀調(diào)用,用于更新AI狀態(tài)。如果基類的 `OnUpdate` 方法返回 `true`,則當(dāng)前方法也返回 `true`。
8. **`OnLogic` 方法**:
? ?- 邏輯更新方法,如果基類的 `OnLogic` 方法返回 `true`,則當(dāng)前方法返回 `false`,表示只執(zhí)行一次。
9. **創(chuàng)建組件函數(shù)**:
? ?- `create_component` 函數(shù)用于創(chuàng)建 `ai_autofight_find_way` 類的新實(shí)例,傳入一個(gè)實(shí)體和一個(gè)優(yōu)先級。
代碼中的一些關(guān)鍵點(diǎn):
- - `IsDead()`:檢查實(shí)體是否死亡。
- - `CanAttack()`:檢查實(shí)體是否可以攻擊。
- - `GetPropertyValue(ePropID_alertRange)`:獲取實(shí)體的警報(bào)范圍屬性。
- - `game_get_world()`:獲取游戲世界配置。
- - `Test(eEBPrepareFight)` 和 `Test(eEBDisAttack)`:檢查實(shí)體的行為狀態(tài)。
- - `MoveTo()`:移動到指定位置。
這個(gè)腳本為游戲中的AI提供了一個(gè)自動戰(zhàn)斗中尋找路徑的基礎(chǔ)框架,可以根據(jù)具體游戲的需求進(jìn)行擴(kuò)展和修改。以下是一些具體的邏輯處理:
- - 根據(jù)不同的地圖類型(如 `g_BASE_DUNGEON`、`g_ACTIVITY` 等),AI的行為可能會有所不同。
- - 計(jì)算與目標(biāo)的距離,并根據(jù)距離決定是否移動。
- - 考慮地圖上的特定點(diǎn)(如物品掉落點(diǎn)、怪物刷新點(diǎn))來決定移動路徑。
- - 使用 `vec3_dist` 函數(shù)計(jì)算兩個(gè)位置之間的距離,并根據(jù)距離決定是否移動到該位置。
整體而言,這個(gè)類的目的是在自動戰(zhàn)斗模式下,根據(jù)游戲世界的當(dāng)前狀態(tài)和配置,為AI實(shí)體找到合適的移動路徑。
重點(diǎn)解釋一下?OnEnter:
function ai_autofight_find_way:OnEnter()if BASE.OnEnter(self) thenlocal entity = self._entity;local radius = entity:GetPropertyValue(ePropID_alertRange);local logic = game_get_logic();local world = game_get_world();if world then-- 如果世界配置中有自動戰(zhàn)斗半徑,則使用該值if world._cfg.autofightradius thenradius = world._cfg.autofightradius;end-- 根據(jù)不同的地圖類型執(zhí)行不同的邏輯if world._mapType == g_BASE_DUNGEON or world._mapType == g_ACTIVITY or ... then-- 檢查所有掉落物品,如果物品處于激活狀態(tài),則移動到該物品位置for k,v in pairs(world._ItemDrops) doif v and v:GetStatus() == eSItemDropActive thenlocal _pos = logic_pos_to_world_pos(v._curPos);entity:MoveTo(_pos);return false; -- 移動到物品位置后,退出函數(shù)endend-- 如果地圖類型是開放區(qū)域,并且有怪物刷新點(diǎn)或當(dāng)前活動區(qū)域if world._openType == g_FIELD then-- 尋找一個(gè)有活著的怪物的刷新點(diǎn)local _pos = nil;local isfind = false;for k1,v1 in pairs(world._curArea._spawns) dofor k2,v2 in pairs(v1._monsters) doif not v2:IsDead() thenisfind = true;break;endendif isfind then_pos = v1._cfg.pos;break;endend-- 如果沒有找到有活著的怪物的刷新點(diǎn),使用第一個(gè)刷新點(diǎn)的位置if not _pos then_pos = world._curArea._spawns[1]._cfg.pos;end-- 計(jì)算實(shí)體當(dāng)前位置到刷新點(diǎn)或地圖增益點(diǎn)的距離local dist = vec3_dist(entity._curPos,world_pos_to_logic_pos(_pos));local mindist = dist;-- 尋找最近的地圖增益點(diǎn)for k,v in pairs(world._mapbuffs) doif v and v:GetStatus() == 1 thenlocal distbuff = vec3_dist(v._curPos,entity._curPos);if distbuff < mindist and distbuff < db_common.droppick.AutoFightMapbuffAutoRange thenmindist = distbuff;_pos = logic_pos_to_world_pos(v._curPos);endendend-- 移動實(shí)體到計(jì)算出的位置entity:MoveTo(_pos);end-- 其他地圖類型的邏輯...elseif world._mapType == g_FIELD or world._mapType == g_Life then-- 對于其他地圖類型,尋找最近的地圖增益點(diǎn)并移動實(shí)體-- ...endendreturn false; -- 如果沒有找到目標(biāo)位置或執(zhí)行了移動邏輯,則返回falseendreturn false; -- 如果沒有調(diào)用基類的OnEnter或基類返回false,則返回false
end
在 OnEnter
方法中,首先調(diào)用基類的 OnEnter
方法,如果它返回 false
,則直接返回 false
。如果基類的 OnEnter
方法返回 true
,則繼續(xù)執(zhí)行以下邏輯:
- 獲取實(shí)體的警報(bào)范圍?
radius
。 - 檢查游戲世界配置,如果存在自動戰(zhàn)斗半徑配置,則使用該配置值覆蓋實(shí)體的警報(bào)范圍。
- 根據(jù)當(dāng)前的地圖類型,執(zhí)行不同的邏輯來尋找目標(biāo)位置。例如:
- 如果是?
g_BASE_DUNGEON
、g_ACTIVITY
?等地圖類型,會檢查所有物品掉落點(diǎn),尋找激活的物品并移動到該位置。 - 如果是開放區(qū)域(
g_FIELD
),會尋找有活著的怪物的刷新點(diǎn)或最近的地圖增益點(diǎn),并移動實(shí)體到該位置。
- 如果是?
- 使用?
vec3_dist
?函數(shù)計(jì)算實(shí)體當(dāng)前位置到目標(biāo)位置的距離,并根據(jù)這個(gè)距離來確定是否移動實(shí)體。 - 如果找到目標(biāo)位置,則調(diào)用?
entity:MoveTo(_pos)
?方法移動實(shí)體到該位置,然后返回?false
?退出函數(shù)。 - 如果沒有找到目標(biāo)位置或不滿足移動條件,則返回?
false
。
整體而言,OnEnter
方法的目的是確定AI在自動戰(zhàn)斗模式下應(yīng)該移動到哪個(gè)位置,并執(zhí)行移動操作。
全部代碼實(shí)現(xiàn):
----------------------------------------------------------------
module(..., package.seeall)local require = requirelocal BASE = require("logic/entity/ai/ai_base").ai_base;------------------------------------------------------
ai_autofight_find_way = class("ai_autofight_find_way", BASE);
function ai_autofight_find_way:ctor(entity)self._type = eAType_AUTOFIGHT_FIND_WAY;self._target = nil;
endfunction ai_autofight_find_way:IsValid()local entity = self._entity;if not entity._AutoFight thenreturn false;endif entity:IsDead() or not entity:CanAttack() thenreturn false;endif entity._behavior:Test(eEBPrepareFight) thenreturn false;endif entity._behavior:Test(eEBDisAttack) thenreturn false;endlocal radius = entity:GetPropertyValue(ePropID_alertRange);local world = game_get_world();if world thenif world._cfg.autofightradius thenradius = world._cfg.autofightradius;endlocal target = entity._alives[2][1]; -- 敵方if entity._alives[3][1] then--中立local trap = entity._alives[3][1];if trap.entity and trap.entity._traptype == eSTrapActive thentarget = entity._alives[3][1]; endendif target thenif target.dist < radius thenif target.entity._groupType == eGroupType_N and target.dist > db_common.droppick.AutoFightMapbuffAutoRange thenelsereturn false;endendelseif world._mapType == g_TOURNAMENT thenreturn false;endendif 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 thenif world._openType == g_FIELD thenif #world._spawns == 0 and not world._curArea then return falseendelselocal spawnID = math.abs(g_game_context:GetDungeonSpawnID())if spawnID == 0 thenreturn falseendlocal dist = nil;if spawnID ~= 0 thenspawnPointID = db_spawn_area[spawnID].spawnPoints[1]_pos = db_spawn_point[spawnPointID].posdist = vec3_dist(entity._curPos,world_pos_to_logic_pos(_pos))if dist and dist < 100 thenreturn falseend endendelseif world._mapType == g_FIELD or world._mapType == g_Life thenif entity._PVPStatus ~= g_PeaceMode thenreturn false;endlocal dist = vec3_dist(entity._curPos,entity._AutoFight_Point)if dist < radius thenreturn false;endlocal value = g_game_context:getAutoFightRadius()if value and value == g_OneMap thenreturn false;endelse -- TODOreturn false;endendreturn true;
endfunction ai_autofight_find_way:OnEnter()if BASE.OnEnter(self) thenlocal entity = self._entity;local radius = entity:GetPropertyValue(ePropID_alertRange)local logic = game_get_logic();local world = game_get_world();if world thenif world._cfg.autofightradius thenradius = world._cfg.autofightradiusendif 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 thenfor k,v in pairs(world._ItemDrops) doif v and v:GetStatus() == eSItemDropActive thenlocal _pos = logic_pos_to_world_pos(v._curPos)entity:MoveTo(_pos)return false;endendif world._openType == g_FIELD thenif #world._spawns > 0 or world._curArea thenlocal _pos = nil;local isfind = falsefor k1,v1 in pairs(world._curArea._spawns) dofor k2,v2 in pairs(v1._monsters) doif not v2:IsDead() thenisfind = true;break;endendif isfind then_pos = v1._cfg.pos;break;endendif not _pos then_pos = world._curArea._spawns[1]._cfg.posend--local _pos = world._curArea._spawns[1]._cfg.poslocal dist = vec3_dist(entity._curPos,world_pos_to_logic_pos(_pos))local mindist = distfor k,v in pairs(world._mapbuffs) doif v and v:GetStatus() == 1 thenlocal distbuff = vec3_dist(v._curPos,entity._curPos)if distbuff < mindist and distbuff < db_common.droppick.AutoFightMapbuffAutoRange thenmindist = distbuff_pos = logic_pos_to_world_pos(v._curPos)endendendentity:MoveTo(_pos)endelselocal _pos = nillocal spawnID = math.abs(g_game_context:GetDungeonSpawnID())local dist = 99999999999;if spawnID ~= 0 thenspawnPointID = db_spawn_area[spawnID].spawnPoints[1]_pos = db_spawn_point[spawnPointID].posdist = vec3_dist(entity._curPos,world_pos_to_logic_pos(_pos)) endlocal mindist = distlocal isspawn = truefor k,v in pairs(world._mapbuffs) doif v and v:GetStatus() == 1 thenlocal distbuff = vec3_dist(v._curPos,entity._curPos)if distbuff < mindist and distbuff < db_common.droppick.AutoFightMapbuffAutoRange thenmindist = distbuffisspawn = false;_pos = logic_pos_to_world_pos(v._curPos)endendendif mindist < 150 and isspawn and g_game_context:GetDungeonSpawnID() < 0 theng_game_context:SetDungeonSpawnID(0);_pos = nil;endif _pos thenentity:MoveTo(_pos)endendelseif world._mapType == g_FIELD or world._mapType == g_Life thenfor k,v in pairs(world._mapbuffs) doif v and v:GetStatus() == 1 thenlocal distbuff = vec3_dist(v._curPos,entity._AutoFight_Point)if distbuff < radius and distbuff < db_common.droppick.AutoFightMapbuffAutoRange thenlocal _pos = logic_pos_to_world_pos(v._curPos)entity:MoveTo(_pos)return false;endendendendendreturn false;endreturn false;
endfunction ai_autofight_find_way:OnLeave()if BASE.OnLeave(self) thenreturn true;endreturn false;
endfunction ai_autofight_find_way:OnUpdate(dTime)if BASE.OnUpdate(self, dTime) thenreturn true;endreturn false;
endfunction ai_autofight_find_way:OnLogic(dTick)if BASE.OnLogic(self, dTick) thenreturn false; -- only one frameendreturn false;
endfunction create_component(entity, priority)return ai_autofight_find_way.new(entity, priority);
end