Browse Source

feat: add prop, Bullet, and skill

tags/0.1.0
shangfengh 2 years ago
parent
commit
2d7b7bd3c4
21 changed files with 1250 additions and 379 deletions
  1. +0
    -2
      logic/.gitignore
  2. +20
    -0
      logic/GameClass/GameObj/BombedBullet.cs
  3. +238
    -0
      logic/GameClass/GameObj/Bullet.cs
  4. +0
    -172
      logic/GameClass/GameObj/Character.BuffManager.cs
  5. +0
    -51
      logic/GameClass/GameObj/Character.SkillManager.cs
  6. +176
    -0
      logic/GameClass/GameObj/Character/Character.BuffManager.cs
  7. +101
    -0
      logic/GameClass/GameObj/Character/Character.SkillManager.cs
  8. +53
    -27
      logic/GameClass/GameObj/Character/Character.cs
  9. +18
    -10
      logic/GameClass/GameObj/GameObj.cs
  10. +2
    -1
      logic/GameClass/GameObj/ObjOfCharacter.cs
  11. +24
    -0
      logic/GameClass/GameObj/PickedProp.cs
  12. +125
    -0
      logic/GameClass/GameObj/Prop.cs
  13. +2
    -1
      logic/GameClass/GameObj/Team.cs
  14. +219
    -0
      logic/GameClass/Skill/CommonSkill.cs
  15. +23
    -0
      logic/GameClass/Skill/ISkill.cs
  16. +152
    -0
      logic/GameClass/Skill/PassiveSkill.cs
  17. +82
    -81
      logic/GameEngine/MoveEngine.cs
  18. +2
    -1
      logic/Gaming/MoveManager.cs
  19. +6
    -6
      logic/Preparation/GameData/GameData.cs
  20. +1
    -1
      logic/Preparation/Utility/XY.cs
  21. +6
    -26
      logic/logic.sln

+ 0
- 2
logic/.gitignore View File

@@ -400,5 +400,3 @@ FodyWeavers.xsd
#THUAI playback file #THUAI playback file
*.thuaipb *.thuaipb


Client/
CSharpInterface/

+ 20
- 0
logic/GameClass/GameObj/BombedBullet.cs View File

@@ -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;
}
}
}

+ 238
- 0
logic/GameClass/GameObj/Bullet.cs View File

@@ -0,0 +1,238 @@
using Preparation.GameData;
using Preparation.Interface;
using Preparation.Utility;
using System;

namespace GameClass.GameObj
{
public abstract class Bullet : ObjOfCharacter
{
/// <summary>
/// //攻击力
/// </summary>
public abstract int AP { get; }
public abstract int Speed { get; }

private readonly bool hasSpear;
/// <summary>
/// 是否有矛
/// </summary>
public bool HasSpear => hasSpear;

/// <summary>
/// 与THUAI4不同的一个攻击判定方案,通过这个函数判断爆炸时能否伤害到target
/// </summary>
/// <param name="target">被尝试攻击者</param>
/// <returns>是否可以攻击到</returns>
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;
}
}
}
}

+ 0
- 172
logic/GameClass/GameObj/Character.BuffManager.cs View File

@@ -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;
/// <summary>
/// 角色携带的buff管理器
/// </summary>
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;
}
}

/// <summary>
/// buff列表
/// </summary>
private readonly LinkedList<BuffValue>[] buffList;
private readonly object[] buffListLock;

private void AddBuff(BuffValue bf, int buffTime, BuffType buffType, Action ReCalculateFunc)
{
new Thread
(
() =>
{
LinkedListNode<BuffValue> 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<int> 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;
}
}
}
/// <summary>
/// 清除所有buff
/// </summary>
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<BuffValue>[buffTypeArray.Length];
buffListLock = new object[buffList.Length];
int i = 0;
foreach (BuffType type in buffTypeArray)
{
buffList[i] = new LinkedList<BuffValue>();
buffListLock[i++] = new object();
}
}
}
}
}

+ 0
- 51
logic/GameClass/GameObj/Character.SkillManager.cs View File

@@ -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!");
}
}
}

+ 176
- 0
logic/GameClass/GameObj/Character/Character.BuffManager.cs View File

@@ -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;
/// <summary>
/// 角色携带的buff管理器
/// </summary>
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;
}
}

/// <summary>
/// buff列表
/// </summary>
private readonly LinkedList<BuffValue>[] buffList;
private readonly object[] buffListLock;

