Browse Source

Merge pull request #256 from shangfengh/new

perf:  add whatInteractingWith to make a great optimization
tags/0.1.0
Changli Tang GitHub 3 years ago
parent
commit
3a2c1912c4
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 191 additions and 116 deletions
  1. +32
    -23
      logic/GameClass/GameObj/Character/Character.cs
  2. +16
    -11
      logic/GameClass/GameObj/Map/Chest.cs
  3. +29
    -41
      logic/Gaming/ActionManager.cs
  4. +2
    -2
      logic/Gaming/AttackManager.cs
  5. +5
    -5
      logic/Gaming/CharacterManager .cs
  6. +1
    -1
      logic/Gaming/PropManager.cs
  7. +26
    -1
      logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs
  8. +1
    -1
      logic/Preparation/Interface/ICharacter.cs
  9. +31
    -0
      logic/Preparation/Interface/IOccupation.cs
  10. +17
    -2
      logic/Preparation/Interface/ISkill.cs
  11. +1
    -0
      logic/Preparation/Utility/EnumType.cs
  12. +6
    -4
      logic/Server/CopyInfo.cs
  13. +7
    -6
      logic/Server/GameServer.cs
  14. +17
    -19
      logic/规则Logic.md

+ 32
- 23
logic/GameClass/GameObj/Character/Character.cs View File

@@ -300,14 +300,6 @@ namespace GameClass.GameObj
if (playerState == PlayerStateType.Null && IsMoving) return PlayerStateType.Moving;
return playerState;
}
set
{
if (value != PlayerStateType.Moving)
lock (gameObjLock)
IsMoving = false;

lock (gameObjLock) playerState = (value == PlayerStateType.Moving) ? PlayerStateType.Null : value;
}
}

public bool NoHp() => (playerState == PlayerStateType.Deceased || playerState == PlayerStateType.Escaped
@@ -323,6 +315,38 @@ namespace GameClass.GameObj
|| playerState == PlayerStateType.Treated || playerState == PlayerStateType.Stunned
|| playerState == PlayerStateType.Null || playerState == PlayerStateType.Moving);

private GameObj? whatInteractingWith = null;
public GameObj? WhatInteractingWith => whatInteractingWith;

public void SetPlayerState(PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null)
{
lock (gameObjLock)
{
switch (playerState)
{
case PlayerStateType.OpeningTheChest:
((Chest)whatInteractingWith).StopOpen();
break;
default:
break;
}
whatInteractingWith = gameObj;
if (value != PlayerStateType.Moving)
IsMoving = false;
playerState = (value == PlayerStateType.Moving) ? PlayerStateType.Null : value;
//Debugger.Output(this,playerState.ToString()+" "+IsMoving.ToString());
}
}

public void SetPlayerStateNaturally()
{
lock (gameObjLock)
{
whatInteractingWith = null;
playerState = PlayerStateType.Null;
}
}

private int score = 0;
public int Score
{
@@ -382,21 +406,6 @@ namespace GameClass.GameObj
}
}
}
/// <summary>
/// 角色携带的信息
/// </summary>
private string message = "THUAI6";
public string Message
{
get => message;
set
{
lock (gameObjLock)
{
message = value;
}
}
}

#region 道具和buff相关属性、方法
private Prop[] propInventory = new Prop[GameData.maxNumOfPropInPropInventory]


+ 16
- 11
logic/GameClass/GameObj/Map/Chest.cs View File

@@ -20,20 +20,25 @@ namespace GameClass.GameObj
private Prop[] propInChest = new Prop[GameData.maxNumOfPropInChest] { new NullProp(), new NullProp() };
public Prop[] PropInChest => propInChest;

