-- 技能 - 子弹相关 local SkillMissileSystem = { --call的列表(整个游戏中的所有的call) CallBulletList = {}, } local private = {} local _tempToRemoveList = {} local LuaConst=LuaConst local table_insert=table.insert local table_remove=table.remove local FP=FP local ipairs=ipairs local pairs=pairs local next=next local _tempV2 = FP.newV2(0,0) -- 摇杆控制的子弹是起点还是终点 local CtrlTypeByJoystick = LuaConst.CtrlMissileTypeByJoystick local CALL_TYPE_DEFAULT = LuaConst.ESkillMissileCallType.DEFAULT local CALL_TYPE_SKILL = LuaConst.ESkillMissileCallType.SKILL local CALL_TYPE_BUFFTRIGGER = LuaConst.ESkillMissileCallType.BUFFTRIGGER local CALL_TYPE_BATTLEEFFECT = LuaConst.ESkillMissileCallType.BATTLEEFFECT local BaseForwardType = { Owner = 0, Target = 1, } -- 相对于基准者朝向的修改朝向 local LocalForwardType = { Base = 0 , -- 与基准者朝向相同 BackToBase = 1, -- 背离基准者 FaceToBase = 2 , -- 面向基准者 BaseToHisTarget = 3 , -- 基准者与基准者的目标的连线 RandomAngle = 4 , -- 随机朝向 } --[[ 切换场景等 清空子弹 ]]-- function SkillMissileSystem.Clear() SkillMissileSystem.CallBulletList = {} end --[[ 技能动作 触发召唤事件 --]] function SkillMissileSystem.OnTriggerAction_Call(entity, skillEvent, skillData) local callBulletId = skillEvent.EventIntParam SkillMissileSystem.TryToDoCall(entity,callBulletId ,skillData ,skillEvent.EventParam) end --返回双摇杆影响子弹的类型,可能返回nil,表示双摇杆不影响子弹 function SkillMissileSystem.GetJoystickCtrlMissileType(skillJoystickData) local result = nil if skillJoystickData then if skillJoystickData.AimPosType == LuaConst.ESkillJoystickAimPosType.Missile or skillJoystickData.AimPosType == LuaConst.ESkillJoystickAimPosType.MissileAndAnimation then result = CtrlTypeByJoystick.MissileStart elseif skillJoystickData.AimPosType == LuaConst.ESkillJoystickAimPosType.MissileEndPos or skillJoystickData.AimPosType == LuaConst.ESkillJoystickAimPosType.MissileEndPosWithDefaultPos then result = CtrlTypeByJoystick.MissileEnd elseif skillJoystickData.AimPosType == LuaConst.ESkillJoystickAimPosType.MissileWithOffset then result = CtrlTypeByJoystick.MissileStartWithOffset end end return result end -- 发起召唤申请(会异步处理这个申请,实际召唤子弹是ExcuteCall) function SkillMissileSystem.TryToDoCall(entity, callBulletId , skillData , effForward, forceFireDir, forcePos, trackerTarget, forceTarget, reasonType, forceOffsetY) local callBulletData = entity:GetCallData(callBulletId) if not callBulletData then return end local skillBaseComponent = entity.components.skillBase local callBulletInfo = RuntimeDataManager.New_CallBulletInfo() callBulletInfo.Entity = entity callBulletInfo.SkillID = skillData and skillData.ID or nil local dynamicDmgFactor = skillData and entity.components.skillBase:GetDynamicSkillDamageFactor(skillData) or nil if dynamicDmgFactor then callBulletInfo.DynamicSkillDmgFactor:Reset(dynamicDmgFactor) end callBulletInfo.CallTime:Reset(callBulletData.DelayTime) callBulletInfo.Data = callBulletData callBulletInfo.EffForward = effForward callBulletInfo.ForceFireDir = forceFireDir callBulletInfo.ForceOffsetY = forceOffsetY callBulletInfo.TrackerTarget = trackerTarget callBulletInfo.ForceTarget = forceTarget -- 此次call的目标entity,可为nil ,目的是覆盖entity.components.target.Target -- 子弹召唤时不用技能释放的锁定位置 (当被技能打断时,会强制MissileAimPos = nil,但是此时召唤的抛物线子弹需要这个值) --MissileAimPos 优先级 :双摇杆 > Ai特定pos > 特种车准星 > 目标现在位置 > 目标在技能开始时的位置 > nil local curSkillJoystickType = nil if reasonType == CALL_TYPE_DEFAULT or reasonType == CALL_TYPE_SKILL then local skillJoystickData = skillBaseComponent.CurSkillJoystickData curSkillJoystickType = SkillMissileSystem.GetJoystickCtrlMissileType(skillJoystickData) end if forcePos then callBulletInfo.ForcePos = forcePos else -- 记录子弹目标的备用位置,(MissileAimPos 子弹目标的备用位置 。在设置出生位置和朝向时,用到目标时发现没目标,就用这个值) if skillBaseComponent.MissileAimPos ~= nil then callBulletInfo.MissileAimPos:Reset(skillBaseComponent.MissileAimPos) else local targetEntity = callBulletInfo.ForceTarget or entity.components.target.Target if targetEntity then callBulletInfo.MissileAimPos:Reset(targetEntity.components.move.LogicPos) local radius = skillData and skillData.AimPosRound or FP.Const.Zero if radius > FP.Const.Zero then local angle = LogicRandom.GetRangeValue(entity, FP.Const.Zero, FP.Const.Degree360 ,29) local randomDir = FP.V2.GetOffsetToAngle(angle, FP.Const.Vector2_Forward) local randomR = LogicRandom.GetRangeValue(entity, 0, radius ,30) callBulletInfo.MissileAimPos:Add(randomDir:Mul(randomR)) end else if skillBaseComponent.RecordAttackTargetPos ~= nil then callBulletInfo.MissileAimPos:Reset(skillBaseComponent.RecordAttackTargetPos) else callBulletInfo.MissileAimPos:Reset(entity:GetLogicPos()) end end end end -- 保存技能摇杆点 if reasonType == CALL_TYPE_DEFAULT or reasonType ~= CALL_TYPE_SKILL then callBulletInfo.skillJoyStickPos = skillBaseComponent.SkillJoystickPos -- SkillJoystickPos 当技能摇杆为0,0时,这个值是空 ; callBulletInfo.ctrlTypeByJoystick = skillBaseComponent.SkillJoystickPos and curSkillJoystickType --当有技能摇杆,但是技能摇杆是点击时,策划配置了使用目标位置,则将技能摇杆设置为目标的位置。 if callBulletInfo.skillJoyStickPos == nil and skillBaseComponent.CurSkillJoystickData and skillBaseComponent.CurSkillJoystickData.IsClickClearJoyStick then -- callBulletInfo.skillJoyStickPos == nil 表示是技能摇杆是点击。 local targetEntity = callBulletInfo.ForceTarget or entity.components.target.Target if targetEntity then callBulletInfo.skillJoyStickPos = targetEntity.components.move.LogicPos:cloneV2() callBulletInfo.ctrlTypeByJoystick = curSkillJoystickType end end end local carAimPos = entity.components.drive:TryGetAimPos() -- 特殊的技能摇杆 if carAimPos then callBulletInfo.skillJoyStickPos = carAimPos -- 只用于落点位置 ,不用于出生位置 callBulletInfo.ctrlTypeByJoystick = CtrlTypeByJoystick.MissileEnd -- 控制skillJoyStickPos只用于落点位置 callBulletInfo.MissileAimPos:Reset(carAimPos) end --信息需要保留 - 位置 if not callBulletData.PosIsNotBaseOnSkill then private.RecordCallPosParams(entity, callBulletData, callBulletInfo) end --信息需要保留 - 朝向参数 if not callBulletData.ForwardIsNotBaseOnSkill then private.RecordCallForwardParams(entity, callBulletData, callBulletInfo) end table_insert(SkillMissileSystem.CallBulletList, callBulletInfo) end function SkillMissileSystem.AddCall(callBulletInfo) table_insert(SkillMissileSystem.CallBulletList, callBulletInfo) end local _tempDeltaTime = FP.newV1(0) --[[ Tick --]] local function OnLogicUpdateNotNil() for index,callBulletInfo in ipairs(SkillMissileSystem.CallBulletList) do local entity = callBulletInfo.Entity local timeComp=entity.components.timeScale _tempDeltaTime:Reset(timeComp:GetCurTimeScale()) _tempDeltaTime:Mul(LuaConst.TimeSpanMs) callBulletInfo.TimeEla:Add(_tempDeltaTime) if callBulletInfo.TimeEla >= callBulletInfo.CallTime then callBulletInfo.TimeEla:Reset(-999999) private.ExcuteCall(entity, callBulletInfo) table_insert(_tempToRemoveList,index) end end for i=#_tempToRemoveList,1,-1 do table_remove(SkillMissileSystem.CallBulletList,_tempToRemoveList[i]) table_remove(_tempToRemoveList) end end SkillMissileSystem.OnLogicUpdate = OnLogicUpdateNotNil --region OnLogicUpdate的重定向 local function OnLogicUpdateNil() end function SkillMissileSystem.SetLogicUpdateNil() SkillMissileSystem.OnLogicUpdate = OnLogicUpdateNil end function SkillMissileSystem.SetLogicUpdateNotNil() SkillMissileSystem.OnLogicUpdate = OnLogicUpdateNotNil end function SkillMissileSystem.LogicUpdateIsNil() return SkillMissileSystem.OnLogicUpdate == OnLogicUpdateNil end --endregion OnLogicUpdate的重定向 local MAX_ANGLE = FP.newV1(359) local _tempV1 = FP.newV1(0) --[[ 生成子弹 --]] local JOYSTICKPOS_OUTBOUND_TOLERANCE = FP.newV1(1.1) function private.ExcuteCall(entity, callBulletInfo) local data = callBulletInfo.Data --信息需要保留 - 位置 if data.PosIsNotBaseOnSkill then private.RecordCallPosParams(entity, data, callBulletInfo) end --信息需要保留 - 朝向参数 if data.ForwardIsNotBaseOnSkill then private.RecordCallForwardParams(entity, data, callBulletInfo) end local fireBasePos = callBulletInfo.FireBasePos local firePosY = callBulletInfo.FireBasePosY -- 单位是米 local baseForwardParamV2 = callBulletInfo.FireBaseRotateParamV2 --local targetPos = callBulletInfo.skillJoyStickPos or callBulletInfo.MissileAimPos local targetPos if callBulletInfo.skillJoyStickPos then targetPos = callBulletInfo.skillJoyStickPos --越界检测: 玩家可能通过作弊输入超过范围的cmd的双摇杆位置, 此处需要排除一下 if callBulletInfo.SkillID then local skillJoystickData = entity.components.skillBase:GetSkillJoystickData(callBulletInfo.SkillID) if skillJoystickData then _tempV2:Reset(targetPos):Sub(entity:GetLogicPos()) _tempV2:SqrMagnitude(_tempV1) local controlRange = entity.components.skillBase:GetSkillJoyStickOverrideData(skillJoystickData.ID, "ControlRange") or skillJoystickData.ControlRange _tempV1:Div(controlRange):Div(controlRange) local needChangeFirePos = targetPos == fireBasePos if _tempV1 > JOYSTICKPOS_OUTBOUND_TOLERANCE then _tempV2:Normalize() _tempV2:Mul(controlRange) targetPos = FP.newV2(0, 0) targetPos:Reset(_tempV2):Add(entity:GetLogicPos()) callBulletInfo.skillJoyStickPos = targetPos if needChangeFirePos and fireBasePos then fireBasePos:Reset(targetPos) end end end end else targetPos = callBulletInfo.MissileAimPos if not callBulletInfo.IsNextMissile and fireBasePos then --越界检测: 玩家可能通过作弊输入超过范围的cmd的双摇杆位置, 此处需要排除一下 --这块会有bug隐患:比如执行一个延迟很久才发射的Call,在延迟期间走到很远的地方,那么最后发射的子弹位置会被修正,导致位置不对 if callBulletInfo.SkillID then local skillJoystickData = entity.components.skillBase:GetSkillJoystickData(callBulletInfo.SkillID) if skillJoystickData then _tempV2:Reset(fireBasePos):Sub(entity:GetLogicPos()) _tempV2:SqrMagnitude(_tempV1) local controlRange = entity.components.skillBase:GetSkillJoyStickOverrideData(skillJoystickData.ID, "ControlRange") or skillJoystickData.ControlRange _tempV1:Div(controlRange):Div(controlRange) if _tempV1 > JOYSTICKPOS_OUTBOUND_TOLERANCE then _tempV2:Normalize() _tempV2:Mul(controlRange) fireBasePos = FP.newV2(0, 0) fireBasePos:Reset(_tempV2):Add(entity:GetLogicPos()) end end end end end local basePosEntityRotateDir = callBulletInfo.FireBaseRotateDir -- 子弹生成在A身上时,A的朝向 local baseForward = FP.newV2(0,1) local randomUseIndex = {} for index = 1, data.Number do local forward = FP.newV2(0,1) local position = FP.newV2(0,0) local posOffset = FP.newV2(0,0) local offsetY = FP.newV1(0) local fireRotate = nil local transformTable = data.Transform_Table if not data.IsRulePolygon then--无规则形状 private.SetMissileForward(entity, data, fireBasePos, baseForward , baseForwardParamV2 , callBulletInfo.ForceFireDir) forward:Reset(baseForward) -- 无规则形状一定不会配置 朝向为1,2(面向基准,背对基准),所以baseForward一定不为空 if not next(transformTable) or not transformTable[1].FireOffset then --随机 if callBulletInfo.ctrlTypeByJoystick == CtrlTypeByJoystick.MissileStart then --被摇杆控制时,需要忽略offset position:Reset(fireBasePos) else local radius = LogicRandom.GetRangeValue(entity, FP.Const.Zero, data.Radius ,23) local radian = LogicRandom.GetRangeValue(entity, FP.Const.Zero, FP.Const.PI2 ,24) local sin = FP.Math.Sin(radian) local cos = FP.Math.Cos(radian) posOffset = FP.newV2(radius * cos, radius * sin) position:Reset(fireBasePos):Add(posOffset) end else --无随机 local fireRotateList = {} if next(transformTable) and transformTable[1].FireRotate then for i, v in ipairs(transformTable) do local rotateTable = v.FireRotate local x = rotateTable[1] local y = rotateTable[2] local z = rotateTable[3] table_insert(fireRotateList, {x = x, y = y, z = z}) end end local fireOffsetList if callBulletInfo.ctrlTypeByJoystick ~= CtrlTypeByJoystick.MissileStart then fireOffsetList = {} if next(transformTable) and transformTable[1].FireOffset then for i, v in ipairs(transformTable) do local offsetTable = v.FireOffset local x = offsetTable[1] local y = offsetTable[2] local z = offsetTable[3] table_insert(fireOffsetList, {x = x, y = y, z = z}) end end end local useIndex = index local calcRandomIndexList = fireOffsetList or fireRotateList if calcRandomIndexList and #calcRandomIndexList > data.Number then if #randomUseIndex == 0 then -- 统计随机范围 for i=1,#calcRandomIndexList do table_insert(randomUseIndex,i) end end local randomIndex = LogicRandom.GetIntegerValue(entity, 1, #randomUseIndex ,10) useIndex = randomUseIndex[randomIndex] table_remove(randomUseIndex ,randomIndex) end if callBulletInfo.ctrlTypeByJoystick == CtrlTypeByJoystick.MissileStart then --被摇杆控制时,需要忽略offset position:Reset(fireBasePos) else ---gws注意:米欧策划说了,当代码走到这(子弹有固定相对位置的)绝对不会配置 BornForwardType = 1 or 2 ,如果想要1,2效果,她会自己配置子弹旋转实现 2021-3-6 --- BornForwardType = 1 or 2 仅仅给 半径内随机召唤子弹用的 ;需要子弹确切位置后,才能计算出来 --- 关于:随机朝向的子弹 ,策划说:随机朝向的时候不会配置相对偏移位置 -- gws:应策划需求逻辑是:1.用BornForwardType(1,2除外)调整方向 ,2.再用这个朝向调整位置(FireOffset) 3,用FireRotate修改这个朝向为最终朝向 2021-3-6 local right = FP.V2.GetRightByForward(baseForward) local pos = fireOffsetList[useIndex] or fireOffsetList[1] posOffset:Reset(pos.x,pos.z) offsetY:Reset(pos.y) --等效关系 position = fireBasePos + baseForward * pos.z + right * pos.x _tempV2:Reset(baseForward):Mul(pos.z) position:Reset(right):Mul(pos.x):Add(_tempV2):Add(fireBasePos) end -- 逻辑:先用BornForwardType调整方向,再用 Transform_Table 调整 if data.BornForwardType == LocalForwardType.BackToBase or data.BornForwardType == LocalForwardType.FaceToBase then logging.error(LTAG.ERROR, "【战斗策划注意:】: 有固定相对位置的子弹 ,不能配置 BornForwardType 为1或2 ;如果需要面向或者背离,自己配置角度。2021-3-6米欧规定的") end local rotateAngles = fireRotateList[useIndex] if rotateAngles then local angleY = FP.newV1(rotateAngles.y) forward = FP.V2.GetOffsetToAngle(angleY, baseForward) fireRotate = FP.newV2(rotateAngles.x , rotateAngles.y) end end else --规则形状 local diffAngle = 360 / data.Number _tempV1:Reset(diffAngle):Mul(index -1) local angle = _tempV1 if data.RandomPolygonRevolute then angle:Add(LogicRandom.GetIntegerValue(entity, FP.Const.Zero, MAX_ANGLE, 43892944)) else angle:Add(data.PolygonRevolute) end -- 规则图形的子弹位置拜访一定是从目标人的脸前开始摆 。 和策划说好的 2021-5-20 。 local offsetForward = FP.V2.GetOffsetToAngle(angle, basePosEntityRotateDir) position:Reset(offsetForward):Mul(data.Radius):Add(fireBasePos) local rad = FP.Math.Radian(angle)-- 相对世界坐标的偏移,需要转换为相对于firePos的偏移坐标 posOffset:Reset(FP.newV2( data.Radius * FP.Math.Sin(rad) ,data.Radius * FP.Math.Cos(rad)) ) private.SetMissileForward(entity, data, position, baseForward , baseForwardParamV2, callBulletInfo.ForceFireDir) forward:Reset(baseForward) end if callBulletInfo.ForcePos then position:Reset(callBulletInfo.ForcePos) end if data.RandomDelayTime > FP.Const.Zero then -- 有随机延迟就晚点做;没有就现在做 local missileDelayTime = LogicRandom.GetRangeValue(entity, FP.Const.Zero, data.RandomDelayTime, 29) MissileManager.AddCallAction(entity, data, forward, position, firePosY, posOffset, targetPos, offsetY, fireRotate, callBulletInfo ,missileDelayTime) else MissileManager.DoCallAction(entity, data, forward, position, firePosY, posOffset, targetPos, offsetY, fireRotate, callBulletInfo) end end end -- 统计位置相关参数 【如果是出生点是目标,优先级: 摇杆 > AI强制设定的子弹位置 >当前目标位置 > 发射时目标所在位置(AI锁定地点 > call时刻目标位置 > useskill时刻目标置)】 function private.RecordCallPosParams(entity, callBulletData, callBulletInfo) local moveComponent = entity.components.move if callBulletInfo.ctrlTypeByJoystick == CtrlTypeByJoystick.MissileStart or callBulletInfo.ctrlTypeByJoystick == CtrlTypeByJoystick.MissileStartWithOffset then --被摇杆控制时,优先使用摇杆位置 callBulletInfo.FireBasePos:Reset(callBulletInfo.skillJoyStickPos) local hasTerrain = LuaShoveManager.GetHeightByPos(callBulletInfo.skillJoyStickPos , callBulletInfo.FireBasePosY) private.TryRevisePosY(hasTerrain, callBulletInfo.FireBasePosY,moveComponent:GetLogicPosY()) callBulletInfo.FireBaseRotateDir:Reset(moveComponent.LogicRotateDir) if callBulletInfo.ForceOffsetY then callBulletInfo.FireBasePosY:Add(callBulletInfo.ForceOffsetY) end return end if callBulletData.BornAtTarget == 0 then -- 施法者位置 callBulletInfo.FireBasePos:Reset(moveComponent.LogicPos) callBulletInfo.FireBasePosY:Reset(moveComponent:GetLogicPosY()) callBulletInfo.FireBaseRotateDir:Reset(moveComponent.LogicRotateDir) elseif callBulletData.BornAtTarget == 1 then -- 目标位置 local decisionRecordDic = nil if entity.components.aiBase.CurDecisionData then decisionRecordDic = entity.components.aiBase:GetDecisionRecordDic(entity.components.aiBase.CurDecisionData) end if decisionRecordDic and decisionRecordDic.forceMissilePos then -- AI要求强制使用设置的子弹位置 callBulletInfo.FireBasePos:Reset(callBulletInfo.MissileAimPos) local hasTerrain = LuaShoveManager.GetHeightByPos(callBulletInfo.MissileAimPos , callBulletInfo.FireBasePosY) private.TryRevisePosY(hasTerrain, callBulletInfo.FireBasePosY,moveComponent:GetLogicPosY()) callBulletInfo.FireBaseRotateDir:Reset(moveComponent.LogicRotateDir) else local target = callBulletInfo.ForceTarget or entity.components.target.Target if target then local targetMoveComp = target.components.move callBulletInfo.FireBasePos:Reset(targetMoveComp.LogicPos) callBulletInfo.FireBasePosY:Reset(targetMoveComp:GetLogicPosY()) callBulletInfo.FireBaseRotateDir:Reset(targetMoveComp.LogicRotateDir) else callBulletInfo.FireBasePos:Reset(callBulletInfo.MissileAimPos) local hasTerrain = LuaShoveManager.GetHeightByPos(callBulletInfo.MissileAimPos , callBulletInfo.FireBasePosY) private.TryRevisePosY(hasTerrain, callBulletInfo.FireBasePosY,moveComponent:GetLogicPosY()) callBulletInfo.FireBaseRotateDir:Reset(moveComponent.LogicRotateDir) end end end if callBulletInfo.ForceOffsetY then callBulletInfo.FireBasePosY:Add(callBulletInfo.ForceOffsetY) end end -- 统计朝向相关参数 function private.RecordCallForwardParams(entity, callBulletData, callBulletInfo) local baseEntity = nil local ownerForceTarget = nil -- 施法者的强制目标 if callBulletData.BornForwardTargetType == BaseForwardType.Owner then --施法者 baseEntity = entity ownerForceTarget = callBulletInfo.ForceTarget elseif callBulletData.BornForwardTargetType == BaseForwardType.Target then --目标 baseEntity = (callBulletInfo.ForceTarget or entity.components.target.Target) or entity end local moveComp = baseEntity.components.move if callBulletData.BornForwardType == LocalForwardType.Base then --同基准者朝向, --FireBaseRotateParamV2 是基准者的朝向 callBulletInfo.FireBaseRotateParamV2:Reset(moveComp.LogicRotateDir) elseif callBulletData.BornForwardType == LocalForwardType.BackToBase or callBulletData.BornForwardType == LocalForwardType.FaceToBase then -- 背对或者面向基准者,FireBaseRotateParamV2 是基准者位置 callBulletInfo.FireBaseRotateParamV2:Reset(moveComp.LogicPos) elseif callBulletData.BornForwardType == LocalForwardType.BaseToHisTarget then -- 基准者与基准者的目标的连线,FireBaseRotateParamV2 是连线方向 local aimPos = nil if callBulletInfo.ctrlTypeByJoystick == CtrlTypeByJoystick.MissileEnd then --被摇杆控制时,优先使用摇杆位置 aimPos = callBulletInfo.skillJoyStickPos else local targetOfBase = ownerForceTarget or baseEntity.components.target.Target if targetOfBase then aimPos = targetOfBase.components.move.LogicPos elseif callBulletInfo.MissileAimPos then aimPos = callBulletInfo.MissileAimPos end end if aimPos then callBulletInfo.FireBaseRotateParamV2:Reset(aimPos):Sub(moveComp.LogicPos):Normalize() else callBulletInfo.FireBaseRotateParamV2:Reset(moveComp.LogicRotateDir) -- 如果没有目标位置 ,则是基准者的朝向 end end end function private.SetMissileForward(entity, callData, missilePos , baseForward ,paramV2, forceFireDir) if forceFireDir then baseForward:Reset(forceFireDir) return end --设置朝向 --朝向的基准 if callData.BornForwardType == LocalForwardType.Base then baseForward:Reset(paramV2) -- misslePos 有值,说明子弹的最终位置已经确定下来了 ; BackToBase 和 FaceToBase 必须先算出子弹真实位置后才能计算,所以这两种朝向先不计算 elseif missilePos and callData.BornForwardType == LocalForwardType.BackToBase then baseForward:Reset(missilePos):Sub(paramV2):Normalize() elseif missilePos and callData.BornForwardType == LocalForwardType.FaceToBase then baseForward:Reset(paramV2):Sub(missilePos):Normalize() elseif callData.BornForwardType == LocalForwardType.BaseToHisTarget then --目标(优先级:地点坐标 > 被攻击entity坐标 > 自身面向) baseForward:Reset(paramV2) elseif callData.BornForwardType == LocalForwardType.RandomAngle then local radian = LogicRandom.GetRangeValue(entity, FP.Const.Zero, FP.Const.PI2 ,25) local offX = FP.Math.Cos(radian) local offZ = FP.Math.Sin(radian) baseForward.x:Reset(offX) baseForward.z:Reset(offZ) end end function private.TryRevisePosY(hasTerrain, posY,correctPosy) if not hasTerrain then -- 非行走面内 posY:Reset(correctPosy) end end return SkillMissileSystem