You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

MoveEngine.cs 7.4 kB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. using System;
  2. using System.Threading;
  3. using Preparation.Interface;
  4. using Preparation.Utility;
  5. using Timothy.FrameRateTask;
  6. using Preparation.GameData;
  7. namespace GameEngine
  8. {
  9. public class MoveEngine
  10. {
  11. /// <summary>
  12. /// 碰撞结束后要做的事情
  13. /// </summary>
  14. public enum AfterCollision
  15. {
  16. ContinueCheck = 0, // 碰撞后继续检查其他碰撞
  17. MoveMax = 1, // 行走最远距离
  18. Destroyed = 2 // 物体已经毁坏
  19. }
  20. private readonly ITimer gameTimer;
  21. private readonly Action<IMoveable> EndMove;
  22. private readonly CollisionChecker collisionChecker;
  23. private readonly Func<IMoveable, IGameObj, XY, AfterCollision> OnCollision;
  24. /// <summary>
  25. /// Constrctor
  26. /// </summary>
  27. /// <param name="gameMap">游戏地图</param>
  28. /// <param name="OnCollision">发生碰撞时要做的事情,第一个参数为移动的物体,第二个参数为撞到的物体,第三个参数为移动的位移向量,返回值见AfterCollision的定义</param>
  29. /// <param name="EndMove">结束碰撞时要做的事情</param>
  30. public MoveEngine(
  31. IMap gameMap,
  32. Func<IMoveable, IGameObj, XY, AfterCollision> OnCollision,
  33. Action<IMoveable> EndMove
  34. )
  35. {
  36. this.gameTimer = gameMap.Timer;
  37. this.EndMove = EndMove;
  38. this.OnCollision = OnCollision;
  39. this.collisionChecker = new CollisionChecker(gameMap);
  40. }
  41. /// <summary>
  42. /// 在无碰撞的前提下行走最远的距离
  43. /// </summary>
  44. /// <param name="obj">移动物体,默认obj.Rigid为true</param>
  45. /// <param name="moveVec">移动的位移向量</param>
  46. private void MoveMax(IMoveable obj, XY moveVec)
  47. {
  48. /*由于四周是墙,所以人物永远不可能与越界方块碰撞*/
  49. XY nextPos = obj.Position + XY.VectorToXY(moveVec);
  50. double maxLen = collisionChecker.FindMax(obj, nextPos, moveVec);
  51. maxLen = Math.Min(maxLen, obj.MoveSpeed / GameData.numOfStepPerSecond);
  52. _ = obj.Move(new Vector(moveVec.angle, maxLen));
  53. }
  54. public void MoveObj(IMoveable obj, int moveTime, double direction)
  55. {
  56. if (obj.IsMoving) // 已经移动的物体不能再移动
  57. return;
  58. new Thread
  59. (
  60. ()=>
  61. {
  62. if (!obj.IsAvailable&&gameTimer.IsGaming) //不能动就直接return,后面都是能动的情况
  63. return;
  64. lock (obj.MoveLock)
  65. obj.IsMoving = true;
  66. XY moveVec = new(direction, 0.0);
  67. double deltaLen = moveVec.length - Math.Sqrt(obj.Move(moveVec)); // 转向,并用deltaLen存储行走的误差
  68. IGameObj? collisionObj = null;
  69. bool isDestroyed = false;
  70. new FrameRateTaskExecutor<int>(
  71. () => gameTimer.IsGaming && obj.CanMove && !obj.IsResetting,
  72. () =>
  73. {
  74. moveVec.length = obj.MoveSpeed / GameData.numOfStepPerSecond;
  75. // 越界情况处理:如果越界,则与越界方块碰撞
  76. bool flag; // 循环标志
  77. do
  78. {
  79. flag = false;
  80. collisionObj = collisionChecker.CheckCollision(obj, moveVec);
  81. if (collisionObj == null)
  82. break;
  83. switch (OnCollision(obj, collisionObj, moveVec))
  84. {
  85. case AfterCollision.ContinueCheck:
  86. flag = true;
  87. break;
  88. case AfterCollision.Destroyed:
  89. Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game.");
  90. isDestroyed = true;
  91. return false;
  92. case AfterCollision.MoveMax:
  93. MoveMax(obj, moveVec);
  94. moveVec.length = 0;
  95. break;
  96. }
  97. } while (flag);
  98. deltaLen += moveVec.length - Math.Sqrt(obj.Move(moveVec));
  99. return true;
  100. },
  101. GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond,
  102. () =>
  103. {
  104. int leftTime = moveTime % (GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond);
  105. bool flag;
  106. do
  107. {
  108. flag = false;
  109. if (!isDestroyed)
  110. {
  111. moveVec.length = deltaLen + leftTime * obj.MoveSpeed / GameData.numOfPosGridPerCell;
  112. if ((collisionObj = collisionChecker.CheckCollision(obj, moveVec)) == null)
  113. {
  114. obj.Move(moveVec);
  115. }
  116. else
  117. {
  118. switch (OnCollision(obj, collisionObj, moveVec))
  119. {
  120. case AfterCollision.ContinueCheck:
  121. flag = true;
  122. break;
  123. case AfterCollision.Destroyed:
  124. Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game.");
  125. isDestroyed = true;
  126. break;
  127. case AfterCollision.MoveMax:
  128. MoveMax(obj, moveVec);
  129. moveVec.length = 0;
  130. break;
  131. }
  132. }
  133. }
  134. } while (flag);
  135. if (leftTime > 0)
  136. {
  137. Thread.Sleep(leftTime); // 多移动的在这里补回来
  138. }
  139. lock (obj.MoveLock)
  140. obj.IsMoving = false; // 结束移动
  141. EndMove(obj);
  142. return 0;
  143. },
  144. maxTotalDuration: moveTime
  145. ) {
  146. AllowTimeExceed = true,
  147. MaxTolerantTimeExceedCount = ulong.MaxValue,
  148. TimeExceedAction = b =>
  149. {
  150. if (b)
  151. Console.WriteLine("Fatal Error: The computer runs so slow that the object cannot finish moving during this time!!!!!!");
  152. #if DEBUG
  153. else
  154. {
  155. Console.WriteLine("Debug info: Object moving time exceed for once.");
  156. }
  157. #endif
  158. }
  159. }.Start();
  160. }
  161. ).Start();
  162. }
  163. }
  164. }