local Base = require("Battle/Logic/Level/LevelFunction/LevelFunction") local RogueLikeLevelFunction = class("RogueLikeLevelFunction",Base) local private = {} local SkillMissileSystem = require "Battle/Logic/Entity/System/SkillMissileSystem" local EventSystem = require('Event/EventSystem') local FP_V2_DistanceSqr = FP.V2.DistanceSqr local SqrMagnitude = FP.V2.SqrMagnitude local tonumberV1 = FP.tonumberV1 local tonumberV2 = FP.tonumberV2 local temp_v1 = FP.newV1(0) local temp_v2 = FP.newV2(0,0) local tempPos_v2 = FP.newV2(0,0) local temp_score = FP.newV1(0) local Const_FPZero = FP.Const.Zero local Const_SearchTargetSqr = 225 -- 搜索目标的距离平方 local Const_PickUpMaxNum = 4000--DataSheetManager.ConstData:GetDataByID("Rogue_SkillMaxGrade").IntValue -- 经验的最大数量 local Const_SkillMaxID = 900 -- 需要记录等级的技能最大id。 大于此值则不记录到升级列表中 local HeroBodyBound = 1 --武将的身体半径 local Const_PillFlyToMeSped = DataSheetManager.ConstData:GetDataByID("Rogue_PillFlyToMeSped").IntValue -- 经验豆飞向我的速度 1m/s local Const_PlayerMaxGrade = DataSheetManager.ConstData:GetDataByID("Rogue_PlayerMaxGrade").IntValue -- 玩家最大等级 local Const_SkillMaxGrade = DataSheetManager.ConstData:GetDataByID("Rogue_SkillMaxGrade").IntValue -- 技能能达到的最大等级 local Const_MaxNode = {998, 999} local Const_LevelPlayerMaxSkillLimit = 900 -- 玩家满级后,才能选择的技能最小Id值 local Const_SkillCDReduceFactor = DataSheetManager.ConstData:GetDataByID("Rogue_SkillCDReduceFactor").IntValue -- 让玩家闪避CD变长比例(-1 表示加一倍时长) -- 怪物出生半径 单位:米 local BornScreenRadius = DataSheetManager.ConstData:GetDataByID("Rogue_BornScreenRadius").IntValue local EliteBornScreenRadius = DataSheetManager.ConstData:GetDataByID("Rogue_EliteBornScreenRadius").IntValue local Const_MatrixGap = DataSheetManager.ConstData:GetDataByID("Rogue_MatrixGap").IntValue -- 矩阵兵的间隔 local GroupDeadFrame = DataSheetManager.ConstData:GetDataByID("Rogue_GroupDeadFrame").IntValue -- 阵列怪物的存活时长(单位:帧) local RoutFrame = 60 -- 溃散时间 3秒 local MonsterBornRuleType = { HoldCount = 1, -- 总数保持一定的量 OnceGroup = 2, -- 一次出生一组怪(不会在玩家跟前停止) OnceBoss = 3, -- 一次刷个怪(只限于boss) } function RogueLikeLevelFunction:InitLevel() self.leftReviveNum = 0 -- 剩余复活次数 self.reselectNum = 0 -- 重新随机技能的次数 self.reselectTotalNum = 0 -- 重新随机技能的总次数(此关卡中,总共添加的次数) self.rogueScore = FP.newV1(0) -- 积分 self.rogueScoreRate = FP.newV1(1) -- 积分增加时的倍率 self.curGradeExp = FP.newV1(0) -- 当前级别的经验值(经验值满后,升级) self.gradeExpRate = FP.newV1(1) -- 经验增加时的倍率 self.curGrade = 1 -- 当前的级别 self.curGradeExpMax = FP.newV1( DataSheetManager.RogueLikeGradeData:GetDataByID(self.curGrade + 1).exptonextlv ) -- 当前级别的最大经验值 self.bornMonsterRuleList = {} -- 出生的怪物规则具体的数据 self.bornMonsterRuleDic = {} -- 出生的怪物规则记录的实时数据 self.skillRandomPool = {} --技能随机池 {[1]=nodeId,[2]=nodeWeight} self.preSkillRandomPool = {} -- 当技能节点满足等级要求后,当时未满足其他条件,则需要等待满足条件后才能真正的进入随机池 self.randomResult = {} -- 随机出来的技能加点 self.skillGradeList = {} -- 技能类别对应的等级, {[1] = SkillID ,[2] = Grade} 【不用字典是为了记录添加的时序】 self.skillSelectList = {} -- 玩家选择技能节点的记录 self.nearSearchList = {} -- Const_SearchTargetSqr范围内的20个的怪物。--目的是为了优化寻敌用 LevelPlayerManager.SetCanSwitchHeroByCommand(false) --禁止手动切将(为了保险加上了这句代码) Base.InitLevel(self) self.curPickUpNum = 0 -- 当前可拾取物的数量 self.nextShowTipsFrame = 0 -- 下次提示可拾取物的数量超标的时间 self.killMonsterNum = 0 -- 杀死的怪物数量 self.MonsterBornRuleFunctionDic = {} -- 不同出生规则对应的方法 self:InitMonsterBornRuleFunctionDic() self.dontIgnoreEnemy = true --不使用忽略敌人机制,节省性能 self.isRouting = false -- 正在让杂兵溃散 self.normalMonsterDeadDistanceSqr = DataSheetManager.ConstData:GetDataByID("Rogue_NormalMonsterDeadDistanceSqr").IntValue -- 普通怪物死亡的距离 self.pickUpDistance = FP.newV1(0):Reset(DataSheetManager.ConstData:GetDataByID("Rogue_pickUpDistance").FloatValue) -- 拾取物品的距离( 可以被升级改变 ) self.pickUpDistanceSqr = tonumberV1(self.pickUpDistance * self.pickUpDistance) end --记录当前玩家的Entity,为了性能好一些 function RogueLikeLevelFunction:BeginLevel() Base.BeginLevel(self) self.curEntity = LevelPlayerManager.GetPlayerActiveEntity(LuaConst.STANDALONE_PLAYER_PlayID) -- 中途不会切将所以不用担心此值会变 self:InitMonsterBornRules() self:AddFirstNodeToPlayer() SystemManager.ChangeEntityName(self.curEntity, "")--让玩家头顶名字不显示 SystemManager.BanKeyPositions(self.curEntity,self.curEntity, {LuaConst.ESkillKeyPosition.Slash, LuaConst.ESkillKeyPosition.Skill1, LuaConst.ESkillKeyPosition.Skill2, LuaConst.ESkillKeyPosition.Skill3, LuaConst.ESkillKeyPosition.MusouNormal, LuaConst.ESkillKeyPosition.Adjutant,})--禁用除了闪避外的其他技能 --修改一下技能CD属性,取巧:让闪避CD变长 self.curEntity:SetAttrBaseValue(LuaConst.AttrType.cdrdc, Const_SkillCDReduceFactor) self:ResetSomeMethodForOpt() end --region 重定向 --为了优化而做的重定向 function RogueLikeLevelFunction:ResetSomeMethodForOpt() logging.crit(LTAG.CRIT, "[肉鸽]:性能优化 :重定向方法! 挤压+分阵营") --重定向挤压功能 LuaShoveManager.SetEntityShoveNil() -- 重定向camp CampManager.SetOnEntityCreatedNotSort() end -- 此方法是个保底方法,防止出现异常导致不能恢复 function RogueLikeLevelFunction:StopLevel() self:RecoverSomeMethodForOpt("stopLevel") self:RecoverSomeMethodForPause() Base.StopLevel(self) end --为了优化而做的重定向 function RogueLikeLevelFunction:RecoverSomeMethodForOpt(type) --重定向挤压功能-撤回 logging.crit(LTAG.CRIT, "[肉鸽]:性能优化重定向方法 - 撤回! type = ", type) LuaShoveManager.SetEntityShoveNotNil() CampManager.SetOnEntityCreatedSort() end -- 为了暂停逻辑做的重定向 function RogueLikeLevelFunction:ResetSomeMethodForPause() logging.crit(LTAG.CRIT, "[肉鸽]:关卡暂停-重定向更新方法为nil") MissileManager.SetLogicUpdateNil() SystemManager.SetLogicUpdateNil() SkillMissileSystem.SetLogicUpdateNil() end --为了优化而做的重定向 function RogueLikeLevelFunction:RecoverSomeMethodForPause() logging.crit(LTAG.CRIT, "[肉鸽]:关卡暂停-重定向更新方法 恢复!") --重定向挤压功能-撤回 MissileManager.SetLogicUpdateNotNil() SystemManager.SetLogicUpdateNotNil() SkillMissileSystem.SetLogicUpdateNotNil() end -- --endregion 重定向 --让玩家不要挤压其他单位 function RogueLikeLevelFunction:OnHeroBorn(entity) SystemManager.AddBuff(entity, LuaConst.SpecialBuffs.IgnoreShoveOthers, entity) end -- 出生后且active后的处理 --entity active 后 function RogueLikeLevelFunction:OnEntityActive(entity) if entity.isMinion and not entity.isPickupItem then -- 杂兵禁用AI SystemManager.OnLockAI(entity, true) SystemManager.SetNextState(LuaConst.StateType.Move, entity, 0) -- 掉落的金币monsterId local success, dropPillData = DataSheetManager.RogueMonsterBornPill:TryGetDataByMonsterID(entity._logicInitData.CharacterID) if success then entity.rogueDropMonsterPillId = dropPillData.DropPill end end if entity.isPickupItem then entity.needBatchPosDir = false -- 刚出生暂不更新位置(当玩家走进后,才开始移动) self.curPickUpNum = self.curPickUpNum + 1 entity.rogueExp = DataSheetManager.RogueExpPill:GetDataByMonsterID(entity._logicInitData.CharacterID).ExpValue if self.curPickUpNum > Const_PickUpMaxNum and LogicUpdateManager._clientHandleFrame > self.nextShowTipsFrame then self.nextShowTipsFrame = LogicUpdateManager._clientHandleFrame + 200 ExpLevelManager.ShowTips(entity, "IDS_LevelTips_ExpMax", true) -- 有 10秒CD end end end -- 每帧的更新 function RogueLikeLevelFunction:OnUpdate() if self.isLogicPause then -- 关卡暂停了,在选择技能中 return end table.clearArray(self.nearSearchList) local nearSearchListNum = 0 local mainEntityPos = self.curEntity:GetLogicPos() self.mainEntityPos = mainEntityPos -- 为了性能添加此缓存 -- 不用base的OnUpdate self:OnUpdateMonsterBornRule() -- 根据怪物的出生规则tick -- 检查是否溃散时间到了,删除所有杂兵 self:RoutMonsterUpdate() if self.lastMainEntityPos == nil then self.lastMainEntityPos = FP.newV2(0,0) end if self.lastMainEntityPos.x[1] ~= mainEntityPos.x[1] or self.lastMainEntityPos.z[1] ~= mainEntityPos.z[1] then self.mainEntityMoved = true self.lastMainEntityPos:Reset(mainEntityPos) else self.mainEntityMoved = false end -- 碰撞检测 和 时间检测 local index = 1 for i = 1, #LogicUpdateManager.EntityList_Normal do local entity = LogicUpdateManager.EntityList_Normal[index] -- 检查是否可以拾取经验 if entity.isPickupItem then -- 经验豆的处理 if self.curPickUpNum > Const_PickUpMaxNum then SystemManager.DeadQuit(entity) -- 死亡 index = index - 1 else local doSub = false -- 是否计算过pos-mainpos了 if self.mainEntityMoved or entity.rogueToMainEntityDisSqr == nil then local pos = entity:GetLogicPos() temp_v2:Reset(mainEntityPos):Sub(pos) -- 未归一化的方向向量 SqrMagnitude(temp_v2, temp_v1) --temp_v1 距离的平方 entity.rogueToMainEntityDisSqr = tonumberV1(temp_v1) doSub = true end local disSqr = entity.rogueToMainEntityDisSqr if disSqr <= HeroBodyBound then self:AddRogueLikeExp(entity.rogueExp) -- 添加经验 SystemManager.DeadQuit(entity) -- 死亡 index = index - 1 elseif disSqr <= self.pickUpDistanceSqr then local moveComp = entity.components.move if doSub == false then temp_v2:Reset(mainEntityPos):Sub(moveComp.LogicPos) -- 未归一化的方向向量 SqrMagnitude(temp_v2, temp_v1) --temp_v1 距离的平方 entity.rogueToMainEntityDisSqr = tonumberV1(temp_v1) end temp_v2:Normalize() temp_v2:Mul(Const_PillFlyToMeSped):Add(moveComp.LogicPos)-- 速度 2m/s写死了 moveComp:SetLogicPos(temp_v2, false, true) if not entity.needBatchPosDir then entity.needBatchPosDir = true end end end elseif entity.isMinion then -- 杂兵的处理 local pos = entity:GetLogicPos() temp_v2:Reset(mainEntityPos):Sub(pos) -- 未归一化的方向向量 SqrMagnitude(temp_v2, temp_v1) --temp_v1 距离的平方 local disSqr = tonumberV1(temp_v1) if nearSearchListNum < 20 and disSqr <= Const_SearchTargetSqr then table.insert(self.nearSearchList, entity) nearSearchListNum= nearSearchListNum + 1 end if entity.isRogueLockMatrixMonster then -- (矩阵兵,不受距离控制死亡,其出生后朝向不能改变) elseif disSqr >= self.normalMonsterDeadDistanceSqr then -- 检查怪物是否因距离太远而要死亡 SystemManager.DeadQuit(entity) -- 死亡 index = index - 1 elseif disSqr >= HeroBodyBound then -- 只要没有挨着主将则都要移动 local moveComp = entity.components.move if self.isRouting then -- 溃散中 temp_v2:Negative() end moveComp:SetWantDir(temp_v2) moveComp:SetWantRotateDir(moveComp.WantMoveDir) else local moveComp = entity.components.move moveComp:SetWantDir() end if entity.rogueLifeFrame and entity.rogueLifeFrame > 0 then entity.rogueLifeFrame = entity.rogueLifeFrame - 1 if entity.rogueLifeFrame == 0 then SystemManager.DeadQuit(entity) -- 死亡 index = index - 1 end end elseif entity.isBoss or entity.isElite then table.insert(self.nearSearchList, entity) -- boss一定进入选择目标列表,且不影响小兵数量 end index = index + 1 end end -- 怪物死亡计算积分 function RogueLikeLevelFunction:MonsterDeadCountStatisticAdd(monsterID, entity) Base.MonsterDeadCountStatisticAdd(self, monsterID, entity) local killer = entity.components.record.KillerEntity if killer and killer.isHero then self.killMonsterNum = self.killMonsterNum + 1 local success, scoreData = DataSheetManager.RogueMonsterPointData:TryGetDataByID(monsterID) if success then temp_score:Reset(self.rogueScoreRate):Mul(scoreData.MonsterPoint) self.rogueScore:Add(temp_score) EventSystem.Dispatch(EventID.RogueLike_ScoreChange, FP.tonumberV1(self.rogueScore)) else --logging.error(LTAG.ERROR, "[战斗策划] 肉鸽没配置积分:怪物id = ", monsterID) end if entity.rogueRuleId then -- entity是由规则生成的怪物 local ruleInfo = self.bornMonsterRuleDic[entity.rogueRuleId] if ruleInfo then ruleInfo.curMonsterCount = ruleInfo.curMonsterCount - 1 end end -- 尝试出生经验怪物 if not entity.isPickupItem and entity.rogueDropMonsterPillId ~= nil then local posX, posZ = tonumberV2(entity:GetLogicPos()) SystemManager.CreateMonster(entity.rogueDropMonsterPillId, posX, posZ, 0, 1) end end if not entity.isBoss then entity.components.record.IsUnload = true -- 需要立刻死亡,不要有倒地动画 end if entity.isPickupItem then self.curPickUpNum = self.curPickUpNum - 1 end end -- 获取经验值,达到最大经验值后升级。 local temp_exp = FP.newV1(0) function RogueLikeLevelFunction:AddRogueLikeExp(exp) temp_exp:Reset(self.gradeExpRate):Mul(exp) self.curGradeExp:Add(temp_exp) if self.curGradeExp >= self.curGradeExpMax then --尝试获取是否有下一级数据,没有的话则认为已经满级 local success, nextData = DataSheetManager.RogueLikeGradeData:TryGetDataByID(self.curGrade + 1) if success then -- 未到最大等级 self.curGrade = self.curGrade + 1 local hasNext, toGradeData = DataSheetManager.RogueLikeGradeData:TryGetDataByID(self.curGrade + 1) if hasNext then self.curGradeExpMax:Reset(toGradeData.exptonextlv) end end self.curGradeExp:Reset(0) --self.curGradeExp - self.curGradeExpMax self:GetRandomSkillNode() -- 结果存在 self.randomResult 中 self:PauseLogic(true) -- 关卡暂停 --如果是是回放,则不需要打开界面 if not LevelManager.IsReplayBattle() then EventSystem.Dispatch(EventID.RogueLike_GradeChange, self.randomResult) -- 告知界面可现实出技能选项了 end end EventSystem.Dispatch(EventID.RogueLike_ExpChange, self.curGrade, FP.tonumberV1(self.curGradeExp), FP.tonumberV1(self.curGradeExpMax)) end -- 收到点击重新随机技能按钮 function RogueLikeLevelFunction:ReRandomSkillList() if self.reselectNum <= 0 then logging.error(LTAG.ERROR, "【gws】:肉鸽玩法,已经没有重新随机次数了!") return end self.reselectNum = self.reselectNum - 1 self:GetRandomSkillNode() -- 结果存在 self.randomResult 中 if not LevelManager.IsReplayBattle() then EventSystem.Dispatch(EventID.RogueLike_GradeChange, self.randomResult) -- 告知界面可现实出技能选项了 end end -- 收到点击选择的升级技能cmd function RogueLikeLevelFunction:RogueSelectUpgradeSkill(selectIndex) local skillNodeId = self.randomResult[selectIndex] local skillNodeData = DataSheetManager.RogueSkillNodeData:GetDataByNodeID(skillNodeId) -- 添加效果 SystemManager.AddBuff(self.curEntity, skillNodeData.BuffID, self.curEntity) --处理技能升级 local curGrade = 1 if skillNodeData.BelongToSkill < Const_SkillMaxID then local find = false for _, info in ipairs(self.skillGradeList) do if info[1] == skillNodeData.BelongToSkill then info[2] = info[2] + 1 find = true curGrade = info[2] break end end if not find then table.insert(self.skillGradeList, {skillNodeData.BelongToSkill, 1}) end end table.insert(self.skillSelectList, skillNodeId) -- 处理随机池 for i = #self.skillRandomPool, 1, -1 do if self.skillRandomPool[i][1] == skillNodeId then table.remove(self.skillRandomPool, i) break end end local nodeData = DataSheetManager.RogueSkillNodeData:GetDataByNodeID(skillNodeId) if nodeData.NextNode > 0 then self:SkillNodeToRandomPool(nodeData.NextNode) end if curGrade >= Const_SkillMaxGrade then self:SkillUptoMaxRefreshRandomPool(skillNodeData.BelongToSkill) -- 最高级后则移除 else self:SkillLevelUpRefreshRandomPool(skillNodeData.BelongToSkill, curGrade) -- 检测本技能是否有新功能分支进入随机池 end self:PauseLogic(false) -- 关卡继续 EventSystem.Dispatch(EventID.RogueLike_SkillGradeUp, false, skillNodeData.BelongToSkill, curGrade) -- 通知界面,哪个技能升级到了多少级 end -- 关卡暂停或者继续 function RogueLikeLevelFunction:PauseLogic(isPause) self.isLogicPause = isPause LogicUpdateManager.PauseEntity(isPause) -- 关卡暂停 -- 关卡时间暂停 if isPause then LevelItemManager.Global:FreezeLevelTime() self:ResetSomeMethodForPause() else LevelItemManager.Global:CancelFreezeLevelTime() self:RecoverSomeMethodForPause() end EventSystem.Dispatch(EventID.Level_Pause,isPause) end --region 关卡结束 --玩家死亡 function RogueLikeLevelFunction:OnPlayerOneHeroDead(entity) if self.leftReviveNum > 0 then self.leftReviveNum = self.leftReviveNum - 1 SystemManager.OnRevive(entity) SystemManager.SetNextState(LuaConst.StateType.Idle, entity) else LevelItemManager.Global:DoAction(LuaConst.LevelActionType.Global_LevelFail) end end function RogueLikeLevelFunction:OnLevelSucceed(withShow) local showPose = false local mainEntity = self.curEntity if mainEntity and mainEntity:IsAlive() then showPose = true end Base.OnLevelSucceed(self, showPose) end function RogueLikeLevelFunction:QuitRoom(entity) --不调用base LevelItemManager.Global:DoAction(LuaConst.LevelActionType.Global_LevelFail) end --endregion 关卡结束 --region 怪物行为特殊处理 function RogueLikeLevelFunction:RoutMonsterUpdate() if self.isRouting then if LogicUpdateManager._clientHandleFrame >= self.endRoutFrame then self:RoutMonster(false) -- 小兵溃散完毕,恢复挤压 self:RecoverSomeMethodForOpt("Rout") end end end --让小兵怪物溃散 boolVal true-开始,false-停止 function RogueLikeLevelFunction:RoutMonster(boolVal) self.isRouting = boolVal self.endRoutFrame = boolVal and LogicUpdateManager._clientHandleFrame + RoutFrame or nil -- 记录结束帧数 if not boolVal then local count = #LogicUpdateManager.EntityList_Normal for i = count,1, -1 do local entity = LogicUpdateManager.EntityList_Normal[i] if entity.isMinion and not entity.isPickupItem then -- 杂兵的处理 SystemManager.OnDead(entity) end end end end --endregion 怪物行为特殊处理 --region 刷怪规则 function RogueLikeLevelFunction:InitMonsterBornRules() --统计本关卡的所有的出生怪物规则 local levelBornRuleList = DataSheetManager.RogueLevelRule:GetDataByLevelID(LevelManager.GetCurLevelID()).RuleList for _,ruleId in ipairs(levelBornRuleList) do local ruleData = DataSheetManager.RogueMonsterBornRule:GetDataByRuleID(ruleId) table.insert(self.bornMonsterRuleList, {ruleId = ruleId, ruleData = ruleData, isActive = false, startTime = ruleData.BeginTime, endTime = ruleData.EndTime } )-- 过了规则时间后,就从中移除了 self.bornMonsterRuleDic[ruleId] = {curMonsterCount = 0} -- 过了规则时间后,就从Dic中移除了 end end function RogueLikeLevelFunction:OnUpdateMonsterBornRule() local curLevelPassTime = FP.tonumberV1(LevelItemManager.Global:GetPassTime()) local count = #self.bornMonsterRuleList -- 检测是否需要加怪(根据时间规则和数量限制进行加怪) for i = count, 1, -1 do local ruleInfo = self.bornMonsterRuleList[i] if ruleInfo.isActive then if curLevelPassTime < ruleInfo.endTime then -- 尝试补充怪物 self:TryAddMonster(ruleInfo.ruleId, ruleInfo.ruleData) if ruleInfo.ruleData.RuleType == MonsterBornRuleType.OnceBoss or ruleInfo.ruleData.RuleType == MonsterBornRuleType.OnceGroup then table.remove(self.bornMonsterRuleList, i) self.bornMonsterRuleDic[ruleInfo.ruleId] = nil end else table.remove(self.bornMonsterRuleList, i) self.bornMonsterRuleDic[ruleInfo.ruleId] = nil end else if curLevelPassTime >= ruleInfo.startTime then ruleInfo.isActive = true end end end end -- 根据同步规则生成怪物 function RogueLikeLevelFunction:TryAddMonster(ruleId, ruleData) local ruleInfo = self.bornMonsterRuleDic[ruleId] self.MonsterBornRuleFunctionDic[ruleData.RuleType](self, ruleId, ruleData, ruleInfo) end -- 在玩家周围固定半径的圆上随机生成一个出生点 function RogueLikeLevelFunction:GetBornPosOnCircle(radius, notIgnoreTerrain) local theta = LogicRandom.GetRangeValue(nil, FP.Const.Zero, FP.Const.PI2 ,202403011) --极坐标θ local sin = FP.Math.Sin(theta) local cos = FP.Math.Cos(theta) temp_v2.x:Reset(radius):Mul(cos) temp_v2.z:Reset(radius):Mul(sin) temp_v2:Add(self.mainEntityPos) if notIgnoreTerrain then -- 为了提高效率,只找四个点,找不到就不找了,就让其从行走面外出生 if not LuaShoveManager.CanBornIn(temp_v2) then temp_v2:Sub(self.mainEntityPos) temp_v2:Negative() temp_v2:Add(self.mainEntityPos)-----------对称点 if not LuaShoveManager.CanBornIn(temp_v2) then temp_v2:Sub(self.mainEntityPos) temp_v2:Reset(-tonumberV1(temp_v2.z), tonumberV1(temp_v2.x)) ---- 旋转90点 temp_v2:Add(self.mainEntityPos) if not LuaShoveManager.CanBornIn(temp_v2) then temp_v2:Sub(self.mainEntityPos) temp_v2:Negative() temp_v2:Add(self.mainEntityPos)-----------旋转90点后的对称点 end end end end return tonumberV1(temp_v2.x), tonumberV1(temp_v2.z) end --- 不同出生规则的方法 -- 总数保持一定的量 function RogueLikeLevelFunction:BornMonster_HoldCount(ruleId, ruleData, ruleInfo) local curMonsterCount = ruleInfo.curMonsterCount local needAddCount = ruleData.MonsterNumber - curMonsterCount if needAddCount > 0 then needAddCount = needAddCount > 1 and 1 or needAddCount -- 最多一帧出生1个 local posX, posZ for i = 1, needAddCount do posX, posZ = self:GetBornPosOnCircle(BornScreenRadius, true) local newEntity = SystemManager.CreateMonster(ruleData.MonsterID, posX, posZ, 0, 1, nil, true) newEntity.rogueRuleId = ruleId -- 统计entity属于哪个规则,方便死亡时curMonsterCount值减少 end ruleInfo.curMonsterCount = curMonsterCount + needAddCount end end -- 一次出生一组怪(暂时订为正方形方阵) function RogueLikeLevelFunction:BornMonster_OnceGroup(ruleId, ruleData) local needAddCount = ruleData.MonsterNumber local posX, posZ = self:GetBornPosOnCircle(BornScreenRadius) -- 矩阵中离玩家较近的点 temp_v2:Reset(posX, posZ):Sub(self.mainEntityPos) -- 判断象限 local moveDir = FP.V2.Normalized(temp_v2):Negative() local deltaX = temp_v2.x > Const_FPZero and Const_MatrixGap or -Const_MatrixGap local deltaZ = temp_v2.z > Const_FPZero and Const_MatrixGap or -Const_MatrixGap local col = math.ceil(math.sqrt(needAddCount)) local row = math.ceil(needAddCount / col) local bornX,bornZ tempPos_v2:Reset(posX, posZ) local addIndex = 0 for c = 0, col-1 do for r = 0, row-1 do temp_v2:Reset(c * deltaX, r * deltaZ) -- 偏移值 temp_v2:Add(tempPos_v2) bornX,bornZ = tonumberV2(temp_v2) local newEntity = SystemManager.CreateMonster(ruleData.MonsterID, bornX, bornZ, 0, 1, nil, true) newEntity.rogueRuleId = ruleId -- 统计entity属于哪个规则,方便死亡时curMonsterCount值减少 newEntity.isRogueLockMatrixMonster = true -- 标记是否是矩阵兵 (出生后朝向不能改变) newEntity.rogueLifeFrame = GroupDeadFrame -- 计时死亡用 ,死亡倒计时-帧。 local moveComp = newEntity.components.move moveComp:SetWantDir(moveDir) moveComp:SetWantRotateDir(moveDir) addIndex = addIndex + 1 if addIndex >= needAddCount then break end end if addIndex >= needAddCount then break end end FP.releaseV2(moveDir) end --一次出生一个boss类型的怪 -- 总数保持一定的量 function RogueLikeLevelFunction:BornMonster_OnceBoss(ruleId, ruleData, ruleInfo) local posX, posZ posX, posZ = self:GetBornPosOnCircle(EliteBornScreenRadius, true) local newEntity = SystemManager.CreateMonster(ruleData.MonsterID, posX, posZ, 0, 1) newEntity.rogueRuleId = ruleId -- 统计entity属于哪个规则,方便死亡时curMonsterCount值减少 ruleInfo.curMonsterCount = 1 self:RoutMonster(true) -- boss出生则让杂兵溃散 end function RogueLikeLevelFunction:InitMonsterBornRuleFunctionDic() self.MonsterBornRuleFunctionDic = { [MonsterBornRuleType.HoldCount] = self.BornMonster_HoldCount, [MonsterBornRuleType.OnceGroup] = self.BornMonster_OnceGroup, [MonsterBornRuleType.OnceBoss] = self.BornMonster_OnceBoss, } end --endregion 刷怪规则 --region 技能随机规则 --关卡一开始,设置一个节点功能,并刷新随机表 function RogueLikeLevelFunction:AddFirstNodeToPlayer() local heroId = self.curEntity:GetCharacterID() local heroData = DataSheetManager.RogueHeroData:GetDataByHeroID(heroId) local heroSkillData = DataSheetManager.RogueSkillData:GetDataBySkillID(heroData.SkillID) local nodeData = DataSheetManager.RogueSkillNodeData:GetDataByNodeID(heroSkillData.StartNode) if nodeData.NextNode > 0 then self:SkillNodeToRandomPool(nodeData.NextNode) end -- 设置技能随机池子 self:InitRandomSkillNode(heroSkillData.StartNode) table.insert(self.skillGradeList, {heroSkillData.SkillID, 1}) table.insert(self.skillSelectList, heroSkillData.StartNode) --为玩家添加技能buff SystemManager.AddBuff(self.curEntity, nodeData.BuffID, self.curEntity) -- 为玩家添加武将特殊buff SystemManager.AddBuff(self.curEntity, heroData.BuffID, self.curEntity) end -- 关卡一开始设置的起始节点 function RogueLikeLevelFunction:InitRandomSkillNode(usedStartNode) -- 从技能表中找出他们的技能节点 for _,data in DataSheetManager.RogueSkillData:GetEnumerator() do if data.StartNode ~= usedStartNode and data.SkillID < Const_LevelPlayerMaxSkillLimit then self:SkillNodeToRandomPool(data.StartNode) end end end -- 技能升级后,需要查询是否有新增的技能点加入到随机池 function RogueLikeLevelFunction:SkillLevelUpRefreshRandomPool(rogueSkillId, grade) local rogueSkillData = DataSheetManager.RogueSkillData:GetDataBySkillID(rogueSkillId) local gradeOpenList = rogueSkillData.GradeOpenNode local count = #gradeOpenList / 2 for i = 1, count do if grade == gradeOpenList[i*2-1] then local nodeId = gradeOpenList[i*2] self:SkillNodeToRandomPool(nodeId) end end end -- 当某技能升级到满级后,需要将随机池中与其相关的节点删除 function RogueLikeLevelFunction:SkillUptoMaxRefreshRandomPool(rogueSkillId) local count = #self.skillRandomPool for i = count, 1 , -1 do local nodeData = DataSheetManager.RogueSkillNodeData:GetDataByNodeID(self.skillRandomPool[i][1]) if nodeData.BelongToSkill == rogueSkillId then table.remove(self.skillRandomPool, i) end end end -- 将技能节点放入随机池 function RogueLikeLevelFunction:SkillNodeToRandomPool(nodeId) local nodeData = DataSheetManager.RogueSkillNodeData:GetDataByNodeID(nodeId) local conditionTree = ConditionManager.GetConditionDataTree(nodeData.ConditionStr) if ConditionManager.MeetCondition(self.curEntity, conditionTree) then table.insert(self.skillRandomPool, {nodeId, nodeData.Weight } ) else table.insert(self.preSkillRandomPool, {nodeId, nodeData.Weight } ) end end -- 每次升级,需要先将 preSkillRandomPool中的技能节点尝试放入到skillRandomPool中 function RogueLikeLevelFunction:TryAddPreSkillNodeToRandomPool() local count = #self.preSkillRandomPool for i = count, 1, -1 do local nodeInfo = self.preSkillRandomPool[i] local nodeData = DataSheetManager.RogueSkillNodeData:GetDataByNodeID(nodeInfo[1]) local conditionTree = ConditionManager.GetConditionDataTree(nodeData.ConditionStr) if ConditionManager.MeetCondition(self.curEntity, conditionTree) then table.insert(self.skillRandomPool, nodeInfo) table.remove(self.preSkillRandomPool, i) end end end -- 随机获取三个节点,放入到self.randomResult function RogueLikeLevelFunction:GetRandomSkillNode() table.clearArray(self.randomResult) -- 当玩家满级后,随机变为固定的值 if self.curGrade >= Const_PlayerMaxGrade then for _, v in ipairs(Const_MaxNode) do table.insert(self.randomResult, v) end return end -- 每次随机时,需要先将 preSkillRandomPool中的技能节点尝试放入到skillRandomPool中 self:TryAddPreSkillNodeToRandomPool() local randomPool = {} -- 克隆一份,目的是移除型随机,但又不影响之前的随机池 for _,v in ipairs(self.skillRandomPool) do table.insert(randomPool,v) end local needRandomCount = #randomPool >= 3 and 3 or 2 -- 最少两次 for i=1,needRandomCount do local index = private.GetRandomIndex(randomPool) local nodeInfo = randomPool[index] table.insert(self.randomResult, nodeInfo[1]) table.remove(randomPool, index) end if self.randomResult[1] == nil then for _, v in ipairs(Const_MaxNode) do table.insert(self.randomResult, v) end end end function private.GetRandomIndex(randomList) local totalWeight = FP.newV1(0) for _, nodeInfo in ipairs(randomList) do totalWeight:Add(nodeInfo[2]) end local count = #randomList local random = LogicRandom.GetRangeValue(nil, FP.Const.Zero, totalWeight ,20240401) for i = 1, count do local info = randomList[i] random:Sub(info[2]) if FP.LessEquals(random, 0) then return i end end end --endregion 技能随机规则 --region 外部调用接口 function RogueLikeLevelFunction:GetLevelScore() return FP.tonumberV1(self.rogueScore) end -- 增加积分 function RogueLikeLevelFunction:AddRogueScore(entity, value) temp_score:Reset(self.rogueScoreRate):Mul(value) self.rogueScore:Add(temp_score) end -- 扩大拾取物品的拾取范围 function RogueLikeLevelFunction:AddPickUpRange(entity,value) self.pickUpDistance:Add(value) self.pickUpDistanceSqr = tonumberV1(self.pickUpDistance * self.pickUpDistance) end -- 积分增加的倍率 function RogueLikeLevelFunction:AddRogueScoreRate(value) self.rogueScoreRate:Add(value) end -- 增加经验值加成 function RogueLikeLevelFunction:AddRogueLikeGradeExp(value) self.gradeExpRate:Add(value) end -- 增加复活机会 function RogueLikeLevelFunction:AddRogueReviveNum(value) self.leftReviveNum = self.leftReviveNum + value end -- 增加重选机会 function RogueLikeLevelFunction:AddRogueReselectNum(value) self.reselectNum = self.reselectNum + value self.reselectTotalNum = self.reselectTotalNum + value end function RogueLikeLevelFunction:GetNearSearchList() return self.nearSearchList end --endregion return RogueLikeLevelFunction