diff --git a/logic/GameClass/GameObj/Character.cs b/logic/GameClass/GameObj/Character.cs
new file mode 100644
index 0000000..fc16f6b
--- /dev/null
+++ b/logic/GameClass/GameObj/Character.cs
@@ -0,0 +1,457 @@
+using Preparation.GameData;
+using Preparation.Interface;
+using Preparation.Utility;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace GameClass.GameObj
+{
+ public partial class Character : GameObj, ICharacter // 负责人LHR摆烂终了
+ {
+ private readonly object beAttackedLock = new();
+
+#region 角色的基本属性及方法,包括与道具的交互方法
+ /*
+ //THUAI5子弹
+ ///
+ /// 装弹冷却
+ ///
+ protected int cd;
+ public int CD
+ {
+ get => cd;
+ private
+ set {
+ lock (gameObjLock)
+ {
+ cd = value;
+ Debugger.Output(this, string.Format("'s CD has been set to: {0}.", value));
+ }
+ }
+ }
+ public int OrgCD { get; protected set; }
+ protected int maxBulletNum;
+ public int MaxBulletNum => maxBulletNum; // 人物最大子弹数
+ protected int bulletNum;
+ public int BulletNum => bulletNum; // 目前持有的子弹数
+ */
+ public int MaxHp { get; protected set; } // 最大血量
+ protected int hp;
+ public int HP
+ {
+ get => hp;
+ set {
+ lock (gameObjLock)
+ hp = value <= MaxHp ? value : MaxHp;
+ }
+ }
+ private int deathCount = 0;
+ public int DeathCount => deathCount; // 玩家的死亡次数
+
+ private int score = 0;
+ public int Score
+ {
+ get => score;
+ }
+
+ //public double AttackRange => BulletFactory.BulletAttackRange(this.BulletOfPlayer);
+
+ private double vampire = 0; // 回血率:0-1之间
+ public double Vampire
+ {
+ get => vampire;
+ set {
+ if (value > 1)
+ lock (gameObjLock)
+ vampire = 1;
+ else if (value < 0)
+ lock (gameObjLock)
+ vampire = 0;
+ else
+ lock (gameObjLock)
+ vampire = value;
+ }
+ }
+ private double OriVampire { get; }
+
+ /*
+ public readonly BulletType OriBulletOfPlayer;
+ private BulletType bulletOfPlayer;
+ public BulletType BulletOfPlayer
+ {
+ get => bulletOfPlayer;
+ set {
+ lock (gameObjLock)
+ bulletOfPlayer = value;
+ }
+ }
+ */
+
+ private Prop? propInventory;
+ public Prop? PropInventory // 持有的道具
+ {
+ get => propInventory;
+ set {
+ lock (gameObjLock)
+ {
+ propInventory = value;
+ Debugger.Output(this, " prop becomes " + (PropInventory == null ? "null" : PropInventory.ToString()));
+ }
+ }
+ }
+
+ ///
+ /// 使用物品栏中的道具
+ ///
+ /// 被使用的道具
+ public Prop? UseProp()
+ {
+ lock (gameObjLock)
+ {
+ var oldProp = PropInventory;
+ PropInventory = null;
+ return oldProp;
+ }
+ }
+
+ ///
+ /// 是否正在更换道具(包括捡起与抛出)
+ ///
+ private bool isModifyingProp = false;
+ public bool IsModifyingProp
+ {
+ get => isModifyingProp;
+ set {
+ lock (gameObjLock)
+ {
+ isModifyingProp = value;
+ }
+ }
+ }
+
+ ///
+ /// 是否在隐身
+ ///
+ private bool isInvisible = false;
+ public bool IsInvisible
+ {
+ get => isInvisible;
+ set {
+ lock (gameObjLock)
+ {
+ isInvisible = value;
+ }
+ }
+ }
+ /*
+ ///
+ /// 进行一次远程攻击
+ ///
+ /// 子弹初始位置偏差值
+ /// 攻击操作发出的子弹
+ public Bullet? RemoteAttack(XY posOffset)
+ {
+ if (TrySubBulletNum())
+ return ProduceOneBullet(this.Position + posOffset);
+ else
+ return null;
+ }
+ protected Bullet? ProduceOneBullet(XY initPos)
+ {
+ var newBullet = BulletFactory.GetBullet(this);
+ newBullet?.SetPosition(initPos);
+ return newBullet;
+ }
+
+ ///
+ /// 尝试将子弹数量减1
+ ///
+ /// 减操作是否成功
+ private bool TrySubBulletNum()
+ {
+ lock (gameObjLock)
+ {
+ if (bulletNum > 0)
+ {
+ --bulletNum;
+ return true;
+ }
+ return false;
+ }
+ }
+ ///
+ /// 尝试将子弹数量加1
+ ///
+ /// 加操作是否成功
+ public bool TryAddBulletNum()
+ {
+ lock (gameObjLock)
+ {
+ if (bulletNum < maxBulletNum)
+ {
+ ++bulletNum;
+ return true;
+ }
+ return false;
+ }
+ }
+ */
+ ///
+ /// 尝试加血
+ ///
+ /// 欲加量
+ /// 加操作是否成功
+ public bool TryAddHp(int add)
+ {
+ if (hp < MaxHp)
+ {
+ lock (gameObjLock)
+ hp = MaxHp > hp + add ? hp + add : MaxHp;
+ Debugger.Output(this, " hp has added to: " + hp.ToString());
+ return true;
+ }
+ return false;
+ }
+ ///
+ /// 尝试减血
+ ///
+ /// 减血量
+ /// 减操作是否成功
+ public bool TrySubHp(int sub)
+ {
+ if (hp > 0)
+ {
+ lock (gameObjLock)
+ hp = 0 >= hp - sub ? 0 : hp - sub;
+ Debugger.Output(this, " hp has subed to: " + hp.ToString());
+ return true;
+ }
+ return false;
+ }
+ ///
+ /// 增加死亡次数
+ ///
+ /// 当前死亡次数
+ private int AddDeathCount()
+ {
+ lock (gameObjLock)
+ {
+ ++deathCount;
+ return deathCount;
+ }
+ }
+ ///
+ /// 加分
+ ///
+ /// 增加量
+ public void AddScore(int add)
+ {
+ lock (gameObjLock)
+ {
+ score += add;
+ Debugger.Output(this, " 's score has been added to: " + score.ToString());
+ }
+ }
+ ///
+ /// 减分
+ ///
+ /// 减少量
+ public void SubScore(int sub)
+ {
+ lock (gameObjLock)
+ {
+ score -= sub;
+ Debugger.Output(this, " 's score has been subed to: " + score.ToString());
+ }
+ }
+ /*
+ ///
+ /// 遭受攻击
+ ///
+ ///
+ ///
+ /// 伤害来源
+ /// 人物在受到攻击后死了吗
+ public bool BeAttack(Bullet bullet)
+ {
+
+ lock (beAttackedLock)
+ {
+ if (hp <= 0)
+ return false; // 原来已经死了
+ if (bullet.Parent.TeamID != this.TeamID)
+ {
+
+ if (HasShield)
+ {
+ if (bullet.HasSpear)
+ _ = TrySubHp(bullet.AP);
+ else
+ return false;
+ }
+ else
+ {
+ TrySubHp(bullet.AP);
+ }
+#if DEBUG
+ Console.WriteLine($"PlayerID:{ID} is being shot! Now his hp is {hp}.");
+#endif
+ if (hp <= 0)
+ TryActivatingLIFE(); // 如果有复活甲
+ }
+ return hp <= 0;
+ }
+ }
+ ///
+ /// 攻击被反弹,反弹伤害不会再被反弹
+ ///
+ ///
+ ///
+ /// 反弹伤害者
+ /// 是否因反弹伤害而死
+ private bool BeBounced(int subHP, bool hasSpear, Character? bouncer)
+ {
+ lock (beAttackedLock)
+ {
+ if (hp <= 0)
+ return false;
+ if (!(bouncer?.TeamID == this.TeamID))
+ {
+ if (hasSpear || !HasShield)
+ _ = TrySubHp(subHP);
+ if (hp <= 0)
+ TryActivatingLIFE();
+ }
+ return hp <= 0;
+ }
+ }
+ */
+ ///
+ /// 角色所属队伍ID
+ ///
+ private long teamID = long.MaxValue;
+ public long TeamID
+ {
+ get => teamID;
+ set {
+ lock (gameObjLock)
+ {
+ teamID = value;
+ Debugger.Output(this, " joins in the team: " + value.ToString());
+ }
+ }
+ }
+ private long playerID = long.MaxValue;
+ public long PlayerID
+ {
+ get => playerID;
+ set {
+ lock (gameObjLock)
+ {
+ playerID = value;
+ }
+ }
+ }
+ ///
+ /// 角色携带的信息
+ ///
+ private string message = "THUAI5";
+ public string Message
+ {
+ get => message;
+ set {
+ lock (gameObjLock)
+ {
+ message = value;
+ }
+ }
+ }
+#endregion
+
+#region 角色拥有的buff相关属性、方法
+ public void AddMoveSpeed(int buffTime, double add = 2.0) => buffManeger.AddMoveSpeed(add, buffTime, newVal =>
+ { MoveSpeed = newVal < GameData.characterMaxSpeed ? newVal : GameData.characterMaxSpeed; },
+ OrgMoveSpeed);
+ public bool HasFasterSpeed => buffManeger.HasFasterSpeed;
+
+ public void AddShield(int shieldTime) => buffManeger.AddShield(shieldTime);
+ public bool HasShield => buffManeger.HasShield;
+
+ public void AddLIFE(int LIFETime) => buffManeger.AddLIFE(LIFETime);
+ public bool HasLIFE => buffManeger.HasLIFE;
+
+ public void AddSpear(int spearTime) => buffManeger.AddSpear(spearTime);
+ public bool HasSpear => buffManeger.HasSpear;
+
+ private Array buffTypeArray = Enum.GetValues(typeof(BuffType));
+ public Dictionary Buff
+ {
+ get {
+ Dictionary buff = new Dictionary();
+ foreach (BuffType type in buffTypeArray)
+ {
+ if (type != BuffType.Null)
+ buff.Add(type, GetBuffStatus(type));
+ }
+ return buff;
+ }
+ }
+ private bool GetBuffStatus(BuffType type)
+ {
+ switch (type)
+ {
+ case BuffType.Spear:
+ return this.HasSpear;
+ case BuffType.AddSpeed:
+ return this.HasFasterSpeed;
+ case BuffType.Shield:
+ return this.HasShield;
+ case BuffType.AddLIFE:
+ return this.HasLIFE;
+ default:
+ return false;
+ }
+ }
+ private void TryActivatingLIFE()
+ {
+ if (buffManeger.TryActivatingLIFE())
+ {
+ hp = MaxHp;
+ }
+ }
+#endregion
+ public override void Reset() // 要加锁吗?
+ {
+ _ = AddDeathCount();
+ base.Reset();
+ this.MoveSpeed = OrgMoveSpeed;
+ HP = MaxHp;
+ PropInventory = null;
+ //BulletOfPlayer = OriBulletOfPlayer;
+ //lock (gameObjLock)
+ // bulletNum = maxBulletNum;
+
+ buffManeger.ClearAll();
+ IsInvisible = false;
+ this.Vampire = this.OriVampire;
+ }
+ public override bool IsRigid => true;
+ public override ShapeType Shape => ShapeType.Circle;
+ protected override bool IgnoreCollideExecutor(IGameObj targetObj)
+ {
+ if (targetObj.Type == GameObjType.BirthPoint)
+ {
+ if (object.ReferenceEquals(((BirthPoint)targetObj).Parent, this)) // 自己的出生点可以忽略碰撞
+ {
+ return true;
+ }
+ }
+ else if (targetObj.Type == GameObjType.Prop) // 自己队的地雷忽略碰撞
+ {
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/logic/GameEngine/CollisionChecker.cs b/logic/GameEngine/CollisionChecker.cs
new file mode 100644
index 0000000..93e0074
--- /dev/null
+++ b/logic/GameEngine/CollisionChecker.cs
@@ -0,0 +1,224 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using Preparation.Interface;
+using Preparation.Utility;
+using Preparation.GameData;
+
+namespace GameEngine
+{
+ internal class CollisionChecker
+ {
+ ///
+ /// 碰撞检测,如果这样行走是否会与之碰撞,返回与之碰撞的物体
+ ///
+ /// 移动的物体
+ /// 移动的位移向量
+ /// 和它碰撞的物体
+ public IGameObj? CheckCollision(IMoveable obj, XY moveVec)
+ {
+ XY nextPos = obj.Position + XY.VectorToXY(moveVec);
+ if (!obj.IsRigid)
+ {
+ if (gameMap.IsOutOfBound(obj))
+ return gameMap.GetOutOfBound(nextPos);
+ return null;
+ }
+ //在列表中检查碰撞
+ Func, ReaderWriterLockSlim, IGameObj?> CheckCollisionInList =
+ (IEnumerable lst, ReaderWriterLockSlim listLock) =>
+ {
+ IGameObj? collisionObj = null;
+ listLock.EnterReadLock();
+ try
+ {
+ foreach (var listObj in lst)
+ {
+ if (obj.WillCollideWith(listObj, nextPos))
+ {
+ collisionObj = listObj;
+ break;
+ }
+ }
+ }
+ finally { listLock.ExitReadLock(); }
+ return collisionObj;
+ };
+
+ IGameObj? collisionObj = null;
+ foreach (var list in lists)
+ {
+ if ((collisionObj = CheckCollisionInList(list.Item1, list.Item2)) != null)
+ {
+ return collisionObj;
+ }
+ }
+
+ return null;
+ }
+ ///
+ /// /// 可移动物体(圆)向矩形物体移动时,可移动且不会碰撞的最大距离。直接用double计算,防止误差
+ ///
+ ///
+ /// 矩形的中心坐标
+ ///
+ //private double MaxMoveToSquare(IMoveable obj, IGameObj square)
+ //{
+ // double tmpMax;
+ // double angle = Math.Atan2(square.Position.y - obj.Position.y, square.Position.x - obj.Position.x);
+ // if (obj.WillCollideWith(square, obj.Position))
+ // tmpMax = 0;
+ // else tmpMax =
+ // Math.Abs(XYPosition.Distance(obj.Position, square.Position) - obj.Radius -
+ // (square.Radius / Math.Min(Math.Abs(Math.Cos(angle)), Math.Abs(Math.Sin(angle)))));
+ // return tmpMax;
+ //}
+
+ //private double FindMaxOnlyConsiderWall(IMoveable obj, Vector moveVec)
+ //{
+ // var desination = moveVec;
+ // double maxOnlyConsiderWall = moveVec.length;
+ // if (desination.length > 0) //如果length足够长,还是有可能穿墙的
+ // {
+ // XYPosition nextXY = Vector.Vector2XY(desination) + obj.Position + new XYPosition((int)(obj.Radius * Math.Cos(moveVec.angle)), (int)(obj.Radius * Math.Sin(moveVec.angle)));
+ // if (gameMap.IsWall(nextXY)) //对下一步的位置进行检查,但这里只是考虑移动物体的宽度,只是考虑下一步能达到的最远位置
+ // {
+ // maxOnlyConsiderWall = MaxMoveToSquare(obj, gameMap.GetCell(nextXY));
+ // }
+ // else //考虑物体宽度
+ // {
+ // double dist = 0;
+ // XYPosition nextXYConsiderWidth;
+ // nextXYConsiderWidth = nextXY + new XYPosition((int)(obj.Radius * Math.Cos(moveVec.angle + Math.PI / 4)), (int)(obj.Radius * Math.Sin(moveVec.angle + Math.PI / 4)));
+ // if (gameMap.IsWall(nextXYConsiderWidth)) //对下一步的位置进行检查,但这里只是考虑移动物体的宽度,只是考虑下一步能达到的最远位置
+ // {
+ // dist = MaxMoveToSquare(obj, gameMap.GetCell(nextXYConsiderWidth));
+ // if (dist < maxOnlyConsiderWall)
+ // maxOnlyConsiderWall = dist;
+ // }
+ // nextXYConsiderWidth = nextXY + new XYPosition((int)(obj.Radius * Math.Cos(moveVec.angle - Math.PI / 4)), (int)(obj.Radius * Math.Sin(moveVec.angle - Math.PI / 4)));
+ // if (gameMap.IsWall(nextXYConsiderWidth)) //对下一步的位置进行检查,但这里只是考虑移动物体的宽度,只是考虑下一步能达到的最远位置
+ // {
+ // dist = MaxMoveToSquare(obj, gameMap.GetCell(nextXYConsiderWidth));
+ // if (dist < maxOnlyConsiderWall)
+ // maxOnlyConsiderWall = dist;
+ // }
+ // }
+ // }
+ // return maxOnlyConsiderWall;
+ //}
+
+ ///
+ /// 寻找最大可能移动距离
+ ///
+ /// 移动物体,默认obj.Rigid为true
+ /// 下一步要到达的位置
+ /// 移动的位移向量,默认与nextPos协调
+ /// 最大可能的移动距离
+ public double FindMax(IMoveable obj, XY nextPos, XY moveVec)
+ {
+ double maxLen = (double)uint.MaxValue;
+ double tmpMax = maxLen; //暂存最大值
+
+ // 先找只考虑墙的最大距离
+ //double maxOnlyConsiderWall = FindMaxOnlyConsiderWall(obj, moveVec);
+ double maxDistance = maxLen;
+ foreach (var listWithLock in lists)
+ {
+ var lst = listWithLock.Item1;
+ var listLock = listWithLock.Item2;
+ listLock.EnterReadLock();
+ try
+ {
+ foreach (IGameObj listObj in lst)
+ {
+ //如果再走一步发生碰撞
+ if (obj.WillCollideWith(listObj, nextPos))
+ {
+ {
+ switch (listObj.Shape) //默认obj为圆形
+ {
+ case ShapeType.Circle:
+ {
+ //计算两者之间的距离
+ double mod = XY.Distance(listObj.Position, obj.Position);
+ int orgDeltaX = listObj.Position.x - obj.Position.x;
+ int orgDeltaY = listObj.Position.y - obj.Position.y;
+
+ if (mod < listObj.Radius + obj.Radius) //如果两者已经重叠
+ {
+ tmpMax = 0;
+ }
+ else
+ {
+ double tmp = mod - obj.Radius - listObj.Radius;
+ //计算能走的最长距离,好像这么算有一点误差?
+ tmp = tmp / Math.Cos(Math.Atan2(orgDeltaY, orgDeltaX) - moveVec.angle);
+ if (tmp < 0 || tmp > uint.MaxValue || tmp == double.NaN)
+ {
+ tmpMax = uint.MaxValue;
+ }
+ else tmpMax = tmp;
+ }
+ break;
+ }
+ case ShapeType.Square:
+ {
+ //if (obj.WillCollideWith(listObj, obj.Position))
+ // tmpMax = 0;
+ //else tmpMax = MaxMoveToSquare(obj, listObj);
+ //break;
+ if (obj.WillCollideWith(listObj, obj.Position))
+ tmpMax = 0;
+ else
+ {
+ //二分查找最大可能移动距离
+ int left = 0, right = (int)moveVec.length;
+ while (left < right - 1)
+ {
+ int mid = (right - left) / 2 + left;
+ if (obj.WillCollideWith(listObj, obj.Position + new XY((int)(mid * Math.Cos(moveVec.angle)), (int)(mid * Math.Sin(moveVec.angle)))))
+ {
+ right = mid;
+ }
+ else left = mid;
+ }
+ tmpMax = (uint)left;
+ }
+ break;
+ }
+ default:
+ tmpMax = uint.MaxValue;
+ break;
+ }
+ if (tmpMax < maxDistance)
+ maxDistance = tmpMax;
+ }
+ }
+ }
+ }
+ finally
+ {
+ //maxLen = Math.Min(maxOnlyConsiderWall, maxDistance); //最大可能距离的最小值
+ listLock.ExitReadLock();
+ }
+ }
+ //return maxLen;
+ return maxDistance;
+ }
+
+ readonly IMap gameMap;
+ private readonly Tuple, ReaderWriterLockSlim>[] lists;
+
+ public CollisionChecker(IMap gameMap)
+ {
+ this.gameMap = gameMap;
+ lists = new Tuple, ReaderWriterLockSlim>[gameMap.GameObjDict.Count];
+ int i = 0;
+ foreach(var keyValuePair in gameMap.GameObjDict)
+ {
+ lists[i++] = new Tuple, ReaderWriterLockSlim>(keyValuePair.Value as IList, gameMap.GameObjLockDict[keyValuePair.Key]);
+ }
+ }
+ }
+}
diff --git a/logic/GameEngine/GameEngine.csproj b/logic/GameEngine/GameEngine.csproj
new file mode 100644
index 0000000..2adc507
--- /dev/null
+++ b/logic/GameEngine/GameEngine.csproj
@@ -0,0 +1,17 @@
+
+
+
+ Library
+ net6.0
+ enable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/logic/GameEngine/MoveEngine.cs b/logic/GameEngine/MoveEngine.cs
new file mode 100644
index 0000000..0424397
--- /dev/null
+++ b/logic/GameEngine/MoveEngine.cs
@@ -0,0 +1,176 @@
+using System;
+using System.Threading;
+using Preparation.Interface;
+using Preparation.Utility;
+using Timothy.FrameRateTask;
+using Preparation.GameData;
+
+namespace GameEngine
+{
+ public class MoveEngine
+ {
+ ///
+ /// 碰撞结束后要做的事情
+ ///
+ public enum AfterCollision
+ {
+ ContinueCheck = 0, // 碰撞后继续检查其他碰撞
+ MoveMax = 1, // 行走最远距离
+ Destroyed = 2 // 物体已经毁坏
+ }
+
+ private readonly ITimer gameTimer;
+ private readonly Action EndMove;
+ private readonly CollisionChecker collisionChecker;
+ private readonly Func OnCollision;
+ ///
+ /// Constrctor
+ ///
+ /// 游戏地图
+ /// 发生碰撞时要做的事情,第一个参数为移动的物体,第二个参数为撞到的物体,第三个参数为移动的位移向量,返回值见AfterCollision的定义
+ /// 结束碰撞时要做的事情
+ public MoveEngine
+ (
+ IMap gameMap,
+ Func OnCollision,
+ Action EndMove
+ )
+ {
+ this.gameTimer = gameMap.Timer;
+ this.EndMove = EndMove;
+ this.OnCollision = OnCollision;
+ this.collisionChecker = new CollisionChecker(gameMap);
+ }
+
+ ///
+ /// 在无碰撞的前提下行走最远的距离
+ ///
+ /// 移动物体,默认obj.Rigid为true
+ /// 移动的位移向量
+ private void MoveMax(IMoveable obj, XY moveVec)
+ {
+
+ /*由于四周是墙,所以人物永远不可能与越界方块碰撞*/
+ XY nextPos = obj.Position + XY.VectorToXY(moveVec);
+ double maxLen = collisionChecker.FindMax(obj, nextPos, moveVec);
+ maxLen = Math.Min(maxLen, obj.MoveSpeed / GameData.numOfStepPerSecond);
+ _ = obj.Move(new Vector(moveVec.angle, maxLen));
+ }
+
+ public void MoveObj(IMoveable obj, int moveTime, double direction)
+ {
+ if (obj.IsMoving) //已经移动的物体不能再移动
+ return;
+ new Thread
+ (
+ ()=>
+ {
+ if (!obj.IsAvailable&&gameTimer.IsGaming) //不能动就直接return,后面都是能动的情况
+ return;
+ lock (obj.MoveLock)
+ obj.IsMoving = true;
+
+ XY moveVec = new(direction, 0.0);
+ double deltaLen = moveVec.length - Math.Sqrt(obj.Move(moveVec)); //转向,并用deltaLen存储行走的误差
+ IGameObj? collisionObj = null;
+ bool isDestroyed = false;
+ new FrameRateTaskExecutor
+ (
+ () => gameTimer.IsGaming && obj.CanMove && !obj.IsResetting,
+ () =>
+ {
+ moveVec.length = obj.MoveSpeed / GameData.numOfStepPerSecond;
+
+ //越界情况处理:如果越界,则与越界方块碰撞
+ bool flag; //循环标志
+ do
+ {
+ flag = false;
+ collisionObj = collisionChecker.CheckCollision(obj, moveVec);
+ if (collisionObj == null) break;
+
+ switch (OnCollision(obj, collisionObj, moveVec))
+ {
+ case AfterCollision.ContinueCheck:
+ flag = true;
+ break;
+ case AfterCollision.Destroyed:
+ Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game.");
+ isDestroyed = true;
+ return false;
+ case AfterCollision.MoveMax:
+ MoveMax(obj, moveVec);
+ moveVec.length = 0;
+ break;
+ }
+ } while (flag);
+
+ deltaLen += moveVec.length - Math.Sqrt(obj.Move(moveVec));
+
+ return true;
+ },
+ GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond,
+ () =>
+ {
+ int leftTime = moveTime % (GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond);
+ bool flag;
+ do
+ {
+ flag = false;
+ if (!isDestroyed)
+ {
+ moveVec.length = deltaLen + leftTime * obj.MoveSpeed / GameData.numOfPosGridPerCell;
+ if ((collisionObj = collisionChecker.CheckCollision(obj, moveVec)) == null)
+ {
+ obj.Move(moveVec);
+ }
+ else
+ {
+ switch (OnCollision(obj, collisionObj, moveVec))
+ {
+ case AfterCollision.ContinueCheck:
+ flag = true;
+ break;
+ case AfterCollision.Destroyed:
+ Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game.");
+ isDestroyed = true;
+ break;
+ case AfterCollision.MoveMax:
+ MoveMax(obj, moveVec);
+ moveVec.length = 0;
+ break;
+ }
+ }
+ }
+ } while (flag);
+ if (leftTime > 0)
+ {
+ Thread.Sleep(leftTime); //多移动的在这里补回来
+ }
+ lock(obj.MoveLock)
+ obj.IsMoving = false; //结束移动
+ EndMove(obj);
+ return 0;
+ },
+ maxTotalDuration: moveTime
+ )
+ {
+ AllowTimeExceed = true,
+ MaxTolerantTimeExceedCount = ulong.MaxValue,
+ TimeExceedAction = b =>
+ {
+ if (b) Console.WriteLine("Fatal Error: The computer runs so slow that the object cannot finish moving during this time!!!!!!");
+
+#if DEBUG
+ else
+ {
+ Console.WriteLine("Debug info: Object moving time exceed for once.");
+ }
+#endif
+ }
+ }.Start();
+ }
+ ).Start();
+ }
+ }
+}