diff --git a/logic/Preparation/GameData/GameData.cs b/logic/Preparation/GameData/GameData.cs new file mode 100644 index 0000000..2d13d58 --- /dev/null +++ b/logic/Preparation/GameData/GameData.cs @@ -0,0 +1,77 @@ +using Preparation.Utility; + +namespace Preparation.GameData +{ + public static class GameData + { +#region 基本常数与常方法 + public const int numOfPosGridPerCell = 1000; // 每格的【坐标单位】数 + public const int numOfStepPerSecond = 20; // 每秒行走的步数 + public const int lengthOfMap = 50000; // 地图长度 + public const int rows = 50; // 行数 + public const int cols = 50; // 列数 + public const long gameDuration = 600000; // 游戏时长600000ms = 10min + public const long frameDuration = 50; // 每帧时长 + + public const int MinSpeed = 1; // 最小速度 + public const int MaxSpeed = int.MaxValue; // 最大速度 + + public static XYPosition GetCellCenterPos(int x, int y) // 求格子的中心坐标 + { + XYPosition ret = new((x * numOfPosGridPerCell) + (numOfPosGridPerCell / 2), (y * numOfPosGridPerCell) + (numOfPosGridPerCell / 2)); + return ret; + } + public static int PosGridToCellX(XYPosition pos) // 求坐标所在的格子的x坐标 + { + return pos.x / numOfPosGridPerCell; + } + public static int PosGridToCellY(XYPosition pos) // 求坐标所在的格子的y坐标 + { + return pos.y / numOfPosGridPerCell; + } + public static bool IsInTheSameCell(XYPosition pos1, XYPosition pos2) + { + return PosGridToCellX(pos1) == PosGridToCellX(pos2) && PosGridToCellY(pos1) == PosGridToCellY(pos2); + } +#endregion +#region 角色相关 + /// + /// 玩家相关 + /// + public const int characterRadius = numOfPosGridPerCell / 2; // 人物半径 + public const int basicAp = 3000; // 初始攻击力 + public const int basicHp = 6000; // 初始血量 + public const int basicCD = 3000; // 初始子弹冷却 + public const int basicBulletNum = 3; // 基本初始子弹量 + public const int MinAP = 0; // 最小攻击力 + public const int MaxAP = int.MaxValue; // 最大攻击力 + public const double basicAttackRange = 9000; // 基本攻击范围 + public const double basicBulletBombRange = 3000; // 基本子弹爆炸范围 + public const int basicMoveSpeed = 3000; // 基本移动速度,单位:s-1 + public const int basicBulletMoveSpeed = 3000; // 基本子弹移动速度,单位:s-1 + public const int characterMaxSpeed = 12000; // 最大速度 + public const int addScoreWhenKillOneLevelPlayer = 30; // 击杀一级角色获得的加分 + public const int commonSkillCD = 30000; // 普通技能标准冷却时间 + public const int commonSkillTime = 10000; // 普通技能标准持续时间 + public const int bulletRadius = 200; // 默认子弹半径 + public const int reviveTime = 30000; // 复活时间 + public const int shieldTimeAtBirth = 3000; // 复活时的护盾时间 + public const int gemToScore = 4; // 一个宝石的标准加分 + /// + /// 道具相关 + /// + public const int MinPropTypeNum = 1; + public const int MaxPropTypeNum = 10; + public const int PropRadius = numOfPosGridPerCell / 2; + public const int PropMoveSpeed = 3000; + public const int PropMaxMoveDistance = 15 * numOfPosGridPerCell; + public const int MaxGemSize = 5; // 随机生成的宝石最大size + public const long GemProduceTime = 10000; + public const long PropProduceTime = 10000; + public const int PropDuration = 10000; +#endregion +#region 游戏帧相关 + public const long checkInterval = 50; // 检查位置标志、补充子弹的帧时长 +#endregion + } +} diff --git a/logic/Preparation/Interface/ICharacter.cs b/logic/Preparation/Interface/ICharacter.cs new file mode 100644 index 0000000..a708e00 --- /dev/null +++ b/logic/Preparation/Interface/ICharacter.cs @@ -0,0 +1,11 @@ +using System; +using Preparation.Utility; + +namespace Preparation.Interface +{ + public interface ICharacter : IGameObj + { + public long TeamID { get; } + public int HP { get; set; } + } +} \ No newline at end of file diff --git a/logic/Preparation/Interface/IGameObj.cs b/logic/Preparation/Interface/IGameObj.cs new file mode 100644 index 0000000..a32a1c5 --- /dev/null +++ b/logic/Preparation/Interface/IGameObj.cs @@ -0,0 +1,20 @@ +using Preparation.Utility; + +namespace Preparation.Interface +{ + public interface IGameObj + { + public GameObjType Type { get; set; } + public long ID { get; } + public XYPosition Position { get; } // if Square, Pos equals the center + public double FacingDirection { get; } + public bool IsRigid { get; } + public ShapeType Shape { get; } + public bool CanMove { get; set; } + public bool IsMoving { get; set; } + public bool IsResetting { get; set; } // reviving + public bool IsAvailable { get; } + public int Radius { get; } // if Square, Radius equals half length of one side + public PlaceType Place { get; set; } + } +} diff --git a/logic/Preparation/Interface/IMap.cs b/logic/Preparation/Interface/IMap.cs new file mode 100644 index 0000000..0d781b3 --- /dev/null +++ b/logic/Preparation/Interface/IMap.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Threading; +using Preparation.Utility; + +namespace Preparation.Interface +{ + public interface IMap + { + ITimer Timer { get; } + + // the two dicts must have same keys + Dictionary> GameObjDict { get; } + Dictionary GameObjLockDict { get; } + + public bool IsOutOfBound(IGameObj obj); + public IOutOfBound GetOutOfBound(XYPosition pos); // 返回新建的一个OutOfBound对象 + } +} diff --git a/logic/Preparation/Interface/IMoveable.cs b/logic/Preparation/Interface/IMoveable.cs new file mode 100644 index 0000000..bc16f5b --- /dev/null +++ b/logic/Preparation/Interface/IMoveable.cs @@ -0,0 +1,37 @@ +using System; +using Preparation.Utility; + +namespace Preparation.Interface +{ + public interface IMoveable : IGameObj + { + object MoveLock { get; } + public int MoveSpeed { get; } + public long Move(Vector moveVec); + protected bool IgnoreCollide(IGameObj targetObj); // 忽略碰撞,在具体类中实现 + public bool WillCollideWith(IGameObj? targetObj, XYPosition nextPos) // 检查下一位置是否会和目标物碰撞 + { + if (targetObj == null) + return false; + // 会移动的只有子弹和人物,都是Circle + if (!targetObj.IsRigid || targetObj.ID == ID) + return false; + if (IgnoreCollide(targetObj)) + return false; + if (targetObj.Shape == ShapeType.Circle) + { + return XYPosition.Distance(nextPos, targetObj.Position) < targetObj.Radius + Radius; + } + else // Square + { + long deltaX = Math.Abs(nextPos.x - targetObj.Position.x), deltaY = Math.Abs(nextPos.y - targetObj.Position.y); + if (deltaX >= targetObj.Radius + Radius || deltaY >= targetObj.Radius + Radius) + return false; + if (deltaX < targetObj.Radius || deltaY < targetObj.Radius) + return true; + else + return ((long)(deltaX - targetObj.Radius) * (deltaX - targetObj.Radius)) + ((long)(deltaY - targetObj.Radius) * (deltaY - targetObj.Radius)) <= (long)Radius * (long)Radius; + } + } + } +} diff --git a/logic/Preparation/Interface/IObjOfCharacter.cs b/logic/Preparation/Interface/IObjOfCharacter.cs new file mode 100644 index 0000000..92c5e40 --- /dev/null +++ b/logic/Preparation/Interface/IObjOfCharacter.cs @@ -0,0 +1,9 @@ +using System; + +namespace Preparation.Interface +{ + public interface IObjOfCharacter : IGameObj + { + ICharacter? Parent { get; set; } + } +} diff --git a/logic/Preparation/Interface/ITimer.cs b/logic/Preparation/Interface/ITimer.cs new file mode 100644 index 0000000..bdcdcbc --- /dev/null +++ b/logic/Preparation/Interface/ITimer.cs @@ -0,0 +1,9 @@ + +namespace Preparation.Interface +{ + public interface ITimer + { + bool IsGaming { get; } + public bool StartGame(int timeInMilliseconds); + } +} diff --git a/logic/Preparation/Utility/Debugger.cs b/logic/Preparation/Utility/Debugger.cs new file mode 100644 index 0000000..282d9b3 --- /dev/null +++ b/logic/Preparation/Utility/Debugger.cs @@ -0,0 +1,14 @@ +using System; + +namespace Preparation.Utility +{ + public class Debugger + { + static public void Output(object current, string str) + { +#if DEBUG + Console.WriteLine(current.GetType() + " " + current.ToString() + " " + str); +#endif + } + } +} diff --git a/logic/Preparation/Utility/EnumType.cs b/logic/Preparation/Utility/EnumType.cs new file mode 100644 index 0000000..5dfb8cc --- /dev/null +++ b/logic/Preparation/Utility/EnumType.cs @@ -0,0 +1,96 @@ + +namespace Preparation.Utility +{ + /// + /// 存放所有用到的枚举类型 + /// + public enum GameObjType + { + Null = 0, + Character = 1, + Prop = 2, + PickedProp = 3, + Bullet = 4, + BombedBullet = 5, + + Wall = 6, + Grass = 7, + Generator = 8, // 发电机 + BirthPoint = 9, + Exit = 10, + EmergencyExit = 11, + OutOfBoundBlock = 12, // 范围外 + } + public enum ShapeType + { + Null = 0, + Circle = 1, // 子弹和人物为圆形,格子为方形 + Square = 2 + } + public enum PlaceType // 位置标志,包括陆地(一般默认为陆地,如墙体等),草丛。游戏中每一帧都要刷新各个物体的该属性 + { + Null = 0, + Land = 1, + Grass1 = 2, + Grass2 = 3, + Grass3 = 4, + Grass4 = 5, + Grass5 = 6, + } + public enum BulletType // 子弹类型 + { + Null = 0, + OrdinaryBullet = 1, // 普通子弹 + AtomBomb = 2, // 原子弹 + FastBullet = 3, // 快速子弹 + LineBullet = 4 // 直线子弹 + } + public enum PropType // 道具类型 + { + Null = 0, + addSpeed = 1, + addLIFE = 2, + Shield = 3, + Spear = 4, + Gem = 5, // 新增:宝石 + } + public enum PassiveSkillType // 被动技能 + { + Null = 0, + RecoverAfterBattle = 1, + SpeedUpWhenLeavingGrass = 2, + Vampire = 3, + PSkill3 = 4, + PSkill4 = 5, + PSkill5 = 6 + } + public enum ActiveSkillType // 主动技能 + { + Null = 0, + BecomeVampire = 1, + BecomeAssassin = 2, + NuclearWeapon = 3, + SuperFast = 4, + ASkill4 = 5, + ASkill5 = 6 + } + public enum BuffType // buff + { + Null = 0, + AddSpeed = 1, + AddLIFE = 2, + Shield = 3, + Spear = 4 + } + public enum GameObjIdx + { + None = 0, + Player = 1, + Bullet = 2, + Prop = 3, + Gem = 4, + Map = 5, + BombedBullet = 6, + PickedProp = 7 + } +} diff --git a/logic/Preparation/Utility/MapEncoder.cs b/logic/Preparation/Utility/MapEncoder.cs new file mode 100644 index 0000000..d8e2c4e --- /dev/null +++ b/logic/Preparation/Utility/MapEncoder.cs @@ -0,0 +1,17 @@ +using System; + +namespace Preparation.Utility +{ + public class MapEncoder + { + static public char Dec2Hex(int d) + { + return char.Parse(d.ToString("X")); + } + static public int Hex2Dec(char h) + { + string hexabet = "0123456789ABCDEF"; + return hexabet.IndexOf(h); + } + } +} diff --git a/logic/Preparation/Utility/Tools.cs b/logic/Preparation/Utility/Tools.cs new file mode 100644 index 0000000..78ee847 --- /dev/null +++ b/logic/Preparation/Utility/Tools.cs @@ -0,0 +1,20 @@ +using System; + +namespace Preparation.Utility +{ + public static class Tools + { + public static double CorrectAngle(double angle) // 将幅角转化为主值0~2pi + { + if (double.IsNaN(angle) || double.IsInfinity(angle)) + { + return 0.0; + } + while (angle < 0) + angle += 2 * Math.PI; + while (angle >= 2 * Math.PI) + angle -= 2 * Math.PI; + return angle; + } + } +} diff --git a/logic/Preparation/Utility/Vector.cs b/logic/Preparation/Utility/Vector.cs new file mode 100644 index 0000000..50614f0 --- /dev/null +++ b/logic/Preparation/Utility/Vector.cs @@ -0,0 +1,57 @@ +using System; + +namespace Preparation.Utility +{ + public struct Vector + { + public double angle; + public double length; + + public static XYPosition VectorToXY(Vector v) + { + return new XYPosition((int)(v.length * Math.Cos(v.angle)), (int)(v.length * Math.Sin(v.angle))); + } + public Vector2 ToVector2() + { + return new Vector2((int)(this.length * Math.Cos(this.angle)), (int)(this.length * Math.Sin(this.angle))); + } + public static Vector XYToVector(double x, double y) + { + return new Vector(Math.Atan2(y, x), Math.Sqrt((x * x) + (y * y))); + } + public Vector(double angle, double length) + { + if (length < 0) + { + angle += Math.PI; + length = -length; + } + this.angle = Tools.CorrectAngle(angle); + this.length = length; + } + } + + public struct Vector2 + { + public double x; + public double y; + public Vector2(double x, double y) + { + this.x = x; + this.y = y; + } + + public static double operator*(Vector2 v1, Vector2 v2) + { + return (v1.x * v2.x) + (v1.y * v2.y); + } + public static Vector2 operator +(Vector2 v1, Vector2 v2) + { + return new Vector2(v1.x + v2.x, v1.y + v2.y); + } + public static Vector2 operator -(Vector2 v1, Vector2 v2) + { + return new Vector2(v1.x - v2.x, v1.y - v2.y); + } + } +} diff --git a/logic/Preparation/Utility/XYPosition.cs b/logic/Preparation/Utility/XYPosition.cs new file mode 100644 index 0000000..55647ec --- /dev/null +++ b/logic/Preparation/Utility/XYPosition.cs @@ -0,0 +1,49 @@ +using System; + +namespace Preparation.Utility +{ + public struct XYPosition + { + public int x; + public int y; + public XYPosition(int x, int y) + { + this.x = x; + this.y = y; + } + public override string ToString() + { + return "(" + x.ToString() + "," + y.ToString() + ")"; + } + public static XYPosition operator +(XYPosition p1, XYPosition p2) + { + return new XYPosition(p1.x + p2.x, p1.y + p2.y); + } + public static XYPosition operator -(XYPosition p1, XYPosition p2) + { + return new XYPosition(p1.x - p2.x, p1.y - p2.y); + } + public static double Distance(XYPosition p1, XYPosition p2) + { + return Math.Sqrt(((long)(p1.x - p2.x) * (p1.x - p2.x)) + ((long)(p1.y - p2.y) * (p1.y - p2.y))); + } + /*public static XYPosition[] GetSquareRange(uint edgeLen) // 从THUAI4的BULLET.CS移植而来,不知还有用否 + { + XYPosition[] range = new XYPosition[edgeLen * edgeLen]; + int offset = (int)(edgeLen >> 1); + for (int i = 0; i < (int)edgeLen; ++i) + { + for (int j = 0; j < (int)edgeLen; ++j) + { + range[i * edgeLen + j].x = i - offset; + range[i * edgeLen + j].y = j - offset; + } + } + return range; + }*/ + public Vector2 ToVector2() + { + return new Vector2(this.x, this.y); + } + } +}