private int openDegree = 0;
public int OpenDegree
private int openStartTime = 0;
public int OpenStartTime => openStartTime;
private Character? whoOpen = null;
public Character? WhoOpen => whoOpen;
public void Open(int startTime, Character character)
{
get => openDegree;
set
lock (gameObjLock)
{
if (value > 0)
lock (gameObjLock)
openDegree = (value > GameData.degreeOfOpenedChest) ? GameData.degreeOfOpenedChest : value;
else
lock (gameObjLock)
openDegree = 0;
openStartTime = startTime;
whoOpen = character;
}
}
public void StopOpen()
{
lock (gameObjLock)
{
openStartTime = 0;
whoOpen = null;
}
}
public bool IsOpen() => (OpenDegree == GameData.degreeOfOpenedChest);
}
}

+ 29
- 41
logic/Gaming/ActionManager.cs View File

@@ -38,7 +38,7 @@ namespace Gaming
public bool MovePlayer(Character playerToMove, int moveTimeInMilliseconds, double moveDirection)
{
if (!playerToMove.Commandable()) return false;
playerToMove.PlayerState = PlayerStateType.Moving;
playerToMove.SetPlayerState(PlayerStateType.Moving);
moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection);
return true;
}
@@ -47,7 +47,7 @@ namespace Gaming
{
if (player.Commandable())
{
player.PlayerState = PlayerStateType.Null;
player.SetPlayerState();
return true;
}
return false;
@@ -63,7 +63,7 @@ namespace Gaming
return false;

++generatorForFix.NumOfFixing;
player.PlayerState = PlayerStateType.Fixing;
player.SetPlayerState(PlayerStateType.Fixing);
new Thread
(
() =>
@@ -74,7 +74,7 @@ namespace Gaming
{
if (generatorForFix.Repair(player.FixSpeed * GameData.frameDuration, player))
{
player.PlayerState = PlayerStateType.Null;
player.SetPlayerState();
gameMap.NumOfRepairedGenerators++;
}
},
@@ -99,7 +99,7 @@ namespace Gaming
if (doorwayToOpen == null || doorwayToOpen.IsOpening || !doorwayToOpen.PowerSupply)
return false;

player.PlayerState = PlayerStateType.OpeningTheDoorway;
player.SetPlayerState(PlayerStateType.OpeningTheDoorway);
doorwayToOpen.IsOpening = true;
new Thread
(
@@ -120,7 +120,7 @@ namespace Gaming
if (doorwayToOpen.OpenDegree >= GameData.degreeOfOpenedDoorway)
{
if (player.PlayerState == PlayerStateType.OpeningTheDoorway)
player.PlayerState = PlayerStateType.Null;
player.SetPlayerState();
}
}

@@ -163,7 +163,7 @@ namespace Gaming
playerTreated = gameMap.StudentForInteract(player.Position);
if (playerTreated == null) return false;
}
if (player == playerTreated || (!player.Commandable()) || player.PlayerState == PlayerStateType.Treating ||
if (player == playerTreated || (!player.Commandable()) || playerTreated.PlayerState == PlayerStateType.Treated ||
(!playerTreated.Commandable()) ||
playerTreated.HP == playerTreated.MaxHp || !GameData.ApproachToInteract(playerTreated.Position, player.Position))
return false;
@@ -172,22 +172,22 @@ namespace Gaming
(
() =>
{
playerTreated.PlayerState = PlayerStateType.Treated;
player.PlayerState = PlayerStateType.Treating;
playerTreated.SetPlayerState(PlayerStateType.Treated);
player.SetPlayerState(PlayerStateType.Treating);
new FrameRateTaskExecutor<int>(
loopCondition: () => playerTreated.PlayerState == PlayerStateType.Treated && player.PlayerState == PlayerStateType.Treating && gameMap.Timer.IsGaming,
loopToDo: () =>
{
if (playerTreated.AddDegreeOfTreatment(GameData.frameDuration * player.TreatSpeed, player))
playerTreated.PlayerState = PlayerStateType.Null;
playerTreated.SetPlayerState();
},
timeInterval: GameData.frameDuration,
finallyReturn: () => 0
)
.Start();

if (player.PlayerState == PlayerStateType.Treating) player.PlayerState = PlayerStateType.Null;
else if (playerTreated.PlayerState == PlayerStateType.Treated) playerTreated.PlayerState = PlayerStateType.Null;
if (player.PlayerState == PlayerStateType.Treating) player.SetPlayerState();
else if (playerTreated.PlayerState == PlayerStateType.Treated) playerTreated.SetPlayerState();
}
)
{ IsBackground = true }.Start();
@@ -200,11 +200,10 @@ namespace Gaming
playerRescued = gameMap.StudentForInteract(player.Position);
if (playerRescued == null) return false;
}
if ((!player.Commandable()) || playerRescued.PlayerState != PlayerStateType.Addicted || player == playerRescued
|| !GameData.ApproachToInteract(playerRescued.Position, player.Position) || playerRescued.TimeOfRescue > 0)
if ((!player.Commandable()) || playerRescued.PlayerState != PlayerStateType.Addicted || !GameData.ApproachToInteract(playerRescued.Position, player.Position))
return false;
player.PlayerState = PlayerStateType.Rescuing;
playerRescued.PlayerState = PlayerStateType.Rescued;
player.SetPlayerState(PlayerStateType.Rescuing);
playerRescued.SetPlayerState(PlayerStateType.Rescued);

new Thread
(
@@ -226,14 +225,14 @@ namespace Gaming
{
if (playerRescued.TimeOfRescue >= GameData.basicTimeOfRescue)
{
playerRescued.PlayerState = PlayerStateType.Null;
playerRescued.SetPlayerState();
playerRescued.HP = playerRescued.MaxHp / 2;
player.AddScore(GameData.StudentScoreRescue);
}
else
playerRescued.PlayerState = PlayerStateType.Addicted;
playerRescued.SetPlayerState(PlayerStateType.Addicted);
}
if (player.PlayerState == PlayerStateType.Rescuing) player.PlayerState = PlayerStateType.Null;
if (player.PlayerState == PlayerStateType.Rescuing) player.SetPlayerState();
playerRescued.TimeOfRescue = 0;
}
)
@@ -247,30 +246,21 @@ namespace Gaming
return false;
Chest? chestToOpen = (Chest?)gameMap.OneForInteract(player.Position, GameObjType.Chest);