private void AddBuff(BuffValue bf, int buffTime, BuffType buffType, Action ReCalculateFunc)
{
new Thread
(
() =>
{
LinkedListNode<BuffValue> 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<int> 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;
}
}
}
/// <summary>
/// 清除所有buff
/// </summary>
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<BuffValue>[buffTypeArray.Length];
buffListLock = new object[buffList.Length];
int i = 0;
foreach (BuffType type in buffTypeArray)
{
buffList[i] = new LinkedList<BuffValue>();
buffListLock[i++] = new object();
}
}
}
}
}

+ 101
- 0
logic/GameClass/GameObj/Character/Character.SkillManager.cs View File

@@ -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!");
}
}
}

logic/GameClass/GameObj/Character.cs → logic/GameClass/GameObj/Character/Character.cs View File

@@ -11,9 +11,8 @@ namespace GameClass.GameObj
{ {
private readonly object beAttackedLock = new(); private readonly object beAttackedLock = new();


#region 角色的基本属性及方法,包括与道具的交互方法
/*
//THUAI5子弹
#region 角色的基本属性及方法,包括与道具的交互方法

/// <summary> /// <summary>
/// 装弹冷却 /// 装弹冷却
/// </summary> /// </summary>
@@ -21,8 +20,9 @@ namespace GameClass.GameObj
public int CD public int CD
{ {
get => cd; get => cd;
private
set {
private
set
{
lock (gameObjLock) lock (gameObjLock)
{ {
cd = value; cd = value;
@@ -35,13 +35,14 @@ namespace GameClass.GameObj
public int MaxBulletNum => maxBulletNum; // 人物最大子弹数 public int MaxBulletNum => maxBulletNum; // 人物最大子弹数
protected int bulletNum; protected int bulletNum;
public int BulletNum => bulletNum; // 目前持有的子弹数 public int BulletNum => bulletNum; // 目前持有的子弹数
*/
public int MaxHp { get; protected set; } // 最大血量 public int MaxHp { get; protected set; } // 最大血量
protected int hp; protected int hp;
public int HP public int HP
{ {
get => hp; get => hp;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
hp = value <= MaxHp ? value : MaxHp; hp = value <= MaxHp ? value : MaxHp;
} }
@@ -55,13 +56,31 @@ namespace GameClass.GameObj
get => score; get => score;
} }


// public double AttackRange => BulletFactory.BulletAttackRange(this.BulletOfPlayer);
public double AttackRange => BulletFactory.BulletAttackRange(this.BulletOfPlayer);


private double vampire = 0; // 回血率:0-1之间 private double vampire = 0; // 回血率:0-1之间
public double Vampire public double Vampire
{ {
get => 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) if (value > 1)
lock (gameObjLock) lock (gameObjLock)
vampire = 1; vampire = 1;
@@ -73,26 +92,27 @@ namespace GameClass.GameObj
vampire = value; vampire = value;
} }
} }
private double OriVampire { get; }


/*
public readonly BulletType OriBulletOfPlayer; public readonly BulletType OriBulletOfPlayer;
private BulletType bulletOfPlayer; private BulletType bulletOfPlayer;
public BulletType BulletOfPlayer public BulletType BulletOfPlayer
{ {
get => bulletOfPlayer; get => bulletOfPlayer;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
bulletOfPlayer = value; bulletOfPlayer = value;
} }
} }
*/


