local ExpMoveMissileSystem = {} local private = {} local Vector3_New=Vector3.New local _tempV3 = Vector3_New(0,0,0) local _forwardV3 = Vector3_New(0,0,0) local tonumberV2=FP.tonumberV2 local tonumberV1=FP.tonumberV1 local Const_Zero=FP.Const.Zero local Vector3_up=Vector3.up local Vector3_left=Vector3.left local LuaConst_MissileMoveType_Bind=LuaConst.MissileMoveType.Bind local LuaConst_MissileMoveType_Parabola=LuaConst.MissileMoveType.Parabola local LuaConst_MissileMoveType_BindWithOutRotate=LuaConst.MissileMoveType.BindWithOutRotate local LuaConst_MissileMoveType_BindAndAroundRotate=LuaConst.MissileMoveType.BindAndAroundRotate function ExpMoveMissileSystem.OnFire(expMissile,paramData,isForOptimize) end function ExpMoveMissileSystem.UpdateExpressionPosAndDir(expMissile,deltaTime) local missile = expMissile.Missile local missileData = missile.MissileData if missile.IsTracker then if missile.InFreeFly then --自由飞行阶段 if missile.IsBinding then--跟随角色位移 local x,y,z = missile.Attacker.ExpEntity:GetPosition() local attackerMoveComponent = missile.Attacker.components.move local dirX,dirZ = FP.tonumberV2(attackerMoveComponent.LogicRotateDir) local dir = Vector3_New(dirX, 0, dirZ) local right = Vector3_New(dir.z, 0 , -dir.x) local offset = dir * expMissile.PosOffset.z + right * expMissile.PosOffset.x expMissile.Pos = Vector3_New(x + offset.x, y + expMissile.PosOffset.y, z + offset.z) expMissile.Trans:SetPosition(expMissile.Pos.x,expMissile.Pos.y,expMissile.Pos.z) if missile.FireRotate then local forward = dir local right = Vector3_New(dirZ, 0, -dirX) local rx, rz = tonumberV2(missile.FireRotate) dir = Quaternion.AngleAxis(rx, right) * forward dir = Quaternion.AngleAxis(rz, Vector3_up) * dir end expMissile.MoveVec = dir expMissile.Trans.forward = expMissile.MoveVec elseif missile.MissileData.FreeFlyType == 1 then --直线 private.TrackerExpressionPosAndDir(expMissile, missileData, deltaTime, true) end else --追击阶段 if missile.MissileData.TrackFlyType == 1 then --直线 private.TrackerExpressionPosAndDir(expMissile, missileData, deltaTime, true) else private.TrackerExpressionPosAndDir(expMissile, missileData, deltaTime, false) end end elseif missile.MoveType == LuaConst_MissileMoveType_Parabola then private.ParabolaExpressionPosAndDir(expMissile,missileData,deltaTime) elseif missile.MoveType == LuaConst_MissileMoveType_Bind then private.BindingExpressionPosAndDir(expMissile,missileData,deltaTime) elseif missile.MoveType == LuaConst_MissileMoveType_BindWithOutRotate then private.BindingNoRotateExpressionPosAndDir(expMissile,missileData,deltaTime) elseif missile.MoveType == LuaConst_MissileMoveType_BindAndAroundRotate then private.BindingAroundRotateExpressionPosAndDir(expMissile,missileData,deltaTime) else private.LineExpressionPosAndDir(expMissile,missileData,deltaTime) end end --追踪弹 function private.TrackerExpressionPosAndDir(expMissile, missileData, deltaTime, isLine) local missile = expMissile.Missile local timeScale = tonumberV1(missile.Attacker.components.timeScale:GetCurMissileTimeScale()) if missile.InFreeFly and missileData.FreeFlySpd <= 0 then return end local speedX = expMissile.Missile.InFreeFly and missileData.FreeFlySpd or tonumberV1(missile.TrackSpeed) if missile.InFreeFly then --自由飞行阶段 _tempV3:Set(expMissile.MoveVec.x,expMissile.MoveVec.y,expMissile.MoveVec.z) expMissile.Trans.forward = _tempV3 expMissile.Pos:Add(_tempV3:Mul(speedX * deltaTime * timeScale)) expMissile.Trans:SetPosition(expMissile.Pos.x,expMissile.Pos.y,expMissile.Pos.z) else --追击阶段 local targetY = 0 if missile.TrackerTarget then local tx,tz = tonumberV2(missile.TrackerTarget.components.move.LogicPos) local offsetx,offsetz = tonumberV2(missile.TrackerOffset) _tempV3:Set(tx+offsetx, 0, tz+offsetz) --TODO 临时加判空逻辑,后面希望将TrackerTarget的引用从missile中移除 if missile.TrackerTarget.ExpEntity:GetRenderEntity() then local slotInt = LuaConst.HumanEquipSlot[missileData.AimNode] local y = missile.TrackerTarget.ExpEntity:GetEquipSlotHeight(slotInt ,expMissile.Pos.y) targetY = y + expMissile.TrackerOffset.y else targetY = AuxUtil.GetHigh(_tempV3.x, targetY, _tempV3.z) + expMissile.TrackerOffset.y end else -- 虚拟目标,子弹高度不变 if not missile.TrackerVirtualPos then return end local x,z = tonumberV2(missile.TrackerVirtualPos) _tempV3:Set(x, 0, z) targetY = expMissile.TrackerForceY or expMissile.Pos.y end local mx,mz = expMissile.Pos.x, expMissile.Pos.z local dx,dz = _tempV3.x - mx, _tempV3.z -mz local disY = targetY - expMissile.Pos.y --- 速度为0 ,不追踪了 ,但是朝向实时变化 if speedX == 0 then _forwardV3:Set(dx ,disY,dz) expMissile.Trans.forward = _forwardV3 return end local dis = math.sqrt(dx*dx + dz*dz) local time = math.abs( dis / speedX) local speedY = 0 local setForward = true if isLine then if time <= 0.052 then-- 最后一帧的时间不要在变向了 setForward = false end if dis < math.epsilon then speedY = 0 else speedY = disY / time dx, dz = dx/dis, dz/dis end else if time <= 0.052 then -- 最后一帧的时间不要在变向了 setForward = false end if dis < math.epsilon then speedY = 0 else if math.abs(disY) > 0.1 then local accelerate = 2 * speedX * (speedX * disY - expMissile.TrackerSpeedY * dis) / (dis * dis) -- a = (h-Vy*t)*2/(t*t) t = s/Vx expMissile.TrackerSpeedY = expMissile.TrackerSpeedY + accelerate * deltaTime * timeScale speedY = expMissile.TrackerSpeedY if math.abs(speedY) > 100 then -- gws: Y速度不可能这么快的,如果这么快一定是加速度值计算有问题了 speedY = 0 end else speedY = 0 end dx, dz = dx/dis, dz/dis end end _tempV3:Set(dx * speedX, speedY, dz * speedX) --final Direction if setForward and dis > 0.0005 then expMissile.Trans.forward = _tempV3 end expMissile.Pos:Add(_tempV3:Mul(deltaTime * timeScale)) expMissile.Trans:SetPosition(expMissile.Pos.x,expMissile.Pos.y,expMissile.Pos.z) end end --直线 + 角速度转身 的位移 function private.LineExpressionPosAndDir(expMissile,missileData,deltaTime) local realSpeed = tonumberV1(missileData.MoveSpeed) local realAngleSpeed = tonumberV1(missileData.AngleSpeed) if realSpeed <= 0 and realAngleSpeed == 0 then -- realAngleSpeed 有正负区分 return end local timer = expMissile.ExpressionTimer * 1000 - tonumberV1(missileData.DelayMoveFrame) if timer > 0 then local timeScale = tonumberV1(expMissile.Missile.Attacker.components.timeScale:GetCurMissileTimeScale()) if realAngleSpeed ~= 0 then --[[ 这种算法会产生 table 比较多 local quaternion = Quaternion.AngleAxis(realAngleSpeed * deltaTime * timeScale, Vector3.up) expMissile.MoveVec = quaternion * expMissile.MoveVec expMissile.MoveVec = expMissile.MoveVec.normalized expMissile.Trans.forward = expMissile.MoveVec --]] UIUtils.RotateByUp(expMissile.Trans,realAngleSpeed * deltaTime * timeScale) -- 如果是螺旋向上升 ,还需要判断是否以世界Y轴旋转,目前暂时不考虑了 end -- 水平移动 _tempV3:Set(expMissile.Trans.forward.x ,0 ,expMissile.Trans.forward.z ) -- 现在认为子弹的表现朝向和子弹的飞行方向一致,如果以后有需求,子弹横着飘,需要改这句代码。 expMissile.Pos:Add(_tempV3:Mul(realSpeed * deltaTime * timeScale)) -- 要贴合地面 if missileData.FollowTerrainHeight then expMissile.Pos.y = AuxUtil.GetHigh(expMissile.Pos.x, expMissile.Pos.y, expMissile.Pos.z) elseif expMissile.Missile.SpeedY ~= Const_Zero then-- 垂直移动 expMissile.Pos.y = expMissile.Pos.y + expMissile.SpeedY * deltaTime * timeScale end expMissile.Trans:SetPosition(expMissile.Pos.x,expMissile.Pos.y,expMissile.Pos.z) end end --抛物线位移 function private.ParabolaExpressionPosAndDir(expMissile,missileData,deltaTime) local time = expMissile.ExpressionTimer if time <= 0 then return end local realSpeed = tonumberV1(missileData.MoveSpeed) local x = realSpeed * time ---水平位移 local y = expMissile.ParabolaParam_a * x * x + expMissile.ParabolaParam_b * x; expMissile.Pos:Set(expMissile.MoveVec.x * x, y, expMissile.MoveVec.z * x) expMissile.Pos:Add(expMissile.InitPos) --旋转 if missileData.CanRotate then local timeScale = tonumberV1(expMissile.Missile.Attacker.components.timeScale:GetCurMissileTimeScale()) local angle = expMissile.FireAngleSpeed * deltaTime * timeScale UIUtils.SetPositionAndRotateByLeft(expMissile.Trans,expMissile.Pos.x,expMissile.Pos.y,expMissile.Pos.z,angle) else expMissile.Trans:SetPosition(expMissile.Pos.x,expMissile.Pos.y,expMissile.Pos.z) end end --绑定在发射至身上的子弹更新位置(类似绑定在某个骨骼上) function private.BindingExpressionPosAndDir(expMissile,missileData,deltaTime) local missile = expMissile.Missile local x,y,z = missile.Attacker.ExpEntity:GetPosition() local attackerMoveComponent = missile.Attacker.components.move local dirX,dirZ = FP.tonumberV2(attackerMoveComponent.LogicRotateDir) local dir = Vector3_New(dirX, 0, dirZ) local right = Vector3_New(dir.z, 0 , -dir.x) local offset = dir * expMissile.PosOffset.z + right * expMissile.PosOffset.x expMissile.Pos = Vector3_New(x + offset.x, y + expMissile.PosOffset.y, z + offset.z) expMissile.Trans:SetPosition(expMissile.Pos.x,expMissile.Pos.y,expMissile.Pos.z) local data = missile.CallData if data.BornForwardType == 0 then expMissile.MoveVec = dir elseif data.BornForwardType == 1 then -- 背离 expMissile.MoveVec = Vector3_New(expMissile.Pos.x - x, 0 , expMissile.Pos.z - z) expMissile.MoveVec:SetNormalize() elseif data.BornForwardType == 2 then -- 面向 expMissile.MoveVec = Vector3_New(x - expMissile.Pos.x , 0 , z - expMissile.Pos.z) expMissile.MoveVec:SetNormalize() end expMissile.Trans.forward = expMissile.MoveVec end --绑定在发射至身上的子弹更新位置(不带转向,绝对的位移偏差) function private.BindingNoRotateExpressionPosAndDir(expMissile,missileData,deltaTime) local missile = expMissile.Missile local x,y,z = missile.Attacker.ExpEntity:GetPosition() expMissile.Pos = Vector3_New(x + expMissile.PosOffset.x, y + expMissile.PosOffset.y, z + expMissile.PosOffset.z) expMissile.Trans:SetPosition(expMissile.Pos.x,expMissile.Pos.y,expMissile.Pos.z) end --围绕在发射者的子弹 更新位置(子弹的朝向始终远离发射者) function private.BindingAroundRotateExpressionPosAndDir(expMissile,missileData,deltaTime) local missile = expMissile.Missile local x,y,z = missile.Attacker.ExpEntity:GetPosition() local angleSpeed = missile.overrideAngleSpeed or missileData.AngleSpeed local realAngleSpeed = tonumberV1(angleSpeed) local toAttackerDistance = tonumberV1(missile.PosOffsetDistance) local timer = expMissile.ExpressionTimer * 1000 - tonumberV1(missileData.DelayMoveFrame) if timer > 0 then local timeScale = tonumberV1(expMissile.Missile.Attacker.components.timeScale:GetCurMissileTimeScale()) if realAngleSpeed ~= 0 then UIUtils.RotateByUp(expMissile.Trans,realAngleSpeed * deltaTime * timeScale) -- 计算角度 end -- 位置 expMissile.Pos = Vector3_New(x + expMissile.Trans.forward.x * toAttackerDistance, y + expMissile.PosOffset.y, z + expMissile.Trans.forward.z * toAttackerDistance) expMissile.Trans:SetPosition(expMissile.Pos.x,expMissile.Pos.y,expMissile.Pos.z) end end return ExpMoveMissileSystem