if (chestToOpen == null || chestToOpen.OpenDegree > 0)
if (chestToOpen == null || chestToOpen.OpenStartTime > 0)
return false;

player.PlayerState = PlayerStateType.OpeningTheChest;
player.SetPlayerState(PlayerStateType.OpeningTheChest, chestToOpen);
int startTime = gameMap.Timer.nowTime();
chestToOpen.Open(startTime, player);
new Thread
(
() =>
{
new FrameRateTaskExecutor<int>(
loopCondition: () => player.PlayerState == PlayerStateType.OpeningTheChest && gameMap.Timer.IsGaming && (!chestToOpen.IsOpen()),
loopToDo: () =>
{
chestToOpen.OpenDegree += GameData.frameDuration * player.SpeedOfOpenChest;
},
timeInterval: GameData.frameDuration,
finallyReturn: () => 0
)
Thread.Sleep(GameData.degreeOfOpenedChest / player.SpeedOfOpenChest);

.Start();

if (chestToOpen.IsOpen())
if (chestToOpen.OpenStartTime == startTime)
{
if (player.PlayerState == PlayerStateType.OpeningTheChest)
player.PlayerState = PlayerStateType.Null;
player.SetPlayerStateNaturally();
for (int i = 0; i < GameData.maxNumOfPropInChest; ++i)
{
Prop prop = chestToOpen.PropInChest[i];
@@ -279,8 +269,6 @@ namespace Gaming
gameMap.Add(prop);
}
}
else chestToOpen.OpenDegree = 0;

}

)
@@ -312,7 +300,7 @@ namespace Gaming
//Wall addWall = new Wall(windowForClimb.Position - 2 * windowToPlayer);
// gameMap.Add(addWall);

