| @@ -62,7 +62,7 @@ enum ButcherBuffType // 屠夫可用的增益效果类型 | |||
| BBUFFTYPE4 = 4; | |||
| } | |||
| // 特别说明:由于Human阵营和Butcher阵营有显著的隔离,且暂定职业、主动技能和被动效果相互绑定,故不按照THUAI5的方式区分ActiveSkillType和PassiveSkillType,而是选择了按照阵营来给不同阵营赋予不同的职业(及技能)。 | |||
| // 特别说明:由于Human阵营和Butcher阵营有显著的隔离,且暂定职业、主动技能和被动效果相互绑定,故不按照THUAI5的方式区分ActiveSkillType和CharacterType,而是选择了按照阵营来给不同阵营赋予不同的职业(及技能)。 | |||
| enum PlayerType | |||
| { | |||
| @@ -45,15 +45,15 @@ namespace GameClass.GameObj | |||
| this.buffManeger = new BuffManeger(); | |||
| IPassiveSkill pSkill; | |||
| ICommonSkill cSkill; | |||
| switch (passiveSkillType) | |||
| switch (characterType) | |||
| { | |||
| case this.CharacterType.RecoverAfterBattle: | |||
| case CharacterType.RecoverAfterBattle: | |||
| pSkill = new RecoverAfterBattle(); | |||
| break; | |||
| case this.CharacterType.SpeedUpWhenLeavingGrass: | |||
| case CharacterType.SpeedUpWhenLeavingGrass: | |||
| pSkill = new SpeedUpWhenLeavingGrass(); | |||
| break; | |||
| case this.CharacterType.Vampire: | |||
| case CharacterType.Vampire: | |||
| pSkill = new Vampire(); | |||
| break; | |||
| default: | |||
| @@ -89,7 +89,7 @@ namespace GameClass.GameObj | |||
| this.OriBulletOfPlayer = pSkill.InitBullet; | |||
| this.passiveSkill = pSkill.SkillEffect; | |||
| this.commonSkill = cSkill.SkillEffect; | |||
| this.passiveSkillType = passiveSkillType; | |||
| this.characterType = characterType; | |||
| this.commonSkillType = commonSkillType; | |||
| // UsePassiveSkill(); //创建player时开始被动技能,这一过程也可以放到gamestart时进行 | |||
| @@ -0,0 +1,212 @@ | |||
| using System; | |||
| using System.Threading; | |||
| using System.Collections.Generic; | |||
| using GameClass.GameObj; | |||
| using Preparation.GameData; | |||
| using Preparation.Utility; | |||
| using GameEngine; | |||
| namespace Gaming | |||
| { | |||
| public partial class Game | |||
| { | |||
| private readonly AttackManager attackManager; | |||
| private class AttackManager | |||
| { | |||
| readonly Map gameMap; | |||
| readonly MoveEngine moveEngine; | |||
| public AttackManager(Map gameMap) | |||
| { | |||
| this.gameMap = gameMap; | |||
| this.moveEngine = new MoveEngine( | |||
| gameMap: gameMap, | |||
| OnCollision: (obj, collisionObj, moveVec) => | |||
| { | |||
| //BulletBomb((Bullet)obj, (GameObj)collisionObj); | |||
| return MoveEngine.AfterCollision.Destroyed; | |||
| }, | |||
| EndMove: obj => | |||
| { | |||
| #if DEBUG | |||
| Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); | |||
| #endif | |||
| BulletBomb((Bullet)obj, null); | |||
| } | |||
| ); | |||
| } | |||
| private void BombOnePlayer(Bullet bullet, Character playerBeingShot) | |||
| { | |||
| if (playerBeingShot.BeAttack(bullet)) | |||
| { | |||
| playerBeingShot.CanMove = false; | |||
| playerBeingShot.IsResetting = true; | |||
| // gameMap.GameObjLockDict[GameObjIdx.Player].EnterWriteLock(); | |||
| // try | |||
| //{ | |||
| // gameMap.GameObjDict[GameObjIdx.Player].Remove(playerBeingShot); | |||
| // } | |||
| // finally | |||
| //{ | |||
| // gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); | |||
| // } | |||
| Prop? dropProp = null; | |||
| if (playerBeingShot.PropInventory != null) // 若角色原来有道具,则原始道具掉落在原地 | |||
| { | |||
| dropProp = playerBeingShot.PropInventory; | |||
| dropProp.SetNewPos(GameData.GetCellCenterPos(playerBeingShot.Position.x / GameData.numOfPosGridPerCell, playerBeingShot.Position.y / GameData.numOfPosGridPerCell)); | |||
| } | |||
| gameMap.GameObjLockDict[GameObjIdx.Prop].EnterWriteLock(); | |||
| try | |||
| { | |||
| if (dropProp != null) | |||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(dropProp); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Prop].ExitWriteLock(); | |||
| } | |||
| playerBeingShot.Reset(); | |||
| ((Character?)bullet.Parent)?.AddScore(GameData.addScoreWhenKillOneLevelPlayer); // 给击杀者加分 | |||
| new Thread | |||
| (() => | |||
| { | |||
| Thread.Sleep(GameData.reviveTime); | |||
| playerBeingShot.AddShield(GameData.shieldTimeAtBirth); // 复活加个盾 | |||
| // 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; | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| } | |||
| private void BulletBomb(Bullet bullet, GameObj? objBeingShot) | |||
| { | |||
| #if DEBUG | |||
| Debugger.Output(bullet, "bombed!"); | |||
| #endif | |||
| bullet.CanMove = false; | |||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].EnterWriteLock(); | |||
| try | |||
| { | |||
| foreach (ObjOfCharacter _bullet in gameMap.GameObjDict[GameObjIdx.Bullet]) | |||
| { | |||
| if (_bullet.ID == bullet.ID) | |||
| { | |||
| 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; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].ExitWriteLock(); | |||
| } | |||
| /*if (objBeingShot != null) | |||
| { | |||
| else if (objBeingShot is Bullet) //子弹不能相互引爆,若要更改这一设定,取消注释即可。 | |||
| { | |||
| 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(); | |||
| } | |||
| foreach (Character beAttackedPlayer in beAttackedList) | |||
| { | |||
| BombOnePlayer(bullet, beAttackedPlayer); | |||
| } | |||
| beAttackedList.Clear(); | |||
| } | |||
| public bool Attack(Character? player, double angle) // 射出去的子弹泼出去的水(狗头) | |||
| { // 子弹如果没有和其他物体碰撞,将会一直向前直到超出人物的attackRange | |||
| if (player == null) | |||
| { | |||
| #if DEBUG | |||
| Console.WriteLine("the player who will attack is NULL!"); | |||
| #endif | |||
| 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 DEBUG | |||
| Console.WriteLine($"playerID:{player.ID} successfully attacked!"); | |||
| #endif | |||
| return true; | |||
| } | |||
| else | |||
| { | |||
| #if DEBUG | |||
| Console.WriteLine($"playerID:{player.ID} has no bullets so that he can't attack!"); | |||
| #endif | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,360 @@ | |||
| using System; | |||
| using System.Threading; | |||
| using System.Collections.Generic; | |||
| using GameClass.GameObj; | |||
| using Preparation.Utility; | |||
| using Preparation.GameData; | |||
| using Timothy.FrameRateTask; | |||
| using Preparation.Interface; | |||
| namespace Gaming | |||
| { | |||
| public partial class Game | |||
| { | |||
| public struct PlayerInitInfo | |||
| { | |||
| public uint birthPointIndex; | |||
| public long teamID; | |||
| public long playerID; | |||
| public CharacterType characterType; | |||
| public ActiveSkillType commonSkill; | |||
| public PlayerInitInfo(uint birthPointIndex, long teamID, long playerID, CharacterType characterType, ActiveSkillType commonSkill) | |||
| { | |||
| this.birthPointIndex = birthPointIndex; | |||
| this.teamID = teamID; | |||
| this.characterType = characterType; | |||
| this.commonSkill = commonSkill; | |||
| this.playerID = playerID; | |||
| } | |||
| } | |||
| private readonly List<Team> teamList; | |||
| public List<Team> TeamList => teamList; | |||
| private readonly Map gameMap; | |||
| public Map GameMap => gameMap; | |||
| private readonly int numOfTeam; | |||
| public long AddPlayer(PlayerInitInfo playerInitInfo) | |||
| { | |||
| if (!Team.teamExists(playerInitInfo.teamID)) | |||
| /* || !MapInfo.ValidBirthPointIdx(playerInitInfo.birthPointIdx) | |||
| || gameMap.BirthPointList[playerInitInfo.birthPointIdx].Parent != null)*/ | |||
| return GameObj.invalidID; | |||
| XY pos = gameMap.BirthPointList[playerInitInfo.birthPointIndex].Position; | |||
| // Console.WriteLine($"x,y: {pos.x},{pos.y}"); | |||
| Character newPlayer = new(pos, GameData.characterRadius, gameMap.GetPlaceType(pos), playerInitInfo.characterType, playerInitInfo.commonSkill); | |||
| gameMap.BirthPointList[playerInitInfo.birthPointIndex].Parent = newPlayer; | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].EnterWriteLock(); | |||
| try | |||
| { | |||
| gameMap.GameObjDict[GameObjIdx.Player].Add(newPlayer); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); | |||
| } | |||
| // Console.WriteLine($"GameObjDict[GameObjIdx.Player] length:{gameMap.GameObjDict[GameObjIdx.Player].Count}"); | |||
| teamList[(int)playerInitInfo.teamID].AddPlayer(newPlayer); | |||
| newPlayer.TeamID = playerInitInfo.teamID; | |||
| newPlayer.PlayerID = playerInitInfo.playerID; | |||
| new Thread //人物装弹 | |||
| ( | |||
| () => | |||
| { | |||
| while (!gameMap.Timer.IsGaming) | |||
| Thread.Sleep(newPlayer.CD); | |||
| 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 | |||
| ) | |||
| { | |||
| 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(); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| return newPlayer.ID; | |||
| } | |||
| public bool StartGame(int milliSeconds) | |||
| { | |||
| if (gameMap.Timer.IsGaming) | |||
| return false; | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||
| { | |||
| player.CanMove = true; | |||
| player.AddShield(GameData.shieldTimeAtBirth); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitReadLock(); | |||
| } | |||
| propManager.StartProducing(); | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| new FrameRateTaskExecutor<int> | |||
| ( | |||
| loopCondition: () => gameMap.Timer.IsGaming, | |||
| 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(); | |||
| } | |||
| } | |||
| } | |||
| }, | |||
| timeInterval: GameData.checkInterval, | |||
| finallyReturn: () => 0 | |||
| ) | |||
| { | |||
| AllowTimeExceed = true | |||
| }.Start(); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| // 开始游戏 | |||
| if (!gameMap.Timer.StartGame(milliSeconds)) | |||
| return false; | |||
| EndGame(); // 游戏结束时要做的事 | |||
| return true; | |||
| } | |||
| public void EndGame() | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].EnterWriteLock(); | |||
| /*try | |||
| { | |||
| } | |||
| finally | |||
| { | |||
| }*/ | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); | |||
| } | |||
| public void MovePlayer(long playerID, int moveTimeInMilliseconds, double angle) | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return; | |||
| Character? player = gameMap.FindPlayer(playerID); | |||
| if (player != null) | |||
| { | |||
| moveManager.MovePlayer(player, moveTimeInMilliseconds, angle); | |||
| #if DEBUG | |||
| Console.WriteLine($"PlayerID:{playerID} move to ({player.Position.x},{player.Position.y})!"); | |||
| #endif | |||
| } | |||
| else | |||
| { | |||
| #if DEBUG | |||
| Console.WriteLine($"PlayerID:{playerID} player does not exists!"); | |||
| #endif | |||
| } | |||
| } | |||
| public void Attack(long playerID, double angle) | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return; | |||
| Character? player = gameMap.FindPlayer(playerID); | |||
| if (player != null) | |||
| { | |||
| _ = attackManager.Attack(player, angle); | |||
| } | |||
| } | |||
| public void UseProp(long playerID) | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return; | |||
| Character? player = gameMap.FindPlayer(playerID); | |||
| if (player != null) | |||
| { | |||
| propManager.UseProp(player); | |||
| } | |||
| } | |||
| public void ThrowProp(long playerID, int timeInmillionSeconds, double angle) | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return; | |||
| Character? player = gameMap.FindPlayer(playerID); | |||
| if (player != null) | |||
| { | |||
| propManager.ThrowProp(player, timeInmillionSeconds, angle); | |||
| } | |||
| } | |||
| public bool PickProp(long playerID, PropType propType = PropType.Null) | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return false; | |||
| Character? player = gameMap.FindPlayer(playerID); | |||
| if (player != null) | |||
| { | |||
| return propManager.PickProp(player, propType); | |||
| } | |||
| return false; | |||
| } | |||
| public bool UseCommonSkill(long playerID) | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return false; | |||
| Character? player = gameMap.FindPlayer(playerID); | |||
| if (player != null) | |||
| { | |||
| return skillManager.UseCommonSkill(player); | |||
| } | |||
| else | |||
| return false; | |||
| } | |||
| public void AllPlayerUsePassiveSkill() | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return; | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].EnterWriteLock(); | |||
| try | |||
| { | |||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||
| { | |||
| skillManager.UsePassiveSkill(player); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); | |||
| } | |||
| } | |||
| public void ClearLists(GameObjIdx[] objIdxes) | |||
| { | |||
| foreach (var idx in objIdxes) | |||
| { | |||
| if (idx != GameObjIdx.None) | |||
| { | |||
| gameMap.GameObjLockDict[idx].EnterWriteLock(); | |||
| try | |||
| { | |||
| gameMap.GameObjDict[idx].Clear(); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[idx].ExitWriteLock(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| public void ClearAllLists() | |||
| { | |||
| foreach (var keyValuePair in gameMap.GameObjDict) | |||
| { | |||
| if (keyValuePair.Key != GameObjIdx.Map) | |||
| { | |||
| 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 | |||
| { | |||
| gameMap.GameObjLockDict[keyValuePair.Key].ExitWriteLock(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| public int GetTeamScore(long teamID) | |||
| { | |||
| return teamList[(int)teamID].Score; | |||
| } | |||
| public List<IGameObj> GetGameObj() | |||
| { | |||
| var gameObjList = new List<IGameObj>(); | |||
| 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(); | |||
| } | |||
| } | |||
| } | |||
| return gameObjList; | |||
| } | |||
| public Game(uint[,] mapResource, int numOfTeam) | |||
| { | |||
| // if (numOfTeam > maxTeamNum) throw new TeamNumOverFlowException(); | |||
| gameMap = new Map(mapResource); | |||
| // 加入队伍 | |||
| this.numOfTeam = numOfTeam; | |||
| teamList = new List<Team>(); | |||
| for (int i = 0; i < numOfTeam; ++i) | |||
| { | |||
| teamList.Add(new Team()); | |||
| } | |||
| skillManager = new SkillManager(); | |||
| attackManager = new AttackManager(gameMap); | |||
| moveManager = new MoveManager(gameMap); | |||
| propManager = new PropManager(gameMap); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,247 @@ | |||
| using System.Collections.Generic; | |||
| using GameClass.GameObj; | |||
| using System.Threading; | |||
| using Preparation.GameData; | |||
| using Preparation.Utility; | |||
| using System; | |||
| using Timothy.FrameRateTask; | |||
| using GameEngine; | |||
| namespace Gaming | |||
| { | |||
| public partial class Game | |||
| { | |||
| private readonly PropManager propManager; | |||
| private class PropManager | |||
| { | |||
| private readonly Map gameMap; | |||
| private MoveEngine moveEngine; | |||
| private bool isProducingProp = false; | |||
| private readonly List<XY> availableCellForGenerateProp; | |||
| public void StartProducing() | |||
| { | |||
| if (isProducingProp) | |||
| return; | |||
| isProducingProp = true; | |||
| ProduceProp(); | |||
| } | |||
| public void UseProp(Character player) | |||
| { | |||
| if (player.IsResetting) | |||
| return; | |||
| Prop? prop = player.UseProp(); | |||
| switch (prop?.GetPropType()) | |||
| { | |||
| case PropType.Spear: | |||
| player.AddSpear(GameData.PropDuration); | |||
| break; | |||
| case PropType.Shield: | |||
| player.AddShield(GameData.PropDuration); | |||
| break; | |||
| case PropType.addLIFE: | |||
| player.AddLIFE(GameData.PropDuration); | |||
| break; | |||
| case PropType.addSpeed: | |||
| player.AddMoveSpeed(GameData.PropDuration); | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// | |||
| /// </summary> | |||
| /// <param name="player"></param> | |||
| /// <param name="propType">若不指定,则自动判断可捡起什么道具</param> | |||
| /// <returns></returns> | |||
| public bool PickProp(Character player, PropType propType = PropType.Null) | |||
| { | |||
| if (player.IsResetting) | |||
| return false; | |||
| Prop? pickProp = null; | |||
| if (propType == PropType.Null) // 自动检查有无道具可捡 | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Prop].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (Prop prop in gameMap.GameObjDict[GameObjIdx.Prop]) | |||
| { | |||
| if (GameData.IsInTheSameCell(prop.Position, player.Position) && prop.CanMove == false) | |||
| { | |||
| pickProp = prop; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Prop].ExitReadLock(); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Prop].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (Prop prop in gameMap.GameObjDict[GameObjIdx.Prop]) | |||
| { | |||
| if (prop.GetPropType() == propType) | |||
| { | |||
| if (GameData.IsInTheSameCell(prop.Position, player.Position) && prop.CanMove == false) | |||
| { | |||
| pickProp = prop; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Prop].ExitReadLock(); | |||
| } | |||
| } | |||
| if (pickProp != null) | |||
| { | |||
| // pickProp.CanMove = false; | |||
| Prop? dropProp = null; | |||
| if (player.PropInventory != null) // 若角色原来有道具,则原始道具掉落在原地 | |||
| { | |||
| dropProp = player.PropInventory; | |||
| dropProp.SetNewPos(GameData.GetCellCenterPos(player.Position.x / GameData.numOfPosGridPerCell, player.Position.y / GameData.numOfPosGridPerCell)); | |||
| } | |||
| player.PropInventory = pickProp; | |||
| gameMap.GameObjLockDict[GameObjIdx.Prop].EnterWriteLock(); | |||
| try | |||
| { | |||
| gameMap.GameObjDict[GameObjIdx.Prop].Remove(pickProp); | |||
| if (dropProp != null) | |||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(dropProp); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Prop].ExitWriteLock(); | |||
| } | |||
| gameMap.GameObjLockDict[GameObjIdx.PickedProp].EnterWriteLock(); | |||
| try | |||
| { | |||
| gameMap.GameObjDict[GameObjIdx.PickedProp].Add(new PickedProp(pickProp)); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.PickedProp].ExitWriteLock(); | |||
| } | |||
| return true; | |||
| } | |||
| else | |||
| return false; | |||
| } | |||
| public void ThrowProp(Character player, int timeInMilliseconds, double angle) | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return; | |||
| if (player.IsResetting) // 移动中也能扔,但由于“惯性”,可能初始位置会有点变化 | |||
| return; | |||
| Prop? prop = player.UseProp(); | |||
| if (prop == null) | |||
| return; | |||
| prop.CanMove = true; | |||
| prop.SetNewPos(player.Position); | |||
| gameMap.GameObjLockDict[GameObjIdx.Prop].EnterWriteLock(); | |||
| try | |||
| { | |||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(prop); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Prop].ExitWriteLock(); | |||
| } | |||
| timeInMilliseconds = timeInMilliseconds < GameData.PropMaxMoveDistance / prop.MoveSpeed * 1000 ? timeInMilliseconds : GameData.PropMaxMoveDistance / prop.MoveSpeed * 1000; | |||
| moveEngine.MoveObj(prop, timeInMilliseconds, angle); | |||
| } | |||
| private void ProduceProp() | |||
| { | |||
| int len = availableCellForGenerateProp.Count; | |||
| Random r = new Random(Environment.TickCount); | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| while (!gameMap.Timer.IsGaming) | |||
| 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)) | |||
| { | |||
| 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(); | |||
| } | |||
| public PropManager(Map gameMap) // 道具不能扔过墙 | |||
| { | |||
| this.gameMap = gameMap; | |||
| this.moveEngine = new MoveEngine( | |||
| gameMap: gameMap, | |||
| OnCollision: (obj, collision, moveVec) => | |||
| { return MoveEngine.AfterCollision.MoveMax; }, | |||
| EndMove: obj => | |||
| { | |||
| // obj.Place = gameMap.GetPlaceType((GameObj)obj); | |||
| obj.CanMove = false; | |||
| Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); | |||
| } | |||
| ); | |||
| availableCellForGenerateProp = new List<XY>(); | |||
| 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) | |||
| { | |||
| availableCellForGenerateProp.Add(GameData.GetCellCenterPos(i, j)); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,21 @@ | |||
| using System; | |||
| using GameClass.GameObj; | |||
| namespace Gaming | |||
| { | |||
| public partial class Game | |||
| { | |||
| readonly SkillManager skillManager; | |||
| private class SkillManager | |||
| { | |||
| public bool UseCommonSkill(Character character) | |||
| { | |||
| return character.UseCommonSkill(); | |||
| } | |||
| public void UsePassiveSkill(Character character) | |||
| { | |||
| character.UsePassiveSkill(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -7,5 +7,6 @@ namespace Preparation.Interface | |||
| { | |||
| public long TeamID { get; } | |||
| public int HP { get; set; } | |||
| public double Vampire { get; } | |||
| } | |||
| } | |||
| @@ -85,10 +85,11 @@ namespace Preparation.Utility | |||
| { | |||
| None = 0, | |||
| Player = 1, | |||
| Prop = 2, | |||
| Map = 3, | |||
| BombedBullet = 4, | |||
| PickedProp = 5 | |||
| Bullet = 2, | |||
| Prop = 3, | |||
| Map = 4, | |||
| BombedBullet = 5, | |||
| PickedProp = 6 | |||
| } | |||
| } | |||
| public enum MapInfoObjType | |||