diff --git a/logic/.gitignore b/logic/.gitignore index 762b4b5..a9bdd24 100644 --- a/logic/.gitignore +++ b/logic/.gitignore @@ -400,5 +400,3 @@ FodyWeavers.xsd #THUAI playback file *.thuaipb -Client/ -CSharpInterface/ diff --git a/logic/GameClass/GameObj/BombedBullet.cs b/logic/GameClass/GameObj/BombedBullet.cs new file mode 100644 index 0000000..749049c --- /dev/null +++ b/logic/GameClass/GameObj/BombedBullet.cs @@ -0,0 +1,20 @@ +using Preparation.Utility; + +namespace GameClass.GameObj +{ + // 为方便界面组做子弹爆炸特效,现引入“爆炸中的子弹”,在每帧发送给界面组 + public sealed class BombedBullet : GameObj + { + public override ShapeType Shape => ShapeType.Circle; + public override bool IsRigid => false; + public long MappingID { get; } + public Bullet bulletHasBombed; + public BombedBullet(Bullet bullet) : + base(bullet.Position, bullet.Radius, bullet.Place, GameObjType.BombedBullet) + { + this.bulletHasBombed = bullet; + this.MappingID = bullet.ID; + this.FacingDirection = bullet.FacingDirection; + } + } +} diff --git a/logic/GameClass/GameObj/Bullet.cs b/logic/GameClass/GameObj/Bullet.cs new file mode 100644 index 0000000..0b56056 --- /dev/null +++ b/logic/GameClass/GameObj/Bullet.cs @@ -0,0 +1,238 @@ +using Preparation.GameData; +using Preparation.Interface; +using Preparation.Utility; +using System; + +namespace GameClass.GameObj +{ + public abstract class Bullet : ObjOfCharacter + { + /// + /// //攻击力 + /// + public abstract int AP { get; } + public abstract int Speed { get; } + + private readonly bool hasSpear; + /// + /// 是否有矛 + /// + public bool HasSpear => hasSpear; + + /// + /// 与THUAI4不同的一个攻击判定方案,通过这个函数判断爆炸时能否伤害到target + /// + /// 被尝试攻击者 + /// 是否可以攻击到 + public abstract bool CanAttack(GameObj target); + + protected override bool IgnoreCollideExecutor(IGameObj targetObj) + { + if (targetObj.Type == GameObjType.BirthPoint || targetObj.Type == GameObjType.Prop || targetObj.Type == GameObjType.Bullet) + return true; + return false; + } + public Bullet(Character player, int radius) : + base(player.Position, radius, PlaceType.Null, GameObjType.Bullet) + { + this.CanMove = true; + this.moveSpeed = this.Speed; + this.hasSpear = player.HasSpear; + this.Parent = player; + } + public override bool IsRigid => true; // 默认为true + public override ShapeType Shape => ShapeType.Circle; // 默认为圆形 + public abstract BulletType TypeOfBullet { get; } + } + + internal sealed class AtomBomb : Bullet + { + public AtomBomb(Character player, int radius = GameData.bulletRadius) : + base(player, radius) + { + } + public const double BulletBombRange = GameData.basicBulletBombRange / 3 * 7; + public const double BulletAttackRange = GameData.basicAttackRange / 9 * 7; + public override int AP => GameData.basicAp / 3 * 7; + public override int Speed => GameData.basicBulletMoveSpeed / 3 * 2; + public override bool CanAttack(GameObj target) + { + // 圆形攻击范围 + return XY.Distance(this.Position, target.Position) <= BulletBombRange; + } + + public override BulletType TypeOfBullet => BulletType.AtomBomb; + } + + internal sealed class OrdinaryBullet : Bullet // 1倍攻击范围,1倍攻击力,一倍速 + { + public OrdinaryBullet(Character player, int radius = GameData.bulletRadius) : + base(player, radius) + { + } + public const double BulletBombRange = GameData.basicBulletBombRange / 6 * 5; + public const double BulletAttackRange = GameData.basicAttackRange / 2; + public override int AP => GameData.basicAp / 6 * 5; + public override int Speed => GameData.basicBulletMoveSpeed / 6 * 5; + public override bool CanAttack(GameObj target) + { + // 圆形攻击范围 + return XY.Distance(this.Position, target.Position) <= BulletBombRange; + } + + public override BulletType TypeOfBullet => BulletType.OrdinaryBullet; + } + + internal sealed class FastBullet : Bullet // 1倍攻击范围,0.2倍攻击力,2倍速 + { + public FastBullet(Character player, int radius = GameData.bulletRadius) : + base(player, radius) + { + } + public const double BulletBombRange = GameData.basicBulletBombRange / 4 * 2; + public const double BulletAttackRange = GameData.basicAttackRange; + public override int AP => (int)(0.5 * GameData.basicAp); + public override int Speed => 5 * GameData.basicBulletMoveSpeed / 3; + + public override bool CanAttack(GameObj target) + { + // 圆形攻击范围 + return XY.Distance(this.Position, target.Position) <= BulletBombRange; + } + + public override BulletType TypeOfBullet => BulletType.FastBullet; + } + + internal sealed class LineBullet : Bullet // 直线爆炸,宽度1格,长度为2倍爆炸范围 + { + public LineBullet(Character player, int radius = GameData.bulletRadius) : + base(player, radius) + { + } + public const double BulletBombRange = GameData.basicBulletBombRange / 3 * 4; + public const double BulletAttackRange = 0.1 * GameData.basicAttackRange; + public override int AP => GameData.basicAp / 3 * 2; + public override int Speed => GameData.basicBulletMoveSpeed / 3; + + public override bool CanAttack(GameObj target) + { + double FacingAngle = Math.Atan2(this.FacingDirection.y, this.FacingDirection.x); + if (Math.Abs(FacingAngle - Math.PI / 2) < 1e-2) + { + if (target.Position.y - this.Position.y > BulletBombRange) + return false; + if (target.Position.x < this.Position.x + GameData.numOfPosGridPerCell / 2 && target.Position.x > this.Position.x - GameData.numOfPosGridPerCell / 2) + return true; + return false; + } + else if (Math.Abs(FacingAngle - Math.PI * 3 / 2) < 1e-2) + { + if (target.Position.y - this.Position.y < -BulletBombRange) + return false; + if (target.Position.x < this.Position.x + GameData.numOfPosGridPerCell / 2 && target.Position.x > this.Position.x - GameData.numOfPosGridPerCell / 2) + return true; + return false; + } + else if (Math.Abs(FacingAngle) < 1e-2) + { + if (target.Position.x - this.Position.x > BulletBombRange) + return false; + if (target.Position.y < this.Position.y + GameData.numOfPosGridPerCell / 2 && target.Position.y > this.Position.y - GameData.numOfPosGridPerCell / 2) + return true; + return false; + } + else if (Math.Abs(FacingAngle - Math.PI) < 1e-2) + { + if (target.Position.x - this.Position.x < -BulletBombRange) + return false; + if (target.Position.y < this.Position.y + GameData.numOfPosGridPerCell / 2 && target.Position.y > this.Position.y - GameData.numOfPosGridPerCell / 2) + return true; + return false; + } + double vertical = Math.Tan(FacingAngle + Math.PI / 2); + bool posValue = vertical * Math.Cos(FacingAngle) - Math.Sin(FacingAngle) > 0; + double dist; + dist = vertical * (target.Position.x - this.Position.x) - (target.Position.y - this.Position.y) / Math.Sqrt(1 + vertical * vertical); + if (Math.Abs(dist) > BulletBombRange) + return false; + else if (dist < 0 && posValue) // 位于直线两侧 + return false; + vertical = Math.Tan(FacingAngle); + dist = Math.Abs(vertical * (target.Position.x - this.Position.x) - (target.Position.y - this.Position.y)) / Math.Sqrt(1 + vertical * vertical); + if (dist > GameData.numOfPosGridPerCell / 2) + return false; + return true; + } + + public override BulletType TypeOfBullet => BulletType.LineBullet; + } + public static class BulletFactory + { + public static Bullet? GetBullet(Character character) + { + Bullet? newBullet = null; + switch (character.BulletOfPlayer) + { + case BulletType.AtomBomb: + newBullet = new AtomBomb(character); + break; + case BulletType.LineBullet: + newBullet = new LineBullet(character); + break; + case BulletType.FastBullet: + newBullet = new FastBullet(character); + break; + case BulletType.OrdinaryBullet: + newBullet = new OrdinaryBullet(character); + break; + default: + break; + } + return newBullet; + } + public static int BulletRadius(BulletType bulletType) + { + switch (bulletType) + { + case BulletType.AtomBomb: + case BulletType.LineBullet: + case BulletType.FastBullet: + case BulletType.OrdinaryBullet: + default: + return GameData.bulletRadius; + } + } + public static double BulletAttackRange(BulletType bulletType) + { + switch (bulletType) + { + case BulletType.AtomBomb: + return AtomBomb.BulletAttackRange; + case BulletType.LineBullet: + return LineBullet.BulletAttackRange; + case BulletType.FastBullet: + return FastBullet.BulletAttackRange; + case BulletType.OrdinaryBullet: + return OrdinaryBullet.BulletAttackRange; + default: + return 0; + } + } + public static double BulletBombRange(BulletType bulletType) + { + switch (bulletType) + { + case BulletType.AtomBomb: + return AtomBomb.BulletBombRange; + case BulletType.LineBullet: + return LineBullet.BulletBombRange; + case BulletType.FastBullet: + return FastBullet.BulletBombRange; + case BulletType.OrdinaryBullet: + return OrdinaryBullet.BulletBombRange; + default: + return 0; + } + } + } +} diff --git a/logic/GameClass/GameObj/Character.BuffManager.cs b/logic/GameClass/GameObj/Character.BuffManager.cs deleted file mode 100644 index b580e9e..0000000 --- a/logic/GameClass/GameObj/Character.BuffManager.cs +++ /dev/null @@ -1,172 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Threading; -using Preparation.Utility; -using Preparation.GameData; - -namespace GameClass.GameObj -{ - public partial class Character - { - private readonly BuffManeger buffManeger; - /// - /// 角色携带的buff管理器 - /// - private class BuffManeger - { - [StructLayout(LayoutKind.Explicit, Size = 8)] - private struct BuffValue // buff参数联合体类型,可能是int或double - { - [FieldOffset(0)] - public int iValue; - [FieldOffset(0)] - public double lfValue; - - public BuffValue(int intValue) - { - this.lfValue = 0.0; - this.iValue = intValue; - } - public BuffValue(double longFloatValue) - { - this.iValue = 0; - this.lfValue = longFloatValue; - } - } - - /// - /// buff列表 - /// - private readonly LinkedList[] buffList; - private readonly object[] buffListLock; - - private void AddBuff(BuffValue bf, int buffTime, BuffType buffType, Action ReCalculateFunc) - { - new Thread - ( - () => - { - LinkedListNode 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]) - { - foreach (var add in buffList[(int)buffType]) - { - times *= add.lfValue; - } - } - return Math.Max(Math.Min((int)Math.Round(orgVal * times), maxVal), minVal); - } - - public void AddMoveSpeed(double add, int buffTime, Action 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]) - { - 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]) - { - return buffList[(int)BuffType.AddLIFE].Count != 0; - } - } - } - public bool TryActivatingLIFE() - { - if (HasLIFE) - { - lock (buffListLock[(int)BuffType.AddLIFE]) - { - buffList[(int)BuffType.AddLIFE].Clear(); - } - return true; - } - return false; - } - - public void AddSpear(int spearTime) => AddBuff(new BuffValue(), spearTime, BuffType.Spear, () => - {}); - public bool HasSpear - { - get { - lock (buffListLock[(int)BuffType.Spear]) - { - return buffList[(int)BuffType.Spear].Count != 0; - } - } - } - /// - /// 清除所有buff - /// - public void ClearAll() - { - for (int i = 0; i < buffList.Length; ++i) - { - lock (buffListLock[i]) - { - buffList[i].Clear(); - } - } - } - - public BuffManeger() - { - var buffTypeArray = Enum.GetValues(typeof(BuffType)); - buffList = new LinkedList[buffTypeArray.Length]; - buffListLock = new object[buffList.Length]; - int i = 0; - foreach (BuffType type in buffTypeArray) - { - buffList[i] = new LinkedList(); - buffListLock[i++] = new object(); - } - } - } -} -} diff --git a/logic/GameClass/GameObj/Character.SkillManager.cs b/logic/GameClass/GameObj/Character.SkillManager.cs deleted file mode 100644 index 2bd8c5f..0000000 --- a/logic/GameClass/GameObj/Character.SkillManager.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Preparation.Utility; -using System.Collections.Generic; -using System; - -namespace GameClass.GameObj -{ - public partial class Character - { - private delegate bool CharacterActiveSkill(Character player); // 返回值:是否成功释放了技能 - private delegate void CharacterPassiveSkill(Character player); - private readonly CharacterActiveSkill commonSkill; - private readonly ActiveSkillType commonSkillType; - public ActiveSkillType CommonSkillType => commonSkillType; - - private readonly CharacterType passiveSkillType; - public CharacterType PassiveSkillType => passiveSkillType; - public bool UseCommonSkill() - { - return commonSkill(this); - } - private int timeUntilCommonSkillAvailable = 0; // 还剩多少时间可以使用普通技能 - public int TimeUntilCommonSkillAvailable - { - get => timeUntilCommonSkillAvailable; - set { - lock (gameObjLock) - timeUntilCommonSkillAvailable = value < 0 ? 0 : value; - } - } - - readonly CharacterPassiveSkill passiveSkill; - public void UsePassiveSkill() - { - passiveSkill(this); - return; - } - public Character(XY initPos, int initRadius, PlaceType initPlace, CharacterType passiveSkillType, ActiveSkillType commonSkillType) : - base(initPos, initRadius, initPlace, GameObjType.Character) - { - this.CanMove = true; - this.score = 0; - this.propInventory = null; - this.buffManeger = new BuffManeger(); - - // UsePassiveSkill(); //创建player时开始被动技能,这一过程也可以放到gamestart时进行 - // 这可以放在AddPlayer中做 - - Debugger.Output(this, "constructed!"); - } - } -} diff --git a/logic/GameClass/GameObj/Character/Character.BuffManager.cs b/logic/GameClass/GameObj/Character/Character.BuffManager.cs new file mode 100644 index 0000000..9b2f724 --- /dev/null +++ b/logic/GameClass/GameObj/Character/Character.BuffManager.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading; +using Preparation.Utility; +using Preparation.GameData; + +namespace GameClass.GameObj +{ + public partial class Character + { + private readonly BuffManeger buffManeger; + /// + /// 角色携带的buff管理器 + /// + private class BuffManeger + { + [StructLayout(LayoutKind.Explicit, Size = 8)] + private struct BuffValue // buff参数联合体类型,可能是int或double + { + [FieldOffset(0)] + public int iValue; + [FieldOffset(0)] + public double lfValue; + + public BuffValue(int intValue) + { + this.lfValue = 0.0; + this.iValue = intValue; + } + public BuffValue(double longFloatValue) + { + this.iValue = 0; + this.lfValue = longFloatValue; + } + } + + /// + /// buff列表 + /// + private readonly LinkedList[] buffList; + private readonly object[] buffListLock; + + private void AddBuff(BuffValue bf, int buffTime, BuffType buffType, Action ReCalculateFunc) + { + new Thread + ( + () => + { + LinkedListNode 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]) + { + foreach (var add in buffList[(int)buffType]) + { + times *= add.lfValue; + } + } + return Math.Max(Math.Min((int)Math.Round(orgVal * times), maxVal), minVal); + } + + public void AddMoveSpeed(double add, int buffTime, Action 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]) + { + 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]) + { + return buffList[(int)BuffType.AddLIFE].Count != 0; + } + } + } + public bool TryActivatingLIFE() + { + if (HasLIFE) + { + lock (buffListLock[(int)BuffType.AddLIFE]) + { + buffList[(int)BuffType.AddLIFE].Clear(); + } + return true; + } + return false; + } + + public void AddSpear(int spearTime) => AddBuff(new BuffValue(), spearTime, BuffType.Spear, () => + { }); + public bool HasSpear + { + get + { + lock (buffListLock[(int)BuffType.Spear]) + { + return buffList[(int)BuffType.Spear].Count != 0; + } + } + } + /// + /// 清除所有buff + /// + public void ClearAll() + { + for (int i = 0; i < buffList.Length; ++i) + { + lock (buffListLock[i]) + { + buffList[i].Clear(); + } + } + } + + public BuffManeger() + { + var buffTypeArray = Enum.GetValues(typeof(BuffType)); + buffList = new LinkedList[buffTypeArray.Length]; + buffListLock = new object[buffList.Length]; + int i = 0; + foreach (BuffType type in buffTypeArray) + { + buffList[i] = new LinkedList(); + buffListLock[i++] = new object(); + } + } + } + } +} diff --git a/logic/GameClass/GameObj/Character/Character.SkillManager.cs b/logic/GameClass/GameObj/Character/Character.SkillManager.cs new file mode 100644 index 0000000..a4c5ab3 --- /dev/null +++ b/logic/GameClass/GameObj/Character/Character.SkillManager.cs @@ -0,0 +1,101 @@ +using GameClass.Skill; +using Preparation.Utility; +using System.Collections.Generic; +using System; + +namespace GameClass.GameObj +{ + public partial class Character + { + private delegate bool CharacterActiveSkill(Character player); // 返回值:是否成功释放了技能 + private delegate void CharacterPassiveSkill(Character player); + private readonly CharacterActiveSkill commonSkill; + private readonly ActiveSkillType commonSkillType; + public ActiveSkillType CommonSkillType => commonSkillType; + + private readonly CharacterType characterType; + public CharacterType CharacterType => characterType; + public bool UseCommonSkill() + { + return commonSkill(this); + } + private int timeUntilCommonSkillAvailable = 0; // 还剩多少时间可以使用普通技能 + public int TimeUntilCommonSkillAvailable + { + get => timeUntilCommonSkillAvailable; + set + { + lock (gameObjLock) + timeUntilCommonSkillAvailable = value < 0 ? 0 : value; + } + } + + readonly CharacterPassiveSkill passiveSkill; + public void UsePassiveSkill() + { + passiveSkill(this); + return; + } + public Character(XY initPos, int initRadius, PlaceType initPlace, CharacterType characterType, ActiveSkillType commonSkillType) : + base(initPos, initRadius, initPlace, GameObjType.Character) + { + this.CanMove = true; + this.score = 0; + this.propInventory = null; + this.buffManeger = new BuffManeger(); + IPassiveSkill pSkill; + ICommonSkill cSkill; + switch (passiveSkillType) + { + case this.CharacterType.RecoverAfterBattle: + pSkill = new RecoverAfterBattle(); + break; + case this.CharacterType.SpeedUpWhenLeavingGrass: + pSkill = new SpeedUpWhenLeavingGrass(); + break; + case this.CharacterType.Vampire: + pSkill = new Vampire(); + break; + default: + pSkill = new NoPassiveSkill(); + break; + } + switch (commonSkillType) + { + case ActiveSkillType.BecomeAssassin: + cSkill = new BecomeAssassin(); + break; + case ActiveSkillType.BecomeVampire: + cSkill = new BecomeVampire(); + break; + case ActiveSkillType.NuclearWeapon: + cSkill = new NuclearWeapon(); + break; + case ActiveSkillType.SuperFast: + cSkill = new SuperFast(); + break; + default: + cSkill = new NoCommonSkill(); + break; + } + this.MaxHp = cSkill.MaxHp; + this.hp = cSkill.MaxHp; + this.OrgMoveSpeed = cSkill.MoveSpeed; + this.moveSpeed = cSkill.MoveSpeed; + this.cd = cSkill.CD; + this.maxBulletNum = cSkill.MaxBulletNum; + this.bulletNum = maxBulletNum; + this.bulletOfPlayer = pSkill.InitBullet; + this.OriBulletOfPlayer = pSkill.InitBullet; + this.passiveSkill = pSkill.SkillEffect; + this.commonSkill = cSkill.SkillEffect; + this.passiveSkillType = passiveSkillType; + this.commonSkillType = commonSkillType; + + // UsePassiveSkill(); //创建player时开始被动技能,这一过程也可以放到gamestart时进行 + // 这可以放在AddPlayer中做 + + Debugger.Output(this, "constructed!"); + } + } +} diff --git a/logic/GameClass/GameObj/Character.cs b/logic/GameClass/GameObj/Character/Character.cs similarity index 92% rename from logic/GameClass/GameObj/Character.cs rename to logic/GameClass/GameObj/Character/Character.cs index 9631793..ba7e617 100644 --- a/logic/GameClass/GameObj/Character.cs +++ b/logic/GameClass/GameObj/Character/Character.cs @@ -11,9 +11,8 @@ namespace GameClass.GameObj { private readonly object beAttackedLock = new(); -#region 角色的基本属性及方法,包括与道具的交互方法 - /* - //THUAI5子弹 + #region 角色的基本属性及方法,包括与道具的交互方法 + /// /// 装弹冷却 /// @@ -21,8 +20,9 @@ namespace GameClass.GameObj public int CD { get => cd; - private - set { + private + set + { lock (gameObjLock) { cd = value; @@ -35,13 +35,14 @@ namespace GameClass.GameObj public int MaxBulletNum => maxBulletNum; // 人物最大子弹数 protected int bulletNum; public int BulletNum => bulletNum; // 目前持有的子弹数 - */ + public int MaxHp { get; protected set; } // 最大血量 protected int hp; public int HP { get => hp; - set { + set + { lock (gameObjLock) hp = value <= MaxHp ? value : MaxHp; } @@ -55,13 +56,31 @@ namespace GameClass.GameObj get => score; } - // public double AttackRange => BulletFactory.BulletAttackRange(this.BulletOfPlayer); + public double AttackRange => BulletFactory.BulletAttackRange(this.BulletOfPlayer); private double vampire = 0; // 回血率:0-1之间 public double Vampire { get => vampire; - set { + set + { + if (value > 1) + lock (gameObjLock) + vampire = 1; + else if (value < 0) + lock (gameObjLock) + vampire = 0; + else + lock (gameObjLock) + vampire = value; + } + } + private double oriVampire = 0; + public double OriVampire + { + get => oriVampire; + set + { if (value > 1) lock (gameObjLock) vampire = 1; @@ -73,26 +92,27 @@ namespace GameClass.GameObj vampire = value; } } - private double OriVampire { get; } - /* + public readonly BulletType OriBulletOfPlayer; private BulletType bulletOfPlayer; public BulletType BulletOfPlayer { get => bulletOfPlayer; - set { + set + { lock (gameObjLock) bulletOfPlayer = value; } } - */ + private Prop? propInventory; public Prop? PropInventory // 持有的道具 { get => propInventory; - set { + set + { lock (gameObjLock) { propInventory = value; @@ -122,7 +142,8 @@ namespace GameClass.GameObj public bool IsModifyingProp { get => isModifyingProp; - set { + set + { lock (gameObjLock) { isModifyingProp = value; @@ -137,14 +158,15 @@ namespace GameClass.GameObj public bool IsInvisible { get => isInvisible; - set { + set + { lock (gameObjLock) { isInvisible = value; } } } - /* + /// /// 进行一次远程攻击 /// @@ -196,7 +218,7 @@ namespace GameClass.GameObj return false; } } - */ + /// /// 尝试加血 /// @@ -265,7 +287,7 @@ namespace GameClass.GameObj Debugger.Output(this, " 's score has been subed to: " + score.ToString()); } } - /* + /// /// 遭受攻击 /// @@ -326,7 +348,7 @@ namespace GameClass.GameObj return hp <= 0; } } - */ + /// /// 角色所属队伍ID /// @@ -334,7 +356,8 @@ namespace GameClass.GameObj public long TeamID { get => teamID; - set { + set + { lock (gameObjLock) { teamID = value; @@ -346,7 +369,8 @@ namespace GameClass.GameObj public long PlayerID { get => playerID; - set { + set + { lock (gameObjLock) { playerID = value; @@ -360,16 +384,17 @@ namespace GameClass.GameObj public string Message { get => message; - set { + set + { lock (gameObjLock) { message = value; } } } -#endregion + #endregion -#region 角色拥有的buff相关属性、方法 + #region 角色拥有的buff相关属性、方法 public void AddMoveSpeed(int buffTime, double add = 2.0) => buffManeger.AddMoveSpeed(add, buffTime, newVal => { MoveSpeed = newVal < GameData.characterMaxSpeed ? newVal : GameData.characterMaxSpeed; }, OrgMoveSpeed); @@ -387,7 +412,8 @@ namespace GameClass.GameObj private Array buffTypeArray = Enum.GetValues(typeof(BuffType)); public Dictionary Buff { - get { + get + { Dictionary buff = new Dictionary(); foreach (BuffType type in buffTypeArray) { @@ -420,7 +446,7 @@ namespace GameClass.GameObj hp = MaxHp; } } -#endregion + #endregion public override void Reset() // 要加锁吗? { _ = AddDeathCount(); diff --git a/logic/GameClass/GameObj/GameObj.cs b/logic/GameClass/GameObj/GameObj.cs index 27f2abd..b2732d1 100644 --- a/logic/GameClass/GameObj/GameObj.cs +++ b/logic/GameClass/GameObj/GameObj.cs @@ -29,8 +29,9 @@ namespace GameClass.GameObj public XY Position { get => position; - protected - set { + protected + set + { lock (gameObjLock) { position = value; @@ -43,7 +44,8 @@ namespace GameClass.GameObj public XY FacingDirection { get => facingDirection; - set { + set + { lock (gameObjLock) facingDirection = value; } @@ -54,7 +56,8 @@ namespace GameClass.GameObj public bool CanMove { get => canMove; - set { + set + { lock (gameObjLock) { canMove = value; @@ -66,7 +69,8 @@ namespace GameClass.GameObj public bool IsMoving { get => isMoving; - set { + set + { lock (gameObjLock) { isMoving = value; @@ -78,7 +82,8 @@ namespace GameClass.GameObj public bool IsResetting { get => isResetting; - set { + set + { lock (gameObjLock) { isResetting = value; @@ -92,7 +97,8 @@ namespace GameClass.GameObj public PlaceType Place { get => place; - set { + set + { lock (gameObjLock) { place = value; @@ -106,7 +112,8 @@ namespace GameClass.GameObj public int MoveSpeed { get => moveSpeed; - set { + set + { lock (gameObjLock) { moveSpeed = value; @@ -120,8 +127,9 @@ namespace GameClass.GameObj public int OrgMoveSpeed { get => orgMoveSpeed; - protected - set { + protected + set + { orgMoveSpeed = value; } } diff --git a/logic/GameClass/GameObj/ObjOfCharacter.cs b/logic/GameClass/GameObj/ObjOfCharacter.cs index a09c6e5..140bab4 100644 --- a/logic/GameClass/GameObj/ObjOfCharacter.cs +++ b/logic/GameClass/GameObj/ObjOfCharacter.cs @@ -12,7 +12,8 @@ namespace GameClass.GameObj public ICharacter? Parent { get => parent; - set { + set + { lock (gameObjLock) { parent = value; diff --git a/logic/GameClass/GameObj/PickedProp.cs b/logic/GameClass/GameObj/PickedProp.cs new file mode 100644 index 0000000..f825062 --- /dev/null +++ b/logic/GameClass/GameObj/PickedProp.cs @@ -0,0 +1,24 @@ +using Preparation.Utility; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GameClass.GameObj +{ + // 为方便界面组做道具拾起特效,现引入“被捡起的道具”,在每帧发送给界面组 + public class PickedProp : GameObj + { + public override ShapeType Shape => ShapeType.Circle; + public override bool IsRigid => false; + public long MappingID { get; } + public Prop PropHasPicked; + public PickedProp(Prop prop) : + base(prop.Position, prop.Radius, prop.Place, GameObjType.PickedProp) + { + this.PropHasPicked = prop; + this.MappingID = prop.ID; + } + } +} diff --git a/logic/GameClass/GameObj/Prop.cs b/logic/GameClass/GameObj/Prop.cs new file mode 100644 index 0000000..1aaba6f --- /dev/null +++ b/logic/GameClass/GameObj/Prop.cs @@ -0,0 +1,125 @@ +using Preparation.Interface; +using Preparation.Utility; +using Preparation.GameData; + +namespace GameClass.GameObj +{ + public abstract class Prop : ObjOfCharacter + { + protected bool laid = false; + public bool Laid => laid; // 道具是否放置在地图上 + + public override bool IsRigid => true; + + protected override bool IgnoreCollideExecutor(IGameObj targetObj) + { + if (targetObj.Type == GameObjType.BirthPoint || targetObj.Type == GameObjType.Prop || targetObj.Type == GameObjType.Bullet || targetObj.Type == GameObjType.Character) + return true; + return false; + } + + public override ShapeType Shape => ShapeType.Square; + + public abstract PropType GetPropType(); + + public Prop(XY initPos, int radius = GameData.PropRadius) : + base(initPos, radius, PlaceType.Land, GameObjType.Prop) + { + this.CanMove = false; + this.moveSpeed = GameData.PropMoveSpeed; + } + public void SetNewPos(XY pos) + { + this.Position = pos; + } + } + /// + /// 增益道具 + /// + public abstract class BuffProp : Prop + { + public BuffProp(XY initPos) : + base(initPos) + { + } + } + ///// + ///// 坑人地雷 + ///// + // public abstract class DebuffMine : Prop + //{ + // public DebuffMine(XYPosition initPos) : base(initPos) { } + // } + #region 所有增益道具 + /// + /// 增加速度 + /// + public sealed class AddSpeed : BuffProp + { + public AddSpeed(XY initPos) : + base(initPos) + { + } + public override PropType GetPropType() => PropType.addSpeed; + } + /// + /// 复活甲 + /// + public sealed class AddLIFE : BuffProp + { + public AddLIFE(XY initPos) : + base(initPos) + { + } + public override PropType GetPropType() => PropType.addLIFE; + } + /// + /// 护盾 + /// + public sealed class Shield : BuffProp + { + public Shield(XY initPos) : + base(initPos) + { + } + public override PropType GetPropType() => PropType.Shield; + } + /// + /// 矛 + /// + public sealed class Spear : BuffProp + { + public Spear(XY initPos) : + base(initPos) + { + } + public override PropType GetPropType() => PropType.Spear; + } + #endregion + // #region 所有坑人地雷 + ///// + ///// 减速 + ///// + // public sealed class MinusSpeed : DebuffMine + //{ + // public MinusSpeed(XYPosition initPos) : base(initPos) { } + // public override PropType GetPropType() => PropType.minusSpeed; + // } + ///// + ///// 减少攻击力 + ///// + // public sealed class MinusAP : DebuffMine + //{ + // public MinusAP(XYPosition initPos) : base(initPos) { } + // public override PropType GetPropType() => PropType.minusAP; + // } + ///// + ///// 增加冷却 + ///// + // public sealed class AddCD : DebuffMine + //{ + // public AddCD(XYPosition initPos) : base(initPos) { } + // public override PropType GetPropType() => PropType.addCD; + // } + // #endregion +} diff --git a/logic/GameClass/GameObj/Team.cs b/logic/GameClass/GameObj/Team.cs index 281ea82..625c68e 100644 --- a/logic/GameClass/GameObj/Team.cs +++ b/logic/GameClass/GameObj/Team.cs @@ -13,7 +13,8 @@ namespace GameClass.GameObj private readonly List playerList; public int Score { - get { + get + { int score = 0; foreach (var player in playerList) score += player.Score; diff --git a/logic/GameClass/Skill/CommonSkill.cs b/logic/GameClass/Skill/CommonSkill.cs new file mode 100644 index 0000000..5933c19 --- /dev/null +++ b/logic/GameClass/Skill/CommonSkill.cs @@ -0,0 +1,219 @@ +using GameClass.GameObj; +using System.Threading; +using Preparation.Interface; +using Preparation.Utility; +using Preparation.GameData; +using System; +using Timothy.FrameRateTask; + +namespace GameClass.Skill +{ + public class BecomeVampire : ICommonSkill //化身吸血鬼 + { + private const int moveSpeed = GameData.basicMoveSpeed; + public int MoveSpeed => moveSpeed; + + private const int maxHp = (int)(GameData.basicHp / 6 * 9.5); + public int MaxHp => maxHp; + + private const int cd = GameData.basicCD; + public int CD => cd; + + private const int maxBulletNum = GameData.basicBulletNum * 2 / 3; + public int MaxBulletNum => maxBulletNum; + + // 以上参数以后再改 + public int SkillCD => GameData.commonSkillCD / 3 * 4; + public int DurationTime => GameData.commonSkillTime; + + private readonly object commonSkillLock = new object(); + public object CommonSkillLock => commonSkillLock; + + public bool SkillEffect(Character player) + { + return CommonSkillFactory.SkillEffect(this, player, () => + { + player.Vampire += 0.5; + Debugger.Output(player, "becomes vampire!"); + }, + () => + { + double tempVam = player.Vampire - 0.5; + player.Vampire = tempVam < player.OriVampire ? player.OriVampire : tempVam; + }); + } + } + public class BecomeAssassin : ICommonSkill //化身刺客,隐身 + { + private const int moveSpeed = GameData.basicMoveSpeed / 3 * 5; + public int MoveSpeed => moveSpeed; + + private const int maxHp = (int)(GameData.basicHp / 6 * 7.5); + public int MaxHp => maxHp; + + private const int cd = GameData.basicCD; + public int CD => cd; + + private const int maxBulletNum = GameData.basicBulletNum; + public int MaxBulletNum => maxBulletNum; + // 以上参数以后再改 + public int SkillCD => GameData.commonSkillCD; + public int DurationTime => GameData.commonSkillTime / 10 * 6; + + private readonly object commonSkillLock = new object(); + public object CommonSkillLock => commonSkillLock; + public bool SkillEffect(Character player) + { + return CommonSkillFactory.SkillEffect(this, player, () => + { + player.IsInvisible = true; + Debugger.Output(player, "uses atombomb!"); + }, + () => { player.IsInvisible = false; }); + } + } + public class NuclearWeapon : ICommonSkill //核武器 + { + private const int moveSpeed = GameData.basicMoveSpeed / 3 * 4; + public int MoveSpeed => moveSpeed; + + private const int maxHp = GameData.basicHp; + public int MaxHp => maxHp; + + private const int cd = GameData.basicCD; + public int CD => cd; + + private const int maxBulletNum = GameData.basicBulletNum * 2 / 3; + public int MaxBulletNum => maxBulletNum; + // 以上参数以后再改 + public int SkillCD => GameData.commonSkillCD / 3 * 7; + public int DurationTime => GameData.commonSkillTime / 10; + private readonly object commonSkillLock = new object(); + public object CommonSkillLock => commonSkillLock; + public bool SkillEffect(Character player) + { + return CommonSkillFactory.SkillEffect(this, player, () => + { + player.BulletOfPlayer = BulletType.AtomBomb; + Debugger.Output(player, "uses atombomb!"); + }, + () => { player.BulletOfPlayer = player.OriBulletOfPlayer; }); + } + } + public class SuperFast : ICommonSkill //3倍速 + { + private const int moveSpeed = GameData.basicMoveSpeed * 4 / 3; + public int MoveSpeed => moveSpeed; + + private const int maxHp = GameData.basicHp / 6 * 4; + public int MaxHp => maxHp; + + private const int cd = GameData.basicCD; + public int CD => cd; + + private const int maxBulletNum = GameData.basicBulletNum * 4 / 3; + public int MaxBulletNum => maxBulletNum; + // 以上参数以后再改 + public int SkillCD => GameData.commonSkillCD; + public int DurationTime => GameData.commonSkillTime / 10 * 4; + private readonly object commonSkillLock = new object(); + public object CommonSkillLock => commonSkillLock; + public bool SkillEffect(Character player) + { + return CommonSkillFactory.SkillEffect(this, player, () => + { + player.AddMoveSpeed(this.DurationTime, 3.0); + Debugger.Output(player, "moves very fast!"); + }, + () => { }); + } + } + public class NoCommonSkill : ICommonSkill //这种情况不该发生,定义着以防意外 + { + private const int moveSpeed = GameData.basicMoveSpeed; + public int MoveSpeed => moveSpeed; + + private const int maxHp = GameData.basicHp; + public int MaxHp => maxHp; + + private const int cd = GameData.basicCD; + public int CD => cd; + + private const int maxBulletNum = GameData.basicBulletNum; + public int MaxBulletNum => maxBulletNum; + // 以上参数以后再改 + public int SkillCD => GameData.commonSkillCD; + public int DurationTime => GameData.commonSkillTime; + private readonly object commonSkillLock = new object(); + public object CommonSkillLock => commonSkillLock; + public bool SkillEffect(Character player) + { + return false; + } + } + + public static class CommonSkillFactory + { + public static bool SkillEffect(ICommonSkill commonSkill, Character player, Action startSkill, Action endSkill) + { + lock (commonSkill.CommonSkillLock) + { + if (player.TimeUntilCommonSkillAvailable == 0) + { + player.TimeUntilCommonSkillAvailable = commonSkill.SkillCD; + new Thread + (() => + { + startSkill(); + new FrameRateTaskExecutor + ( + () => !player.IsResetting, + () => + { + 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 + ( + () => player.TimeUntilCommonSkillAvailable > 0 && !player.IsResetting, + () => + { + player.TimeUntilCommonSkillAvailable -= (int)GameData.frameDuration; + }, + timeInterval: GameData.frameDuration, + () => 0, + maxTotalDuration: (long)(commonSkill.SkillCD - commonSkill.DurationTime) + ) + { + AllowTimeExceed = true, + MaxTolerantTimeExceedCount = ulong.MaxValue, + }.Start(); + + player.TimeUntilCommonSkillAvailable = 0; + Debugger.Output(player, "CommonSkill is ready."); + } + ) + { IsBackground = true }.Start(); + + return true; + } + else + { + Debugger.Output(player, "CommonSkill is cooling down!"); + return false; + } + } + } + } +} diff --git a/logic/GameClass/Skill/ISkill.cs b/logic/GameClass/Skill/ISkill.cs new file mode 100644 index 0000000..e947001 --- /dev/null +++ b/logic/GameClass/Skill/ISkill.cs @@ -0,0 +1,23 @@ +using GameClass.GameObj; +using Preparation.Utility; +using System.Threading; + +namespace GameClass.Skill +{ + public interface IPassiveSkill + { + public BulletType InitBullet { get; } + public void SkillEffect(Character player); + } + public interface ICommonSkill + { + public int MoveSpeed { get; } + public int MaxHp { get; } + public int CD { get; } + public int MaxBulletNum { get; } + public bool SkillEffect(Character player); + public int DurationTime { get; } //技能持续时间 + public int SkillCD { get; } + public object CommonSkillLock { get; } + } +} diff --git a/logic/GameClass/Skill/PassiveSkill.cs b/logic/GameClass/Skill/PassiveSkill.cs new file mode 100644 index 0000000..bd8b209 --- /dev/null +++ b/logic/GameClass/Skill/PassiveSkill.cs @@ -0,0 +1,152 @@ +using System; +using System.Threading; +using GameClass.GameObj; +using Preparation.GameData; +using Preparation.Interface; +using Preparation.Utility; +using Timothy.FrameRateTask; + +namespace GameClass.Skill //被动技能开局时就释放,持续到游戏结束 +{ + public class RecoverAfterBattle : IPassiveSkill //脱战回血,普通子弹 + { + private readonly BulletType initBullet = BulletType.OrdinaryBullet; + public BulletType InitBullet => initBullet; + //以上参数以后再改 + public void SkillEffect(Character player) + { + const int recoverDegree = 5; //每帧回复血量 + int nowHP = player.HP; + int lastHP = nowHP; + long waitTime = 0; + const long interval = 10000; //每隔interval时间不受伤害,角色即开始回血 + new Thread + ( + () => + { + new FrameRateTaskExecutor + ( + () => true, + () => + { + 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); + }, + timeInterval: GameData.frameDuration, + () => 0, + maxTotalDuration: GameData.gameDuration + ) + { + AllowTimeExceed = true, + MaxTolerantTimeExceedCount = ulong.MaxValue, + TimeExceedAction = b => + { + if (b) Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); + +#if DEBUG + else + { + Console.WriteLine("Debug info: passive skill time exceeds for once."); + } +#endif + } + }.Start(); + } + ) + { IsBackground = true }.Start(); + } + } + 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 lastPlace = nowPlace; + bool speedup = false; + const int SpeedUpTime = 2000; //加速时间:2s + new Thread + ( + () => + { + new FrameRateTaskExecutor + ( + () => true, + () => + { + lastPlace = nowPlace; + nowPlace = player.Place; + if ((lastPlace == PlaceType.Grass1 || lastPlace == PlaceType.Grass2 || lastPlace == PlaceType.Grass3) && nowPlace == PlaceType.Land) + { + if (!speedup) + { + new Thread(() => + { + speedup = true; + player.AddMoveSpeed(SpeedUpTime, 3.0); + speedup = false; + }) + { IsBackground = true }.Start(); + } + } + }, + timeInterval: GameData.frameDuration, + () => 0, + maxTotalDuration: GameData.gameDuration + ) + { + AllowTimeExceed = true, + MaxTolerantTimeExceedCount = ulong.MaxValue, + TimeExceedAction = b => + { + if (b) Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); + +#if DEBUG + else + { + Console.WriteLine("Debug info: passive skill time exceeds for once."); + } +#endif + } + }.Start(); + } + ) + { IsBackground = true }.Start(); + } + } + public class Vampire : IPassiveSkill //被动就是吸血,普通子弹 + { + private readonly BulletType initBullet = BulletType.LineBullet; + public BulletType InitBullet => initBullet; + //以上参数以后再改 + public void SkillEffect(Character player) + { + player.OriVampire = 0.5; + player.Vampire = player.OriVampire; + } + } + + public class NoPassiveSkill : IPassiveSkill //没技能,这种情况不应该发生,先定义着以防意外 + { + private readonly BulletType initBullet = BulletType.OrdinaryBullet; + public BulletType InitBullet => initBullet; + //以上参数以后再改 + public void SkillEffect(Character player) + { + + } + } +} diff --git a/logic/GameEngine/MoveEngine.cs b/logic/GameEngine/MoveEngine.cs index f596c4e..f717f57 100644 --- a/logic/GameEngine/MoveEngine.cs +++ b/logic/GameEngine/MoveEngine.cs @@ -66,65 +66,28 @@ namespace GameEngine { if (!obj.IsAvailable && gameTimer.IsGaming) //不能动就直接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( - () => 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( + () => 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))) { case AfterCollision.ContinueCheck: @@ -133,43 +96,81 @@ namespace GameEngine case AfterCollision.Destroyed: Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); isDestroyed = true; - break; + return false; case AfterCollision.MoveMax: MoveMax(obj, new XY(direction, moveVecLength)); moveVecLength = 0; 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 - else - { - Console.WriteLine("Debug info: Object moving time exceed for once."); - } + else + { + Console.WriteLine("Debug info: Object moving time exceed for once."); + } #endif + } + }.Start(); } - }.Start(); - } ).Start(); + } } } -} diff --git a/logic/Gaming/MoveManager.cs b/logic/Gaming/MoveManager.cs index 7c15aa6..d9ad560 100644 --- a/logic/Gaming/MoveManager.cs +++ b/logic/Gaming/MoveManager.cs @@ -54,7 +54,8 @@ namespace Gaming // ActivateMine((Character)obj, (Mine)collisionObj); // return MoveEngine.AfterCollision.ContinueCheck; //} - return MoveEngine.AfterCollision.MoveMax; }, + return MoveEngine.AfterCollision.MoveMax; + }, EndMove: obj => { // Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); diff --git a/logic/Preparation/GameData/GameData.cs b/logic/Preparation/GameData/GameData.cs index 0be6c40..d0ad358 100644 --- a/logic/Preparation/GameData/GameData.cs +++ b/logic/Preparation/GameData/GameData.cs @@ -4,7 +4,7 @@ namespace Preparation.GameData { public static class GameData { -#region 基本常数与常方法 + #region 基本常数与常方法 public const int numOfPosGridPerCell = 1000; // 每格的【坐标单位】数 public const int numOfStepPerSecond = 20; // 每秒行走的步数 public const int lengthOfMap = 50000; // 地图长度 @@ -35,8 +35,8 @@ namespace Preparation.GameData } public static int numOfBirthPoint = 5; -#endregion -#region 角色相关 + #endregion + #region 角色相关 /// /// 玩家相关 /// @@ -71,9 +71,9 @@ namespace Preparation.GameData public const long GemProduceTime = 10000; public const long PropProduceTime = 10000; public const int PropDuration = 10000; -#endregion -#region 游戏帧相关 + #endregion + #region 游戏帧相关 public const long checkInterval = 50; // 检查位置标志、补充子弹的帧时长 -#endregion + #endregion } } diff --git a/logic/Preparation/Utility/XY.cs b/logic/Preparation/Utility/XY.cs index d1b62e1..8f4a29f 100644 --- a/logic/Preparation/Utility/XY.cs +++ b/logic/Preparation/Utility/XY.cs @@ -21,7 +21,7 @@ namespace Preparation.Utility { 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); } diff --git a/logic/logic.sln b/logic/logic.sln index 6d419a1..a030118 100644 --- a/logic/logic.sln +++ b/logic/logic.sln @@ -5,23 +5,17 @@ VisualStudioVersion = 17.0.32014.148 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{D033B809-2FB7-4340-B8B4-DDA30D6CA6FF}" EndProject -<<<<<<< HEAD Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameClass", "GameClass\GameClass.csproj", "{39D838F6-2B84-49E1-9CAF-1DFF22960B5D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameEngine", "GameEngine\GameEngine.csproj", "{91448D70-61C3-499F-9B27-979E16DC9E64}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gaming", "Gaming\Gaming.csproj", "{BE9E3584-93C0-4E0F-8DAC-967CF4792709}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapGenerator", "MapGenerator\MapGenerator.csproj", "{9BC673F1-14B1-4203-944D-474BD0F64EDC}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preparation", "Preparation\Preparation.csproj", "{E3DC4A37-8A83-40CC-AE47-68E70064C9DB}" -======= +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClientTest", "ClientTest\ClientTest.csproj", "{F3C98717-DD4F-45B8-B0F0-C217E7E2B5D4}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Protos", "..\dependency\proto\Protos.csproj", "{9ADA1EF8-DF2F-4C2E-9DE2-BC94DF89B44D}" ->>>>>>> 9f4b5ac18b94330559cd560708f4100ae913260e EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameEngine", "GameEngine\GameEngine.csproj", "{C7A82045-5EE5-46E8-AD0C-04103EFEAF7E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameEngine", "GameEngine\GameEngine.csproj", "{1D1D07F3-C332-4407-AC1B-EAD73F8BB3F3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -33,28 +27,18 @@ Global {D033B809-2FB7-4340-B8B4-DDA30D6CA6FF}.Debug|Any CPU.Build.0 = Debug|Any CPU {D033B809-2FB7-4340-B8B4-DDA30D6CA6FF}.Release|Any CPU.ActiveCfg = Release|Any CPU {D033B809-2FB7-4340-B8B4-DDA30D6CA6FF}.Release|Any CPU.Build.0 = Release|Any CPU -<<<<<<< HEAD {39D838F6-2B84-49E1-9CAF-1DFF22960B5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {39D838F6-2B84-49E1-9CAF-1DFF22960B5D}.Debug|Any CPU.Build.0 = Debug|Any CPU {39D838F6-2B84-49E1-9CAF-1DFF22960B5D}.Release|Any CPU.ActiveCfg = Release|Any CPU {39D838F6-2B84-49E1-9CAF-1DFF22960B5D}.Release|Any CPU.Build.0 = Release|Any CPU - {91448D70-61C3-499F-9B27-979E16DC9E64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {91448D70-61C3-499F-9B27-979E16DC9E64}.Debug|Any CPU.Build.0 = Debug|Any CPU - {91448D70-61C3-499F-9B27-979E16DC9E64}.Release|Any CPU.ActiveCfg = Release|Any CPU - {91448D70-61C3-499F-9B27-979E16DC9E64}.Release|Any CPU.Build.0 = Release|Any CPU {BE9E3584-93C0-4E0F-8DAC-967CF4792709}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BE9E3584-93C0-4E0F-8DAC-967CF4792709}.Debug|Any CPU.Build.0 = Debug|Any CPU {BE9E3584-93C0-4E0F-8DAC-967CF4792709}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE9E3584-93C0-4E0F-8DAC-967CF4792709}.Release|Any CPU.Build.0 = Release|Any CPU - {9BC673F1-14B1-4203-944D-474BD0F64EDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9BC673F1-14B1-4203-944D-474BD0F64EDC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9BC673F1-14B1-4203-944D-474BD0F64EDC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9BC673F1-14B1-4203-944D-474BD0F64EDC}.Release|Any CPU.Build.0 = Release|Any CPU {E3DC4A37-8A83-40CC-AE47-68E70064C9DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E3DC4A37-8A83-40CC-AE47-68E70064C9DB}.Debug|Any CPU.Build.0 = Debug|Any CPU {E3DC4A37-8A83-40CC-AE47-68E70064C9DB}.Release|Any CPU.ActiveCfg = Release|Any CPU {E3DC4A37-8A83-40CC-AE47-68E70064C9DB}.Release|Any CPU.Build.0 = Release|Any CPU -======= {F3C98717-DD4F-45B8-B0F0-C217E7E2B5D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F3C98717-DD4F-45B8-B0F0-C217E7E2B5D4}.Debug|Any CPU.Build.0 = Debug|Any CPU {F3C98717-DD4F-45B8-B0F0-C217E7E2B5D4}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -63,14 +47,10 @@ Global {9ADA1EF8-DF2F-4C2E-9DE2-BC94DF89B44D}.Debug|Any CPU.Build.0 = Debug|Any CPU {9ADA1EF8-DF2F-4C2E-9DE2-BC94DF89B44D}.Release|Any CPU.ActiveCfg = Release|Any CPU {9ADA1EF8-DF2F-4C2E-9DE2-BC94DF89B44D}.Release|Any CPU.Build.0 = Release|Any CPU -<<<<<<< HEAD ->>>>>>> 9f4b5ac18b94330559cd560708f4100ae913260e -======= - {C7A82045-5EE5-46E8-AD0C-04103EFEAF7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C7A82045-5EE5-46E8-AD0C-04103EFEAF7E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C7A82045-5EE5-46E8-AD0C-04103EFEAF7E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C7A82045-5EE5-46E8-AD0C-04103EFEAF7E}.Release|Any CPU.Build.0 = Release|Any CPU ->>>>>>> 3fa94addd0e0b62765b62c0788f217f7cf25b7c1 + {1D1D07F3-C332-4407-AC1B-EAD73F8BB3F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1D1D07F3-C332-4407-AC1B-EAD73F8BB3F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1D1D07F3-C332-4407-AC1B-EAD73F8BB3F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1D1D07F3-C332-4407-AC1B-EAD73F8BB3F3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE