| @@ -23,9 +23,9 @@ find . -iname "*.c" \ | |||||
| | xargs clang-format -i | | xargs clang-format -i | ||||
| done | done | ||||
| cd logic && dotnet format && cd .. | |||||
| cd installer && dotnet format && cd .. | |||||
| cd launcher && dotnet format && cd .. | |||||
| cd playback && dotnet format && cd .. | |||||
| pushd logic && dotnet format && popd | |||||
| pushd installer && dotnet format && popd | |||||
| pushd launcher && dotnet format && popd | |||||
| pushd playback && dotnet format && popd | |||||
| echo "Done!" | |||||
| echo "Done!" | |||||
| @@ -1,6 +1,6 @@ | |||||
| using System.Windows; | using System.Windows; | ||||
| [assembly:ThemeInfo( | |||||
| [assembly: ThemeInfo( | |||||
| ResourceDictionaryLocation.None, // where theme specific resource dictionaries are located | ResourceDictionaryLocation.None, // where theme specific resource dictionaries are located | ||||
| //(used if a resource is not found in the page, | //(used if a resource is not found in the page, | ||||
| // or application resource dictionaries) | // or application resource dictionaries) | ||||
| @@ -71,23 +71,29 @@ namespace starter.viewmodel.settings | |||||
| /// </summary> | /// </summary> | ||||
| public string Route | public string Route | ||||
| { | { | ||||
| get { | |||||
| get | |||||
| { | |||||
| return Downloader.Program.Data.FilePath; | return Downloader.Program.Data.FilePath; | ||||
| } | } | ||||
| set { | |||||
| set | |||||
| { | |||||
| Downloader.Program.Data.FilePath = value; | Downloader.Program.Data.FilePath = value; | ||||
| } | } | ||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| /// if the route was set or is under editing | /// if the route was set or is under editing | ||||
| /// </summary> | /// </summary> | ||||
| public bool EditingRoute { | |||||
| get; set; } | |||||
| public bool EditingRoute | |||||
| { | |||||
| get; set; | |||||
| } | |||||
| ///< summary> | ///< summary> | ||||
| /// if already installed | /// if already installed | ||||
| /// </summary> | /// </summary> | ||||
| public bool installed { | |||||
| get; set; } | |||||
| public bool installed | |||||
| { | |||||
| get; set; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| namespace Downloader | namespace Downloader | ||||
| @@ -224,7 +230,8 @@ namespace Downloader | |||||
| GetObjectRequest request = new GetObjectRequest(bucket, key, localDir, localFileName); | GetObjectRequest request = new GetObjectRequest(bucket, key, localDir, localFileName); | ||||
| Dictionary<string, string> test = request.GetRequestHeaders(); | Dictionary<string, string> test = request.GetRequestHeaders(); | ||||
| request.SetCosProgressCallback(delegate(long completed, long total) { | |||||
| request.SetCosProgressCallback(delegate (long completed, long total) | |||||
| { | |||||
| Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total)); | Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total)); | ||||
| }); | }); | ||||
| // 执行请求 | // 执行请求 | ||||
| @@ -834,7 +841,8 @@ namespace WebConnect | |||||
| async public Task LoginToEEsast(HttpClient client, string useremail, string password) | async public Task LoginToEEsast(HttpClient client, string useremail, string password) | ||||
| { | { | ||||
| string token = ""; | string token = ""; | ||||
| using (var response = await client.PostAsync("https://api.eesast.com/users/login", JsonContent.Create(new { | |||||
| using (var response = await client.PostAsync("https://api.eesast.com/users/login", JsonContent.Create(new | |||||
| { | |||||
| email = useremail, | email = useremail, | ||||
| password = password, | password = password, | ||||
| }))) | }))) | ||||
| @@ -843,9 +851,10 @@ namespace WebConnect | |||||
| { | { | ||||
| case System.Net.HttpStatusCode.OK: | case System.Net.HttpStatusCode.OK: | ||||
| Console.WriteLine("Success login"); | Console.WriteLine("Success login"); | ||||
| token = (System.Text.Json.JsonSerializer.Deserialize(await response.Content.ReadAsStreamAsync(), typeof(LoginResponse), new JsonSerializerOptions() { | |||||
| PropertyNamingPolicy = JsonNamingPolicy.CamelCase, | |||||
| }) as LoginResponse) | |||||
| token = (System.Text.Json.JsonSerializer.Deserialize(await response.Content.ReadAsStreamAsync(), typeof(LoginResponse), new JsonSerializerOptions() | |||||
| { | |||||
| PropertyNamingPolicy = JsonNamingPolicy.CamelCase, | |||||
| }) as LoginResponse) | |||||
| ?.Token ?? | ?.Token ?? | ||||
| throw new Exception("no token!"); | throw new Exception("no token!"); | ||||
| logintoken = token; | logintoken = token; | ||||
| @@ -30,20 +30,24 @@ namespace starter.viewmodel.settings | |||||
| public string Route | public string Route | ||||
| { | { | ||||
| get { | |||||
| get | |||||
| { | |||||
| return obj.Route; | return obj.Route; | ||||
| } | } | ||||
| set { | |||||
| set | |||||
| { | |||||
| obj.Route = value; | obj.Route = value; | ||||
| this.RaisePropertyChanged("Route"); | this.RaisePropertyChanged("Route"); | ||||
| } | } | ||||
| } | } | ||||
| public bool Installed | public bool Installed | ||||
| { | { | ||||
| get { | |||||
| get | |||||
| { | |||||
| return obj.installed; | return obj.installed; | ||||
| } | } | ||||
| set { | |||||
| set | |||||
| { | |||||
| obj.installed = value; | obj.installed = value; | ||||
| this.RaisePropertyChanged("Installed"); | this.RaisePropertyChanged("Installed"); | ||||
| this.RaisePropertyChanged("InstIntroVis"); | this.RaisePropertyChanged("InstIntroVis"); | ||||
| @@ -53,10 +57,12 @@ namespace starter.viewmodel.settings | |||||
| } | } | ||||
| public bool EditingRoute | public bool EditingRoute | ||||
| { | { | ||||
| get { | |||||
| get | |||||
| { | |||||
| return obj.EditingRoute; | return obj.EditingRoute; | ||||
| } | } | ||||
| set { | |||||
| set | |||||
| { | |||||
| obj.EditingRoute = value; | obj.EditingRoute = value; | ||||
| this.RaisePropertyChanged("EditingRoute"); | this.RaisePropertyChanged("EditingRoute"); | ||||
| this.RaisePropertyChanged("MoveIntroVis"); | this.RaisePropertyChanged("MoveIntroVis"); | ||||
| @@ -65,7 +71,8 @@ namespace starter.viewmodel.settings | |||||
| } | } | ||||
| public Visibility RouteBoxVis // if the route editing textbox is visible | public Visibility RouteBoxVis // if the route editing textbox is visible | ||||
| { | { | ||||
| get { | |||||
| get | |||||
| { | |||||
| return obj.EditingRoute ? Visibility.Visible : Visibility.Collapsed; | return obj.EditingRoute ? Visibility.Visible : Visibility.Collapsed; | ||||
| } | } | ||||
| } | } | ||||
| @@ -74,19 +81,22 @@ namespace starter.viewmodel.settings | |||||
| /// </summary> | /// </summary> | ||||
| public Visibility InstIntroVis | public Visibility InstIntroVis | ||||
| { | { | ||||
| get { | |||||
| get | |||||
| { | |||||
| return obj.installed ? Visibility.Collapsed : Visibility.Visible; | return obj.installed ? Visibility.Collapsed : Visibility.Visible; | ||||
| } | } | ||||
| } | } | ||||
| public Visibility EditIntroVis | public Visibility EditIntroVis | ||||
| { | { | ||||
| get { | |||||
| get | |||||
| { | |||||
| return obj.installed ? Visibility.Visible : Visibility.Collapsed; | return obj.installed ? Visibility.Visible : Visibility.Collapsed; | ||||
| } | } | ||||
| } | } | ||||
| public Visibility MoveIntroVis | public Visibility MoveIntroVis | ||||
| { | { | ||||
| get { | |||||
| get | |||||
| { | |||||
| if (obj.installed == true && obj.EditingRoute == true) | if (obj.installed == true && obj.EditingRoute == true) | ||||
| return Visibility.Visible; | return Visibility.Visible; | ||||
| else | else | ||||
| @@ -97,7 +107,8 @@ namespace starter.viewmodel.settings | |||||
| private BaseCommand clickBrowseCommand; | private BaseCommand clickBrowseCommand; | ||||
| public BaseCommand ClickBrowseCommand | public BaseCommand ClickBrowseCommand | ||||
| { | { | ||||
| get { | |||||
| get | |||||
| { | |||||
| if (clickBrowseCommand == null) | if (clickBrowseCommand == null) | ||||
| { | { | ||||
| clickBrowseCommand = new BaseCommand(new Action<object>(o => | clickBrowseCommand = new BaseCommand(new Action<object>(o => | ||||
| @@ -105,31 +116,32 @@ namespace starter.viewmodel.settings | |||||
| using (FolderBrowserDialog dialog = new FolderBrowserDialog()) | using (FolderBrowserDialog dialog = new FolderBrowserDialog()) | ||||
| { | { | ||||
| _ = dialog.ShowDialog(); | _ = dialog.ShowDialog(); | ||||
| if (dialog.SelectedPath != String.Empty) | |||||
| Route = dialog.SelectedPath; | |||||
| if (dialog.SelectedPath != String.Empty) | |||||
| Route = dialog.SelectedPath; | |||||
| } | |||||
| })); | |||||
| } | } | ||||
| })); | |||||
| } | |||||
| return clickBrowseCommand; | |||||
| } | |||||
| } | |||||
| private BaseCommand clickConfirmCommand; | |||||
| public BaseCommand ClickConfirmCommand | |||||
| { | |||||
| get { | |||||
| if (clickConfirmCommand == null) | |||||
| return clickBrowseCommand; | |||||
| } | |||||
| } | |||||
| private BaseCommand clickConfirmCommand; | |||||
| public BaseCommand ClickConfirmCommand | |||||
| { | { | ||||
| get | |||||
| { | |||||
| if (clickConfirmCommand == null) | |||||
| { | |||||
| clickConfirmCommand = new BaseCommand(new Action<object>(o => | clickConfirmCommand = new BaseCommand(new Action<object>(o => | ||||
| { | { | ||||
| if (obj.install()) | if (obj.install()) | ||||
| { | { | ||||
| EditingRoute = false; | EditingRoute = false; | ||||
| Installed = true; | |||||
| } | |||||
| })); | |||||
| Installed = true; | |||||
| } | |||||
| })); | |||||
| } | } | ||||
| return clickConfirmCommand; | |||||
| } | |||||
| } | |||||
| } | |||||
| return clickConfirmCommand; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -1,6 +1,6 @@ | |||||
| using System.Windows; | using System.Windows; | ||||
| [assembly:ThemeInfo( | |||||
| [assembly: ThemeInfo( | |||||
| ResourceDictionaryLocation.None, // where theme specific resource dictionaries are located | ResourceDictionaryLocation.None, // where theme specific resource dictionaries are located | ||||
| //(used if a resource is not found in the page, | //(used if a resource is not found in the page, | ||||
| // or application resource dictionaries) | // or application resource dictionaries) | ||||
| @@ -48,125 +48,129 @@ namespace GameClass.GameObj | |||||
| () => | () => | ||||
| { | { | ||||
| LinkedListNode<BuffValue> buffNode; | LinkedListNode<BuffValue> buffNode; | ||||
| lock (buffListLock[(int)buffType]) | |||||
| { | |||||
| buffNode = buffList[(int)buffType].AddLast(bf); | |||||
| } | |||||
| ReCalculateFunc(); | |||||
| Thread.Sleep(buffTime); | |||||
| try | |||||
| { | |||||
| lock (buffListLock[(int)buffType]) | |||||
| { | |||||
| buffList[(int)buffType].Remove(buffNode); | |||||
| } | |||||
| } | |||||
| catch | |||||
| { | |||||
| } | |||||
| ReCalculateFunc(); | |||||
| } | |||||
| ) | |||||
| { IsBackground = true }.Start(); | |||||
| } | |||||
| private int ReCalculateFloatBuff(BuffType buffType, int orgVal, int maxVal, int minVal) | |||||
| { | |||||
| double times = 1.0; | |||||
| lock (buffListLock[(int)buffType]) | lock (buffListLock[(int)buffType]) | ||||
| { | { | ||||
| buffNode = buffList[(int)buffType].AddLast(bf); | |||||
| } | |||||
| ReCalculateFunc(); | |||||
| Thread.Sleep(buffTime); | |||||
| try | |||||
| { | |||||
| lock (buffListLock[(int)buffType]) | |||||
| foreach (var add in buffList[(int)buffType]) | |||||
| { | { | ||||
| buffList[(int)buffType].Remove(buffNode); | |||||
| times *= add.lfValue; | |||||
| } | } | ||||
| } | } | ||||
| catch | |||||
| { | |||||
| } | |||||
| ReCalculateFunc(); | |||||
| return Math.Max(Math.Min((int)Math.Round(orgVal * times), maxVal), minVal); | |||||
| } | } | ||||
| ) | |||||
| { IsBackground = true }.Start(); | |||||
| } | |||||
| private int ReCalculateFloatBuff(BuffType buffType, int orgVal, int maxVal, int minVal) | |||||
| { | |||||
| double times = 1.0; | |||||
| lock (buffListLock[(int)buffType]) | |||||
| { | |||||
| foreach (var add in buffList[(int)buffType]) | |||||
| public void AddMoveSpeed(double add, int buffTime, Action<int> SetNewMoveSpeed, int orgMoveSpeed) => AddBuff(new BuffValue(add), buffTime, BuffType.AddSpeed, () => SetNewMoveSpeed(ReCalculateFloatBuff(BuffType.AddSpeed, orgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed))); | |||||
| public bool HasFasterSpeed | |||||
| { | |||||
| get | |||||
| { | { | ||||
| times *= add.lfValue; | |||||
| } | |||||
| lock (buffListLock[(int)BuffType.AddSpeed]) | |||||
| { | |||||
| return buffList[(int)BuffType.AddSpeed].Count != 0; | |||||
| } | } | ||||
| return Math.Max(Math.Min((int)Math.Round(orgVal * times), maxVal), minVal); | |||||
| } | |||||
| public void AddMoveSpeed(double add, int buffTime, Action<int> SetNewMoveSpeed, int orgMoveSpeed) => AddBuff(new BuffValue(add), buffTime, BuffType.AddSpeed, () => SetNewMoveSpeed(ReCalculateFloatBuff(BuffType.AddSpeed, orgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed))); | |||||
| public bool HasFasterSpeed | |||||
| { | |||||
| get { | |||||
| lock (buffListLock[(int)BuffType.AddSpeed]) | |||||
| { | |||||
| return buffList[(int)BuffType.AddSpeed].Count != 0; | |||||
| } | } | ||||
| } | |||||
| } | |||||
| } | |||||
| public void AddShield(int shieldTime) => AddBuff(new BuffValue(), shieldTime, BuffType.Shield, () => | |||||
| {}); | |||||
| public bool HasShield | |||||
| { | |||||
| get { | |||||
| lock (buffListLock[(int)BuffType.Shield]) | |||||
| public void AddShield(int shieldTime) => AddBuff(new BuffValue(), shieldTime, BuffType.Shield, () => | |||||
| { }); | |||||
| public bool HasShield | |||||
| { | |||||
| get | |||||
| { | { | ||||
| return buffList[(int)BuffType.Shield].Count != 0; | |||||
| } | |||||
| lock (buffListLock[(int)BuffType.Shield]) | |||||
| { | |||||
| return buffList[(int)BuffType.Shield].Count != 0; | |||||
| } | } | ||||
| } | |||||
| } | |||||
| } | |||||
| public void AddLIFE(int totelTime) => AddBuff(new BuffValue(), totelTime, BuffType.AddLIFE, () => | |||||
| {}); | |||||
| public bool HasLIFE | |||||
| { | |||||
| get { | |||||
| lock (buffListLock[(int)BuffType.AddLIFE]) | |||||
| public void AddLIFE(int totelTime) => AddBuff(new BuffValue(), totelTime, BuffType.AddLIFE, () => | |||||
| { }); | |||||
| public bool HasLIFE | |||||
| { | |||||
| get | |||||
| { | { | ||||
| return buffList[(int)BuffType.AddLIFE].Count != 0; | |||||
| } | |||||
| } | |||||
| } | |||||
| public bool TryActivatingLIFE() | |||||
| { | |||||
| if (HasLIFE) | |||||
| lock (buffListLock[(int)BuffType.AddLIFE]) | |||||
| { | { | ||||
| lock (buffListLock[(int)BuffType.AddLIFE]) | |||||
| { | |||||
| buffList[(int)BuffType.AddLIFE].Clear(); | |||||
| return buffList[(int)BuffType.AddLIFE].Count != 0; | |||||
| } | |||||
| } | } | ||||
| return true; | |||||
| } | |||||
| public bool TryActivatingLIFE() | |||||
| { | |||||
| if (HasLIFE) | |||||
| { | |||||
| lock (buffListLock[(int)BuffType.AddLIFE]) | |||||
| { | |||||
| buffList[(int)BuffType.AddLIFE].Clear(); | |||||
| } | } | ||||
| return false; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| public void AddSpear(int spearTime) => AddBuff(new BuffValue(), spearTime, BuffType.Spear, () => | |||||
| {}); | |||||
| public bool HasSpear | |||||
| { | |||||
| get { | |||||
| lock (buffListLock[(int)BuffType.Spear]) | |||||
| public void AddSpear(int spearTime) => AddBuff(new BuffValue(), spearTime, BuffType.Spear, () => | |||||
| { }); | |||||
| public bool HasSpear | |||||
| { | |||||
| get | |||||
| { | { | ||||
| return buffList[(int)BuffType.Spear].Count != 0; | |||||
| } | |||||
| } | |||||
| } | |||||
| /// <summary> | |||||
| /// 清除所有buff | |||||
| /// </summary> | |||||
| public void ClearAll() | |||||
| { | |||||
| for (int i = 0; i < buffList.Length; ++i) | |||||
| lock (buffListLock[(int)BuffType.Spear]) | |||||
| { | { | ||||
| lock (buffListLock[i]) | |||||
| { | |||||
| buffList[i].Clear(); | |||||
| } | |||||
| return buffList[(int)BuffType.Spear].Count != 0; | |||||
| } | } | ||||
| } | |||||
| public BuffManeger() | |||||
| { | |||||
| var buffTypeArray = Enum.GetValues(typeof(BuffType)); | |||||
| buffList = new LinkedList<BuffValue>[buffTypeArray.Length]; | |||||
| buffListLock = new object[buffList.Length]; | |||||
| int i = 0; | |||||
| foreach (BuffType type in buffTypeArray) | |||||
| } | |||||
| } | |||||
| /// <summary> | |||||
| /// 清除所有buff | |||||
| /// </summary> | |||||
| public void ClearAll() | |||||
| { | |||||
| for (int i = 0; i < buffList.Length; ++i) | |||||
| { | |||||
| lock (buffListLock[i]) | |||||
| { | { | ||||
| buffList[i] = new LinkedList<BuffValue>(); | |||||
| buffListLock[i++] = new object(); | |||||
| buffList[i].Clear(); | |||||
| } | } | ||||
| } | |||||
| } | |||||
| public BuffManeger() | |||||
| { | |||||
| var buffTypeArray = Enum.GetValues(typeof(BuffType)); | |||||
| buffList = new LinkedList<BuffValue>[buffTypeArray.Length]; | |||||
| buffListLock = new object[buffList.Length]; | |||||
| int i = 0; | |||||
| foreach (BuffType type in buffTypeArray) | |||||
| { | |||||
| buffList[i] = new LinkedList<BuffValue>(); | |||||
| buffListLock[i++] = new object(); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| @@ -23,7 +23,8 @@ namespace GameClass.GameObj | |||||
| public int TimeUntilCommonSkillAvailable | public int TimeUntilCommonSkillAvailable | ||||
| { | { | ||||
| get => timeUntilCommonSkillAvailable; | get => timeUntilCommonSkillAvailable; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| timeUntilCommonSkillAvailable = value < 0 ? 0 : value; | timeUntilCommonSkillAvailable = value < 0 ? 0 : value; | ||||
| } | } | ||||
| @@ -11,7 +11,7 @@ namespace GameClass.GameObj | |||||
| { | { | ||||
| private readonly object beAttackedLock = new(); | private readonly object beAttackedLock = new(); | ||||
| #region 角色的基本属性及方法,包括与道具的交互方法 | |||||
| #region 角色的基本属性及方法,包括与道具的交互方法 | |||||
| /// <summary> | /// <summary> | ||||
| /// 装弹冷却 | /// 装弹冷却 | ||||
| @@ -20,8 +20,9 @@ namespace GameClass.GameObj | |||||
| public int CD | public int CD | ||||
| { | { | ||||
| get => cd; | get => cd; | ||||
| private | |||||
| set { | |||||
| private | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| cd = value; | cd = value; | ||||
| @@ -40,7 +41,8 @@ namespace GameClass.GameObj | |||||
| public int HP | public int HP | ||||
| { | { | ||||
| get => hp; | get => hp; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| hp = value <= MaxHp ? value : MaxHp; | hp = value <= MaxHp ? value : MaxHp; | ||||
| } | } | ||||
| @@ -60,7 +62,8 @@ namespace GameClass.GameObj | |||||
| public double Vampire | public double Vampire | ||||
| { | { | ||||
| get => vampire; | get => vampire; | ||||
| set { | |||||
| set | |||||
| { | |||||
| if (value > 1) | if (value > 1) | ||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| vampire = 1; | vampire = 1; | ||||
| @@ -76,7 +79,8 @@ namespace GameClass.GameObj | |||||
| public double OriVampire | public double OriVampire | ||||
| { | { | ||||
| get => oriVampire; | get => oriVampire; | ||||
| set { | |||||
| set | |||||
| { | |||||
| if (value > 1) | if (value > 1) | ||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| vampire = 1; | vampire = 1; | ||||
| @@ -94,7 +98,8 @@ namespace GameClass.GameObj | |||||
| public BulletType BulletOfPlayer | public BulletType BulletOfPlayer | ||||
| { | { | ||||
| get => bulletOfPlayer; | get => bulletOfPlayer; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| bulletOfPlayer = value; | bulletOfPlayer = value; | ||||
| } | } | ||||
| @@ -104,7 +109,8 @@ namespace GameClass.GameObj | |||||
| public Prop? PropInventory // 持有的道具 | public Prop? PropInventory // 持有的道具 | ||||
| { | { | ||||
| get => propInventory; | get => propInventory; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| propInventory = value; | propInventory = value; | ||||
| @@ -134,7 +140,8 @@ namespace GameClass.GameObj | |||||
| public bool IsModifyingProp | public bool IsModifyingProp | ||||
| { | { | ||||
| get => isModifyingProp; | get => isModifyingProp; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| isModifyingProp = value; | isModifyingProp = value; | ||||
| @@ -149,7 +156,8 @@ namespace GameClass.GameObj | |||||
| public bool IsInvisible | public bool IsInvisible | ||||
| { | { | ||||
| get => isInvisible; | get => isInvisible; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| isInvisible = value; | isInvisible = value; | ||||
| @@ -346,7 +354,8 @@ namespace GameClass.GameObj | |||||
| public long TeamID | public long TeamID | ||||
| { | { | ||||
| get => teamID; | get => teamID; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| teamID = value; | teamID = value; | ||||
| @@ -358,7 +367,8 @@ namespace GameClass.GameObj | |||||
| public long PlayerID | public long PlayerID | ||||
| { | { | ||||
| get => playerID; | get => playerID; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| playerID = value; | playerID = value; | ||||
| @@ -372,16 +382,17 @@ namespace GameClass.GameObj | |||||
| public string Message | public string Message | ||||
| { | { | ||||
| get => message; | get => message; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| message = value; | message = value; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #endregion | |||||
| #endregion | |||||
| #region 角色拥有的buff相关属性、方法 | |||||
| #region 角色拥有的buff相关属性、方法 | |||||
| public void AddMoveSpeed(int buffTime, double add = 2.0) => buffManeger.AddMoveSpeed(add, buffTime, newVal => | public void AddMoveSpeed(int buffTime, double add = 2.0) => buffManeger.AddMoveSpeed(add, buffTime, newVal => | ||||
| { MoveSpeed = newVal < GameData.characterMaxSpeed ? newVal : GameData.characterMaxSpeed; }, | { MoveSpeed = newVal < GameData.characterMaxSpeed ? newVal : GameData.characterMaxSpeed; }, | ||||
| OrgMoveSpeed); | OrgMoveSpeed); | ||||
| @@ -399,7 +410,8 @@ namespace GameClass.GameObj | |||||
| private Array buffTypeArray = Enum.GetValues(typeof(BuffType)); | private Array buffTypeArray = Enum.GetValues(typeof(BuffType)); | ||||
| public Dictionary<BuffType, bool> Buff | public Dictionary<BuffType, bool> Buff | ||||
| { | { | ||||
| get { | |||||
| get | |||||
| { | |||||
| Dictionary<BuffType, bool> buff = new Dictionary<BuffType, bool>(); | Dictionary<BuffType, bool> buff = new Dictionary<BuffType, bool>(); | ||||
| foreach (BuffType type in buffTypeArray) | foreach (BuffType type in buffTypeArray) | ||||
| { | { | ||||
| @@ -432,7 +444,7 @@ namespace GameClass.GameObj | |||||
| hp = MaxHp; | hp = MaxHp; | ||||
| } | } | ||||
| } | } | ||||
| #endregion | |||||
| #endregion | |||||
| public override void Reset() // 要加锁吗? | public override void Reset() // 要加锁吗? | ||||
| { | { | ||||
| _ = AddDeathCount(); | _ = AddDeathCount(); | ||||
| @@ -29,8 +29,9 @@ namespace GameClass.GameObj | |||||
| public XY Position | public XY Position | ||||
| { | { | ||||
| get => position; | get => position; | ||||
| protected | |||||
| set { | |||||
| protected | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| position = value; | position = value; | ||||
| @@ -43,7 +44,8 @@ namespace GameClass.GameObj | |||||
| public XY FacingDirection | public XY FacingDirection | ||||
| { | { | ||||
| get => facingDirection; | get => facingDirection; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| facingDirection = value; | facingDirection = value; | ||||
| } | } | ||||
| @@ -54,7 +56,8 @@ namespace GameClass.GameObj | |||||
| public bool CanMove | public bool CanMove | ||||
| { | { | ||||
| get => canMove; | get => canMove; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| canMove = value; | canMove = value; | ||||
| @@ -66,7 +69,8 @@ namespace GameClass.GameObj | |||||
| public bool IsMoving | public bool IsMoving | ||||
| { | { | ||||
| get => isMoving; | get => isMoving; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| isMoving = value; | isMoving = value; | ||||
| @@ -78,7 +82,8 @@ namespace GameClass.GameObj | |||||
| public bool IsResetting | public bool IsResetting | ||||
| { | { | ||||
| get => isResetting; | get => isResetting; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| isResetting = value; | isResetting = value; | ||||
| @@ -92,7 +97,8 @@ namespace GameClass.GameObj | |||||
| public PlaceType Place | public PlaceType Place | ||||
| { | { | ||||
| get => place; | get => place; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| place = value; | place = value; | ||||
| @@ -106,7 +112,8 @@ namespace GameClass.GameObj | |||||
| public int MoveSpeed | public int MoveSpeed | ||||
| { | { | ||||
| get => moveSpeed; | get => moveSpeed; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| moveSpeed = value; | moveSpeed = value; | ||||
| @@ -120,8 +127,9 @@ namespace GameClass.GameObj | |||||
| public int OrgMoveSpeed | public int OrgMoveSpeed | ||||
| { | { | ||||
| get => orgMoveSpeed; | get => orgMoveSpeed; | ||||
| protected | |||||
| set { | |||||
| protected | |||||
| set | |||||
| { | |||||
| orgMoveSpeed = value; | orgMoveSpeed = value; | ||||
| } | } | ||||
| } | } | ||||
| @@ -12,7 +12,8 @@ namespace GameClass.GameObj | |||||
| public ICharacter? Parent | public ICharacter? Parent | ||||
| { | { | ||||
| get => parent; | get => parent; | ||||
| set { | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| parent = value; | parent = value; | ||||
| @@ -43,14 +43,14 @@ namespace GameClass.GameObj | |||||
| { | { | ||||
| } | } | ||||
| } | } | ||||
| ///// <summary> | |||||
| ///// 坑人地雷 | |||||
| ///// </summary> | |||||
| // public abstract class DebuffMine : Prop | |||||
| //{ | |||||
| // public DebuffMine(XYPosition initPos) : base(initPos) { } | |||||
| // } | |||||
| #region 所有增益道具 | |||||
| ///// <summary> | |||||
| ///// 坑人地雷 | |||||
| ///// </summary> | |||||
| // public abstract class DebuffMine : Prop | |||||
| //{ | |||||
| // public DebuffMine(XYPosition initPos) : base(initPos) { } | |||||
| // } | |||||
| #region 所有增益道具 | |||||
| /// <summary> | /// <summary> | ||||
| /// 增加速度 | /// 增加速度 | ||||
| /// </summary> | /// </summary> | ||||
| @@ -95,7 +95,7 @@ namespace GameClass.GameObj | |||||
| } | } | ||||
| public override PropType GetPropType() => PropType.Spear; | public override PropType GetPropType() => PropType.Spear; | ||||
| } | } | ||||
| #endregion | |||||
| #endregion | |||||
| // #region 所有坑人地雷 | // #region 所有坑人地雷 | ||||
| ///// <summary> | ///// <summary> | ||||
| ///// 减速 | ///// 减速 | ||||
| @@ -13,7 +13,8 @@ namespace GameClass.GameObj | |||||
| private readonly List<Character> playerList; | private readonly List<Character> playerList; | ||||
| public int Score | public int Score | ||||
| { | { | ||||
| get { | |||||
| get | |||||
| { | |||||
| int score = 0; | int score = 0; | ||||
| foreach (var player in playerList) | foreach (var player in playerList) | ||||
| score += player.Score; | score += player.Score; | ||||
| @@ -33,8 +33,9 @@ namespace GameClass.Skill | |||||
| { | { | ||||
| return CommonSkillFactory.SkillEffect(this, player, () => | return CommonSkillFactory.SkillEffect(this, player, () => | ||||
| { | { | ||||
| player.Vampire += 0.5; | |||||
| Debugger.Output(player, "becomes vampire!"); }, | |||||
| player.Vampire += 0.5; | |||||
| Debugger.Output(player, "becomes vampire!"); | |||||
| }, | |||||
| () => | () => | ||||
| { | { | ||||
| double tempVam = player.Vampire - 0.5; | double tempVam = player.Vampire - 0.5; | ||||
| @@ -65,8 +66,9 @@ namespace GameClass.Skill | |||||
| { | { | ||||
| return CommonSkillFactory.SkillEffect(this, player, () => | return CommonSkillFactory.SkillEffect(this, player, () => | ||||
| { | { | ||||
| player.IsInvisible = true; | |||||
| Debugger.Output(player, "uses atombomb!"); }, | |||||
| player.IsInvisible = true; | |||||
| Debugger.Output(player, "uses atombomb!"); | |||||
| }, | |||||
| () => | () => | ||||
| { player.IsInvisible = false; }); | { player.IsInvisible = false; }); | ||||
| } | } | ||||
| @@ -93,8 +95,9 @@ namespace GameClass.Skill | |||||
| { | { | ||||
| return CommonSkillFactory.SkillEffect(this, player, () => | return CommonSkillFactory.SkillEffect(this, player, () => | ||||
| { | { | ||||
| player.BulletOfPlayer = BulletType.AtomBomb; | |||||
| Debugger.Output(player, "uses atombomb!"); }, | |||||
| player.BulletOfPlayer = BulletType.AtomBomb; | |||||
| Debugger.Output(player, "uses atombomb!"); | |||||
| }, | |||||
| () => | () => | ||||
| { player.BulletOfPlayer = player.OriBulletOfPlayer; }); | { player.BulletOfPlayer = player.OriBulletOfPlayer; }); | ||||
| } | } | ||||
| @@ -121,10 +124,11 @@ namespace GameClass.Skill | |||||
| { | { | ||||
| return CommonSkillFactory.SkillEffect(this, player, () => | return CommonSkillFactory.SkillEffect(this, player, () => | ||||
| { | { | ||||
| player.AddMoveSpeed(this.DurationTime, 3.0); | |||||
| Debugger.Output(player, "moves very fast!"); }, | |||||
| player.AddMoveSpeed(this.DurationTime, 3.0); | |||||
| Debugger.Output(player, "moves very fast!"); | |||||
| }, | |||||
| () => | () => | ||||
| {}); | |||||
| { }); | |||||
| } | } | ||||
| } | } | ||||
| public class NoCommonSkill : ICommonSkill // 这种情况不该发生,定义着以防意外 | public class NoCommonSkill : ICommonSkill // 这种情况不该发生,定义着以防意外 | ||||
| @@ -164,53 +168,55 @@ namespace GameClass.Skill | |||||
| (() => | (() => | ||||
| { | { | ||||
| startSkill(); | startSkill(); | ||||
| new FrameRateTaskExecutor<int>( | |||||
| () => !player.IsResetting, | |||||
| () => | |||||
| new FrameRateTaskExecutor<int>( | |||||
| () => !player.IsResetting, | |||||
| () => | |||||
| { | |||||
| player.TimeUntilCommonSkillAvailable -= (int)GameData.frameDuration; | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| () => 0, | |||||
| maxTotalDuration: (long)(commonSkill.DurationTime) | |||||
| ) | |||||
| { | { | ||||
| player.TimeUntilCommonSkillAvailable -= (int)GameData.frameDuration; | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| () => 0, | |||||
| maxTotalDuration: (long)(commonSkill.DurationTime) | |||||
| ) { | |||||
| AllowTimeExceed = true, | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||||
| } | |||||
| .Start(); | |||||
| endSkill(); | |||||
| Debugger.Output(player, "return to normal."); | |||||
| new FrameRateTaskExecutor<int>( | |||||
| () => player.TimeUntilCommonSkillAvailable > 0 && !player.IsResetting, | |||||
| () => | |||||
| AllowTimeExceed = true, | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||||
| } | |||||
| .Start(); | |||||
| endSkill(); | |||||
| Debugger.Output(player, "return to normal."); | |||||
| new FrameRateTaskExecutor<int>( | |||||
| () => player.TimeUntilCommonSkillAvailable > 0 && !player.IsResetting, | |||||
| () => | |||||
| { | |||||
| player.TimeUntilCommonSkillAvailable -= (int)GameData.frameDuration; | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| () => 0, | |||||
| maxTotalDuration: (long)(commonSkill.SkillCD - commonSkill.DurationTime) | |||||
| ) | |||||
| { | { | ||||
| player.TimeUntilCommonSkillAvailable -= (int)GameData.frameDuration; | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| () => 0, | |||||
| maxTotalDuration: (long)(commonSkill.SkillCD - commonSkill.DurationTime) | |||||
| ) { | |||||
| AllowTimeExceed = true, | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||||
| } | |||||
| .Start(); | |||||
| AllowTimeExceed = true, | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||||
| } | |||||
| .Start(); | |||||
| player.TimeUntilCommonSkillAvailable = 0; | |||||
| Debugger.Output(player, "CommonSkill is ready."); | |||||
| } | |||||
| player.TimeUntilCommonSkillAvailable = 0; | |||||
| Debugger.Output(player, "CommonSkill is ready."); | |||||
| } | |||||
| ) | ) | ||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| return true; | return true; | ||||
| } | |||||
| else | |||||
| { | |||||
| } | |||||
| else | |||||
| { | |||||
| Debugger.Output(player, "CommonSkill is cooling down!"); | Debugger.Output(player, "CommonSkill is cooling down!"); | ||||
| return false; | return false; | ||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| @@ -29,19 +29,19 @@ namespace GameClass.Skill // 被动技能开局时就释放,持续到游戏 | |||||
| () => true, | () => true, | ||||
| () => | () => | ||||
| { | { | ||||
| lastHP = nowHP; // lastHP等于上一帧的HP | |||||
| nowHP = player.HP; // nowHP更新为这一帧的HP | |||||
| if (lastHP > nowHP) // 这一帧扣血了 | |||||
| { | |||||
| waitTime = 0; | |||||
| } | |||||
| else if (waitTime < interval) | |||||
| { | |||||
| waitTime += GameData.frameDuration; | |||||
| } | |||||
| lastHP = nowHP; // lastHP等于上一帧的HP | |||||
| nowHP = player.HP; // nowHP更新为这一帧的HP | |||||
| if (lastHP > nowHP) // 这一帧扣血了 | |||||
| { | |||||
| waitTime = 0; | |||||
| } | |||||
| else if (waitTime < interval) | |||||
| { | |||||
| waitTime += GameData.frameDuration; | |||||
| } | |||||
| if (waitTime >= interval) // 回复时,每帧(50ms)回复5,即1s回复100。 | |||||
| player.TryAddHp(recoverDegree); | |||||
| if (waitTime >= interval) // 回复时,每帧(50ms)回复5,即1s回复100。 | |||||
| player.TryAddHp(recoverDegree); | |||||
| }, | }, | ||||
| timeInterval: GameData.frameDuration, | timeInterval: GameData.frameDuration, | ||||
| () => 0, | () => 0, | ||||
| @@ -52,29 +52,29 @@ namespace GameClass.Skill // 被动技能开局时就释放,持续到游戏 | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | MaxTolerantTimeExceedCount = ulong.MaxValue, | ||||
| TimeExceedAction = b => | TimeExceedAction = b => | ||||
| { | { | ||||
| if (b) | |||||
| Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); | |||||
| if (b) | |||||
| Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); | |||||
| #if DEBUG | #if DEBUG | ||||
| else | |||||
| { | |||||
| Console.WriteLine("Debug info: passive skill time exceeds for once."); | |||||
| } | |||||
| else | |||||
| { | |||||
| Console.WriteLine("Debug info: passive skill time exceeds for once."); | |||||
| } | |||||
| #endif | #endif | ||||
| } | } | ||||
| }.Start(); | }.Start(); | ||||
| } | |||||
| } | |||||
| ) | ) | ||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| } | |||||
| } | } | ||||
| } | |||||
| public class SpeedUpWhenLeavingGrass : IPassiveSkill // 3倍速 | |||||
| { | |||||
| private readonly BulletType initBullet = BulletType.FastBullet; | |||||
| public BulletType InitBullet => initBullet; | |||||
| // 以上参数以后再改 | |||||
| public void SkillEffect(Character player) | |||||
| public class SpeedUpWhenLeavingGrass : IPassiveSkill // 3倍速 | |||||
| { | { | ||||
| private readonly BulletType initBullet = BulletType.FastBullet; | |||||
| public BulletType InitBullet => initBullet; | |||||
| // 以上参数以后再改 | |||||
| public void SkillEffect(Character player) | |||||
| { | |||||
| PlaceType nowPlace = player.Place; | PlaceType nowPlace = player.Place; | ||||
| PlaceType lastPlace = nowPlace; | PlaceType lastPlace = nowPlace; | ||||
| bool speedup = false; | bool speedup = false; | ||||
| @@ -88,20 +88,20 @@ public class SpeedUpWhenLeavingGrass : IPassiveSkill // 3倍速 | |||||
| () => true, | () => true, | ||||
| () => | () => | ||||
| { | { | ||||
| lastPlace = nowPlace; | |||||
| nowPlace = player.Place; | |||||
| if ((lastPlace == PlaceType.Grass1 || lastPlace == PlaceType.Grass2 || lastPlace == PlaceType.Grass3) && nowPlace == PlaceType.Land) | |||||
| { | |||||
| if (!speedup) | |||||
| { | |||||
| lastPlace = nowPlace; | |||||
| nowPlace = player.Place; | |||||
| if ((lastPlace == PlaceType.Grass1 || lastPlace == PlaceType.Grass2 || lastPlace == PlaceType.Grass3) && nowPlace == PlaceType.Land) | |||||
| { | |||||
| if (!speedup) | |||||
| { | |||||
| new Thread(() => | new Thread(() => | ||||
| { | { | ||||
| speedup = true; | speedup = true; | ||||
| player.AddMoveSpeed(SpeedUpTime, 3.0); | |||||
| speedup = false; | |||||
| }) | |||||
| player.AddMoveSpeed(SpeedUpTime, 3.0); | |||||
| speedup = false; | |||||
| }) | |||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| } | |||||
| } | |||||
| } | } | ||||
| }, | }, | ||||
| timeInterval: GameData.frameDuration, | timeInterval: GameData.frameDuration, | ||||
| @@ -113,41 +113,41 @@ public class SpeedUpWhenLeavingGrass : IPassiveSkill // 3倍速 | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | MaxTolerantTimeExceedCount = ulong.MaxValue, | ||||
| TimeExceedAction = b => | TimeExceedAction = b => | ||||
| { | { | ||||
| if (b) | |||||
| Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); | |||||
| if (b) | |||||
| Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); | |||||
| #if DEBUG | #if DEBUG | ||||
| else | |||||
| { | |||||
| Console.WriteLine("Debug info: passive skill time exceeds for once."); | |||||
| } | |||||
| else | |||||
| { | |||||
| Console.WriteLine("Debug info: passive skill time exceeds for once."); | |||||
| } | |||||
| #endif | #endif | ||||
| } | } | ||||
| }.Start(); | }.Start(); | ||||
| } | |||||
| } | |||||
| ) | ) | ||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| } | |||||
| } | |||||
| public class Vampire : IPassiveSkill // 被动就是吸血,普通子弹 | |||||
| { | |||||
| private readonly BulletType initBullet = BulletType.LineBullet; | |||||
| public BulletType InitBullet => initBullet; | |||||
| // 以上参数以后再改 | |||||
| public void SkillEffect(Character player) | |||||
| { | |||||
| } | |||||
| } | |||||
| public class Vampire : IPassiveSkill // 被动就是吸血,普通子弹 | |||||
| { | |||||
| private readonly BulletType initBullet = BulletType.LineBullet; | |||||
| public BulletType InitBullet => initBullet; | |||||
| // 以上参数以后再改 | |||||
| public void SkillEffect(Character player) | |||||
| { | |||||
| player.OriVampire = 0.5; | player.OriVampire = 0.5; | ||||
| player.Vampire = player.OriVampire; | player.Vampire = player.OriVampire; | ||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| public class NoPassiveSkill : IPassiveSkill // 没技能,这种情况不应该发生,先定义着以防意外 | |||||
| { | |||||
| private readonly BulletType initBullet = BulletType.OrdinaryBullet; | |||||
| public BulletType InitBullet => initBullet; | |||||
| // 以上参数以后再改 | |||||
| public void SkillEffect(Character player) | |||||
| { | |||||
| } | |||||
| } | |||||
| public class NoPassiveSkill : IPassiveSkill // 没技能,这种情况不应该发生,先定义着以防意外 | |||||
| { | |||||
| private readonly BulletType initBullet = BulletType.OrdinaryBullet; | |||||
| public BulletType InitBullet => initBullet; | |||||
| // 以上参数以后再改 | |||||
| public void SkillEffect(Character player) | |||||
| { | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -66,65 +66,28 @@ namespace GameEngine | |||||
| { | { | ||||
| if (!obj.IsAvailable && gameTimer.IsGaming) //不能动就直接return,后面都是能动的情况 | if (!obj.IsAvailable && gameTimer.IsGaming) //不能动就直接return,后面都是能动的情况 | ||||
| return; | return; | ||||
| lock (obj.MoveLock) | |||||
| obj.IsMoving = true; | |||||
| double moveVecLength = 0.0; | |||||
| double deltaLen = moveVecLength - Math.Sqrt(obj.Move(new XY(direction, moveVecLength))); // 转向,并用deltaLen存储行走的误差 | |||||
| IGameObj? collisionObj = null; | |||||
| bool isDestroyed = false; | |||||
| new FrameRateTaskExecutor<int>( | |||||
| () => gameTimer.IsGaming && obj.CanMove && !obj.IsResetting, | |||||
| () => | |||||
| { | |||||
| moveVecLength = obj.MoveSpeed / GameData.numOfStepPerSecond; | |||||
| // 越界情况处理:如果越界,则与越界方块碰撞 | |||||
| bool flag; // 循环标志 | |||||
| do | |||||
| { | |||||
| flag = false; | |||||
| collisionObj = collisionChecker.CheckCollision(obj, new XY(direction, moveVecLength)); | |||||
| if (collisionObj == null) | |||||
| break; | |||||
| lock (obj.MoveLock) | |||||
| obj.IsMoving = true; | |||||
| switch (OnCollision(obj, collisionObj, new XY(direction, moveVecLength))) | |||||
| double moveVecLength = 0.0; | |||||
| double deltaLen = moveVecLength - Math.Sqrt(obj.Move(new XY(direction, moveVecLength))); // 转向,并用deltaLen存储行走的误差 | |||||
| IGameObj? collisionObj = null; | |||||
| bool isDestroyed = false; | |||||
| new FrameRateTaskExecutor<int>( | |||||
| () => gameTimer.IsGaming && obj.CanMove && !obj.IsResetting, | |||||
| () => | |||||
| { | { | ||||
| 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, new XY(direction, moveVecLength)); | |||||
| moveVecLength = 0; | |||||
| break; | |||||
| } | |||||
| } while (flag); | |||||
| moveVecLength = obj.MoveSpeed / GameData.numOfStepPerSecond; | |||||
| deltaLen += moveVecLength - Math.Sqrt(obj.Move(new XY(direction, moveVecLength))); | |||||
| return true; | |||||
| }, | |||||
| GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond, | |||||
| () => | |||||
| { | |||||
| int leftTime = moveTime % (GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond); | |||||
| bool flag; | |||||
| do | |||||
| { | |||||
| flag = false; | |||||
| if (!isDestroyed) | |||||
| { | |||||
| moveVecLength = deltaLen + leftTime * obj.MoveSpeed / GameData.numOfPosGridPerCell; | |||||
| if ((collisionObj = collisionChecker.CheckCollision(obj, new XY(direction, moveVecLength))) == null) | |||||
| { | |||||
| obj.Move(new XY(direction, moveVecLength)); | |||||
| } | |||||
| else | |||||
| // 越界情况处理:如果越界,则与越界方块碰撞 | |||||
| bool flag; // 循环标志 | |||||
| do | |||||
| { | { | ||||
| flag = false; | |||||
| collisionObj = collisionChecker.CheckCollision(obj, new XY(direction, moveVecLength)); | |||||
| if (collisionObj == null) | |||||
| break; | |||||
| switch (OnCollision(obj, collisionObj, new XY(direction, moveVecLength))) | switch (OnCollision(obj, collisionObj, new XY(direction, moveVecLength))) | ||||
| { | { | ||||
| case AfterCollision.ContinueCheck: | case AfterCollision.ContinueCheck: | ||||
| @@ -133,43 +96,81 @@ namespace GameEngine | |||||
| case AfterCollision.Destroyed: | case AfterCollision.Destroyed: | ||||
| Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); | Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); | ||||
| isDestroyed = true; | isDestroyed = true; | ||||
| break; | |||||
| return false; | |||||
| case AfterCollision.MoveMax: | case AfterCollision.MoveMax: | ||||
| MoveMax(obj, new XY(direction, moveVecLength)); | MoveMax(obj, new XY(direction, moveVecLength)); | ||||
| moveVecLength = 0; | moveVecLength = 0; | ||||
| break; | break; | ||||
| } | } | ||||
| } while (flag); | |||||
| deltaLen += moveVecLength - Math.Sqrt(obj.Move(new XY(direction, moveVecLength))); | |||||
| return true; | |||||
| }, | |||||
| GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond, | |||||
| () => | |||||
| { | |||||
| int leftTime = moveTime % (GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond); | |||||
| bool flag; | |||||
| do | |||||
| { | |||||
| flag = false; | |||||
| if (!isDestroyed) | |||||
| { | |||||
| moveVecLength = deltaLen + leftTime * obj.MoveSpeed / GameData.numOfPosGridPerCell; | |||||
| if ((collisionObj = collisionChecker.CheckCollision(obj, new XY(direction, moveVecLength))) == null) | |||||
| { | |||||
| obj.Move(new XY(direction, moveVecLength)); | |||||
| } | |||||
| else | |||||
| { | |||||
| switch (OnCollision(obj, collisionObj, 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: | |||||
| MoveMax(obj, new XY(direction, moveVecLength)); | |||||
| moveVecLength = 0; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| } while (flag); | |||||
| if (leftTime > 0) | |||||
| { | |||||
| Thread.Sleep(leftTime); // 多移动的在这里补回来 | |||||
| } | } | ||||
| } | |||||
| } while (flag); | |||||
| if (leftTime > 0) | |||||
| lock (obj.MoveLock) | |||||
| obj.IsMoving = false; // 结束移动 | |||||
| EndMove(obj); | |||||
| return 0; | |||||
| }, | |||||
| maxTotalDuration: moveTime | |||||
| ) | |||||
| { | { | ||||
| 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!!!!!!"); | |||||
| 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(); | ||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | |||||
| @@ -23,14 +23,16 @@ namespace Gaming | |||||
| OnCollision: (obj, collisionObj, moveVec) => | OnCollision: (obj, collisionObj, moveVec) => | ||||
| { | { | ||||
| //BulletBomb((Bullet)obj, (GameObj)collisionObj); | //BulletBomb((Bullet)obj, (GameObj)collisionObj); | ||||
| return MoveEngine.AfterCollision.Destroyed; }, | |||||
| return MoveEngine.AfterCollision.Destroyed; | |||||
| }, | |||||
| EndMove: obj => | EndMove: obj => | ||||
| { | { | ||||
| #if DEBUG | #if DEBUG | ||||
| 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); | ||||
| #endif | #endif | ||||
| BulletBomb((Bullet)obj, null); } | |||||
| BulletBomb((Bullet)obj, null); | |||||
| } | |||||
| ); | ); | ||||
| } | } | ||||
| private void BombOnePlayer(Bullet bullet, Character playerBeingShot) | private void BombOnePlayer(Bullet bullet, Character playerBeingShot) | ||||
| @@ -75,136 +77,136 @@ namespace Gaming | |||||
| Thread.Sleep(GameData.reviveTime); | Thread.Sleep(GameData.reviveTime); | ||||
| playerBeingShot.AddShield(GameData.shieldTimeAtBirth); // 复活加个盾 | |||||
| playerBeingShot.AddShield(GameData.shieldTimeAtBirth); // 复活加个盾 | |||||
| // gameMap.GameObjLockDict[GameObjIdx.Player].EnterWriteLock(); | |||||
| // try | |||||
| //{ | |||||
| // gameMap.GameObjDict[GameObjIdx.Player].Add(playerBeingShot); | |||||
| // } | |||||
| // finally { gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); } | |||||
| // gameMap.GameObjLockDict[GameObjIdx.Player].EnterWriteLock(); | |||||
| // try | |||||
| //{ | |||||
| // gameMap.GameObjDict[GameObjIdx.Player].Add(playerBeingShot); | |||||
| // } | |||||
| // finally { gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); } | |||||
| if (gameMap.Timer.IsGaming) | |||||
| { | |||||
| playerBeingShot.CanMove = true; | |||||
| } | |||||
| playerBeingShot.IsResetting = false; | |||||
| } | |||||
| if (gameMap.Timer.IsGaming) | |||||
| { | |||||
| playerBeingShot.CanMove = true; | |||||
| } | |||||
| playerBeingShot.IsResetting = false; | |||||
| } | |||||
| ) | ) | ||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| } | |||||
| } | } | ||||
| } | |||||
| private void BulletBomb(Bullet bullet, GameObj? objBeingShot) | |||||
| { | |||||
| private void BulletBomb(Bullet bullet, GameObj? objBeingShot) | |||||
| { | |||||
| #if DEBUG | #if DEBUG | ||||
| Debugger.Output(bullet, "bombed!"); | |||||
| Debugger.Output(bullet, "bombed!"); | |||||
| #endif | #endif | ||||
| bullet.CanMove = false; | |||||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| foreach (ObjOfCharacter _bullet in gameMap.GameObjDict[GameObjIdx.Bullet]) | |||||
| { | |||||
| if (_bullet.ID == bullet.ID) | |||||
| bullet.CanMove = false; | |||||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| foreach (ObjOfCharacter _bullet in gameMap.GameObjDict[GameObjIdx.Bullet]) | |||||
| { | { | ||||
| gameMap.GameObjLockDict[GameObjIdx.BombedBullet].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| gameMap.GameObjDict[GameObjIdx.BombedBullet].Add(new BombedBullet(bullet)); | |||||
| } | |||||
| finally | |||||
| if (_bullet.ID == bullet.ID) | |||||
| { | { | ||||
| gameMap.GameObjLockDict[GameObjIdx.BombedBullet].ExitWriteLock(); | |||||
| gameMap.GameObjLockDict[GameObjIdx.BombedBullet].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| gameMap.GameObjDict[GameObjIdx.BombedBullet].Add(new BombedBullet(bullet)); | |||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[GameObjIdx.BombedBullet].ExitWriteLock(); | |||||
| } | |||||
| gameMap.GameObjDict[GameObjIdx.Bullet].Remove(_bullet); | |||||
| break; | |||||
| } | } | ||||
| gameMap.GameObjDict[GameObjIdx.Bullet].Remove(_bullet); | |||||
| break; | |||||
| } | } | ||||
| } | |||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].ExitWriteLock(); | |||||
| } | |||||
| /*if (objBeingShot != null) | |||||
| { | |||||
| else if (objBeingShot is Bullet) //子弹不能相互引爆,若要更改这一设定,取消注释即可。 | |||||
| } | |||||
| finally | |||||
| { | { | ||||
| new Thread(() => { BulletBomb((Bullet)objBeingShot, null); }) { IsBackground = true }.Start(); | |||||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].ExitWriteLock(); | |||||
| } | } | ||||
| }*/ | |||||
| // 子弹爆炸会发生的事↓↓↓ | |||||
| var beAttackedList = new List<Character>(); | |||||
| gameMap.GameObjLockDict[GameObjIdx.Player].EnterReadLock(); | |||||
| try | |||||
| { | |||||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||||
| { | |||||
| if (bullet.CanAttack(player)) | |||||
| /*if (objBeingShot != null) | |||||
| { | |||||
| else if (objBeingShot is Bullet) //子弹不能相互引爆,若要更改这一设定,取消注释即可。 | |||||
| { | { | ||||
| beAttackedList.Add(player); | |||||
| if (player.ID != bullet.Parent.ID) | |||||
| bullet.Parent.HP = (int)(bullet.Parent.HP + (bullet.Parent.Vampire * bullet.AP)); | |||||
| new Thread(() => { BulletBomb((Bullet)objBeingShot, null); }) { IsBackground = true }.Start(); | |||||
| } | } | ||||
| }*/ | |||||
| // 子弹爆炸会发生的事↓↓↓ | |||||
| var beAttackedList = new List<Character>(); | |||||
| gameMap.GameObjLockDict[GameObjIdx.Player].EnterReadLock(); | |||||
| try | |||||
| { | |||||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||||
| { | |||||
| if (bullet.CanAttack(player)) | |||||
| { | |||||
| beAttackedList.Add(player); | |||||
| if (player.ID != bullet.Parent.ID) | |||||
| bullet.Parent.HP = (int)(bullet.Parent.HP + (bullet.Parent.Vampire * bullet.AP)); | |||||
| } | } | ||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitReadLock(); | |||||
| } | |||||
| } | |||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitReadLock(); | |||||
| } | |||||
| foreach (Character beAttackedPlayer in beAttackedList) | |||||
| { | |||||
| BombOnePlayer(bullet, beAttackedPlayer); | |||||
| foreach (Character beAttackedPlayer in beAttackedList) | |||||
| { | |||||
| BombOnePlayer(bullet, beAttackedPlayer); | |||||
| } | |||||
| beAttackedList.Clear(); | |||||
| } | } | ||||
| beAttackedList.Clear(); | |||||
| } | |||||
| public bool Attack(Character? player, double angle) // 射出去的子弹泼出去的水(狗头) | |||||
| { // 子弹如果没有和其他物体碰撞,将会一直向前直到超出人物的attackRange | |||||
| if (player == null) | |||||
| { | |||||
| public bool Attack(Character? player, double angle) // 射出去的子弹泼出去的水(狗头) | |||||
| { // 子弹如果没有和其他物体碰撞,将会一直向前直到超出人物的attackRange | |||||
| if (player == null) | |||||
| { | |||||
| #if DEBUG | #if DEBUG | ||||
| Console.WriteLine("the player who will attack is NULL!"); | |||||
| Console.WriteLine("the player who will attack is NULL!"); | |||||
| #endif | #endif | ||||
| return false; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| if (player.IsResetting) | |||||
| return false; | |||||
| Bullet? bullet = player.RemoteAttack( | |||||
| new XY // 子弹紧贴人物生成。 | |||||
| ( | |||||
| (int)((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Cos(angle)), | |||||
| (int)((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Sin(angle)) | |||||
| ) | |||||
| ); | |||||
| if (bullet != null) | |||||
| { | |||||
| bullet.CanMove = true; | |||||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| gameMap.GameObjDict[GameObjIdx.Bullet].Add(bullet); | |||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].ExitWriteLock(); | |||||
| } | |||||
| moveEngine.MoveObj(bullet, (int)((player.AttackRange - player.Radius - BulletFactory.BulletRadius(player.BulletOfPlayer)) * 1000 / bullet.MoveSpeed), angle); // 这里时间参数除出来的单位要是ms | |||||
| if (player.IsResetting) | |||||
| return false; | |||||
| Bullet? bullet = player.RemoteAttack( | |||||
| new XY // 子弹紧贴人物生成。 | |||||
| ( | |||||
| (int)((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Cos(angle)), | |||||
| (int)((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Sin(angle)) | |||||
| ) | |||||
| ); | |||||
| if (bullet != null) | |||||
| { | |||||
| bullet.CanMove = true; | |||||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| gameMap.GameObjDict[GameObjIdx.Bullet].Add(bullet); | |||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].ExitWriteLock(); | |||||
| } | |||||
| moveEngine.MoveObj(bullet, (int)((player.AttackRange - player.Radius - BulletFactory.BulletRadius(player.BulletOfPlayer)) * 1000 / bullet.MoveSpeed), angle); // 这里时间参数除出来的单位要是ms | |||||
| #if DEBUG | #if DEBUG | ||||
| Console.WriteLine($"playerID:{player.ID} successfully attacked!"); | |||||
| Console.WriteLine($"playerID:{player.ID} successfully attacked!"); | |||||
| #endif | #endif | ||||
| return true; | |||||
| } | |||||
| else | |||||
| { | |||||
| return true; | |||||
| } | |||||
| else | |||||
| { | |||||
| #if DEBUG | #if DEBUG | ||||
| Console.WriteLine($"playerID:{player.ID} has no bullets so that he can't attack!"); | |||||
| Console.WriteLine($"playerID:{player.ID} has no bullets so that he can't attack!"); | |||||
| #endif | #endif | ||||
| return false; | |||||
| return false; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| @@ -64,57 +64,58 @@ namespace Gaming | |||||
| { | { | ||||
| while (!gameMap.Timer.IsGaming) | while (!gameMap.Timer.IsGaming) | ||||
| Thread.Sleep(newPlayer.CD); | Thread.Sleep(newPlayer.CD); | ||||
| long lastTime = Environment.TickCount64; | |||||
| new FrameRateTaskExecutor<int>( | |||||
| loopCondition: () => gameMap.Timer.IsGaming, | |||||
| loopToDo: () => | |||||
| { | |||||
| if (!newPlayer.IsResetting) | |||||
| long lastTime = Environment.TickCount64; | |||||
| new FrameRateTaskExecutor<int>( | |||||
| loopCondition: () => gameMap.Timer.IsGaming, | |||||
| loopToDo: () => | |||||
| { | |||||
| if (!newPlayer.IsResetting) | |||||
| { | |||||
| long nowTime = Environment.TickCount64; | |||||
| if (newPlayer.BulletNum == newPlayer.MaxBulletNum) | |||||
| lastTime = nowTime; | |||||
| if (nowTime - lastTime >= newPlayer.CD) | |||||
| { | |||||
| _ = newPlayer.TryAddBulletNum(); | |||||
| lastTime = nowTime; | |||||
| } | |||||
| } | |||||
| }, | |||||
| timeInterval: GameData.checkInterval, | |||||
| finallyReturn: () => 0 | |||||
| ) | |||||
| { | { | ||||
| long nowTime = Environment.TickCount64; | |||||
| if (newPlayer.BulletNum == newPlayer.MaxBulletNum) | |||||
| lastTime = nowTime; | |||||
| if (nowTime - lastTime >= newPlayer.CD) | |||||
| AllowTimeExceed = true | |||||
| /*MaxTolerantTimeExceedCount = 5, | |||||
| TimeExceedAction = exceedTooMuch => | |||||
| { | { | ||||
| _ = newPlayer.TryAddBulletNum(); | |||||
| lastTime = nowTime; | |||||
| } | |||||
| if (exceedTooMuch) Console.WriteLine("The computer runs too slow that it cannot check the color below the player in time!"); | |||||
| }*/ | |||||
| } | } | ||||
| }, | |||||
| timeInterval: GameData.checkInterval, | |||||
| finallyReturn: () => 0 | |||||
| ) { | |||||
| AllowTimeExceed = true | |||||
| /*MaxTolerantTimeExceedCount = 5, | |||||
| TimeExceedAction = exceedTooMuch => | |||||
| { | |||||
| if (exceedTooMuch) Console.WriteLine("The computer runs too slow that it cannot check the color below the player in time!"); | |||||
| }*/ | |||||
| } | |||||
| .Start(); | |||||
| } | |||||
| .Start(); | |||||
| } | |||||
| ) | ) | ||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| return newPlayer.ID; | return newPlayer.ID; | ||||
| } | |||||
| public bool StartGame(int milliSeconds) | |||||
| { | |||||
| } | |||||
| public bool StartGame(int milliSeconds) | |||||
| { | |||||
| if (gameMap.Timer.IsGaming) | if (gameMap.Timer.IsGaming) | ||||
| return false; | |||||
| return false; | |||||
| gameMap.GameObjLockDict[GameObjIdx.Player].EnterReadLock(); | gameMap.GameObjLockDict[GameObjIdx.Player].EnterReadLock(); | ||||
| try | try | ||||
| { | { | ||||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||||
| { | |||||
| player.CanMove = true; | |||||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||||
| { | |||||
| player.CanMove = true; | |||||
| player.AddShield(GameData.shieldTimeAtBirth); | |||||
| } | |||||
| player.AddShield(GameData.shieldTimeAtBirth); | |||||
| } | |||||
| } | } | ||||
| finally | finally | ||||
| { | { | ||||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitReadLock(); | |||||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitReadLock(); | |||||
| } | } | ||||
| propManager.StartProducing(); | propManager.StartProducing(); | ||||
| @@ -127,24 +128,24 @@ namespace Gaming | |||||
| loopCondition: () => gameMap.Timer.IsGaming, | loopCondition: () => gameMap.Timer.IsGaming, | ||||
| loopToDo: () => | loopToDo: () => | ||||
| { | { | ||||
| foreach (var kvp in gameMap.GameObjDict) // 检查物体位置 | |||||
| { | |||||
| if (kvp.Key == GameObjIdx.Bullet || kvp.Key == GameObjIdx.Player || kvp.Key == GameObjIdx.Prop) | |||||
| { | |||||
| gameMap.GameObjLockDict[kvp.Key].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| foreach (var item in gameMap.GameObjDict[kvp.Key]) | |||||
| { | |||||
| item.Place = gameMap.GetPlaceType(item.Position); | |||||
| } | |||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[kvp.Key].ExitWriteLock(); | |||||
| } | |||||
| } | |||||
| } | |||||
| foreach (var kvp in gameMap.GameObjDict) // 检查物体位置 | |||||
| { | |||||
| if (kvp.Key == GameObjIdx.Bullet || kvp.Key == GameObjIdx.Player || kvp.Key == GameObjIdx.Prop) | |||||
| { | |||||
| gameMap.GameObjLockDict[kvp.Key].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| foreach (var item in gameMap.GameObjDict[kvp.Key]) | |||||
| { | |||||
| item.Place = gameMap.GetPlaceType(item.Position); | |||||
| } | |||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[kvp.Key].ExitWriteLock(); | |||||
| } | |||||
| } | |||||
| } | |||||
| }, | }, | ||||
| timeInterval: GameData.checkInterval, | timeInterval: GameData.checkInterval, | ||||
| finallyReturn: () => 0 | finallyReturn: () => 0 | ||||
| @@ -152,20 +153,20 @@ namespace Gaming | |||||
| { | { | ||||
| AllowTimeExceed = true | AllowTimeExceed = true | ||||
| }.Start(); | }.Start(); | ||||
| } | |||||
| } | |||||
| ) | ) | ||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| // 开始游戏 | // 开始游戏 | ||||
| if (!gameMap.Timer.StartGame(milliSeconds)) | if (!gameMap.Timer.StartGame(milliSeconds)) | ||||
| return false; | |||||
| return false; | |||||
| EndGame(); // 游戏结束时要做的事 | EndGame(); // 游戏结束时要做的事 | ||||
| return true; | return true; | ||||
| } | |||||
| } | |||||
| public void EndGame() | |||||
| { | |||||
| public void EndGame() | |||||
| { | |||||
| gameMap.GameObjLockDict[GameObjIdx.Player].EnterWriteLock(); | gameMap.GameObjLockDict[GameObjIdx.Player].EnterWriteLock(); | ||||
| /*try | /*try | ||||
| { | { | ||||
| @@ -174,169 +175,169 @@ public void EndGame() | |||||
| { | { | ||||
| }*/ | }*/ | ||||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); | gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); | ||||
| } | |||||
| public void MovePlayer(long playerID, int moveTimeInMilliseconds, double angle) | |||||
| { | |||||
| } | |||||
| public void MovePlayer(long playerID, int moveTimeInMilliseconds, double angle) | |||||
| { | |||||
| if (!gameMap.Timer.IsGaming) | if (!gameMap.Timer.IsGaming) | ||||
| return; | |||||
| return; | |||||
| Character? player = gameMap.FindPlayer(playerID); | Character? player = gameMap.FindPlayer(playerID); | ||||
| if (player != null) | if (player != null) | ||||
| { | { | ||||
| moveManager.MovePlayer(player, moveTimeInMilliseconds, angle); | |||||
| moveManager.MovePlayer(player, moveTimeInMilliseconds, angle); | |||||
| #if DEBUG | #if DEBUG | ||||
| Console.WriteLine($"PlayerID:{playerID} move to ({player.Position.x},{player.Position.y})!"); | |||||
| Console.WriteLine($"PlayerID:{playerID} move to ({player.Position.x},{player.Position.y})!"); | |||||
| #endif | #endif | ||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| #if DEBUG | #if DEBUG | ||||
| Console.WriteLine($"PlayerID:{playerID} player does not exists!"); | |||||
| Console.WriteLine($"PlayerID:{playerID} player does not exists!"); | |||||
| #endif | #endif | ||||
| } | } | ||||
| } | |||||
| public void Attack(long playerID, double angle) | |||||
| { | |||||
| } | |||||
| public void Attack(long playerID, double angle) | |||||
| { | |||||
| if (!gameMap.Timer.IsGaming) | if (!gameMap.Timer.IsGaming) | ||||
| return; | |||||
| return; | |||||
| Character? player = gameMap.FindPlayer(playerID); | Character? player = gameMap.FindPlayer(playerID); | ||||
| if (player != null) | if (player != null) | ||||
| { | { | ||||
| _ = attackManager.Attack(player, angle); | |||||
| _ = attackManager.Attack(player, angle); | |||||
| } | } | ||||
| } | |||||
| public void UseProp(long playerID) | |||||
| { | |||||
| } | |||||
| public void UseProp(long playerID) | |||||
| { | |||||
| if (!gameMap.Timer.IsGaming) | if (!gameMap.Timer.IsGaming) | ||||
| return; | |||||
| return; | |||||
| Character? player = gameMap.FindPlayer(playerID); | Character? player = gameMap.FindPlayer(playerID); | ||||
| if (player != null) | if (player != null) | ||||
| { | { | ||||
| propManager.UseProp(player); | |||||
| propManager.UseProp(player); | |||||
| } | } | ||||
| } | |||||
| public void ThrowProp(long playerID, int timeInmillionSeconds, double angle) | |||||
| { | |||||
| } | |||||
| public void ThrowProp(long playerID, int timeInmillionSeconds, double angle) | |||||
| { | |||||
| if (!gameMap.Timer.IsGaming) | if (!gameMap.Timer.IsGaming) | ||||
| return; | |||||
| return; | |||||
| Character? player = gameMap.FindPlayer(playerID); | Character? player = gameMap.FindPlayer(playerID); | ||||
| if (player != null) | if (player != null) | ||||
| { | { | ||||
| propManager.ThrowProp(player, timeInmillionSeconds, angle); | |||||
| propManager.ThrowProp(player, timeInmillionSeconds, angle); | |||||
| } | } | ||||
| } | |||||
| public bool PickProp(long playerID, PropType propType = PropType.Null) | |||||
| { | |||||
| } | |||||
| public bool PickProp(long playerID, PropType propType = PropType.Null) | |||||
| { | |||||
| if (!gameMap.Timer.IsGaming) | if (!gameMap.Timer.IsGaming) | ||||
| return false; | |||||
| return false; | |||||
| Character? player = gameMap.FindPlayer(playerID); | Character? player = gameMap.FindPlayer(playerID); | ||||
| if (player != null) | if (player != null) | ||||
| { | { | ||||
| return propManager.PickProp(player, propType); | |||||
| return propManager.PickProp(player, propType); | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | |||||
| } | |||||
| public bool UseCommonSkill(long playerID) | |||||
| { | |||||
| public bool UseCommonSkill(long playerID) | |||||
| { | |||||
| if (!gameMap.Timer.IsGaming) | if (!gameMap.Timer.IsGaming) | ||||
| return false; | |||||
| return false; | |||||
| Character? player = gameMap.FindPlayer(playerID); | Character? player = gameMap.FindPlayer(playerID); | ||||
| if (player != null) | if (player != null) | ||||
| { | { | ||||
| return skillManager.UseCommonSkill(player); | |||||
| return skillManager.UseCommonSkill(player); | |||||
| } | } | ||||
| else | else | ||||
| return false; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| public void AllPlayerUsePassiveSkill() | |||||
| { | |||||
| public void AllPlayerUsePassiveSkill() | |||||
| { | |||||
| if (!gameMap.Timer.IsGaming) | if (!gameMap.Timer.IsGaming) | ||||
| return; | |||||
| return; | |||||
| gameMap.GameObjLockDict[GameObjIdx.Player].EnterWriteLock(); | gameMap.GameObjLockDict[GameObjIdx.Player].EnterWriteLock(); | ||||
| try | try | ||||
| { | { | ||||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||||
| { | |||||
| skillManager.UsePassiveSkill(player); | |||||
| } | |||||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||||
| { | |||||
| skillManager.UsePassiveSkill(player); | |||||
| } | |||||
| } | } | ||||
| finally | finally | ||||
| { | { | ||||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); | |||||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); | |||||
| } | } | ||||
| } | |||||
| } | |||||
| public void ClearLists(GameObjIdx[] objIdxes) | |||||
| { | |||||
| public void ClearLists(GameObjIdx[] objIdxes) | |||||
| { | |||||
| foreach (var idx in objIdxes) | foreach (var idx in objIdxes) | ||||
| { | { | ||||
| if (idx != GameObjIdx.None) | |||||
| { | |||||
| gameMap.GameObjLockDict[idx].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| gameMap.GameObjDict[idx].Clear(); | |||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[idx].ExitWriteLock(); | |||||
| } | |||||
| } | |||||
| if (idx != GameObjIdx.None) | |||||
| { | |||||
| gameMap.GameObjLockDict[idx].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| gameMap.GameObjDict[idx].Clear(); | |||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[idx].ExitWriteLock(); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | |||||
| public void ClearAllLists() | |||||
| { | |||||
| } | |||||
| public void ClearAllLists() | |||||
| { | |||||
| foreach (var keyValuePair in gameMap.GameObjDict) | foreach (var keyValuePair in gameMap.GameObjDict) | ||||
| { | { | ||||
| if (keyValuePair.Key != GameObjIdx.Map) | |||||
| { | |||||
| gameMap.GameObjLockDict[keyValuePair.Key].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| if (keyValuePair.Key == GameObjIdx.Player) | |||||
| if (keyValuePair.Key != GameObjIdx.Map) | |||||
| { | { | ||||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||||
| gameMap.GameObjLockDict[keyValuePair.Key].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| if (keyValuePair.Key == GameObjIdx.Player) | |||||
| { | |||||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||||
| { | |||||
| player.CanMove = false; | |||||
| } | |||||
| } | |||||
| gameMap.GameObjDict[keyValuePair.Key].Clear(); | |||||
| } | |||||
| finally | |||||
| { | { | ||||
| player.CanMove = false; | |||||
| gameMap.GameObjLockDict[keyValuePair.Key].ExitWriteLock(); | |||||
| } | } | ||||
| } | } | ||||
| gameMap.GameObjDict[keyValuePair.Key].Clear(); | |||||
| } | } | ||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[keyValuePair.Key].ExitWriteLock(); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| public int GetTeamScore(long teamID) | |||||
| { | |||||
| public int GetTeamScore(long teamID) | |||||
| { | |||||
| return teamList[(int)teamID].Score; | return teamList[(int)teamID].Score; | ||||
| } | |||||
| public List<IGameObj> GetGameObj() | |||||
| { | |||||
| } | |||||
| public List<IGameObj> GetGameObj() | |||||
| { | |||||
| var gameObjList = new List<IGameObj>(); | var gameObjList = new List<IGameObj>(); | ||||
| foreach (var keyValuePair in gameMap.GameObjDict) | foreach (var keyValuePair in gameMap.GameObjDict) | ||||
| { | { | ||||
| if (keyValuePair.Key != GameObjIdx.Map) | |||||
| { | |||||
| gameMap.GameObjLockDict[keyValuePair.Key].EnterReadLock(); | |||||
| try | |||||
| { | |||||
| gameObjList.AddRange(gameMap.GameObjDict[keyValuePair.Key]); | |||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[keyValuePair.Key].ExitReadLock(); | |||||
| } | |||||
| } | |||||
| if (keyValuePair.Key != GameObjIdx.Map) | |||||
| { | |||||
| gameMap.GameObjLockDict[keyValuePair.Key].EnterReadLock(); | |||||
| try | |||||
| { | |||||
| gameObjList.AddRange(gameMap.GameObjDict[keyValuePair.Key]); | |||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[keyValuePair.Key].ExitReadLock(); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| return gameObjList; | return gameObjList; | ||||
| } | |||||
| public Game(uint[,] mapResource, int numOfTeam) | |||||
| { | |||||
| } | |||||
| public Game(uint[,] mapResource, int numOfTeam) | |||||
| { | |||||
| // if (numOfTeam > maxTeamNum) throw new TeamNumOverFlowException(); | // if (numOfTeam > maxTeamNum) throw new TeamNumOverFlowException(); | ||||
| gameMap = new Map(mapResource); | gameMap = new Map(mapResource); | ||||
| @@ -346,13 +347,13 @@ public Game(uint[,] mapResource, int numOfTeam) | |||||
| teamList = new List<Team>(); | teamList = new List<Team>(); | ||||
| for (int i = 0; i < numOfTeam; ++i) | for (int i = 0; i < numOfTeam; ++i) | ||||
| { | { | ||||
| teamList.Add(new Team()); | |||||
| teamList.Add(new Team()); | |||||
| } | } | ||||
| skillManager = new SkillManager(); | skillManager = new SkillManager(); | ||||
| attackManager = new AttackManager(gameMap); | attackManager = new AttackManager(gameMap); | ||||
| moveManager = new MoveManager(gameMap); | moveManager = new MoveManager(gameMap); | ||||
| propManager = new PropManager(gameMap); | propManager = new PropManager(gameMap); | ||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -54,7 +54,8 @@ namespace Gaming | |||||
| // ActivateMine((Character)obj, (Mine)collisionObj); | // ActivateMine((Character)obj, (Mine)collisionObj); | ||||
| // return MoveEngine.AfterCollision.ContinueCheck; | // return MoveEngine.AfterCollision.ContinueCheck; | ||||
| //} | //} | ||||
| return MoveEngine.AfterCollision.MoveMax; }, | |||||
| return MoveEngine.AfterCollision.MoveMax; | |||||
| }, | |||||
| EndMove: obj => | EndMove: obj => | ||||
| { | { | ||||
| // 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); | ||||
| @@ -175,49 +175,49 @@ namespace Gaming | |||||
| { | { | ||||
| while (!gameMap.Timer.IsGaming) | while (!gameMap.Timer.IsGaming) | ||||
| Thread.Sleep(1000); | Thread.Sleep(1000); | ||||
| new FrameRateTaskExecutor<int>( | |||||
| () => gameMap.Timer.IsGaming, | |||||
| () => | |||||
| { | |||||
| int rand = r.Next(0, len); | |||||
| XY randPos = availableCellForGenerateProp[rand]; | |||||
| gameMap.GameObjLockDict[GameObjIdx.Prop].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| switch (r.Next(0, 4)) | |||||
| new FrameRateTaskExecutor<int>( | |||||
| () => gameMap.Timer.IsGaming, | |||||
| () => | |||||
| { | { | ||||
| case 0: | |||||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new AddLIFE(randPos)); | |||||
| break; | |||||
| case 1: | |||||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new AddSpeed(randPos)); | |||||
| break; | |||||
| case 2: | |||||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new Shield(randPos)); | |||||
| break; | |||||
| case 3: | |||||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new Spear(randPos)); | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[GameObjIdx.Prop].ExitWriteLock(); | |||||
| } | |||||
| }, | |||||
| GameData.PropProduceTime, | |||||
| () => 0 | |||||
| ) | |||||
| .Start(); | |||||
| } | |||||
| int rand = r.Next(0, len); | |||||
| XY randPos = availableCellForGenerateProp[rand]; | |||||
| gameMap.GameObjLockDict[GameObjIdx.Prop].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| switch (r.Next(0, 4)) | |||||
| { | |||||
| case 0: | |||||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new AddLIFE(randPos)); | |||||
| break; | |||||
| case 1: | |||||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new AddSpeed(randPos)); | |||||
| break; | |||||
| case 2: | |||||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new Shield(randPos)); | |||||
| break; | |||||
| case 3: | |||||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new Spear(randPos)); | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[GameObjIdx.Prop].ExitWriteLock(); | |||||
| } | |||||
| }, | |||||
| GameData.PropProduceTime, | |||||
| () => 0 | |||||
| ) | |||||
| .Start(); | |||||
| } | |||||
| ) | ) | ||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| } | |||||
| public PropManager(Map gameMap) // 道具不能扔过墙 | |||||
| { | |||||
| } | |||||
| public PropManager(Map gameMap) // 道具不能扔过墙 | |||||
| { | |||||
| this.gameMap = gameMap; | this.gameMap = gameMap; | ||||
| this.moveEngine = new MoveEngine( | this.moveEngine = new MoveEngine( | ||||
| gameMap: gameMap, | gameMap: gameMap, | ||||
| @@ -227,20 +227,21 @@ namespace Gaming | |||||
| { | { | ||||
| // obj.Place = gameMap.GetPlaceType((GameObj)obj); | // obj.Place = gameMap.GetPlaceType((GameObj)obj); | ||||
| obj.CanMove = false; | obj.CanMove = false; | ||||
| 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); | |||||
| } | |||||
| ); | ); | ||||
| availableCellForGenerateProp = new List<XY>(); | availableCellForGenerateProp = new List<XY>(); | ||||
| for (int i = 0; i < gameMap.ProtoGameMap.GetLength(0); i++) | for (int i = 0; i < gameMap.ProtoGameMap.GetLength(0); i++) | ||||
| { | { | ||||
| for (int j = 0; j < gameMap.ProtoGameMap.GetLength(1); j++) | |||||
| { | |||||
| if (gameMap.ProtoGameMap[i, j] == (int)MapInfo.MapInfoObjType.Null) | |||||
| for (int j = 0; j < gameMap.ProtoGameMap.GetLength(1); j++) | |||||
| { | { | ||||
| availableCellForGenerateProp.Add(GameData.GetCellCenterPos(i, j)); | |||||
| if (gameMap.ProtoGameMap[i, j] == (int)MapInfo.MapInfoObjType.Null) | |||||
| { | |||||
| availableCellForGenerateProp.Add(GameData.GetCellCenterPos(i, j)); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| @@ -4,7 +4,7 @@ namespace Preparation.GameData | |||||
| { | { | ||||
| public static class GameData | public static class GameData | ||||
| { | { | ||||
| #region 基本常数与常方法 | |||||
| #region 基本常数与常方法 | |||||
| public const int numOfPosGridPerCell = 1000; // 每格的【坐标单位】数 | public const int numOfPosGridPerCell = 1000; // 每格的【坐标单位】数 | ||||
| public const int numOfStepPerSecond = 20; // 每秒行走的步数 | public const int numOfStepPerSecond = 20; // 每秒行走的步数 | ||||
| public const int lengthOfMap = 50000; // 地图长度 | public const int lengthOfMap = 50000; // 地图长度 | ||||
| @@ -35,8 +35,8 @@ namespace Preparation.GameData | |||||
| } | } | ||||
| public static int numOfBirthPoint = 5; | public static int numOfBirthPoint = 5; | ||||
| #endregion | |||||
| #region 角色相关 | |||||
| #endregion | |||||
| #region 角色相关 | |||||
| /// <summary> | /// <summary> | ||||
| /// 玩家相关 | /// 玩家相关 | ||||
| /// </summary> | /// </summary> | ||||
| @@ -71,9 +71,9 @@ namespace Preparation.GameData | |||||
| public const long GemProduceTime = 10000; | public const long GemProduceTime = 10000; | ||||
| public const long PropProduceTime = 10000; | public const long PropProduceTime = 10000; | ||||
| public const int PropDuration = 10000; | public const int PropDuration = 10000; | ||||
| #endregion | |||||
| #region 游戏帧相关 | |||||
| #endregion | |||||
| #region 游戏帧相关 | |||||
| public const long checkInterval = 50; // 检查位置标志、补充子弹的帧时长 | public const long checkInterval = 50; // 检查位置标志、补充子弹的帧时长 | ||||
| #endregion | |||||
| #endregion | |||||
| } | } | ||||
| } | } | ||||
| @@ -21,7 +21,7 @@ namespace Preparation.Utility | |||||
| { | { | ||||
| return "(" + x.ToString() + "," + y.ToString() + ")"; | return "(" + x.ToString() + "," + y.ToString() + ")"; | ||||
| } | } | ||||
| public static int operator*(XY v1, XY v2) | |||||
| public static int operator *(XY v1, XY v2) | |||||
| { | { | ||||
| return (v1.x * v2.x) + (v1.y * v2.y); | return (v1.x * v2.x) + (v1.y * v2.y); | ||||
| } | } | ||||
| @@ -18,7 +18,7 @@ namespace Server | |||||
| public bool IsGaming | public bool IsGaming | ||||
| { | { | ||||
| get => Interlocked.CompareExchange(ref isGaming, 0, 0) != 0; | get => Interlocked.CompareExchange(ref isGaming, 0, 0) != 0; | ||||
| set => Interlocked.Exchange(ref isGaming, value? 1: 0); | |||||
| set => Interlocked.Exchange(ref isGaming, value ? 1 : 0); | |||||
| } | } | ||||
| public MessageToClient GetCopiedGameInfo() | public MessageToClient GetCopiedGameInfo() | ||||
| @@ -36,14 +36,16 @@ namespace Server | |||||
| return; | return; | ||||
| if (player.PlayerType == PlayerType.HumanPlayer) | if (player.PlayerType == PlayerType.HumanPlayer) | ||||
| { | { | ||||
| gameInfo.HumanMessage.Add(new MessageOfHuman() { | |||||
| gameInfo.HumanMessage.Add(new MessageOfHuman() | |||||
| { | |||||
| PlayerId = player.PlayerId | PlayerId = player.PlayerId | ||||
| }); | }); | ||||
| return; | return; | ||||
| } | } | ||||
| if (player.PlayerType == PlayerType.ButcherPlayer) | if (player.PlayerType == PlayerType.ButcherPlayer) | ||||
| { | { | ||||
| gameInfo.ButcherMessage.Add(new MessageOfButcher() { | |||||
| gameInfo.ButcherMessage.Add(new MessageOfButcher() | |||||
| { | |||||
| PlayerId = player.PlayerId | PlayerId = player.PlayerId | ||||
| }); | }); | ||||
| return; | return; | ||||
| @@ -69,39 +71,39 @@ namespace Server | |||||
| () => IsGaming, | () => IsGaming, | ||||
| () => | () => | ||||
| { | { | ||||
| lock (gameInfo) | |||||
| { | |||||
| for (int i = 0; i < gameInfo.HumanMessage.Count; i++) | |||||
| { | |||||
| if (gameInfo.HumanMessage[i] != null) | |||||
| { | |||||
| gameInfo.HumanMessage[i].X++; | |||||
| gameInfo.HumanMessage[i].Y--; | |||||
| } | |||||
| } | |||||
| for (int i = 0; i < gameInfo.ButcherMessage.Count; i++) | |||||
| { | |||||
| if (gameInfo.ButcherMessage[i] != null) | |||||
| { | |||||
| gameInfo.ButcherMessage[i].X--; | |||||
| gameInfo.ButcherMessage[i].Y++; | |||||
| } | |||||
| } | |||||
| } | |||||
| lock (gameInfo) | |||||
| { | |||||
| for (int i = 0; i < gameInfo.HumanMessage.Count; i++) | |||||
| { | |||||
| if (gameInfo.HumanMessage[i] != null) | |||||
| { | |||||
| gameInfo.HumanMessage[i].X++; | |||||
| gameInfo.HumanMessage[i].Y--; | |||||
| } | |||||
| } | |||||
| for (int i = 0; i < gameInfo.ButcherMessage.Count; i++) | |||||
| { | |||||
| if (gameInfo.ButcherMessage[i] != null) | |||||
| { | |||||
| gameInfo.ButcherMessage[i].X--; | |||||
| gameInfo.ButcherMessage[i].Y++; | |||||
| } | |||||
| } | |||||
| } | |||||
| }, | }, | ||||
| 100, | 100, | ||||
| () => | () => | ||||
| { | { | ||||
| IsGaming = false; | |||||
| waitHandle.Release(); | |||||
| return 0; | |||||
| IsGaming = false; | |||||
| waitHandle.Release(); | |||||
| return 0; | |||||
| }, | }, | ||||
| gameTime | gameTime | ||||
| ).Start(); | ).Start(); | ||||
| } | |||||
| } | |||||
| ) | ) | ||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| return waitHandle; | return waitHandle; | ||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | |||||
| @@ -80,42 +80,42 @@ namespace Server | |||||
| 1000, | 1000, | ||||
| () => | () => | ||||
| { | { | ||||
| ReportGame(); // 最后发一次消息,唤醒发消息的线程,防止发消息的线程由于有概率处在 Wait 状态而卡住 | |||||
| return 0; | |||||
| ReportGame(); // 最后发一次消息,唤醒发消息的线程,防止发消息的线程由于有概率处在 Wait 状态而卡住 | |||||
| return 0; | |||||
| } | } | ||||
| ).Start(); | ).Start(); | ||||
| }) | |||||
| }) | |||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| new Thread(() => | new Thread(() => | ||||
| { | { | ||||
| waitHandle.Wait(); | waitHandle.Wait(); | ||||
| this.endGameSem.Release(); | |||||
| }) | |||||
| this.endGameSem.Release(); | |||||
| }) | |||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| } | |||||
| public void WaitForEnd() | |||||
| { | |||||
| this.endGameSem.Wait(); | |||||
| } | |||||
| } | |||||
| public void WaitForEnd() | |||||
| { | |||||
| this.endGameSem.Wait(); | |||||
| } | |||||
| public void ReportGame() | |||||
| { | |||||
| currentGameInfo = game.GetCopiedGameInfo(); | |||||
| public void ReportGame() | |||||
| { | |||||
| currentGameInfo = game.GetCopiedGameInfo(); | |||||
| foreach (var kvp in semaDict) | |||||
| { | |||||
| kvp.Value.Item1.Release(); | |||||
| } | |||||
| foreach (var kvp in semaDict) | |||||
| { | |||||
| kvp.Value.Item1.Release(); | |||||
| } | |||||
| foreach (var kvp in semaDict) | |||||
| { | |||||
| kvp.Value.Item2.Wait(); | |||||
| } | |||||
| } | |||||
| foreach (var kvp in semaDict) | |||||
| { | |||||
| kvp.Value.Item2.Wait(); | |||||
| } | |||||
| } | |||||
| public GameServer() | |||||
| { | |||||
| } | |||||
| } | |||||
| public GameServer() | |||||
| { | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -14,7 +14,8 @@ namespace Server | |||||
| try | try | ||||
| { | { | ||||
| GameServer gameServer = new(); | GameServer gameServer = new(); | ||||
| Grpc.Core.Server server = new Grpc.Core.Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) }) { | |||||
| Grpc.Core.Server server = new Grpc.Core.Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) }) | |||||
| { | |||||
| Services = { AvailableService.BindService(gameServer) }, | Services = { AvailableService.BindService(gameServer) }, | ||||
| Ports = { new ServerPort("127.0.0.1", 8888, ServerCredentials.Insecure) } | Ports = { new ServerPort("127.0.0.1", 8888, ServerCredentials.Insecure) } | ||||
| }; | }; | ||||