local EventSystem = require('Event/EventSystem') local ExpCameraSystem = {} local EventID=EventID local CameraController=CameraController local LogicUpdateManager = LogicUpdateManager local DISTANCE_IN_TARGET = 35*35 local DISTANCE_OUT_TARGET = 60*60 local FP_V2_IsDistanceSqrGreater = FP.V2.IsDistanceSqrGreater local LuaConst = LuaConst local NUMBER_HUGE_VALUE = 10000000 local private = { _allTargetEntityList = {}, --索敌相机全部的的锁定人列表 _currentTargetEntity = nil, --索敌相机当前的锁定人 _preparedTargetEntityDict = {}, --索敌相机备选的锁定人字典 _inRangeTargetEntityCount = 0, --索敌相机在选定范围内的锁定人数量 _curDriveEntity = nil, --载具相机的主体 _targetCameraLock = LuaConst.DefaultTargetCameraLock -- 是否使用索敌相机(相机模式:索敌和不索敌) } function ExpCameraSystem.OnLevelInit() if MDL.Setting.HasKey(LuaConst.SettingKeyEnum.BossViewLock) then private._targetCameraLock = MDL.Setting.GetKeyValue(LuaConst.SettingKeyEnum.BossViewLock) end private.isAddPreparedTargetOnUpdateValid = true end function ExpCameraSystem.OnActive(expEntity) local entity = expEntity.Entity local featureData = entity.components.base.CurMonsterFeature if featureData.ShowCameraFocus then private.AddCameraTarget(entity) end end -- 初始调用 function ExpCameraSystem.SetCameraTarget(expEntity, removeEntity) local entity = expEntity.Entity if removeEntity then private.RemoveCameraTarget(removeEntity) end private.AddCameraTarget(entity) end function ExpCameraSystem.GetCameraTarget() return private._currentTargetEntity end function ExpCameraSystem.SetGray(isGray) CameraController.Instance:SetGray(isGray) end function ExpCameraSystem.SetAddPreparedTargetOnUpdateValid(value, causer) private.isAddPreparedTargetOnUpdateValid = value if not value and causer == private._currentTargetEntity then private.AddPreparedTarget(private._currentTargetEntity) private.EndCurrentTarget(noCmd) EventSystem.Dispatch(EventID.Camera_TargetChange, nil) end end function ExpCameraSystem.OnUpdate(deltaTime) if not LogicUpdateManager._curEntity then return end -- 索敌相关 ↓ local mainPos = LogicUpdateManager._curEntity.components.move.LogicPos for i, entity in ipairs(private._allTargetEntityList) do local targetPos = entity.components.move.LogicPos if entity == private._currentTargetEntity then if FP_V2_IsDistanceSqrGreater(mainPos, targetPos, DISTANCE_OUT_TARGET) then private.EndCurrentTarget() end else if private._preparedTargetEntityDict[entity] then if FP_V2_IsDistanceSqrGreater(mainPos, targetPos, DISTANCE_OUT_TARGET) then private.RemovePreparedTarget(entity) end else if private.isAddPreparedTargetOnUpdateValid and not FP_V2_IsDistanceSqrGreater(mainPos, targetPos, DISTANCE_IN_TARGET) then private.AddPreparedTarget(entity) end end end end if private._targetCameraLock and not private._currentTargetEntity and private._inRangeTargetEntityCount > 0 then local selected = private.GetSelectedTarget() if selected then private.RemovePreparedTarget(selected) private.StartCurrentTarget(selected) end end -- 索敌相关 ↑ -- 相机融合移动(private.offsetYRatio-目标值,curOffsetYRatio当前值,deltaOffsetYRatio 融合速度) if private.offsetYRatio then private.curOffsetYRatio = private.curOffsetYRatio + private.deltaOffsetYRatio * deltaTime if private.curOffsetYRatio < private.offsetYRatio then CameraController.Instance:SetCamera_OffsetYRatio(private.curOffsetYRatio) else CameraController.Instance:SetCamera_OffsetYRatio(private.offsetYRatio) private.offsetYRatio = nil end end end function ExpCameraSystem.SwitchTargetCameraAim() if private._targetCameraLock then -- 如果当前处于锁定状态 -- 先从备选区选择最优先的目标进行锁定 -- 再将已锁定的目标放入备选区 local selected = private.GetSelectedTarget() if selected then if private._currentTargetEntity then private.AddPreparedTarget(private._currentTargetEntity) private.EndCurrentTarget() end private.RemovePreparedTarget(selected) private.StartCurrentTarget(selected) CTL.Tips.AddTipsMsg(string.FormatByIdsId(Const_IDS.IDS_Battle_ChangeAim, BattleDataGetter.GetEntityName(selected))) end else logging.error(LTAG.ERROR, "错误!不能在非锁定相机时切换锁定目标") end end function ExpCameraSystem.ChangeTargetPattern(noCmd, isPassive) if private._targetCameraLock then if private._currentTargetEntity then private.AddPreparedTarget(private._currentTargetEntity) private.EndCurrentTarget(noCmd) EventSystem.Dispatch(EventID.Camera_TargetChange, nil) end else if not private._currentTargetEntity then local selected = private.GetSelectedTarget() if selected then private.RemovePreparedTarget(selected) private.StartCurrentTarget(selected) end end private.passiveCancelCameraLockEntity = nil end private._targetCameraLock = not private._targetCameraLock if not isPassive then MDL.Setting.SetKeyValue(LuaConst.SettingKeyEnum.BossViewLock, private._targetCameraLock) end EventSystem.Dispatch(EventID.Camera_TargetChangePattern, private._targetCameraLock) end function ExpCameraSystem.OnDead(expEntity) local entity = expEntity.Entity private.RemoveCameraTarget(entity) -- ↓↓↓ 挪到ExpLevelFunction的OnPlayerAllHeroDead里去了 --相机变灰 -- if entity._logicInitData.IsPlayerSelf and LevelPlayerManager.IsAllDead(entity) then -- CameraController.Instance:SetGray(true) -- --TODO : 【lsh】四测临时逻辑,现在没时间改关卡事件底层,先做个临时的写死处理,后面会改掉 -- if LevelManager.IsSyncTeamDifficult() then -- EventSystem.Dispatch(EventID.UI_MainShowDialogue, "Tip_MultHardPlay_0001_01") -- end -- end --↑↑↑↑↑ end function ExpCameraSystem.OnDisActive(expEntity) local entity = expEntity.Entity private.RemoveCameraTarget(entity) end function ExpCameraSystem.OnRevive(expEntity) if expEntity.Entity._logicInitData.IsPlayerSelf then CameraController.Instance:ReactiveCamera() CameraController.Instance:SetGray(false) end end function ExpCameraSystem.OnConvey(expEntity, angle) if expEntity.Entity == LogicUpdateManager._curEntity then if private._currentTargetEntity then local mainPos = LogicUpdateManager._curEntity.components.move.LogicPos local targetPos = private._currentTargetEntity.components.move.LogicPos if FP_V2_IsDistanceSqrGreater(mainPos, targetPos, DISTANCE_OUT_TARGET) then private.EndCurrentTarget() end end CameraController.Instance:ReactiveCamera(angle or 0) end end function ExpCameraSystem.OnChangeModel(expEntity) local entity = expEntity.Entity if entity == LogicUpdateManager._curEntity then CameraController.Instance:RefreshTarget() elseif private._currentTargetEntity == entity then local modelData = entity.components.base.CurModelData local cameraID = string.isNilOrEmpty(modelData.TargetCamera) and 0 or UTL.String.GetIdByString(modelData.TargetCamera) CameraController.Instance:RefreshTargetSystem(entity.ExpEntity:GetRenderEntity(), cameraID, LevelManager.IsSolo()) AuxUtil.RefreshCameraLockTarget(entity.ExpEntity:GetRenderEntity(), LuaConst.HumanEquipSlot.node_chest) end end function ExpCameraSystem.OnAttackEnter(expEntity) local entity = expEntity.Entity if entity == LogicUpdateManager._curEntity then CameraController.Instance:StartSkillCamera(true) end end function ExpCameraSystem.OnAttackQuit(expEntity) local entity = expEntity.Entity if entity == LogicUpdateManager._curEntity then CameraController.Instance:StartSkillCamera(false) end end function ExpCameraSystem.OnRideHorse(expEntity, horseModelData) local entity = expEntity.Entity if entity == LogicUpdateManager._curEntity then if horseModelData.IsSpecialCamera and GameAppInfo.IsVersionGreaterThan15000() then if CameraController.Instance:GetViewMode() == 0 then CameraController.Instance:ChangeFreePattern(false) end CameraController.Instance:SetCamera_ScaleRate(1, true) if horseModelData.SpecialCameraY > 0 then private.offsetYRatio = horseModelData.SpecialCameraY private.curOffsetYRatio = 0.5 private.deltaOffsetYRatio = (private.offsetYRatio - private.curOffsetYRatio) * 2 -- 融合速度(1/2秒) end end end end function ExpCameraSystem.OnOffHorse(expEntity, horseModelData) local entity = expEntity.Entity if entity == LogicUpdateManager._curEntity then if horseModelData.IsSpecialCamera and GameAppInfo.IsVersionGreaterThan15000() then CameraController.Instance:SetCamera_ScaleRate(0.5) if horseModelData.SpecialCameraY > 0 then CameraController.Instance:SetCamera_OffsetYRatio(0.5) end private.offsetYRatio = nil end end end function ExpCameraSystem.OnChangeHorse(expEntity, horseModelData) local entity = expEntity.Entity if entity == LogicUpdateManager._curEntity then if horseModelData.IsSpecialCamera and GameAppInfo.IsVersionGreaterThan15000() then if CameraController.Instance:GetViewMode() == 0 then CameraController.Instance:ChangeFreePattern(false) end CameraController.Instance:SetCamera_ScaleRate(1, true) if horseModelData.SpecialCameraY > 0 then CameraController.Instance:SetCamera_OffsetYRatio(horseModelData.SpecialCameraY) end private.offsetYRatio = nil end end end function ExpCameraSystem.OnDriveEntity(expEntity, isFreeCamera) local entity = expEntity.Entity local driveEntity = entity.components.drive.DriveEntity if driveEntity then private._curDriveEntity = driveEntity if isFreeCamera then AuxUtil.SetCurRenderEntity(driveEntity.ExpEntity:GetRenderEntity()) local driveData = driveEntity.components.drive:GetDriveData() if driveData and driveData.CameraID > 0 then CameraController.Instance:StartCarrierSystem(driveEntity.ExpEntity:GetRenderEntity(), driveData.CameraID) end else local driveData = driveEntity.components.drive:GetDriveData() local pos = driveData.CameraPos local euler = driveData.CameraRotate CameraController.Instance:StartCarrierSystem(driveEntity.ExpEntity:GetRenderEntity(),pos[1],pos[2],pos[3],euler[1],euler[2],euler[3]) end CTL.Sound.SetCameraListener(true) end end function ExpCameraSystem.OnOffDriveEntity(expEntity,carEntity ,isFreeCamera) if private._curDriveEntity == carEntity then if isFreeCamera then AuxUtil.SetCurRenderEntity(expEntity:GetRenderEntity()) local driveData = carEntity.components.drive:GetDriveData() if driveData and driveData.CameraID > 0 then CameraController.Instance:EndCarrierSystem() end else CameraController.Instance:EndCarrierSystem() end CTL.Sound.SetCameraListener(false) private._curDriveEntity = nil end end -- Editor Function Use for Change Const Param function ExpCameraSystem.SetDistanceInRange(value) DISTANCE_IN_TARGET = value * value end function ExpCameraSystem.SetDistanceOutRange(value) DISTANCE_OUT_TARGET = value * value end function ExpCameraSystem.Clear() private._currentTargetEntity = nil private._inRangeTargetEntityCount = 0 table.clearArray(private._allTargetEntityList) table.clear(private._preparedTargetEntityDict) private._curDriveEntity = nil end function private.GetSelectedTarget() local compareAngle = NUMBER_HUGE_VALUE local compareSqrDistance = NUMBER_HUGE_VALUE local selected = nil for entity, inRange in pairs(private._preparedTargetEntityDict) do if LevelManager.CurLevelFunc:CanSeeEntity(LogicUpdateManager._curEntity, entity) then local renderEntity = entity.ExpEntity:GetRenderEntity() local angle = AuxUtil.GetHorizontalAngleToCamera(renderEntity) if angle < compareAngle then compareAngle = angle selected = entity elseif angle == compareAngle then local sqrDistance = AuxUtil.GetHorizontalSqrDistanceToCamera(renderEntity) if sqrDistance < compareSqrDistance then compareSqrDistance = sqrDistance selected = entity end end end end return selected end function private.AddCameraTarget(entity) table.insert(private._allTargetEntityList, entity) end function private.RemoveCameraTarget(entity) if private._currentTargetEntity == entity then private.EndCurrentTarget() end private.RemovePreparedTarget(entity) table.removebyvalue(private._allTargetEntityList,entity) end function private.AddPreparedTarget(entity) if not private._preparedTargetEntityDict[entity] then private._preparedTargetEntityDict[entity] = true private.AddInRangeCount() end end function private.RemovePreparedTarget(entity) if private._preparedTargetEntityDict[entity] then private._preparedTargetEntityDict[entity] = nil private.SubInRangeCount() end end function private.StartCurrentTarget(entity) local modelData = entity.components.base.CurModelData local cameraID = string.isNilOrEmpty(modelData.TargetCamera) and 0 or UTL.String.GetIdByString(modelData.TargetCamera) CameraController.Instance:StartTargetSystem(entity.ExpEntity:GetRenderEntity(), cameraID, LevelManager.IsSolo()) private.AddInRangeCount() private._currentTargetEntity = entity AuxUtil.ShowCameraLockUI(entity.ExpEntity:GetRenderEntity(), LuaConst.HumanEquipSlot.node_chest) EventSystem.Dispatch(EventID.Camera_TargetChange, entity.EntityID) LuaInputManager.CameraLockTarget(entity.EntityID) end function private.EndCurrentTarget(noCmd) CameraController.Instance:EndTargetSystem(false) AuxUtil.StopCameraLockUI(false) private.SubInRangeCount() private._currentTargetEntity = nil if not noCmd then LuaInputManager.CameraLockTarget(0) end end function private.AddInRangeCount() private._inRangeTargetEntityCount = private._inRangeTargetEntityCount + 1 if private._inRangeTargetEntityCount == 1 then EventSystem.Dispatch(EventID.Camera_TargetStart) EventSystem.Dispatch(EventID.Camera_TargetChangePattern, private._targetCameraLock) end if private._inRangeTargetEntityCount == 2 then EventSystem.Dispatch(EventID.Camera_TargetPrepareEntity, true) end end function private.SubInRangeCount() private._inRangeTargetEntityCount = private._inRangeTargetEntityCount - 1 if private._inRangeTargetEntityCount == 0 then EventSystem.Dispatch(EventID.Camera_TargetEnd) end if private._inRangeTargetEntityCount == 1 then EventSystem.Dispatch(EventID.Camera_TargetPrepareEntity, false) end end -- 逃脱了相机锁定(entity 是取消相机索敌的始作俑者 ,并不是逃跑者) function ExpCameraSystem.OnEscapeCameraLock(entity, isDefaultCurLockEntity) private.passiveCancelCameraLockEntity = entity -- 上次是否是被动解除索敌相机 if entity == nil and isDefaultCurLockEntity then private.passiveCancelCameraLockEntity = private._currentTargetEntity end private._targetCameraLock = true ExpCameraSystem.ChangeTargetPattern(true, true) end -- 恢复到索敌 function ExpCameraSystem.OnRecoverCameraLock(entity, isPreparedTargetOnUpdateValid) if private.passiveCancelCameraLockEntity == entity then -- 被动结束锁定的话就需要恢复一下 private._targetCameraLock = true private.passiveCancelCameraLockEntity = nil end if isPreparedTargetOnUpdateValid then ExpCameraSystem.SetAddPreparedTargetOnUpdateValid(isPreparedTargetOnUpdateValid) end end -- 根据之前是否锁敌而恢复到 function ExpCameraSystem.TryRecoverBeforeCameraLock() if private.passiveCancelCameraLockEntity then private._targetCameraLock = true private.passiveCancelCameraLockEntity = nil end end return ExpCameraSystem