private Prop? propInventory; private Prop? propInventory;
public Prop? PropInventory // 持有的道具 public Prop? PropInventory // 持有的道具
{ {
get => propInventory; get => propInventory;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
{ {
propInventory = value; propInventory = value;
@@ -122,7 +142,8 @@ namespace GameClass.GameObj
public bool IsModifyingProp public bool IsModifyingProp
{ {
get => isModifyingProp; get => isModifyingProp;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
{ {
isModifyingProp = value; isModifyingProp = value;
@@ -137,14 +158,15 @@ namespace GameClass.GameObj
public bool IsInvisible public bool IsInvisible
{ {
get => isInvisible; get => isInvisible;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
{ {
isInvisible = value; isInvisible = value;
} }
} }
} }
/*
/// <summary> /// <summary>
/// 进行一次远程攻击 /// 进行一次远程攻击
/// </summary> /// </summary>
@@ -196,7 +218,7 @@ namespace GameClass.GameObj
return false; return false;
} }
} }
*/
/// <summary> /// <summary>
/// 尝试加血 /// 尝试加血
/// </summary> /// </summary>
@@ -265,7 +287,7 @@ namespace GameClass.GameObj
Debugger.Output(this, " 's score has been subed to: " + score.ToString()); Debugger.Output(this, " 's score has been subed to: " + score.ToString());
} }
} }
/*
/// <summary> /// <summary>
/// 遭受攻击 /// 遭受攻击
/// </summary> /// </summary>
@@ -326,7 +348,7 @@ namespace GameClass.GameObj
return hp <= 0; return hp <= 0;
} }
} }
*/
/// <summary> /// <summary>
/// 角色所属队伍ID /// 角色所属队伍ID
/// </summary> /// </summary>
@@ -334,7 +356,8 @@ namespace GameClass.GameObj
public long TeamID public long TeamID
{ {
get => teamID; get => teamID;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
{ {
teamID = value; teamID = value;
@@ -346,7 +369,8 @@ namespace GameClass.GameObj
public long PlayerID public long PlayerID
{ {
get => playerID; get => playerID;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
{ {
playerID = value; playerID = value;
@@ -360,16 +384,17 @@ namespace GameClass.GameObj
public string Message public string Message
{ {
get => message; get => message;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
{ {
message = value; message = value;
} }
} }
} }
#endregion
#endregion


#region 角色拥有的buff相关属性、方法
#region 角色拥有的buff相关属性、方法
public void AddMoveSpeed(int buffTime, double add = 2.0) => buffManeger.AddMoveSpeed(add, buffTime, newVal => public void AddMoveSpeed(int buffTime, double add = 2.0) => buffManeger.AddMoveSpeed(add, buffTime, newVal =>
{ MoveSpeed = newVal < GameData.characterMaxSpeed ? newVal : GameData.characterMaxSpeed; }, { MoveSpeed = newVal < GameData.characterMaxSpeed ? newVal : GameData.characterMaxSpeed; },
OrgMoveSpeed); OrgMoveSpeed);
@@ -387,7 +412,8 @@ namespace GameClass.GameObj
private Array buffTypeArray = Enum.GetValues(typeof(BuffType)); private Array buffTypeArray = Enum.GetValues(typeof(BuffType));
public Dictionary<BuffType, bool> Buff public Dictionary<BuffType, bool> Buff
{ {
get {
get
{
Dictionary<BuffType, bool> buff = new Dictionary<BuffType, bool>(); Dictionary<BuffType, bool> buff = new Dictionary<BuffType, bool>();
foreach (BuffType type in buffTypeArray) foreach (BuffType type in buffTypeArray)
{ {
@@ -420,7 +446,7 @@ namespace GameClass.GameObj
hp = MaxHp; hp = MaxHp;
} }
} }
#endregion
#endregion
public override void Reset() // 要加锁吗? public override void Reset() // 要加锁吗?
{ {
_ = AddDeathCount(); _ = AddDeathCount();

+ 18
- 10
logic/GameClass/GameObj/GameObj.cs View File

@@ -29,8 +29,9 @@ namespace GameClass.GameObj
public XY Position public XY Position
{ {
get => position; get => position;
protected
set {
protected
set
{
lock (gameObjLock) lock (gameObjLock)
{ {
position = value; position = value;
@@ -43,7 +44,8 @@ namespace GameClass.GameObj
public XY FacingDirection public XY FacingDirection
{ {
get => facingDirection; get => facingDirection;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
facingDirection = value; facingDirection = value;
} }
@@ -54,7 +56,8 @@ namespace GameClass.GameObj
public bool CanMove public bool CanMove
{ {
get => canMove; get => canMove;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
{ {
canMove = value; canMove = value;
@@ -66,7 +69,8 @@ namespace GameClass.GameObj
public bool IsMoving public bool IsMoving
{ {
get => isMoving; get => isMoving;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
{ {
isMoving = value; isMoving = value;
@@ -78,7 +82,8 @@ namespace GameClass.GameObj
public bool IsResetting public bool IsResetting
{ {
get => isResetting; get => isResetting;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
{ {
isResetting = value; isResetting = value;
@@ -92,7 +97,8 @@ namespace GameClass.GameObj
public PlaceType Place public PlaceType Place
{ {
get => place; get => place;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
{ {
place = value; place = value;
@@ -106,7 +112,8 @@ namespace GameClass.GameObj
public int MoveSpeed public int MoveSpeed
{ {
get => moveSpeed; get => moveSpeed;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
{ {
moveSpeed = value; moveSpeed = value;
@@ -120,8 +127,9 @@ namespace GameClass.GameObj
public int OrgMoveSpeed public int OrgMoveSpeed
{ {
get => orgMoveSpeed; get => orgMoveSpeed;
protected
set {
protected
set
{
orgMoveSpeed = value; orgMoveSpeed = value;
} }
} }


+ 2
- 1
logic/GameClass/GameObj/ObjOfCharacter.cs View File

@@ -12,7 +12,8 @@ namespace GameClass.GameObj
public ICharacter? Parent public ICharacter? Parent
{ {
get => parent; get => parent;
set {
set
{
lock (gameObjLock) lock (gameObjLock)
{ {
parent = value; parent = value;


+ 24
- 0
logic/GameClass/GameObj/PickedProp.cs View File

@@ -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;
}
}
}

+ 125
- 0
logic/GameClass/GameObj/Prop.cs View File

@@ -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;
}
}
/// <summary>
/// 增益道具
/// </summary>
public abstract class BuffProp : Prop
{
public BuffProp(XY initPos) :
base(initPos)
{
}
}
///// <summary>
///// 坑人地雷
///// </summary>
// public abstract class DebuffMine : Prop
//{
// public DebuffMine(XYPosition initPos) : base(initPos) { }
// }
#region 所有增益道具
/// <summary>
/// 增加速度
/// </summary>
public sealed class AddSpeed : BuffProp
{
public AddSpeed(XY initPos) :
base(initPos)
{
}
public override PropType GetPropType() => PropType.addSpeed;
}
/// <summary>
/// 复活甲
/// </summary>
public sealed class AddLIFE : BuffProp
{
public AddLIFE(XY initPos) :
base(initPos)
{
}
public override PropType GetPropType() => PropType.addLIFE;
}
/// <summary>
/// 护盾
/// </summary>
public sealed class Shield : BuffProp
{
public Shield(XY initPos) :
base(initPos)
{
}
public override PropType GetPropType() => PropType.Shield;
}
/// <summary>
/// 矛
/// </summary>
public sealed class Spear : BuffProp
{
public Spear(XY initPos) :
base(initPos)
{
}
public override PropType GetPropType() => PropType.Spear;
}
#endregion
// #region 所有坑人地雷
///// <summary>
///// 减速
///// </summary>
// public sealed class MinusSpeed : DebuffMine
//{
// public MinusSpeed(XYPosition initPos) : base(initPos) { }
// public override PropType GetPropType() => PropType.minusSpeed;
// }
///// <summary>
///// 减少攻击力
///// </summary>
// public sealed class MinusAP : DebuffMine
//{
// public MinusAP(XYPosition initPos) : base(initPos) { }
// public override PropType GetPropType() => PropType.minusAP;
// }
///// <summary>
///// 增加冷却
///// </summary>
// public sealed class AddCD : DebuffMine
//{
// public AddCD(XYPosition initPos) : base(initPos) { }
// public override PropType GetPropType() => PropType.addCD;
// }
// #endregion
}

+ 2
- 1
logic/GameClass/GameObj/Team.cs View File

@@ -13,7 +13,8 @@ namespace GameClass.GameObj
private readonly List<Character> playerList; private readonly List<Character> playerList;
public int Score public int Score
{ {
get {
get
{
int score = 0; int score = 0;
foreach (var player in playerList) foreach (var player in playerList)
score += player.Score; score += player.Score;


+ 219
- 0
logic/GameClass/Skill/CommonSkill.cs View File

@@ -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<int>
(
() => !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<int>
(
() => 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;
}
}
}
}
}

+ 23
- 0
logic/GameClass/Skill/ISkill.cs View File

@@ -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; }
}
}

+ 152
- 0
logic/GameClass/Skill/PassiveSkill.cs View File

@@ -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<int>
(
() => 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<int>
(
() => 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)
{

}
}
}

+ 82
- 81
logic/GameEngine/MoveEngine.cs View File

@@ -66,65 +66,28 @@ namespace GameEngine
{ {
if (!obj.IsAvailable && gameTimer.IsGaming) //不能动就直接return,后面都是能动的情况 if (!obj.IsAvailable && gameTimer.IsGaming) //不能动就直接return,后面都是能动的情况
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<int>(
() => 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<int>(
() => 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))) switch (OnCollision(obj, collisionObj, new XY(direction, moveVecLength)))
{ {
case AfterCollision.ContinueCheck: case AfterCollision.ContinueCheck:
@@ -133,43 +96,81 @@ namespace GameEngine
case AfterCollision.Destroyed: case AfterCollision.Destroyed:
Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game.");
isDestroyed = true; isDestroyed = true;
break;
return false;
case AfterCollision.MoveMax: case AfterCollision.MoveMax:
MoveMax(obj, new XY(direction, moveVecLength)); MoveMax(obj, new XY(direction, moveVecLength));
moveVecLength = 0; moveVecLength = 0;
break; 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 #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 #endif
}
}.Start();
} }
}.Start();
}
).Start(); ).Start();
}
} }
} }
}

+ 2
- 1
logic/Gaming/MoveManager.cs View File

@@ -54,7 +54,8 @@ namespace Gaming
// ActivateMine((Character)obj, (Mine)collisionObj); // ActivateMine((Character)obj, (Mine)collisionObj);
// return MoveEngine.AfterCollision.ContinueCheck; // return MoveEngine.AfterCollision.ContinueCheck;
//} //}
return MoveEngine.AfterCollision.MoveMax; },
return MoveEngine.AfterCollision.MoveMax;
},
EndMove: obj => EndMove: obj =>
{ {
// Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); // Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64);


+ 6
- 6
logic/Preparation/GameData/GameData.cs View File

@@ -4,7 +4,7 @@ namespace Preparation.GameData
{ {
public static class GameData public static class GameData
{ {
#region 基本常数与常方法
#region 基本常数与常方法
public const int numOfPosGridPerCell = 1000; // 每格的【坐标单位】数 public const int numOfPosGridPerCell = 1000; // 每格的【坐标单位】数
public const int numOfStepPerSecond = 20; // 每秒行走的步数 public const int numOfStepPerSecond = 20; // 每秒行走的步数
public const int lengthOfMap = 50000; // 地图长度 public const int lengthOfMap = 50000; // 地图长度
@@ -35,8 +35,8 @@ namespace Preparation.GameData
} }


public static int numOfBirthPoint = 5; public static int numOfBirthPoint = 5;
#endregion
#region 角色相关
#endregion
#region 角色相关
/// <summary> /// <summary>
/// 玩家相关 /// 玩家相关
/// </summary> /// </summary>
@@ -71,9 +71,9 @@ namespace Preparation.GameData
public const long GemProduceTime = 10000; public const long GemProduceTime = 10000;
public const long PropProduceTime = 10000; public const long PropProduceTime = 10000;
public const int PropDuration = 10000; public const int PropDuration = 10000;
#endregion
#region 游戏帧相关
#endregion
#region 游戏帧相关
public const long checkInterval = 50; // 检查位置标志、补充子弹的帧时长 public const long checkInterval = 50; // 检查位置标志、补充子弹的帧时长
#endregion
#endregion
} }
} }

+ 1
- 1
logic/Preparation/Utility/XY.cs View File

@@ -21,7 +21,7 @@ namespace Preparation.Utility
{ {
return "(" + x.ToString() + "," + y.ToString() + ")"; 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); return (v1.x * v2.x) + (v1.y * v2.y);
} }


+ 6
- 26
logic/logic.sln View File

@@ -5,23 +5,17 @@ VisualStudioVersion = 17.0.32014.148
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{D033B809-2FB7-4340-B8B4-DDA30D6CA6FF}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{D033B809-2FB7-4340-B8B4-DDA30D6CA6FF}"
EndProject EndProject
<<<<<<< HEAD
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameClass", "GameClass\GameClass.csproj", "{39D838F6-2B84-49E1-9CAF-1DFF22960B5D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameClass", "GameClass\GameClass.csproj", "{39D838F6-2B84-49E1-9CAF-1DFF22960B5D}"
EndProject 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}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gaming", "Gaming\Gaming.csproj", "{BE9E3584-93C0-4E0F-8DAC-967CF4792709}"
EndProject 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}" 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}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClientTest", "ClientTest\ClientTest.csproj", "{F3C98717-DD4F-45B8-B0F0-C217E7E2B5D4}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Protos", "..\dependency\proto\Protos.csproj", "{9ADA1EF8-DF2F-4C2E-9DE2-BC94DF89B44D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Protos", "..\dependency\proto\Protos.csproj", "{9ADA1EF8-DF2F-4C2E-9DE2-BC94DF89B44D}"
>>>>>>> 9f4b5ac18b94330559cd560708f4100ae913260e
EndProject 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 EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution 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}.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.ActiveCfg = Release|Any CPU
{D033B809-2FB7-4340-B8B4-DDA30D6CA6FF}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
{39D838F6-2B84-49E1-9CAF-1DFF22960B5D}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
{39D838F6-2B84-49E1-9CAF-1DFF22960B5D}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
{BE9E3584-93C0-4E0F-8DAC-967CF4792709}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
{BE9E3584-93C0-4E0F-8DAC-967CF4792709}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
{E3DC4A37-8A83-40CC-AE47-68E70064C9DB}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
{E3DC4A37-8A83-40CC-AE47-68E70064C9DB}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
{F3C98717-DD4F-45B8-B0F0-C217E7E2B5D4}.Debug|Any CPU.Build.0 = 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 {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}.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.ActiveCfg = Release|Any CPU
{9ADA1EF8-DF2F-4C2E-9DE2-BC94DF89B44D}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE


Loading…
Cancel
Save