player.PlayerState = PlayerStateType.ClimbingThroughWindows;
player.SetPlayerState(PlayerStateType.ClimbingThroughWindows);
windowForClimb.WhoIsClimbing = player;
new Thread
(
@@ -354,7 +342,7 @@ namespace Gaming
// gameMap.Remove(addWall);
if (player.PlayerState == PlayerStateType.ClimbingThroughWindows)
{
player.PlayerState = PlayerStateType.Null;
player.SetPlayerState();
}
}

@@ -394,7 +382,7 @@ namespace Gaming
}
if (!flag) return false;

player.PlayerState = PlayerStateType.LockingOrOpeningTheDoor;
player.SetPlayerState(PlayerStateType.LockingOrOpeningTheDoor);
new Thread
(
() =>
@@ -417,7 +405,7 @@ namespace Gaming
doorToLock.IsOpen = (!doorToLock.IsOpen);
}
if (player.PlayerState == PlayerStateType.LockingOrOpeningTheDoor)
player.PlayerState = PlayerStateType.Null;
player.SetPlayerState();
doorToLock.OpenOrLockDegree = 0;
}



+ 2
- 2
logic/Gaming/AttackManager.cs View File

@@ -174,7 +174,7 @@ namespace Gaming

if (bullet.CastTime > 0)
{
player.PlayerState = PlayerStateType.TryingToAttack;
player.SetPlayerState(PlayerStateType.TryingToAttack);

new Thread
(() =>
@@ -195,7 +195,7 @@ namespace Gaming
{
if (player.PlayerState == PlayerStateType.TryingToAttack)
{
player.PlayerState = PlayerStateType.Null;
player.SetPlayerState();
}
else
bullet.IsMoving = false;


+ 5
- 5
logic/Gaming/CharacterManager .cs View File

@@ -216,7 +216,7 @@ namespace Gaming
return;
}
}
player.PlayerState = PlayerStateType.Addicted;
player.SetPlayerState(PlayerStateType.Addicted);
new Thread
(() =>
{
@@ -252,10 +252,10 @@ namespace Gaming
new Thread
(() =>
{
player.PlayerState = PlayerStateType.Stunned;
player.SetPlayerState(PlayerStateType.Stunned);
Thread.Sleep(time);
if (player.PlayerState == PlayerStateType.Stunned)
player.PlayerState = PlayerStateType.Null;
player.SetPlayerState();
}
)
{ IsBackground = true }.Start();
@@ -341,7 +341,7 @@ namespace Gaming
{
if (player == null || time <= 0) return false;
if (player.PlayerState == PlayerStateType.Swinging || (!player.Commandable() && player.PlayerState != PlayerStateType.TryingToAttack)) return false;
player.PlayerState = PlayerStateType.Swinging;
player.SetPlayerState(PlayerStateType.Swinging);

new Thread
(() =>
@@ -350,7 +350,7 @@ namespace Gaming

if (player.PlayerState == PlayerStateType.Swinging)
{
player.PlayerState = PlayerStateType.Null;
player.SetPlayerState();
}
}
)


+ 1
- 1
logic/Gaming/PropManager.cs View File

@@ -57,7 +57,7 @@ namespace Gaming
if (player.PlayerState == PlayerStateType.Stunned)
{
player.AddScore(GameData.ScorePropRecoverFromDizziness);
player.PlayerState = PlayerStateType.Null;
player.SetPlayerState();
}
break;
default:


+ 26
- 1
logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs View File

@@ -28,6 +28,31 @@ namespace Gaming
{ });
}

public static bool ShowTime(Character player)
{
if ((!player.Commandable())) return false;
IActiveSkill skill = player.FindIActiveSkill(ActiveSkillType.ShowTime);
Debugger.Output(player, ": It's show time!");

return ActiveSkillEffect(skill, player, () =>
{
/* Thread
* new FrameRateTaskExecutor<int>(
loopCondition: () => player.PlayerState == PlayerStateType.OpeningTheChest && gameMap.Timer.IsGaming && (!chestToOpen.IsOpen()),
loopToDo: () =>
{
chestToOpen.OpenStartTime += GameData.frameDuration * player.SpeedOfOpenChest;
},
timeInterval: GameData.frameDuration,
finallyReturn: () => 0
)

.Start();*/
},
() =>
{ });
}

public static bool BecomeInvisible(Character player)
{
if ((!player.Commandable())) return false;
@@ -180,7 +205,7 @@ namespace Gaming
{
if ((character.PlayerState == PlayerStateType.Addicted) && gameMap.CanSee(player, character))
{
character.PlayerState = PlayerStateType.Null;
character.SetPlayerState();
character.HP = GameData.RemainHpWhenAddLife;
((Student)character).TimeOfRescue = 0;
player.AddScore(GameData.StudentScoreRescue);


+ 1
- 1
logic/Preparation/Interface/ICharacter.cs View File

@@ -10,7 +10,7 @@ namespace Preparation.Interface
public int Score { get; }
public void AddScore(int add);
public double Vampire { get; }
public PlayerStateType PlayerState { get; set; }
public PlayerStateType PlayerState { get; }
public BulletType BulletOfPlayer { get; set; }

public bool IsGhost();


+ 31
- 0
logic/Preparation/Interface/IOccupation.cs View File

@@ -91,6 +91,37 @@ namespace Preparation.Interface
public int speedOfOpenChest = (int)(GameData.basicSpeedOfOpenChest * 1.1);
public int SpeedOfOpenChest => speedOfOpenChest;
}
public class Idol : IGhostType
{
private const int moveSpeed = GameData.basicGhostMoveSpeed;
public int MoveSpeed => moveSpeed;

private const int maxHp = GameData.basicHp;
public int MaxHp => maxHp;

public BulletType InitBullet => BulletType.CommonAttackOfGhost;

public List<ActiveSkillType> ListOfIActiveSkill => new(new ActiveSkillType[] { });
public List<PassiveSkillType> ListOfIPassiveSkill => new(new PassiveSkillType[] { });

public double concealment = GameData.basicConcealment;
public double Concealment => concealment;

public int alertnessRadius = GameData.basicGhostAlertnessRadius;
public int AlertnessRadius => alertnessRadius;

public int viewRange = GameData.basicGhostViewRange * 11 / 10;
public int ViewRange => viewRange;

public int speedOfOpeningOrLocking = GameData.basicSpeedOfOpeningOrLocking;
public int SpeedOfOpeningOrLocking => speedOfOpeningOrLocking;

public int speedOfClimbingThroughWindows = GameData.basicGhostSpeedOfClimbingThroughWindows;
public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows;

public int speedOfOpenChest = GameData.basicSpeedOfOpenChest;
public int SpeedOfOpenChest => speedOfOpenChest;
}
public class ANoisyPerson : IGhostType
{
private const int moveSpeed = (int)(GameData.basicGhostMoveSpeed * 1.07);


+ 17
- 2
logic/Preparation/Interface/ISkill.cs View File

@@ -33,7 +33,7 @@ namespace Preparation.Interface

public class BecomeInvisible : IActiveSkill
{
public int SkillCD => GameData.commonSkillCD;
public int SkillCD => GameData.commonSkillCD * 2;
public int DurationTime => GameData.commonSkillTime * 6 / 10;

private readonly object commonSkillLock = new object();
@@ -121,6 +121,21 @@ namespace Preparation.Interface
}
}

public class ShowTime : IActiveSkill
{
public int SkillCD => GameData.commonSkillCD * 3;
public int DurationTime => GameData.commonSkillTime;

private readonly object commonSkillLock = new object();
public object ActiveSkillLock => commonSkillLock;

public bool isBeingUsed = false;
public bool IsBeingUsed
{
get => isBeingUsed; set => isBeingUsed = value;
}
}

public class JumpyBomb : IActiveSkill
{
public int SkillCD => GameData.commonSkillCD / 2;
@@ -137,7 +152,7 @@ namespace Preparation.Interface

public class UseKnife : IActiveSkill
{
public int SkillCD => GameData.commonSkillCD * 2 / 3;
public int SkillCD => GameData.commonSkillCD;
public int DurationTime => GameData.commonSkillTime / 10;
private readonly object commonSkillLock = new object();
public object ActiveSkillLock => commonSkillLock;


+ 1
- 0
logic/Preparation/Utility/EnumType.cs View File

@@ -100,6 +100,7 @@ namespace Preparation.Utility
Rouse = 11,
Encourage = 12,
Inspire = 13,
ShowTime = 14,
}
public enum PassiveSkillType
{


+ 6
- 4
logic/Server/CopyInfo.cs View File

@@ -3,13 +3,14 @@ using System.Collections.Generic;
using GameClass.GameObj;
using System.Numerics;
using Preparation.Utility;
using Gaming;

namespace Server
{

public static class CopyInfo
{
public static MessageOfObj? Auto(GameObj gameObj)
public static MessageOfObj? Auto(GameObj gameObj, int time)
{
switch (gameObj.Type)
{
@@ -29,7 +30,7 @@ namespace Server
case Preparation.Utility.GameObjType.Generator:
return Classroom((Generator)gameObj);
case Preparation.Utility.GameObjType.Chest:
return Chest((Chest)gameObj);
return Chest((Chest)gameObj, time);
case Preparation.Utility.GameObjType.Doorway:
return Gate((Doorway)gameObj);
case Preparation.Utility.GameObjType.EmergencyExit:
@@ -223,13 +224,14 @@ namespace Server
msg.DoorMessage.IsOpen = door.IsOpen;
return msg;
}
private static MessageOfObj Chest(Chest chest)
private static MessageOfObj Chest(Chest chest, int time)
{
MessageOfObj msg = new MessageOfObj();
msg.ChestMessage = new();
msg.ChestMessage.X = chest.Position.x;
msg.ChestMessage.Y = chest.Position.y;
msg.ChestMessage.Progress = chest.OpenDegree;
int progress = (chest.OpenStartTime > 0) ? ((time - chest.OpenStartTime) * chest.WhoOpen.SpeedOfOpenChest) : 0;
msg.ChestMessage.Progress = (progress > GameData.degreeOfOpenedChest) ? GameData.degreeOfOpenedChest : progress;
return msg;
}
}


+ 7
- 6
logic/Server/GameServer.cs View File

@@ -135,22 +135,23 @@ namespace Server
currentGameInfo.ObjMessage.Add(currentMapMsg);
IsSpectatorJoin = false;
}
int time = game.GameMap.Timer.nowTime();
foreach (GameObj gameObj in gameObjList)
{
MessageOfObj? msg = CopyInfo.Auto(gameObj);
if (msg != null) currentGameInfo.ObjMessage.Add(CopyInfo.Auto(gameObj));
MessageOfObj? msg = CopyInfo.Auto(gameObj, time);
if (msg != null) currentGameInfo.ObjMessage.Add(msg);
}
lock (newsLock)
{
foreach (var news in currentNews)
{
MessageOfObj? msg = CopyInfo.Auto(news);
if (msg != null) currentGameInfo.ObjMessage.Add(CopyInfo.Auto(news));
if (msg != null) currentGameInfo.ObjMessage.Add(msg);
}
currentNews.Clear();
}
currentGameInfo.GameState = gameState;
currentGameInfo.AllMessage = GetMessageOfAll();
currentGameInfo.AllMessage = GetMessageOfAll(time);
mwr?.WriteOne(currentGameInfo);
break;
default:
@@ -211,10 +212,10 @@ namespace Server
return false;
}

private MessageOfAll GetMessageOfAll()
private MessageOfAll GetMessageOfAll(int time)
{
MessageOfAll msg = new MessageOfAll();
msg.GameTime = game.GameMap.Timer.nowTime();
msg.GameTime = time;
msg.SubjectFinished = (int)game.GameMap.NumOfRepairedGenerators;
msg.StudentGraduated = (int)game.GameMap.NumOfEscapedStudent;
msg.StudentQuited = (int)game.GameMap.NumOfDeceasedStudent;


+ 17
- 19
logic/规则Logic.md View File

@@ -8,10 +8,10 @@
- **极坐标以x坐标轴为极轴,角度逆时针为正方向**。
- 地图由50 * 50个格子构成,其中每个格子代表1000 * 1000的正方形。每个格子的编号(CellX,CellY)可以计算得到:
- 略
- 地图上的每个格子有自己的区域类型:陆地、墙、草地、教室、校门、隐藏校门、门、窗、箱子
- 地图上格子有自己的区域类型:陆地、墙、草地、教室、校门、隐藏校门、门、窗、箱子

### 移动
- `std::future<bool> Move(int64_t timeInMilliseconds, double angleInRadian)`:移动,`timeInMilliseconds` 为移动时间,单位毫秒;`angleInRadian` 表示移动方向,单位弧度,使用极坐标,**竖直向下方向为x轴,水平向右方向为y轴**
- `std::future<bool> Move(int64_t timeInMilliseconds, double angleInRadian)`:移动,`timeInMilliseconds` 为移动时间,单位毫秒;`angleInRadian` 表示移动方向,单位弧度,使用极坐标,**竖直向下方向为x轴,水平向右方向为y轴**

### 使用技能
- `std::future<bool> UseSkill(int32_t skillID)`:使用对应序号的主动技能
@@ -20,6 +20,7 @@
- 人物半径为800
- 人物共有17种不可叠加的状态:
1. (可)移动状态
- `std::future<bool> EndAllAction()`:可以使处在下者八项状态中的玩家终止交互
2. 学习
3. 被勉励
4. 在勉励
@@ -28,7 +29,7 @@
7. 使用技能
8. 开启校门
9. 唤醒他人中
- 之后八项为不可行动状态
10. 被唤醒中
11. 沉迷
12. 退学
@@ -38,9 +39,6 @@
16. 后摇
17. 翻窗

- 其中后8项为不可行动状态
- `std::future<bool> EndAllAction()`:可以使处在2-9状态的玩家终止对应交互,对于后8项状态无效

### 攻击
- `std::future<bool> Attack(double angleInRadian)`:`angleInRadian`为攻击方向,无论近战远程均产生bullet表示攻击
- 攻击类型CommonAttackOfGhost攻击未写完的作业,会造成对应攻击力的损坏
@@ -67,17 +65,17 @@
- 每张地图都有10间教室,学生需要完成其中的**7间**教室的作业,才可以开启任意校门。
- `std::future<bool> StartLearning()`:在教室(旁)做作业
- `std::future<bool> StartOpenGate()`:开启校门,所需时间为18秒,开启的进度不清空
- 隐藏校门会在**3间**教室的作业完成的情况下在3-5个隐藏校门刷新点之一随机显现,当学生只剩1名时,隐藏校门将会自动打开。
- 当**3间**教室的作业完成时,隐藏校门在3-5个刷新点之一随机显现;当只剩1名学生时,隐藏校门自动打开。
- `std::future<bool> Graduate()`:从开启的校门或隐藏校门毕业。

#### 勉励(Treat)
- `std::future<bool> StartTreatMate(int64_t mateID)`:勉励对应玩家ID的学生,当达到被勉励程度达到1500000或者最大血量与当前血量的差值时,勉励结束
- `std::future<bool> StartTreatMate(int64_t mateID)`:勉励对应玩家ID的学生,当达到被勉励程度达到1500000或者最大学习毅力与当前学习毅力的差值时,勉励完成,学生毅力增加对应被勉励程度
- 勉励中断时,被勉励程度保留;遭到攻击时被勉励程度清空

#### 沉迷与唤醒
- 当学生血量归零时,学生原地进入沉迷状态,每毫秒增加1沉迷度
- `std::future<bool> StartRescueMate(int64_t mateID)`:唤醒对应玩家ID的沉迷的学生,需要时间1秒,之后血量恢复至1/2。沉迷程度不清空。
- 进入沉迷状态时如果学生原沉迷程度在(0,该玩家最大沉迷度/3)中,沉迷程度直接变为其最大沉迷度/3;原沉迷程度在[其最大沉迷度/3,其最大沉迷度x2/3)中,沉迷程度直接变为其最大沉迷度x2/3;原沉迷程度大于其最大沉迷度x2/3,从游戏中出局;
- 当学生学习毅力归零时,学生原地进入沉迷状态,每毫秒增加1沉迷度
- `std::future<bool> StartRescueMate(int64_t mateID)`:唤醒对应玩家ID的沉迷的学生,需要时间1秒,之后学习毅力恢复至1/2。沉迷程度不清空。
- 进入沉迷状态时如果学生原沉迷程度在(0,该玩家最大沉迷度/3)中,沉迷程度直接变为其最大沉迷度/3;原沉迷程度在[其最大沉迷度/3,其最大沉迷度x2/3)中,沉迷程度直接变为其最大沉迷度x2/3;原沉迷程度大于其最大沉迷度x2/3,从游戏中出局;
- 当学生沉迷程度达到其最大沉迷程度时,从游戏中出局

#### 门
@@ -99,12 +97,12 @@
3. 学习的声音: 捣蛋鬼警戒半径内有人学习时收到;bgmVolume=(警戒半径x学习进度百分比)/二者距离

### 队内信息
- `std::future<bool> SendMessage(int64_t, std::string)`:给同队的队友发送消息。`toPlayerID`指定发送的对象,`message`指定发送的内容。`message`的长度不能超过 64,否则将发送失败!
- `std::future<bool> SendMessage(int64_t, std::string)`:给同队的队友发送消息。第一个参数指定发送的对象,第二个参数指定发送的内容。
- `bool HaveMessage()`:是否有队友发来的尚未接收的信息。
- `std::pair<int64_t, std::string> GetMessage()`:从玩家ID为第一个参数的队友获取信息。

### 信息受限
- 主动行为每 50ms 最多总共可以调用 50 次;
- `bool Wait()`:asynchronous 为 true 的情况下,选手可以调用此函数,阻塞当前线程,直到下一次消息更新时继续运行。
### 线程控制
- `bool Wait()`:阻塞当前线程,直到下一次消息更新时继续运行。

### 信息获取
`std::vector<std::shared_ptr<const THUAI6::Student>> GetStudents() const` :返回所有可视学生的信息。
@@ -189,11 +187,11 @@
- 普通攻击为 搞蛋鬼的一般攻击
- 主动技能
- 隐身
- CD:30s 持续时间:6s
- CD:60s 持续时间:6s
- 在持续时间内玩家隐身
- 使用瞬间得分
- 使用飞刀
- CD:20s 持续时间:1s
- CD:30s 持续时间:1s
- 在持续时间内,攻击类型变为飞刀
- 不直接得分

@@ -412,14 +410,14 @@ public:

### 交互
- 在指令仍在进行时,重复发出同一类型的交互指令是无效的,你需要先发出Stop指令终止进行的指令
- 实际上救援或勉励不同的人是有效的
- 实际上唤醒或勉励不同的人是有效的

### 破译与逃脱
- 隐藏校门与校门对于人有碰撞体积
- 一个校门同时最多可以由一人开启

### 攻击
- 每次学生受到攻击后会损失对应子弹的攻击力的血量
- 每次学生受到攻击后会损失对应子弹的攻击力的学习毅力
- 前摇期间攻击被打断时,子弹消失。
- 此处,前摇指 从播放攻击动作开始 攻击者不能交互 的时间



Loading…
Cancel
Save