fix: 🐛 fix the bug about attacking When clipping
tags/0.1.0
| @@ -618,6 +618,7 @@ void Logic::LoadBuffer(const protobuf::MessageToClient& message) | |||||
| { | { | ||||
| std::lock_guard<std::mutex> lock(mtxState); | std::lock_guard<std::mutex> lock(mtxState); | ||||
| std::swap(currentState, bufferState); | std::swap(currentState, bufferState); | ||||
| counterState = counterBuffer; | |||||
| logger->info("Update State!"); | logger->info("Update State!"); | ||||
| } | } | ||||
| freshed = true; | freshed = true; | ||||
| @@ -476,6 +476,7 @@ class Logic(ILogic): | |||||
| if Setting.asynchronous(): | if Setting.asynchronous(): | ||||
| with self.__mtxState: | with self.__mtxState: | ||||
| self.__currentState, self.__bufferState = self.__bufferState, self.__currentState | self.__currentState, self.__bufferState = self.__bufferState, self.__currentState | ||||
| self.__counterState = self.__counterBuffer | |||||
| self.__logger.info("Update state!") | self.__logger.info("Update state!") | ||||
| self.__freshed = True | self.__freshed = True | ||||
| else: | else: | ||||
| @@ -8,7 +8,8 @@ | |||||
| #### 移动 | #### 移动 | ||||
| - `def Move(self, timeInMilliseconds: int, angle: float) -> Future[bool]`:移动,`timeInMilliseconds` 为移动时间,单位毫秒;`angleInRadian` 表示移动方向,单位弧度,使用极坐标,**竖直向下方向为 x 轴,水平向右方向为 y 轴**因为移动过程中你会受到多种干扰使得移动结果不符合你的预期;因此建议小步移动,边移动边考虑之后的行为。 | |||||
| - `def Move(self, timeInMilliseconds: int, angle: float) -> Future[bool]`:移动,`timeInMilliseconds` 为移动时间,单位毫秒;`angleInRadian` 表示移动方向,单位弧度,使用极坐标,**竖直向下方向为 x 轴,水平向右方向为 y 轴**因为移动过程中你会受到多种干扰使得移动结果不符合你的预期;因此建议小步移动,边移动边考虑之后的行为。 | |||||
| - 5ms以内的移动指令会被禁止,你不应当使用过小的移动指令 | |||||
| - `def MoveRight(self, timeInMilliseconds: int) -> Future[bool]`即向右移动,`MoveLeft`、`MoveDown`、`MoveUp`同理 | - `def MoveRight(self, timeInMilliseconds: int) -> Future[bool]`即向右移动,`MoveLeft`、`MoveDown`、`MoveUp`同理 | ||||
| #### 使用技能 | #### 使用技能 | ||||
| @@ -62,12 +62,15 @@ A: | |||||
| - 可能措施1. | - 可能措施1. | ||||
| 首先保证Python版本在3.9及以上 | 首先保证Python版本在3.9及以上 | ||||
| - 可能措施2. 更换为国内镜像源 | - 可能措施2. 更换为国内镜像源 | ||||
| 在终端输入 | |||||
| `pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple` | |||||
| 在终端输入 `pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple` | |||||
| - 可能措施3. 更新pip | - 可能措施3. 更新pip | ||||
| `python -m pip install --upgrade pip` (pip 版本最好为23.1) | `python -m pip install --upgrade pip` (pip 版本最好为23.1) | ||||
| ## 比赛相关 | ## 比赛相关 | ||||
| Q:职业数值会修改吗? | Q:职业数值会修改吗? | ||||
| A:初赛结束会调数值及机制,增加新角色 | |||||
| A:初赛结束会调数值及机制,增加新角色 | |||||
| Q:初赛后会修改什么呢? | |||||
| A:技能冷却时间等属性设为不可见;出生点随机性或可选性;增强教师等职业,削弱职业;规范Debug信息 | |||||
| @@ -36,6 +36,7 @@ namespace GameClass.GameObj | |||||
| public override bool IgnoreCollideExecutor(IGameObj targetObj) | public override bool IgnoreCollideExecutor(IGameObj targetObj) | ||||
| { | { | ||||
| if (targetObj == Parent && CanMove) return true; | |||||
| if (targetObj.Type == GameObjType.Prop || targetObj.Type == GameObjType.Bullet) | if (targetObj.Type == GameObjType.Prop || targetObj.Type == GameObjType.Bullet) | ||||
| return true; | return true; | ||||
| return false; | return false; | ||||
| @@ -594,7 +594,7 @@ namespace GameClass.GameObj | |||||
| { | { | ||||
| return true; | return true; | ||||
| } | } | ||||
| if (targetObj.Type == GameObjType.Character && XY.DistanceFloor3(targetObj.Position, this.Position) < this.Radius + targetObj.Radius) | |||||
| if (targetObj.Type == GameObjType.Character && XY.DistanceCeil3(targetObj.Position, this.Position) < this.Radius + targetObj.Radius - GameData.adjustLength) | |||||
| return true; | return true; | ||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -91,106 +91,132 @@ namespace GameEngine | |||||
| double deltaLen = moveVecLength - Math.Sqrt(obj.MovingSetPos(res, GetPlaceType(obj.Position + res))); // 转向,并用deltaLen存储行走的误差 | double deltaLen = moveVecLength - Math.Sqrt(obj.MovingSetPos(res, GetPlaceType(obj.Position + res))); // 转向,并用deltaLen存储行走的误差 | ||||
| IGameObj? collisionObj = null; | IGameObj? collisionObj = null; | ||||
| bool isDestroyed = false; | bool isDestroyed = false; | ||||
| new FrameRateTaskExecutor<int>( | |||||
| () => gameTimer.IsGaming && obj.CanMove && !obj.IsResetting && obj.IsMoving, | |||||
| () => | |||||
| bool flag; // 循环标志 | |||||
| do | |||||
| { | |||||
| flag = false; | |||||
| collisionObj = collisionChecker.CheckCollision(obj, obj.Position); | |||||
| if (collisionObj == null) | |||||
| break; | |||||
| switch (OnCollision(obj, collisionObj, res)) | |||||
| { | { | ||||
| moveVecLength = obj.MoveSpeed / GameData.numOfStepPerSecond; | |||||
| res = new XY(direction, moveVecLength); | |||||
| 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: | |||||
| break; | |||||
| } | |||||
| } while (flag); | |||||
| // 越界情况处理:如果越界,则与越界方块碰撞 | |||||
| bool flag; // 循环标志 | |||||
| do | |||||
| if (!isDestroyed) | |||||
| { | |||||
| new FrameRateTaskExecutor<int>( | |||||
| () => gameTimer.IsGaming && obj.CanMove && !obj.IsResetting && obj.IsMoving, | |||||
| () => | |||||
| { | { | ||||
| flag = false; | |||||
| collisionObj = collisionChecker.CheckCollisionWhenMoving(obj, res); | |||||
| if (collisionObj == null) | |||||
| break; | |||||
| moveVecLength = obj.MoveSpeed / GameData.numOfStepPerSecond; | |||||
| res = new XY(direction, moveVecLength); | |||||
| switch (OnCollision(obj, collisionObj, res)) | |||||
| // 越界情况处理:如果越界,则与越界方块碰撞 | |||||
| bool flag; // 循环标志 | |||||
| do | |||||
| { | { | ||||
| 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, res); | |||||
| moveVecLength = 0; | |||||
| res = new XY(direction, moveVecLength); | |||||
| flag = false; | |||||
| collisionObj = collisionChecker.CheckCollisionWhenMoving(obj, res); | |||||
| if (collisionObj == null) | |||||
| break; | break; | ||||
| } | |||||
| } while (flag); | |||||
| deltaLen += moveVecLength - Math.Sqrt(obj.MovingSetPos(res, GetPlaceType(obj.Position + res))); | |||||
| switch (OnCollision(obj, collisionObj, res)) | |||||
| { | |||||
| 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, res); | |||||
| moveVecLength = 0; | |||||
| res = new XY(direction, moveVecLength); | |||||
| break; | |||||
| } | |||||
| } while (flag); | |||||
| return true; | |||||
| }, | |||||
| GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond, | |||||
| () => | |||||
| { | |||||
| int leftTime = moveTime % (GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond); | |||||
| bool flag; | |||||
| do | |||||
| deltaLen += moveVecLength - Math.Sqrt(obj.MovingSetPos(res, GetPlaceType(obj.Position + res))); | |||||
| return true; | |||||
| }, | |||||
| GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond, | |||||
| () => | |||||
| { | { | ||||
| flag = false; | |||||
| if (!isDestroyed) | |||||
| int leftTime = moveTime % (GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond); | |||||
| bool flag; | |||||
| do | |||||
| { | { | ||||
| moveVecLength = deltaLen + leftTime * obj.MoveSpeed / GameData.numOfPosGridPerCell; | |||||
| res = new XY(direction, moveVecLength); | |||||
| if ((collisionObj = collisionChecker.CheckCollisionWhenMoving(obj, res)) == null) | |||||
| { | |||||
| obj.MovingSetPos(res, GetPlaceType(obj.Position + res)); | |||||
| } | |||||
| else | |||||
| flag = false; | |||||
| if (!isDestroyed) | |||||
| { | { | ||||
| switch (OnCollision(obj, collisionObj, res)) | |||||
| moveVecLength = deltaLen + leftTime * obj.MoveSpeed / GameData.numOfPosGridPerCell; | |||||
| res = new XY(direction, moveVecLength); | |||||
| if ((collisionObj = collisionChecker.CheckCollisionWhenMoving(obj, res)) == null) | |||||
| { | |||||
| obj.MovingSetPos(res, GetPlaceType(obj.Position + res)); | |||||
| } | |||||
| else | |||||
| { | { | ||||
| 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, res); | |||||
| moveVecLength = 0; | |||||
| res = new XY(direction, moveVecLength); | |||||
| break; | |||||
| switch (OnCollision(obj, collisionObj, res)) | |||||
| { | |||||
| 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, res); | |||||
| moveVecLength = 0; | |||||
| res = new XY(direction, moveVecLength); | |||||
| break; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } while (flag); | |||||
| if (leftTime > 0 && obj.IsMoving) | |||||
| { | |||||
| Thread.Sleep(leftTime); // 多移动的在这里补回来 | |||||
| } | } | ||||
| } while (flag); | |||||
| if (leftTime > 0 && obj.IsMoving) | |||||
| { | |||||
| Thread.Sleep(leftTime); // 多移动的在这里补回来 | |||||
| } | |||||
| lock (obj.MoveLock) | |||||
| obj.IsMoving = false; // 结束移动 | |||||
| EndMove(obj); | |||||
| return 0; | |||||
| }, | |||||
| maxTotalDuration: moveTime | |||||
| ) | |||||
| { | |||||
| AllowTimeExceed = true, | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||||
| TimeExceedAction = b => | |||||
| lock (obj.MoveLock) | |||||
| obj.IsMoving = false; // 结束移动 | |||||
| EndMove(obj); | |||||
| return 0; | |||||
| }, | |||||
| maxTotalDuration: moveTime | |||||
| ) | |||||
| { | { | ||||
| if (b) | |||||
| Console.WriteLine("Fatal Error: The computer runs so slow that the object cannot finish moving during this time!!!!!!"); | |||||
| 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 | #if DEBUG | ||||
| else | |||||
| { | |||||
| Console.WriteLine("Debug info: Object moving time exceed for once."); | |||||
| } | |||||
| else | |||||
| { | |||||
| Console.WriteLine("Debug info: Object moving time exceed for once."); | |||||
| } | |||||
| #endif | #endif | ||||
| } | |||||
| }.Start(); | |||||
| } | |||||
| }.Start(); | |||||
| } | |||||
| } | } | ||||
| ).Start(); | ).Start(); | ||||
| } | } | ||||
| @@ -35,6 +35,7 @@ namespace Gaming | |||||
| } | } | ||||
| public bool MovePlayer(Character playerToMove, int moveTimeInMilliseconds, double moveDirection) | public bool MovePlayer(Character playerToMove, int moveTimeInMilliseconds, double moveDirection) | ||||
| { | { | ||||
| if (moveTimeInMilliseconds < 5) return false; | |||||
| if (!playerToMove.Commandable() || !TryToStop()) return false; | if (!playerToMove.Commandable() || !TryToStop()) return false; | ||||
| characterManager.SetPlayerState(playerToMove, PlayerStateType.Moving); | characterManager.SetPlayerState(playerToMove, PlayerStateType.Moving); | ||||
| moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection); | moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection); | ||||
| @@ -34,6 +34,7 @@ namespace Gaming | |||||
| Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); | Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); | ||||
| if (obj.CanMove && ((Bullet)obj).TypeOfBullet != BulletType.JumpyDumpty) | if (obj.CanMove && ((Bullet)obj).TypeOfBullet != BulletType.JumpyDumpty) | ||||
| BulletBomb((Bullet)obj, null); | BulletBomb((Bullet)obj, null); | ||||
| obj.CanMove = false; | |||||
| } | } | ||||
| ); | ); | ||||
| this.characterManager = characterManager; | this.characterManager = characterManager; | ||||
| @@ -171,17 +172,19 @@ namespace Gaming | |||||
| return false; | return false; | ||||
| Debugger.Output(player, player.CharacterType.ToString() + "Attack in " + player.BulletOfPlayer.ToString()); | Debugger.Output(player, player.CharacterType.ToString() + "Attack in " + player.BulletOfPlayer.ToString()); | ||||
| Debugger.Output(player, player.Position.ToString() + " " + player.Radius.ToString() + " " + BulletFactory.BulletRadius(player.BulletOfPlayer).ToString()); | |||||
| XY res = player.Position + new XY // 子弹紧贴人物生成。 | XY res = player.Position + new XY // 子弹紧贴人物生成。 | ||||
| ( | ( | ||||
| (int)((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Cos(angle)), | |||||
| (int)((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Sin(angle)) | |||||
| (int)(Math.Abs((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Cos(angle))) * ((Math.Cos(angle) > 0) ? 1 : -1), | |||||
| (int)(Math.Abs((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Sin(angle))) * ((Math.Sin(angle) > 0) ? 1 : -1) | |||||
| ); | ); | ||||
| Bullet? bullet = player.Attack(res, gameMap.GetPlaceType(res)); | Bullet? bullet = player.Attack(res, gameMap.GetPlaceType(res)); | ||||
| if (bullet != null) | if (bullet != null) | ||||
| { | { | ||||
| Debugger.Output(player, "Attack in " + bullet.ToString()); | |||||
| player.FacingDirection = new(angle, bullet.BulletAttackRange); | |||||
| Debugger.Output(bullet, "Attack in " + bullet.Position.ToString()); | |||||
| bullet.AP += player.TryAddAp() ? GameData.ApPropAdd : 0; | bullet.AP += player.TryAddAp() ? GameData.ApPropAdd : 0; | ||||
| bullet.CanMove = true; | bullet.CanMove = true; | ||||
| gameMap.Add(bullet); | gameMap.Add(bullet); | ||||
| @@ -398,10 +398,8 @@ namespace Gaming | |||||
| ((SummonGolem)(((Golem)player).Parent.FindIActiveSkill(ActiveSkillType.SummonGolem))).GolemSummoned = null; | ((SummonGolem)(((Golem)player).Parent.FindIActiveSkill(ActiveSkillType.SummonGolem))).GolemSummoned = null; | ||||
| player.FindIActiveSkill(ActiveSkillType.UseRobot).IsBeingUsed = false; | player.FindIActiveSkill(ActiveSkillType.UseRobot).IsBeingUsed = false; | ||||
| } | } | ||||
| gameMap.Remove(player); | |||||
| return; | return; | ||||
| } | } | ||||
| gameMap.Remove(player); | |||||
| ++gameMap.NumOfDeceasedStudent; | ++gameMap.NumOfDeceasedStudent; | ||||
| } | } | ||||
| @@ -9,7 +9,8 @@ namespace Preparation.Utility | |||||
| #region 基本常数 | #region 基本常数 | ||||
| public const int numOfStepPerSecond = 20; // 每秒行走的步数 | public const int numOfStepPerSecond = 20; // 每秒行走的步数 | ||||
| public const int tolerancesLength = 10; | |||||
| public const int tolerancesLength = 3; | |||||
| public const int adjustLength = 3; | |||||
| public const int frameDuration = 50; // 每帧时长 | public const int frameDuration = 50; // 每帧时长 | ||||
| public const int checkInterval = 50; // 检查位置标志、补充子弹的帧时长 | public const int checkInterval = 50; // 检查位置标志、补充子弹的帧时长 | ||||