--移动 local MoveSystem = {} --local z = 0 --调试用 local private = {} local newV1=FP.newV1 local newV2=FP.newV2 local releaseV2= FP.releaseV2 local FP_Const_Zero=FP.Const.Zero local FP_Const_Vector2_Zero=FP.Const.Vector2_Zero local IsDistanceSqrGreater=FP.V2.IsDistanceSqrGreater local GetOffsetToForward=FP.V2.GetOffsetToForward local tonumberV1=FP.tonumberV1 local LuaConst=LuaConst local math_max=math.max local math_floor=math.floor local math_ceil=math.ceil local FP_Math_Abs=FP.Math.Abs local LimitSqr = newV1(0.008) * newV1(0.008) --优化用的临时变量数据 local temp_addPos = newV2(0,0) local temp_newPos = newV2(0,0) local temp_extraAddPos = newV2(0,0) local temp_animMoveData = newV2(0,0) local temp_lastLeftTime = newV1(0) local temp_cutExrTime = newV1(0) local temp_durationTime = newV1(0) local temp_FinalPos = newV2(0,0) local tempV1 = newV1(0) --[[ 传送 --]] function MoveSystem.OnConvey(entity, pos, ignoreBlock) private.SetInitPos(entity.components.move, pos, ignoreBlock) end --[[ 变身 --]] function MoveSystem.OnSwitchHero(fromEntity, toEntity, dontBackground) if not dontBackground then local fromMove = fromEntity.components.move local toMove = toEntity.components.move fromMove:RemoveAllPosAnchorButLevel() private.SetInitPos(toMove, fromMove.LogicPos) end end --[[ 复活 --]] function MoveSystem.OnRevive(entity, isInBornPoint, isNearestBornPoint) if isInBornPoint then if isNearestBornPoint then local nearestDistSqr = FP.newV1(99999999) for i=1,LevelManager.bornPointCount do local bornItem = LevelItemManager.GetBornItem(i) local tempV1Dist = FP.newV1(0) if bornItem then entity:GetLogicPos():DistanceSqr(bornItem.ItemData.ItemPos, tempV1Dist) if tempV1Dist < nearestDistSqr then nearestDistSqr:Reset(tempV1Dist) entity._logicInitData:SetBornItemID(bornItem.LevelItemID) end end end end MoveSystem.BackToBornPoint(entity) end end --[[ 回到出生点 --]] function MoveSystem.BackToBornPoint(entity) local bornItemID = entity._logicInitData.BornItemID local itemData = LevelItemManager.GetItemDataByID(bornItemID) if itemData then private.SetInitPos(entity.components.move, LogicRandom.GetRandomPointInLevelItem(entity, itemData, 46865511)) else logging.error(LTAG.ERROR, "HYW : item nil Error @MoveSystem.BackToBornPoint bornItemID : ", bornItemID) end end function MoveSystem.OnDead(entity) entity.components.move:OnDead() end function MoveSystem.OnSetShovePriority(entity,priority) local comp_Move = entity.components.move local oldShovePriority = comp_Move.ShovePriority comp_Move:SetShovePriority(priority) if oldShovePriority > 50 then LuaShoveManager.ReSetGridDataOfEntity(entity,true) end if comp_Move.ShovePriority > 50 then LuaShoveManager.SetGridDataByPriorityOfEntity(entity,comp_Move.ShovePriority,true,true) end end function MoveSystem.OnResetShovePriority(entity) local comp_Move = entity.components.move local comp_Base = entity.components.base local oldShovePriority = comp_Move.ShovePriority entity.shoveOffsetZ = entity.components.base.CurModelData.ForwardShoveOffset --local sizeX = entity.components.base.CurModelData.ShoveDiameterX --local sizeZ = entity.components.base.CurModelData.ShoveDiameterZ comp_Move:ResetShovePriority(comp_Base.CurCharacterData) if comp_Move.ShovePriority > 50 then LuaShoveManager.SetGridDataByPriorityOfEntity(entity,comp_Move.ShovePriority,true,true) else if oldShovePriority > 50 then LuaShoveManager.ReSetGridDataOfEntity(entity,true) end end end function MoveSystem.OnAttackEnter(entity ,skillData) local comp_Move = entity.components.move comp_Move:SetIgnoreOthersShoveMe(skillData.IgnoreBeShoved) --z = 0 end function MoveSystem.OnAttackQuit(entity) local comp_Move = entity.components.move comp_Move:SetIgnoreOthersShoveMe(false) end --[[ Tick --]] function MoveSystem.OnLogicUpdate(entity) local comp_Move = entity.components.move comp_Move.LastFrameLogicPos:Reset(comp_Move.LogicPos) comp_Move.LogicMoveDir:Reset(comp_Move.WantMoveDir) local comp_Buff = entity.components.buff --被动位移 if comp_Buff.CurrentBuffHitType ~= LuaConst.BuffHitType.None then local timeScale = entity.components.timeScale:GetCurTimeScale() temp_newPos:Reset(entity.components.hit.HitAddPos):Mul(timeScale):Add(comp_Move.LogicPos) private.SetPos(comp_Move, temp_newPos, entity) return end private.UpdateMove(entity,comp_Move, not comp_Buff.CurrentBuffStates:Get(LuaConst.SpecialBuffs.CanMove)) end function MoveSystem.OnLogicUpdate_NPC(entity) local comp_Move = entity.components.move comp_Move.LogicMoveDir:Reset(comp_Move.WantMoveDir) private.UpdateMove(entity,comp_Move) end local temp_distSqr = newV1(0) local temp_passedFrame = newV1(0) local temp_lastPassedFrame = newV1(0) local temp_back = newV2(0,0) function private.UpdateMove(entity, comp_Move, canNotMove) if LevelManager.IsTown then --主城可以访问MDL if MDL.Team.IsTrainFollowing(entity) or SyncMoveManager.IsFollowingNPC(entity) then --在主城里,单位如果处于火车跟随状态中,不进行移动的Update,会由SyncMoveManager来移动,所以这里直接return。 -- 或者跟随者镖车 return end end local components=entity.components local comp_Anim = components.anim local comp_TimeScale = components.timeScale local timeScale = comp_TimeScale:GetCurTimeScale() if comp_Anim.CurMoveMode == LuaConst.MoveMode.ByMoveManual then if canNotMove then return end --骑马移动 if entity:CheckHasBuffState(LuaConst.SpecialBuffs.InRiding) then private.RideHorseMove(comp_Move,timeScale ,entity) elseif entity.components.drive and entity.components.drive.BeDrived and entity.components.drive:GetDriveData() then -- 载具移动 private.DriveMove( comp_Move , timeScale ,entity) else if comp_Move.ForceSyncPosEntity then temp_newPos:Reset(comp_Move.ForceSyncPosEntity:GetLogicPos()) private.SetPos(comp_Move, temp_newPos, entity) else local realSpeed = components.attr:GetAttrValue(LuaConst.AttrType.spd) if realSpeed > FP_Const_Zero and comp_Move.LogicMoveDir ~= FP_Const_Vector2_Zero then temp_addPos:Reset(comp_Move.LogicMoveDir):Normalize() temp_addPos:Mul(realSpeed):Mul(LuaConst.TimeSpan):Mul(timeScale) temp_addPos:SqrMagnitude(temp_distSqr) if comp_Move.WantPos and not IsDistanceSqrGreater(comp_Move.WantPos, comp_Move.LogicPos, temp_distSqr) then temp_newPos:Reset(comp_Move.WantPos) private.SetPos(comp_Move, temp_newPos, entity) else private.SetPos(comp_Move, temp_addPos:Add(comp_Move.LogicPos), entity) end else temp_newPos:Reset(comp_Move.LogicPos) private.SetPos(comp_Move, temp_newPos, entity) -- 把自己的原位置给自己设置一下目的:计算挤压 end end end elseif comp_Anim.CurMoveMode == LuaConst.MoveMode.ByAnimation then if not comp_Anim.CurAnimMoveData or comp_Anim.CurAnimDataLock or comp_Anim.LockCurAnimMove then return end if components.aiBase.CurStateType == LuaConst.StateType.Wander and canNotMove then return end if entity.components.drive and entity.components.drive.DriveEntity then -- 驾驶时如果强制释放出了技能,不应该有移动 return end if comp_Move.ForceSyncPosEntity then -- 有强制同步位置时如果强制释放出了技能,不应该有移动 temp_newPos:Reset(comp_Move.ForceSyncPosEntity:GetLogicPos()) private.SetPos(comp_Move, temp_newPos, entity) return end --判断技能索敌时 贴上目标后 不移动 local target = components.target.Target local curSkillData = components.skillBase.CurSkillData if target and curSkillData and curSkillData.MeetAimStop then local mysize = math_max(components.base.CurModelData.ShoveDiameterX,components.base.CurModelData.ShoveDiameterZ) local othersize = math_max(target.components.base.CurModelData.ShoveDiameterX,target.components.base.CurModelData.ShoveDiameterZ) local dis = tempV1:Reset(mysize + othersize):Mul(0.71) --外接圆半径 local skillCanMove = IsDistanceSqrGreater(target.components.move.LogicPos, comp_Move.LogicPos, dis:Mul(dis) ) if not skillCanMove then --除了位置判断,朝向判断也需要判定。若是远离目标,也不应该移动(判断cosα <0判断身后) local aDir = temp_back:Reset(target.components.move.LogicPos):Sub(comp_Move.LogicPos) local cosA = FP.V2.Dot(aDir,comp_Move.LogicRotateDir) skillCanMove = cosA <= FP_Const_Zero end if not skillCanMove then if not components.skillBase.HasMeetTarget then components.skillBase.HasMeetTarget = true BattleEventSystem.OnEntitySkillMeetTarget(entity,curSkillData) end return end end if comp_Anim.StatePassTime <= comp_Anim.StateLastPassTime then return end temp_passedFrame:Reset(comp_Anim.StatePassTime):Div(LuaConst.TimeSpanMs) temp_lastPassedFrame:Reset(comp_Anim.StateLastPassTime):Div(LuaConst.TimeSpanMs) local frameCount = comp_Anim.CurAnimDataCount local xMoveList = comp_Anim.CurAnimMoveData.XArray local zMoveList = comp_Anim.CurAnimMoveData.ZArray --comp_Anim.AnimDisPercent 会在AnimSystem里管理,当过了MSEndTime毫秒之后,会被重置为1 -- 每一帧的位移 ,都会算进去 ,如果在某时刻如2.5帧的时候恢复到1倍速度 ,那么以后每帧的位移都要算半个 ,2.5-3.5 ,3.5-4.5 --[[ 1 2 3 4 -- 帧数 |----------|----------|----------|----------| 移动的数据 0 1 2 3 4 -- 时间t(50ms的倍数) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -- 帧数 |----|----|----|----|----|----|----|----|----|----|----|----|----|----|----| 移动的数据 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -- 时间t(50ms的倍数) --]] --print("----------------------------------------------------------------") local moveDataIndex = 0 local lastFrameIndex = math_ceil(tonumberV1(temp_lastPassedFrame)) local currFrameIndex = math_floor(tonumberV1(temp_passedFrame)) if currFrameIndex >= lastFrameIndex then -- 增加前余数据 temp_lastLeftTime:Reset(lastFrameIndex):Sub(temp_lastPassedFrame) -- 需要添加的上次帧剩余 if temp_lastLeftTime > FP_Const_Zero then moveDataIndex = lastFrameIndex temp_animMoveData:Reset(xMoveList and xMoveList[moveDataIndex] or 0,zMoveList and zMoveList[moveDataIndex] or 0):Mul(comp_Anim.MoveSize):Mul(temp_lastLeftTime) --z = z + (zMoveList[moveDataIndex] or 0) * temp_lastLeftTime[1] /1000 --print(" 跨帧-前余: 帧号: ," ,moveDataIndex , "总位移: ",z , "当前计算的区间:" ,FP.tonumberV1(temp_lastPassedFrame) , " - " ,FP.tonumberV1(temp_passedFrame) ,"小数:" ,FP.tonumberV1(temp_lastLeftTime )) private.SetPosByAnim(comp_Anim, comp_Move, temp_animMoveData, entity) end -- 增加后余数据 temp_cutExrTime:Reset(temp_passedFrame):Sub(currFrameIndex) -- 需要添加的当前帧多余 if temp_cutExrTime > FP_Const_Zero then moveDataIndex = currFrameIndex + 1 temp_animMoveData:Reset(xMoveList and xMoveList[moveDataIndex] or 0,zMoveList and zMoveList[moveDataIndex] or 0):Mul(comp_Anim.MoveSize):Mul(temp_cutExrTime) --z = z + (zMoveList[moveDataIndex]or 0) * temp_cutExrTime[1] /1000 --print(" 跨帧-后余: 帧号: ," ,moveDataIndex , "总位移: ",z , "当前计算的区间:" ,FP.tonumberV1(temp_lastPassedFrame) , " - " ,FP.tonumberV1(temp_passedFrame) ,"小数:" ,FP.tonumberV1(temp_cutExrTime )) private.SetPosByAnim(comp_Anim, comp_Move, temp_animMoveData, entity) end -- 增加中间数据 if currFrameIndex > frameCount then currFrameIndex = frameCount end for i = lastFrameIndex + 1 , currFrameIndex do moveDataIndex = i temp_animMoveData:Reset(xMoveList and xMoveList[moveDataIndex] or 0,zMoveList and zMoveList[moveDataIndex] or 0):Mul(comp_Anim.MoveSize) --z = z + zMoveList[moveDataIndex] --print(" N > > > 帧:," ,moveDataIndex , " 总位移:",z ) private.SetPosByAnim(comp_Anim, comp_Move, temp_animMoveData, entity) end end --如果 currFrameIndex < lastFrameIndex 说明时间缩放小于1 ,且此时 没有跨帧(如果满足这条件,上面的计算都不会有移动量的) if lastFrameIndex > currFrameIndex then temp_durationTime:Reset(temp_passedFrame):Sub(temp_lastPassedFrame) moveDataIndex = lastFrameIndex temp_animMoveData:Reset(xMoveList and xMoveList[moveDataIndex] or 0,zMoveList and zMoveList[moveDataIndex] or 0):Mul(comp_Anim.MoveSize):Mul(temp_durationTime) --z = z + (zMoveList[moveDataIndex]or 0) * temp_durationTime[1] /1000 --print(" 同一帧内: 帧号: ," ,moveDataIndex , "总位移: ",z , "当前计算的区间:" ,FP.tonumberV1(temp_lastPassedFrame) , " - " ,FP.tonumberV1(temp_passedFrame) ) private.SetPosByAnim(comp_Anim, comp_Move, temp_animMoveData, entity) end end end function private.SetPosByAnim(comp_Anim, comp_Move, temp_animMoveData, entity) GetOffsetToForward(comp_Anim.CurAnimStartDir, temp_animMoveData,temp_addPos) temp_addPos:Mul(comp_Anim.AnimDisPercent) temp_newPos:Reset(comp_Move.LogicPos):Add(temp_addPos) private.SetPos(comp_Move, temp_newPos, entity)-- GWS :说明:以下每个数据上都有SetPos是为了防止时间缩放一次移动量过大,会穿过墙 end --[[ 直接设置位置( 忽略锚点) --]] function private.SetInitPos(moveComponent, pos, ignoreBlock) moveComponent:SetLogicPos(ignoreBlock and pos or LuaShoveManager.GetFinalInitPos(pos), false, true) moveComponent.LastLogicPos:Reset(pos) end function private.SetPos(comp_Move, newPos, entity) local components = entity.components if comp_Move.GravityForceEntity then -- 有额外受力时,添加上移动量 temp_extraAddPos:Reset(comp_Move.GravityForceEntity:GetLogicPos()) temp_extraAddPos:Sub(comp_Move.LogicPos) if FP_Math_Abs(temp_extraAddPos.x) > comp_Move.GravitySpeed and FP_Math_Abs(temp_extraAddPos.z) > comp_Move.GravitySpeed then temp_extraAddPos:Normalize() temp_extraAddPos:Mul(comp_Move.GravitySpeed) end newPos:Add(temp_extraAddPos) end --同步位置协议 if entity._logicInitData.IsPlayerSelf then if comp_Move.LogicPos ~= comp_Move.ServerPos then --服务器需求:如果客户端位置是服务器拉回的,不要给服务器发送move或者stop if comp_Move.LastLogicPos == comp_Move.LogicPos then SyncMoveManager.C2SRoleMoveOrStop(0) else SyncMoveManager.C2SRoleMoveOrStop(1) end end end local priority = comp_Move.ShovePriority if not comp_Move.IgnoreOthersShoveMe then --new↓ --减少一些gc和运算 comp_Move.ShoveForce:SqrMagnitude(tempV1) --将ShoveForce的长度的平方写入tempV1 if tempV1 > LimitSqr then newPos:Add(comp_Move.ShoveForce) end --new↑ -- old↓ -- if IsDistanceSqrGreater(comp_Move.ShoveForce, FP_Const_Vector2_Zero, LimitSqr) then -- newPos:Add(comp_Move.ShoveForce) -- end -- old↑ end comp_Move.LastLogicPos:Reset(comp_Move.LogicPos) if comp_Move.LogicPos ~= newPos then local ignoreBlock = components.buff and components.buff:GetBuffUpdateData(LuaConst.SpecialBuffs.IgnoreBlock) or comp_Move.isInCliff or comp_Move.ForceSyncPosEntity~=nil if ignoreBlock then -- 忽略地形阻挡 comp_Move:SetLogicPos(newPos) else local isCliff = LuaShoveManager.GetFinalPos(comp_Move.LogicPos, newPos, priority,comp_Move:CanEnterCliff(), temp_FinalPos) if isCliff and isCliff ~= comp_Move.isInCliff then SystemManager.SetKeepFallDown(entity,true) end comp_Move:SetLogicPos(temp_FinalPos,isCliff) end SystemManager.OnMove(entity) end if priority > 50 and components.attr:IsAlive() then local originX, originZ = LuaShoveManager.ConvertPosToGrid(comp_Move.LastLogicPos) local finalX, finalZ = LuaShoveManager.ConvertPosToGrid(comp_Move.LogicPos) local lastShoveRotate = entity:GetLastShoveRotate() local curShoveRotate = entity:GetShoveRotate() if finalX ~= originX or finalZ ~= originZ or lastShoveRotate ~= curShoveRotate then --local sizeX = entity.components.base.CurModelData.ShoveDiameterX --local sizeZ = entity.components.base.CurModelData.ShoveDiameterZ --LuaShoveManager.ReSetGridDataByPriorityWithRotate(sizeX,sizeZ,lastShoveRotate,comp_Move.LastLogicPos) LuaShoveManager.ReSetGridDataOfEntity(entity,false) --LuaShoveManager.SetGridDataByPriorityWithRotate(sizeX,sizeZ,curShoveRotate,priority, comp_Move.LogicPos, true, true) LuaShoveManager.SetGridDataByPriorityOfEntity(entity,priority,true,true) end end end function MoveSystem.ForbidMoveJoystick(entity) entity.components.move:ForbidMoveJoystick() end function MoveSystem.CancelForbidMoveJoystick(entity) entity.components.move:CancelForbidMoveJoystick() end function MoveSystem.OnOffHorse(entity) local moveComp = entity.components.move moveComp.RideSpeedRate:Reset() moveComp.RideAngleSpeedRate:Reset() moveComp.RideMaxSpeed:Reset() moveComp.RideMaxAngleSpeed:Reset() end --骑马时的移动,由于马刹车也需要向前移动 且 马的移动朝向不是movedir 而是LogicRotateDir ,所以和其他的移动分开了 function private.RideHorseMove(comp_Move,timeScale ,entity) if comp_Move.RideSpeedRate > FP_Const_Zero then local realSpeed = entity.components.attr:GetAttrValue(LuaConst.AttrType.ridespd) temp_addPos:Reset(comp_Move.LogicRotateDir) temp_addPos:Mul(realSpeed):Mul(comp_Move.RideSpeedRate):Mul(LuaConst.TimeSpan):Mul(timeScale) temp_addPos:SqrMagnitude(temp_distSqr) if comp_Move.WantPos and not IsDistanceSqrGreater(comp_Move.WantPos, comp_Move.LogicPos, temp_distSqr) then temp_newPos:Reset(comp_Move.WantPos) private.SetPos(comp_Move, temp_newPos, entity) else private.SetPos(comp_Move, temp_addPos:Add(comp_Move.LogicPos), entity) end end end function MoveSystem.OnRideHorse(entity) if entity.components.aiBase.CurStateType == LuaConst.StateType.Move then local realSpeed = entity.components.attr:GetAttrValue(LuaConst.AttrType.ridespd) local curSpeed = entity.components.attr:GetAttrValue(LuaConst.AttrType.spd) entity.components.move.RideSpeedRate:Reset(curSpeed):Div(realSpeed) end end function MoveSystem.OnDrive(driver, car, becomeOne) local driverMove = driver.components.move driverMove:RemoveAllPosAnchorButLevel() -- 上车时,强制清理锚点。如果人和车一起动,则车会有锚点限制 ;如果不随车移动,则人不受控制也是在原地的,故符合预期。 driverMove.LastLogicPos:Reset(driverMove.LogicPos) driverMove:SetLogicPos(car.components.move.LogicPos) -- 如果car没有驾驶参数,则一定是让他们变为一体 if car.components.drive:GetDriveData() == nil then becomeOne = true end if becomeOne then driver.components.move:SetForceSyncPosEntity(car) end end function MoveSystem.OnOffDrive(driverEntity, carEntity) if carEntity == driverEntity.components.move.ForceSyncPosEntity then driverEntity.components.move:SetForceSyncPosEntity(nil) end end -- 驾驶载具时的移动 function private.DriveMove( comp_Move , timeScale ,entity) local carDriveComp = entity.components.drive local firstPerspective = carDriveComp.IsFirstPerspective local realSpeed = entity.components.attr:GetAttrValue(LuaConst.AttrType.spd) if realSpeed > FP_Const_Zero then local needMove = false if firstPerspective then if comp_Move.StepOnAccelerator then needMove = true end elseif comp_Move.LogicMoveDir ~= FP_Const_Vector2_Zero then needMove = true end if needMove then local logicMoveDir = comp_Move.LogicMoveDir local logicRotateDir = comp_Move.LogicRotateDir local isFreeMove = carDriveComp.IsFreeMove if isFreeMove then temp_addPos:Reset(logicMoveDir):Normalize() -- 看策划需求是否用: 非U型轨迹(直线) else temp_addPos:Reset(logicRotateDir):Normalize() -- 看策划需求是否用: U型轨迹 end -- 第三人称驾驶车 ,如果在后30度 ,则需要停止转动 ,向后移动 local cosA = FP.V2.Dot(logicMoveDir,logicRotateDir) if cosA < LuaConst.BackCarAngleCos then temp_addPos:Negative() temp_addPos:Mul(carDriveComp.DriveData.ReverseSpeed) end temp_addPos:Mul(realSpeed):Mul(LuaConst.TimeSpan):Mul(timeScale) private.SetPos(comp_Move, temp_addPos:Add(comp_Move.LogicPos), entity) -- 一旦载具移动了 ,人也要跟随移动 (如果不移动,1. 车远离了人,就会没有下车按钮了 2. 策划想要的车触发关卡事件 需要额外的写代码) ; -- 如果想实现,操作车移动,人下车后还是在上车原地的话 ,用battleeffect实现 。下车事件已经写了 。 -- 对于人跟随车和不跟随车的实现 ,两种方法都能实现,考虑目前状况 ,暂时用方法 :默认人随车动 ,若下车不想在车中心位置,可用battleeffect实现 local driverEntity = carDriveComp.BeDrivedByEntity local driverMove = driverEntity.components.move driverMove.LastLogicPos:Reset(driverMove.LogicPos) driverMove:SetLogicPos(comp_Move.LogicPos) else temp_newPos:Reset(comp_Move.LogicPos) private.SetPos(comp_Move, temp_newPos, entity) -- 把自己的原位置给自己设置一下目的:计算挤压 end end end return MoveSystem