using System; using System.Collections.Generic; using UnityEngine; namespace ET { [ObjectSystem] public class MoveComponentDestroySystem : DestroySystem { public override void Destroy(MoveComponent self) { self.Clear(); } } [ObjectSystem] public class MoveComponentAwakeSystem : AwakeSystem { public override void Awake(MoveComponent self) { self.StartTime = 0; self.StartPos = Vector3.zero; self.NeedTime = 0; self.MoveTimer = 0; self.Callback = null; self.Targets.Clear(); self.Speed = 0; self.N = 0; } } public static class MoveComponentSystem { public static bool IsArrived(this MoveComponent self) { return self.Targets.Count == 0; } public static bool ChangeSpeed(this MoveComponent self, float speed) { if (self.IsArrived()) { return false; } if (speed < 0.0001) { return false; } Unit unit = self.GetParent(); using (ListComponent path = ListComponent.Create()) { self.MoveForward(true); path.List.Add(unit.Position); // 第一个是Unit的pos for (int i = self.N; i < self.Targets.Count; ++i) { path.List.Add(self.Targets[i]); } self.MoveToAsync(path.List, speed).Coroutine(); } return true; } public static async ETTask MoveToAsync(this MoveComponent self, List targets, float speed, ETCancellationToken cancellationToken = null) { self.Stop(); foreach (var item in targets) { self.Targets.Add(item); } self.IsTurnHorizontal = true; self.Speed = speed; ETTaskCompletionSource tcs = new ETTaskCompletionSource(); self.Callback = (ret) => { tcs.SetResult(ret); }; Game.EventSystem.Publish_Sync(new EventType.MoveStart() { unit = self.GetParent() }); self.StartMove(); void CancelAction() { self.Stop(); } bool moveRet; try { cancellationToken?.Add(CancelAction); moveRet = await tcs.Task; } finally { cancellationToken?.Remove(CancelAction); } if (moveRet) { Game.EventSystem.Publish_Sync(new EventType.MoveStop() { unit = self.GetParent() }); } return moveRet; } public static void MoveForward(this MoveComponent self, bool needCancel) { Unit unit = self.GetParent(); long timeNow = TimeHelper.ClientNow(); long moveTime = timeNow - self.StartTime; while (true) { if (moveTime <= 0) { return; } // 计算位置插值 if (moveTime >= self.NeedTime) { unit.Position = self.NextTarget; unit.YAngle = self.To; } else { // 计算位置插值 float amount = moveTime * 1f / self.NeedTime; if (amount > 0) { Vector3 newPos = Vector3.Lerp(self.StartPos, self.NextTarget, amount); unit.Position = newPos; } // 计算方向插值 unit.YAngle = self.To; } moveTime -= self.NeedTime; // 表示这个点还没走完,等下一帧再来 if (moveTime < 0) { return; } // 到这里说明这个点已经走完 // 如果是最后一个点 if (self.N >= self.Targets.Count - 1) { unit.Position = self.NextTarget; unit.YAngle = self.To; Action callback = self.Callback; self.Callback = null; self.Clear(); callback?.Invoke(!needCancel); return; } self.SetNextTarget(); } } private static void StartMove(this MoveComponent self) { Unit unit = self.GetParent(); self.BeginTime = TimeHelper.ClientNow(); self.StartTime = self.BeginTime; self.SetNextTarget(); self.MoveTimer = TimerComponent.Instance.NewFrameTimer(() => { try { self.MoveForward(false); } catch (Exception e) { Log.Error($"move timer error: {unit.Id}\n{e}"); } } ); } private static void SetNextTarget(this MoveComponent self) { Unit unit = self.GetParent(); ++self.N; // 时间计算用服务端的位置, 但是移动要用客户端的位置来插值 Vector3 v = self.GetFaceV(); float distance = v.magnitude; // 插值的起始点要以unit的真实位置来算 self.StartPos = unit.Position; self.StartTime += self.NeedTime; self.NeedTime = (long)(distance / self.Speed * 1000); self.To = v.x > 0 ? 0 : 180; unit.YAngle = self.To; } private static Vector3 GetFaceV(this MoveComponent self) { return self.NextTarget - self.PreTarget; } public static bool FlashTo(this MoveComponent self, Vector3 target) { Unit unit = self.GetParent(); unit.Position = target; return true; } public static bool MoveTo(this MoveComponent self, Vector3 target, float speed, bool isTurnHorizontal = false) { if (speed < 0.001) { Log.Error($"speed is 0 {self.GetParent().Id} {speed}"); return false; } self.Stop(); self.IsTurnHorizontal = isTurnHorizontal; self.Targets.Add(self.GetParent().Position); self.Targets.Add(target); self.Speed = speed; self.StartMove(); return true; } public static void Stop(this MoveComponent self) { if (self.Targets.Count > 0) { self.MoveForward(true); } self.Clear(); } public static void Clear(this MoveComponent self) { self.StartTime = 0; self.StartPos = Vector3.zero; self.BeginTime = 0; self.NeedTime = 0; TimerComponent.Instance.Remove(ref self.MoveTimer); self.Targets.Clear(); self.Speed = 0; self.N = 0; self.IsTurnHorizontal = false; if (self.Callback != null) { Action callback = self.Callback; self.Callback = null; callback.Invoke(false); } } } }