设计一个 entity class
,用于创建和管理游戏世界中的实体对象。这个类包含了大量的函数,用于处理实体的各种行为和属性,例如创建、移动、播放动画、同步状态等。
ctor
函数在 Lua 中是一个构造函数,用于初始化类的新实例。在面向对象编程中,构造函数是一个特殊的方法,当创建一个新对象时会自动调用它,以设置对象的初始状态。
-- entity 类的构造函数,用于初始化实体对象的基本属性
function entity:ctor(guid)
-- 导入所需的模块,以提供类所需的额外功能
local TRI = require("logic/entity/ai/trigger");
-- 初始化内部属性,这些属性定义了实体的基本特征和行为
self._id = -1; -- 实体的内部ID,初始值设为-1表示未指定
self._isCreated = false; -- 标记以追踪实体是否已被成功创建
self._syncRpc = false; -- 同步远程过程调用的标志,默认为不同步
self._groupType = eGroupType_N; -- 实体所属的组类型,默认为eGroupType_N(未指定)
self._ctrlType = eCtrlType_AI; -- 控制类型,默认为AI控制
self._renderable = true; -- 渲染标志,默认实体是可渲染的
-- 初始化实体的朝向和位置向量
self._faceDir = vec3(0, 0, 0); -- 实体面向的方向,默认为(0, 0, 0)
self._orientation = vec3(0, 0, 0); -- 实体的前倾方向,默认与朝向相同
-- 初始化移动相关属性
self._movable = false; -- 移动标志,默认实体不可移动
self._cacheable = false; -- 缓存标志,默认实体不可缓存
-- 初始化行为控制属性
self._actionPause = 0; -- 行为暂停计数器,用于控制行为的暂停与恢复
self._actionName = nil; -- 当前行为名称
self._actionLst = nil; -- 行为列表
self._actionChanged = false; -- 行为改变标志
self._actionLoops = -999; -- 行为循环次数
self._aiController = nil; -- AI控制器
self._camera = nil; -- 摄像机控制器
-- 初始化位置和速度
self._curPos = Engine.SVector3(0, 0, 0); -- 实体当前位置
self._curPosE = Engine.SVector3(0, 0, 0); -- 实体当前位置的引擎表示
self._velocity = nil; -- 实体速度向量
-- 初始化目标和恐惧位置
self._targetPos = nil; -- 目标位置
self._fearPos = nil; -- 实体恐惧的位置
-- 初始化路径和跟随属性
self._movePaths = { }; -- 移动路径表
self._follow = nil; -- 跟随的实体
-- 初始化AI和行为更新属性
self._moveChanged = false; -- 移动改变标志
self._forceMove = false; -- 强制移动标志
self._turnMode = false; -- 转向模式标志
-- 初始化更新和渲染相关属性
self._updateAlives = true; -- 更新存活状态的标志
self._updateAliveTick = 0; -- 更新存活状态的计时器
self._lastUpdateAliveTick = 0; -- 上次更新存活状态的时间
-- 初始化属性表
self._properties = { }; -- 实体属性表
-- 初始化其他属性和资源创建相关属性
-- ... 其他属性初始化代码
-- 使用传入的 guid 初始化实体的唯一标识符
self._guid = guid;
-- 初始化实体的名称
self._name = "";
-- 创建与AI触发器管理器的实例
self._triMgr = TRI.ai_trigger_mgr_create(self);
-- 初始化资源创建标志
self._resCreated = 1;
-- 初始化标题颜色
self._TitleColor = { -- 一系列颜色值,用于不同情况下的标题显示
tonumber("0xffffffff", 16), -- 白色
-- ... 其他颜色定义
};
-- 初始化显示标志
self._isShow = false;
-- 初始化选择效果的缩放
self._selEffScale = 1.0;
-- 初始化标题信息
self._titleInfo = {
name = false, -- 标题名称显示标志
blood = false, -- 血量显示标志
buff = false, -- 增益效果显示标志
vis = false -- 可见性标志
};
-- 初始化缓存清除时间
self._cacheClearTime = 0;
-- 初始化离开缓存标志
self._inLeaveCache = false;
-- 初始化世界内标志
self._inWorld = false;
-- 初始化移动信息
self._moveInfo = {
ticks = 0, -- 移动计时器
speed = 0, -- 移动速度
dirs = { }, -- 移动方向表
paths = { } -- 移动路径表
};
-- 初始化标题显示标志
self._titleshow = true;
-- 初始化车辆状态,可能用于控制实体是否在车辆上
self._carState = 0;
-- 初始化区域ID,可能用于区域相关的逻辑
self._sectID = 0;
-- 初始化队伍ID,可能用于队伍相关的逻辑
self._teamID = 0;
-- 初始化是否为演员(可能用于特殊行为或逻辑)
self._is_actor = false;
-- 初始化乘客相关属性,可能用于控制乘客逻辑
self._passengers = {};
-- 初始化相依相偎模式相关属性
self._hugMode = {
valid = false, -- 标记相依相偎模式是否有效
isLeader = false -- 标记是否是相依相偎模式的主导者
};
-- 初始化特殊技能或效果的动画ID
self._rideSpecialSpr = nil;
-- 初始化延迟属性更新队列,可能用于处理属性更新的延迟逻辑
self._DelayProps = {};
end
详细步骤:
- 导入模块:使用
require
函数导入其他模块,这些模块提供了额外的功能,如 AI 触发器管理。 - 属性初始化:为实体对象的属性设置初始值,这些属性定义了实体的基本特征,如 ID、控制类型、渲染状态等。
- AI 和行为控制:初始化与 AI 控制和行为相关的属性,如行为名称、行为列表、AI 控制器等。
- 位置和移动:初始化实体的位置、速度、目标位置和移动路径等属性。
- 更新和渲染:设置更新存活状态的标志和计时器,以及渲染相关的标志。
- 资源创建:初始化资源创建标志和其他资源相关属性。
- 唯一标识符:使用传入的
guid
参数设置实体的唯一标识符。 - 标题和显示:初始化标题颜色、显示标志和标题信息。
- 缓存和世界状态:设置缓存清除时间、离开缓存标志和世界内标志。
- 移动信息:初始化移动信息,包括计时器、速度和方向。
- 其他属性:根据需要初始化其他相关属性。
- 结束构造函数:所有属性初始化完成后,构造函数结束,实体对象具备了基本的属性和行为。
CreateActor
函数在 entity
类中的作用是初始化和创建与实体相关联的游戏引擎中的 actor。Actor 通常是指在游戏世界中可以独立行动的实体,例如玩家角色、NPC(非玩家角色)、怪物或其他可交互对象。在游戏引擎中,actor 可能负责处理实体的渲染、动画、物理和交互等。
-- 为实体创建一个 actor,这是实体成为可在游戏中操作和交互的第一步
function entity:CreateActor()
-- 首先检查实体是否已经被标记为一个 actor
if not self._is_actor then
-- 如果实体尚未成为 actor,将其标记为 actor
self._is_actor = true;
-- 创建一个 Engine.MEntity 对象,这是游戏引擎中用于表示实体的类
self._entity = Engine.MEntity(self._guid);
-- 调用 Engine.MEntity 的 Create 方法来初始化 actor
-- 这可能涉及设置实体的初始状态、属性和在游戏世界中注册实体
self._entity:Create();
-- 将创建的实体注册到游戏系统中,这样游戏就知道如何管理和渲染这个实体
-- 这里假设 game_register_entity 是游戏系统中用于注册实体的函数
game_register_entity(self._guid, self);
end
end
详细步骤:
-
检查 Actor 状态:首先检查
self._is_actor
是否为false
,这表明实体尚未创建为 actor。 -
设置 Actor 标记:如果实体不是 actor,将
self._is_actor
设置为true
,标记实体现在是一个 actor。 -
创建 Engine.MEntity 对象:使用
Engine.MEntity
类和实体的_guid
作为参数创建一个新实例。_guid
是实体的唯一标识符。 -
初始化 Actor:调用新创建的
MEntity
对象的Create
方法。这个方法可能执行必要的初始化,如设置初始位置、默认动画、物理属性等。 -
注册实体:使用
game_register_entity
函数将新创建的 actor 注册到游戏系统中。这通常涉及到将实体的元数据或引用添加到游戏的实体管理系统中,以便它可以被正确地更新和渲染。 -
结束创建 Actor:如果实体已经是 actor(
self._is_actor
为true
),则不执行任何操作。
Create
函数在 entity
类中的作用是初始化并设置实体对象的具体属性,如 ID 和名称,同时根据实体的类型进行相应的初始化操作。这个函数是创建实体过程中的关键步骤,它确保实体被正确配置并准备好加入游戏世界。
-- 用于创建实体并初始化其属性的函数
function entity:Create(id, name)
-- 设置实体的 ID
self._id = id
-- 设置实体的名称
self._name = name
-- 初始化实体的基础属性
self._properties = self:InitProperties()
-- 判断逻辑部分,确保 AI 管理器存在
local aiMgr = require("logic/entity/ai/ai_mgr")
if not aiMgr then
-- 如果 AI 管理器不存在,可能是模块未找到或初始化失败,返回 false 表示创建失败
return false
end
-- 使用 AI 管理器为实体创建一个 AI 控制器
self._aiController = aiMgr.create_mgr(self)
-- 如果实体已经关联有引擎对象,则同步其在游戏场景中的位置
if self._entity then
self._entity:SyncScenePos(self:IsPlayer())
end
-- 特殊处理玩家实体的创建状态
if self:IsPlayer() then
self._isCreated = true
end
-- 创建成功后返回 true
return true
end
详细步骤:
-
设置实体 ID 和名称:将传入的
id
和name
参数分别赋值给实体的_id
和_name
属性。 -
初始化属性:调用
InitProperties
方法来初始化实体的基础属性,这可能包括生命值、法力值、攻击力等。 -
检查 AI 管理器:使用
require
函数加载 AI 管理器模块,确保它存在。如果不存在,表示可能存在配置或加载错误,函数返回false
表示创建失败。 -
创建 AI 控制器:如果 AI 管理器存在,使用它为实体创建一个 AI 控制器,这个控制器将负责管理实体的 AI 行为。
-
同步位置:如果实体已经有一个关联的引擎对象(
self._entity
),调用SyncScenePos
方法同步其在游戏世界中的位置。 -
玩家实体特殊处理:如果实体是玩家控制的(
self:IsPlayer()
返回true
),将_isCreated
标记设置为true
,表示玩家实体已经完全创建并初始化。 -
创建成功:如果所有步骤都成功完成,函数返回
true
,表示实体创建成功。
IsCheckModelByPackId
函数在 entity
类中的作用是确定是否需要根据分包下载模式来检查和替换实体所使用的模型 ID。在一些游戏中,为了优化加载时间和内存使用,资源(如模型)可能会被分割成不同的包,并且只有在需要时才会加载特定的包。
-- 根据分包下载模式检查并替换实体使用的模型 ID
function entity:IsCheckModelByPackId(modelID)
-- 定义一个局部变量用于存储检查结果,默认为 false
local isCheck = false;
-- 检查实体类型是否为 NPC、怪物、雇佣兵或资源点之一
-- 这些类型可能需要根据分包模式来检查和替换模型
if self:GetEntityType() == eET_NPC or self:GetEntityType() == eET_Monster
or self:GetEntityType() == eET_Mercenary or self:GetEntityType() == eET_ResourcePoint then
-- 如果是上述类型之一,设置检查结果为 true
isCheck = true;
end
-- 如果需要检查,调用 engine_check_is_use_stock_model 函数来检查模型 ID
-- 这个函数可能是游戏引擎提供的功能,用于确定是否应该使用备选模型
-- 这可能取决于当前的资源加载情况或玩家的设置
if isCheck then
return engine_check_is_use_stock_model(modelID)
end
-- 如果不需要检查或在检查后不需要替换,返回原始模型 ID
return modelID;
end
详细步骤:
-
初始化检查结果:定义一个局部变量
isCheck
并初始化为false
,用于存储是否需要检查模型 ID。 -
检查实体类型:通过调用
GetEntityType
方法获取实体的类型,并检查它是否是 NPC、怪物、雇佣兵或资源点之一。如果是,这些类型的实体可能需要根据分包下载模式来检查模型 ID。 -
设置检查结果:如果实体类型需要检查,将
isCheck
设置为true
。 -
执行模型检查:如果
isCheck
为true
,则调用engine_check_is_use_stock_model
函数,并传入modelID
作为参数。这个函数会根据当前的资源加载情况或玩家的设置来决定是否使用备选模型。 -
返回结果:根据
isCheck
的值返回检查结果或原始模型 ID。如果需要检查并且engine_check_is_use_stock_model
函数返回了一个新的模型 ID,则使用这个新的模型 ID;否则,返回原始的modelID
。
CreateRes
函数在 entity
类中的作用是创建实体的资源,这通常涉及到加载和初始化实体的3D模型、动画、纹理等游戏资源。这个函数对于将实体可视化并准备其在游戏中的呈现至关重要。
-- 用于创建实体的资源,包括模型、动画等
function entity:CreateRes(modelID)
-- 检查是否处于分包下载模式,如果是,则可能需要根据模型ID检查和替换模型
modelID = self:IsCheckModelByPackId(modelID)
-- 获取创建模型的ID,这可能是一个基于当前实体状态和环境条件的模型ID
modelID = self:GetCreateModelId(modelID)
-- 检查是否需要同步创建资源
if self._syncCreateRes then
-- 如果需要同步创建,调用同步创建资源的方法
self:CreateResSync(modelID)
return
end
-- 获取模型配置,这可能包括模型路径、缩放、选择效果缩放等信息
local mcfg = db_models[modelID]
-- 检查模型配置是否存在以及实体是否已经关联了引擎对象
if mcfg and self._entity then
-- 保存模型配置,以便后续使用
self._rescfg = mcfg
-- 异步创建主机模型,这里使用模型配置中的路径和实体的唯一标识符作为名称
self._entity:AsyncCreateHosterModel(mcfg.path, string.format("entity_%s", self._guid))
-- 根据实体是否在战斗中进入世界
if self._inSprog then
self._entity:EnterWorld(true)
else
self._entity:EnterWorld(false)
end
-- 设置动作混合时间,这影响动画转换的速度
self._entity:SetActionBlendTime(0)
-- 根据实体类型设置视距,这里区分了普通实体和怪物
if self:GetEntityType() ~= eET_Monster then
self._entity:SetViewDistance(db_common.filter.FilterRadius / 100)
else
self._entity:SetViewDistance(db_common.filter.FilterMonsterRadius / 100)
end
-- 设置实体的高度、选择效果缩放和基础缩放
self._height = mcfg.titleOffset
self._selEffScale = mcfg.selEffScale
self._baseScale = mcfg.scale
self:SetScale(mcfg.scale)
-- 设置实体颜色,这里调用了全局数据库函数来获取颜色
self:SetColor(g_db.db_get_map_entity_color())
end
end
详细步骤:
-
模型ID检查:首先检查是否需要根据分包下载模式来检查和替换模型ID。
-
获取创建模型ID:根据实体的当前状态和环境条件获取要创建的模型的ID。
-
同步创建资源:如果设置了同步创建资源的标志,则调用同步创建资源的方法并返回。
-
获取模型配置:根据模型ID获取模型配置信息,这可能包括模型文件的路径和其他相关设置。
-
检查配置和引擎对象:确保模型配置存在并且实体已经关联了引擎对象。
-
异步创建模型:使用模型配置中的路径和实体的唯一标识符异步创建主机模型。
-
进入世界:根据实体是否处于战斗中来决定如何进入世界。
-
设置动作混合时间:设置动作混合时间,影响动画之间的过渡效果。
-
设置视距:根据实体类型设置视距,影响实体在世界中的可见范围。
-
设置实体尺寸:设置实体的高度、选择效果的缩放和基础缩放。
-
设置实体颜色:根据全局数据库函数获取并设置实体的颜色。
CreateResSync
函数在 entity
类中的作用是同步创建实体的资源。与 CreateRes
相比,这个函数不是异步执行的,而是会立即执行资源的创建过程。这通常用于那些需要立即加载资源以避免游戏过程中的加载中断或延迟的情况。
-- 同步创建实体资源的方法,用于立即加载模型和相关资源
function entity:CreateResSync(modelID)
-- 获取模型配置,这可能包括模型路径、缩放等信息
local mcfg = db_models[modelID]
-- 检查模型配置是否存在以及实体是否已经关联了引擎对象
if mcfg and self._entity then
-- 保存模型配置以供后续使用
self._rescfg = mcfg
-- 同步创建主机模型,这里使用模型配置中的路径和实体的唯一标识符作为名称
-- 与异步创建不同,这个方法会立即创建资源,而不是在后台线程中进行
if self._entity:CreateHosterModel(mcfg.path, string.format("entity_%s", self._guid)) then
-- 资源创建成功后,更新资源创建状态
self._resCreated = self._resCreated - 1
-- 设置实体的高度、选择效果缩放和基础缩放
self._height = mcfg.titleOffset
self._selEffScale = mcfg.selEffScale
-- 创建标题,这可能涉及到设置实体名称等信息
self._title = self:CreateTitle()
-- 如果标题节点存在,设置其可见性并让其进入世界
if self._title and self._title.node then
self._title.node:SetVisible(true)
self._title.node:EnterWorld()
-- 将标题节点添加到实体上,设置标题的偏移量
self._entity:AddTitleNode(self._title.node:GetTitle(), mcfg.titleOffset)
end
-- 设置实体的基础缩放
self._baseScale = mcfg.scale
self:SetScale(self._baseScale)
-- 根据实体是否显示标题设置标题的可见性
if self:GetTitleShow() ~= nil then
self:SetTitleVisiable(self:GetTitleShow())
end
-- 设置实体的视距,这里区分了普通实体和怪物
if self:GetEntityType() ~= eET_Monster then
self._entity:SetViewDistance(db_common.filter.FilterRadius / 100)
else
self._entity:SetViewDistance(db_common.filter.FilterMonsterRadius / 100)
end
-- 让实体进入世界,但不立即渲染
self._entity:EnterWorld(false)
-- 如果实体是玩家控制的,可能需要设置特定的颜色或其他属性
if self:IsPlayer() then
-- 这里可以添加玩家特定资源加载的代码
end
end
end
end
详细步骤:
-
获取模型配置:通过模型ID从数据库
db_models
中获取模型的配置信息。 -
检查配置和引擎对象:确保获取到的模型配置有效,并且实体已经关联了引擎对象。
-
同步创建模型:调用引擎对象的
CreateHosterModel
方法同步创建模型,并传入模型路径和实体名称。 -
更新资源创建状态:如果模型创建成功,更新实体的资源创建状态。
-
设置实体尺寸:根据模型配置设置实体的高度和选择效果缩放。
-
创建标题:调用
CreateTitle
方法创建实体的标题,并设置标题的可见性和进入世界。 -
添加标题节点:如果标题节点存在,将其添加到实体上,并设置标题的偏移量。
-
设置基础缩放:根据模型配置设置实体的基础缩放。
-
设置标题可见性:根据实体的标题显示状态设置标题的可见性。
-
设置视距:根据实体类型设置视距,影响实体在世界中的可见范围。
-
进入世界:让实体进入游戏世界,但不立即渲染,以便可以进行进一步的设置或初始化。
-
玩家特定设置:如果是玩家控制的实体,可能需要进行额外的设置,如颜色或特殊属性。
OnAsyncLoaded
函数在 entity
类中的作用是处理异步加载完成后的回调。当实体的资源(如模型、纹理、动画等)通过异步方式加载并准备好后,这个函数会被调用,以便进行后续的初始化和设置。
-- 处理异步加载完成后的回调
function entity:OnAsyncLoaded()
-- 检查实体是否拥有关联的引擎对象
if self._entity then
-- 减少资源创建计数,表示资源已经加载完成
self._resCreated = self._resCreated - 1
-- 如果实体类型不是幽灵,继续进行初始化
if self:GetEntityType() ~= eET_Ghost then
-- 创建标题,这可能包括设置实体名称等信息
self._title = self:CreateTitle()
-- 如果标题节点存在,设置其可见性并让其进入世界
if self._title and self._title.node then
self._title.node:SetVisible(true)
self._title.node:EnterWorld()
-- 将标题节点添加到实体上,可能需要设置标题的偏移量
if self._rescfg then
self._entity:AddTitleNode(self._title.node:GetTitle(), self._rescfg.titleOffset)
else
self._entity:AddTitleNode(self._title.node:GetTitle(), 0)
end
end
-- 如果实体不是处于隐形行为状态,显示实体和标题节点
if not self._behavior:Test(eEBInvisible) then
self:Show(self._isShow, true)
self:ShowTitleNode(self._titleInfo.vis)
end
-- 设置实体的面向方向
self:SetFaceDir(self._faceDir.x, self._faceDir.y, self._faceDir.z)
-- 设置实体的渲染状态
self:EnableRender(self._renderable)
-- 根据实体的标题显示设置,设置标题节点的可见性
if self:GetTitleShow() ~= nil then
self:SetTitleVisiable(self:GetTitleShow())
end
-- 如果实体处于隐形行为状态,隐藏实体
if self._behavior:Test(eEBInvisible) then
self:Show(false, true)
end
end
-- 如果实体类型是怪物并且不是在战斗同步状态,添加特殊效果
if self:GetEntityType() == eET_Monster and not game_get_world()._syncRpc then
self:AddSpecialEffect()
end
-- 播放实体的动画
self:PlayAction()
-- 设置实体的颜色
self:SetColor(g_db.db_get_map_entity_color())
-- 调用标题颜色测试,可能涉及到根据实体状态或类型设置不同颜色的逻辑
self:TitleColorTest()
end
end
详细步骤:
-
检查引擎对象:确保实体拥有一个关联的引擎对象。
-
更新资源创建计数:资源加载完成后,更新
_resCreated
计数。 -
排除幽灵类型:如果实体不是幽灵类型,执行进一步的初始化。
-
创建标题:为实体创建标题,可能包括设置名称和其他视觉元素。
-
设置标题可见性和进入世界:如果标题节点存在,设置其可见性并让其成为游戏世界的一部分。
-
添加标题节点:将标题节点添加到实体上,并根据配置设置标题的偏移量。
-
显示实体和标题节点:如果实体没有处于隐形行为状态,显示实体和标题节点。
-
设置面向方向:根据实体的面向方向设置其在游戏世界中的朝向。
-
设置渲染状态:根据实体的渲染状态设置其是否应该被渲染。
-
设置标题可见性:根据实体的标题显示设置,调整标题节点的可见性。
-
隐藏实体(如果需要):如果实体处于隐形行为状态,隐藏实体。
-
添加特殊效果:对于怪物类型的实体,如果不是在战斗同步状态,添加特殊效果。
-
播放动画:调用
PlayAction
方法播放实体的动画。 -
设置颜色:根据全局数据库获取并设置实体的颜色。
-
标题颜色测试:执行额外的逻辑来测试和设置标题的颜色。