| @@ -62,7 +62,7 @@ enum ButcherBuffType // 屠夫可用的增益效果类型 | |||||
| BBUFFTYPE4 = 4; | BBUFFTYPE4 = 4; | ||||
| } | } | ||||
| // 特别说明:由于Human阵营和Butcher阵营有显著的隔离,且暂定职业、主动技能和被动效果相互绑定,故不按照THUAI5的方式区分ActiveSkillType和PassiveSkillType,而是选择了按照阵营来给不同阵营赋予不同的职业(及技能)。 | |||||
| // 特别说明:由于Human阵营和Butcher阵营有显著的隔离,且暂定职业、主动技能和被动效果相互绑定,故不按照THUAI5的方式区分ActiveSkillType和CharacterType,而是选择了按照阵营来给不同阵营赋予不同的职业(及技能)。 | |||||
| enum PlayerType | enum PlayerType | ||||
| { | { | ||||
| @@ -45,15 +45,15 @@ namespace GameClass.GameObj | |||||
| this.buffManeger = new BuffManeger(); | this.buffManeger = new BuffManeger(); | ||||
| IPassiveSkill pSkill; | IPassiveSkill pSkill; | ||||
| ICommonSkill cSkill; | ICommonSkill cSkill; | ||||
| switch (passiveSkillType) | |||||
| switch (characterType) | |||||
| { | { | ||||
| case this.CharacterType.RecoverAfterBattle: | |||||
| case CharacterType.RecoverAfterBattle: | |||||
| pSkill = new RecoverAfterBattle(); | pSkill = new RecoverAfterBattle(); | ||||
| break; | break; | ||||
| case this.CharacterType.SpeedUpWhenLeavingGrass: | |||||
| case CharacterType.SpeedUpWhenLeavingGrass: | |||||
| pSkill = new SpeedUpWhenLeavingGrass(); | pSkill = new SpeedUpWhenLeavingGrass(); | ||||
| break; | break; | ||||
| case this.CharacterType.Vampire: | |||||
| case CharacterType.Vampire: | |||||
| pSkill = new Vampire(); | pSkill = new Vampire(); | ||||
| break; | break; | ||||
| default: | default: | ||||
| @@ -89,7 +89,7 @@ namespace GameClass.GameObj | |||||
| this.OriBulletOfPlayer = pSkill.InitBullet; | this.OriBulletOfPlayer = pSkill.InitBullet; | ||||
| this.passiveSkill = pSkill.SkillEffect; | this.passiveSkill = pSkill.SkillEffect; | ||||
| this.commonSkill = cSkill.SkillEffect; | this.commonSkill = cSkill.SkillEffect; | ||||
| this.passiveSkillType = passiveSkillType; | |||||
| this.characterType = characterType; | |||||
| this.commonSkillType = commonSkillType; | this.commonSkillType = commonSkillType; | ||||
| // UsePassiveSkill(); //创建player时开始被动技能,这一过程也可以放到gamestart时进行 | // 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 long TeamID { get; } | ||||
| public int HP { get; set; } | public int HP { get; set; } | ||||
| public double Vampire { get; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -85,10 +85,11 @@ namespace Preparation.Utility | |||||
| { | { | ||||
| None = 0, | None = 0, | ||||
| Player = 1, | Player = 1, | ||||
| Prop = 2, | |||||
| Map = 3, | |||||
| BombedBullet = 4, | |||||
| PickedProp = 5 | |||||
| Bullet = 2, | |||||
| Prop = 3, | |||||
| Map = 4, | |||||
| BombedBullet = 5, | |||||
| PickedProp = 6 | |||||
| } | } | ||||
| } | } | ||||
| public enum MapInfoObjType | public enum MapInfoObjType | ||||