From cab03a228d82aff8cdfea74c18f13560744d31bf Mon Sep 17 00:00:00 2001
From: shangfengh <3495281661@qq.com>
Date: Sat, 15 Oct 2022 00:49:27 +0800
Subject: [PATCH 1/4] chore:add logic/Preparation/Utility
---
logic/Preparation/Utility/Debugger.cs | 14 ++++
logic/Preparation/Utility/EnumType.cs | 96 +++++++++++++++++++++++++
logic/Preparation/Utility/MapEncoder.cs | 17 +++++
logic/Preparation/Utility/Tools.cs | 20 ++++++
logic/Preparation/Utility/Vector.cs | 57 +++++++++++++++
logic/Preparation/Utility/XYPosition.cs | 49 +++++++++++++
6 files changed, 253 insertions(+)
create mode 100644 logic/Preparation/Utility/Debugger.cs
create mode 100644 logic/Preparation/Utility/EnumType.cs
create mode 100644 logic/Preparation/Utility/MapEncoder.cs
create mode 100644 logic/Preparation/Utility/Tools.cs
create mode 100644 logic/Preparation/Utility/Vector.cs
create mode 100644 logic/Preparation/Utility/XYPosition.cs
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);
+ }
+ }
+}
From 1616030e5a20b3bcca7a510bcc4b06a67ea510ab Mon Sep 17 00:00:00 2001
From: shangfengh <3495281661@qq.com>
Date: Sat, 15 Oct 2022 11:46:15 +0800
Subject: [PATCH 2/4] chore: add logic/Preparation/Interface
---
logic/Preparation/Interface/ICharacter.cs | 11 ++++++
logic/Preparation/Interface/IGameObj.cs | 20 +++++++++++
logic/Preparation/Interface/IMap.cs | 18 ++++++++++
logic/Preparation/Interface/IMoveable.cs | 36 +++++++++++++++++++
.../Preparation/Interface/IObjOfCharacter.cs | 9 +++++
logic/Preparation/Interface/ITimer.cs | 9 +++++
6 files changed, 103 insertions(+)
create mode 100644 logic/Preparation/Interface/ICharacter.cs
create mode 100644 logic/Preparation/Interface/IGameObj.cs
create mode 100644 logic/Preparation/Interface/IMap.cs
create mode 100644 logic/Preparation/Interface/IMoveable.cs
create mode 100644 logic/Preparation/Interface/IObjOfCharacter.cs
create mode 100644 logic/Preparation/Interface/ITimer.cs
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..000a534
--- /dev/null
+++ b/logic/Preparation/Interface/IMoveable.cs
@@ -0,0 +1,36 @@
+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);
+ }
+}
From 8c975d57a112337f94e63082bd32fefd6454669b Mon Sep 17 00:00:00 2001
From: shangfengh <3495281661@qq.com>
Date: Sat, 15 Oct 2022 12:02:37 +0800
Subject: [PATCH 3/4] add logic/Preparation/GameData
---
logic/Preparation/GameData/GameData.cs | 77 ++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
create mode 100644 logic/Preparation/GameData/GameData.cs
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
+ }
+}
From 250af1de52291c1b1170ff190dc9f9d4d5d4b5c3 Mon Sep 17 00:00:00 2001
From: shangfengh <3495281661@qq.com>
Date: Sat, 15 Oct 2022 15:18:54 +0800
Subject: [PATCH 4/4] fix: logic/Preparation/.../Imoveable.cs reuse
IgnoreCollide
---
logic/Preparation/Interface/IMoveable.cs | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/logic/Preparation/Interface/IMoveable.cs b/logic/Preparation/Interface/IMoveable.cs
index 000a534..bc16f5b 100644
--- a/logic/Preparation/Interface/IMoveable.cs
+++ b/logic/Preparation/Interface/IMoveable.cs
@@ -8,7 +8,7 @@ namespace Preparation.Interface
object MoveLock { get; }
public int MoveSpeed { get; }
public long Move(Vector moveVec);
- // protected bool IgnoreCollide(IGameObj targetObj); // 忽略碰撞,在具体类中实现
+ protected bool IgnoreCollide(IGameObj targetObj); // 忽略碰撞,在具体类中实现
public bool WillCollideWith(IGameObj? targetObj, XYPosition nextPos) // 检查下一位置是否会和目标物碰撞
{
if (targetObj == null)
@@ -16,7 +16,8 @@ namespace Preparation.Interface
// 会移动的只有子弹和人物,都是Circle
if (!targetObj.IsRigid || targetObj.ID == ID)
return false;
- // if (IgnoreCollide(targetObj)) return false;
+ if (IgnoreCollide(targetObj))
+ return false;
if (targetObj.Shape == ShapeType.Circle)
{
return XYPosition.Distance(nextPos, targetObj.Position) < targetObj.Radius + Radius;