PGRData/Script/matrix/xmodule/xrestaurant/xgameobject/XRestaurantChar.lua
2024-09-01 22:49:41 +02:00

412 lines
No EOL
11 KiB
Lua

local XRestaurantIScene = require("XModule/XRestaurant/XGameObject/XRestaurantIScene")
---@class XRestaurantChar : XRestaurantIScene
---@field _Id
---@field _Animator UnityEngine.Animator
---@field _CtrlResource XIResource
---@field _Input XGoInputHandler
---@field _BubbleOffset UnityEngine.Vector3 气泡偏移
---@field _Agent BehaviorTree.XAgent
---@field _ReferenceCount number 引用计数
---@field _EffectLoader XUiLoadPrefab
---@field _IsShowDelayBubble boolean
---@field _IsDoLoadBehaviour boolean
---@field _MoveSpeed number 移动速度
---@field _MoveAgent XMoveAgent
local XRestaurantChar = XClass(XRestaurantIScene, "XRestaurantChar")
--行为树代理
--require("XEntity/XRestaurant/XBehaviour/XRestaurantCharAgent")
local ResourceUnloadTime = 10000 --延时销毁
function XRestaurantChar:Ctor(root, id)
self._Id = id
self._ReferenceCount = 0
self._BubbleOffset = XRestaurantConfigs.StrPos2Vector3(XRestaurantConfigs.GetClientConfig("CharacterProperty", 2))
self:InitData()
end
function XRestaurantChar:Init()
self._MoveSpeed = tonumber(XRestaurantConfigs.GetClientConfig("CharacterProperty", 1))
end
function XRestaurantChar:InitData()
end
function XRestaurantChar:Born(bornCb)
self._ReferenceCount = self._ReferenceCount + 1
if self:Exist() then
self:Show()
if bornCb then bornCb() end
return
end
if self:IsLoading() then
return
end
self:Load(bornCb)
end
function XRestaurantChar:Dispose()
if not self:Exist() then
self._ReferenceCount = 0
return
end
self._ReferenceCount = self._ReferenceCount - 1
self:Hide()
XScheduleManager.ScheduleOnce(self._DelayReleaseCb, ResourceUnloadTime)
end
function XRestaurantChar:DisposeImmediately()
self:Release()
end
function XRestaurantChar:OnLoadSuccess()
--动画
self._Animator = self._GameObject:GetComponent(typeof(CS.UnityEngine.Animator))
-- 加载自定义状态机
local path = self:GetControllerPath()
if not string.IsNilOrEmpty(path) then
local resource = CS.XResourceManager.Load(path)
if not (resource and resource.Asset) then
XLog.Error(string.format("%s:角色状态机加载失败, 路径: %s", self:GetCharTypeDesc(), path))
return
end
self._CtrlResource = resource
self._Animator.runtimeAnimatorController = resource.Asset
end
--取消动画自带的位移
self._Animator.applyRootMotion = false
--行为树代理
self._Agent = self._GameObject:GetComponent(typeof(CS.BehaviorTree.XAgent))
if not self._Agent then
self._Agent = self._GameObject:AddComponent(typeof(CS.BehaviorTree.XAgent))
self._Agent.ProxyType = "RestaurantChar"
self._Agent:InitProxy()
end
self._Agent.Proxy.LuaAgentProxy:SetRole(self)
--是否需要点击
if self:IsNeedClick() then
--设置层级,点击生效
self._GameObject:SetLayerRecursively(CS.UnityEngine.LayerMask.NameToLayer(HomeSceneLayerMask.HomeCharacter))
self._Input = self._GameObject:GetComponent(typeof(CS.XGoInputHandler))
if not self._Input then
self._Input = self._GameObject:AddComponent(typeof(CS.XGoInputHandler))
end
self._Input:AddPointerClickListener(handler(self, self.OnClick))
end
--处理旋转/位移/缩放
self:InitCharTransform()
--处理阴影
CS.XMaterialContainerHelper.SetCharacterShadowVolumeEnable(self._GameObject, false)
CS.XShadowHelper.AddShadow(self._GameObject, true)
self._DelayReleaseCb = handler(self, self.DelayRelease)
self:PlayBehaviour()
end
function XRestaurantChar:Release()
if self._Agent then
self._Agent:ClearVarDic()
end
XRestaurantIScene.Release(self)
if self._CtrlResource then
self._CtrlResource:Release()
self._CtrlResource = nil
end
self._Animator = nil
self._Input = nil
self._Agent = nil
self._EffectLoader = nil
self._Effect = nil
self._MoveAgent = nil
self._ReferenceCount = 0
self._IsShowDelayBubble = false
end
function XRestaurantChar:Hide()
XRestaurantIScene.Hide(self)
self:DoHideBubble()
self._IsDoLoadBehaviour = false
end
function XRestaurantChar:DelayRelease()
if not self:Exist() then
return
end
--还有引用,不销毁
if self._ReferenceCount > 0 then
return
end
self:Release()
end
function XRestaurantChar:GetControllerPath()
return ""
end
--Debug 输出, 不用于实际业务
function XRestaurantChar:GetCharTypeDesc()
return ""
end
function XRestaurantChar:IsNeedClick()
return false
end
function XRestaurantChar:OnClick()
XLog.Warning("未实现点击方法!")
end
function XRestaurantChar:InitCharTransform()
end
function XRestaurantChar:PlayBehaviour()
XLog.Error("子类未实现该方法")
end
function XRestaurantChar:ChangeState(state)
end
--播放动画
function XRestaurantChar:DoAction(actionId, needFadeCross, crossDuration)
if not self:Exist() then
return
end
if needFadeCross then
self._Animator:CrossFade(actionId, crossDuration, -1, 0)
else
self._Animator:Play(actionId, -1, 0)
end
end
--根据下标播放动画
function XRestaurantChar:DoActionIndex(index, needFadeCross, crossDuration)
self:DoAction(self:GetActionId(index), needFadeCross, crossDuration)
end
function XRestaurantChar:CheckPlayRepeat(index, isRequireRepeat)
if isRequireRepeat then
return true
end
local stateInfo = self._Animator:GetCurrentAnimatorStateInfo(0)
local nextInfo = self._Animator:GetNextAnimatorStateInfo(0)
local actionId = self:GetActionId(index)
local newHash = CS.UnityEngine.Animator.StringToHash(actionId)
if newHash == stateInfo.shortNameHash
or nextInfo.shortNameHash == newHash then
return false
end
return true
end
function XRestaurantChar:GetActionId(index)
XLog.Error("子类调用,但未实现该方法")
return "Error"
end
function XRestaurantChar:GetActionDuration(index)
local actionId = self:GetActionId(index)
if string.IsNilOrEmpty(actionId) then
return 0
end
local animationClips = self._Animator.runtimeAnimatorController.animationClips;
for i = 0, animationClips.Length - 1 do
local clip = animationClips[i]
if clip and clip.name == actionId then
return clip.length
end
end
return 0
end
--弹出聊天气泡
function XRestaurantChar:DoRandomBubble()
if XTool.UObjIsNil(self._GameObject) or self:IsHide() then
return
end
local text = self:GetRandomBubbleText()
XEventManager.DispatchEvent(XEventId.EVENT_RESTAURANT_SHOW_3D_DIALOG, self:GetBubbleKey(), text, nil, self._Transform, self._BubbleOffset)
end
function XRestaurantChar:DoBubble(index)
if XTool.UObjIsNil(self._GameObject) or self:IsHide() then
return
end
local text = self:GetBubbleText(index)
XEventManager.DispatchEvent(XEventId.EVENT_RESTAURANT_SHOW_3D_DIALOG, self:GetBubbleKey(), text, nil, self._Transform, self._BubbleOffset)
end
--- 延时弹出气泡
---@param delay number 毫秒
--------------------------
function XRestaurantChar:DoRandomBubbleDelay(delay)
--上次的正在展示
if self:IsShowDelayBubble() then
return
end
if not self._RandomBubbleHandler then
self._RandomBubbleHandler = function()
if not self:Exist() then
return
end
self:DoRandomBubble()
XScheduleManager.ScheduleOnce(function()
self:DoHideBubble()
self._IsShowDelayBubble = false
end, XRestaurantConfigs.BubbleDuration * XScheduleManager.SECOND)
end
end
self._IsShowDelayBubble = true
XScheduleManager.ScheduleOnce(self._RandomBubbleHandler, delay)
end
function XRestaurantChar:IsShowDelayBubble()
return self._IsShowDelayBubble
end
--隐藏气泡
function XRestaurantChar:DoHideBubble()
if XTool.UObjIsNil(self._GameObject) then
return
end
XEventManager.DispatchEvent(XEventId.EVENT_RESTAURANT_HIDE_3D_DIALOG, self:GetBubbleKey())
end
--获取随机聊天气泡
function XRestaurantChar:GetRandomBubbleText()
XLog.Error("子类调用,但未实现该方法")
return "Error"
end
--通过下标获取冒泡
function XRestaurantChar:GetBubbleText(index)
XLog.Error("子类调用,但未实现该方法")
return "Error"
end
--获取气泡Id
function XRestaurantChar:GetBubbleKey()
if not self:Exist() then
return self._Id
end
return self._GameObject:GetHashCode()
end
--随机寻路
function XRestaurantChar:DoFindRandomPoint()
local point = self:GetRandomPoint()
self._Agent:SetVarDicByKey("TargetPosition", point)
end
--随机点位方法
function XRestaurantChar:GetRandomPoint()
XLog.Error("子类调用,但未实现该方法")
return CS.UnityEngine.Vector3.zero
end
function XRestaurantChar:DoStopMove()
if not self:Exist() then
return
end
if not self._MoveAgent then
return
end
self._MoveAgent:Stop()
end
function XRestaurantChar:GetId()
return self._Id
end
--加载特效
function XRestaurantChar:DoLoadEffect(path, initPos)
if XTool.UObjIsNil(self._GameObject) then
return
end
if self._EffectLoader and self._EffectLoader.PrefabAssetUrl == path and not XTool.UObjIsNil(self._Effect) then
self._Effect.gameObject:SetActiveEx(true)
self._Effect.transform.localPosition = initPos
return
end
self._Effect = self._Transform:LoadPrefab(path)
if not self._EffectLoader then
self._EffectLoader = self._Transform:GetComponent(typeof(CS.XUiLoadPrefab))
end
self._Effect.gameObject:SetActiveEx(true)
self._Effect.transform.localPosition = initPos
end
--隐藏特效
function XRestaurantChar:DoHideEffect()
if XTool.UObjIsNil(self._GameObject)
or XTool.UObjIsNil(self._Effect) then
return
end
self._Effect.gameObject:SetActiveEx(false)
end
--销毁
function XRestaurantChar:DoDestroyEffect()
if XTool.UObjIsNil(self._GameObject)
or XTool.UObjIsNil(self._Effect) then
return
end
XUiHelper.Destroy(self._Effect.gameObject)
end
--是否在工作
function XRestaurantChar:DoIsWorking()
return false
end
function XRestaurantChar:DoCheckInt(intValue)
return false
end
function XRestaurantChar:DoLoadComplete()
self:OnLoadBehaviourComplete()
end
--加载行为完成
function XRestaurantChar:OnLoadBehaviourComplete()
self._IsDoLoadBehaviour = true
end
-- 添加移动控件
function XRestaurantChar:TryAddNavMeshAgent()
if XTool.UObjIsNil(self._GameObject) then
return
end
local agent = self._GameObject:GetComponent(typeof(CS.XMoveAgent))
if not agent then
agent = CS.XNavMeshUtility.AddMoveAgent(self._GameObject)
agent.Radius = 0.35
agent.IsObstacle = true
agent.IsIgnoreCollide = false
agent.CeilSize = 0.3
agent.Speed = self._MoveSpeed
self._MoveAgent = agent
end
end
return XRestaurantChar