Browse Source

Merge pull request #646 from shangfengh/new

refactor:  add the AtomicInt and AtomicBool
dev
Changli Tang GitHub 2 years ago
parent
commit
ac08fc3e06
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 91 additions and 104 deletions
  1. +5
    -5
      logic/GameClass/GameObj/Bullet/Bullet.Ghost.cs
  2. +3
    -12
      logic/GameClass/GameObj/Bullet/Bullet.cs
  3. +2
    -2
      logic/GameClass/GameObj/Character/Character.Skill.cs
  4. +3
    -3
      logic/GameClass/GameObj/Character/Character.cs
  5. +2
    -11
      logic/GameClass/GameObj/GameObj.cs
  6. +0
    -2
      logic/GameClass/GameObj/Immovable.cs
  7. +4
    -32
      logic/GameClass/GameObj/Moveable.cs
  8. +2
    -2
      logic/GameClass/GameObj/Prop/Gadget.cs
  9. +2
    -2
      logic/GameClass/GameObj/Prop/Item.cs
  10. +4
    -4
      logic/GameEngine/MoveEngine.cs
  11. +2
    -2
      logic/Gaming/ActionManager.cs
  12. +4
    -8
      logic/Gaming/AttackManager.cs
  13. +0
    -10
      logic/Gaming/CharacterManager.cs
  14. +1
    -1
      logic/Gaming/Game.cs
  15. +1
    -1
      logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs
  16. +1
    -1
      logic/Preparation/Interface/IGameObj.cs
  17. +3
    -4
      logic/Preparation/Interface/IMoveable.cs
  18. +51
    -0
      logic/Preparation/Utility/LockedValue.cs
  19. +1
    -2
      logic/Preparation/Utility/XY.cs

+ 5
- 5
logic/GameClass/GameObj/Bullet/Bullet.Ghost.cs View File

@@ -8,7 +8,7 @@ namespace GameClass.GameObj
public CommonAttackOfGhost(Character player, XY pos, int radius = GameData.bulletRadius) :
base(player, radius, pos)
{
ap = GameData.basicApOfGhost;
AP.Set(GameData.basicApOfGhost);
}
public override double BulletBombRange => 0;
public override double AttackDistance => GameData.basicAttackShortRange;
@@ -45,7 +45,7 @@ namespace GameClass.GameObj
public Strike(Character player, XY pos, int radius = GameData.bulletRadius) :
base(player, radius, pos)
{
ap = GameData.basicApOfGhost * 16 / 15;
AP.Set(GameData.basicApOfGhost * 16 / 15);
}
public override double BulletBombRange => 0;
public override double AttackDistance => GameData.basicAttackShortRange * 20 / 22;
@@ -83,7 +83,7 @@ namespace GameClass.GameObj
public FlyingKnife(Character player, XY pos, int radius = GameData.bulletRadius) :
base(player, radius, pos)
{
ap = GameData.basicApOfGhost * 4 / 5;
AP.Set(GameData.basicApOfGhost * 4 / 5);
}
public override double BulletBombRange => 0;
public override double AttackDistance => GameData.basicRemoteAttackRange * 13;
@@ -123,7 +123,7 @@ namespace GameClass.GameObj
{
public BombBomb(Character player, XY pos, int radius = GameData.bulletRadius) : base(player, radius, pos)
{
ap = (int)(GameData.basicApOfGhost * 6.0 / 5);
AP.Set((int)(GameData.basicApOfGhost * 6.0 / 5));
}
public override double BulletBombRange => GameData.basicBulletBombRange;
public override double AttackDistance => GameData.basicAttackShortRange;
@@ -163,7 +163,7 @@ namespace GameClass.GameObj
{
public JumpyDumpty(Character player, XY pos, int radius = GameData.bulletRadius) : base(player, radius, pos)
{
ap = (int)(GameData.basicApOfGhost * 0.6);
AP.Set((int)(GameData.basicApOfGhost * 0.6));
}
public override double BulletBombRange => GameData.basicBulletBombRange / 2;
public override double AttackDistance => GameData.basicAttackShortRange * 18 / 22;


+ 3
- 12
logic/GameClass/GameObj/Bullet/Bullet.cs View File

@@ -11,16 +11,7 @@ namespace GameClass.GameObj
/// </summary>
public abstract double BulletBombRange { get; }
public abstract double AttackDistance { get; }
protected int ap;
public int AP
{
get => Interlocked.CompareExchange(ref ap, 0, 0);
}
public void AddAP(int addAp)
{
Interlocked.Add(ref ap, addAp);
}

public AtomicInt AP { get; }
public abstract int Speed { get; }
public abstract bool IsRemoteAttack { get; }
public abstract int CastTime { get; }
@@ -52,8 +43,8 @@ namespace GameClass.GameObj
public Bullet(Character player, int radius, XY Position) :
base(Position, radius, GameObjType.Bullet)
{
this.ReSetCanMove(true);
this.MoveSpeed = this.Speed;
this.CanMove.Set(true);
this.MoveSpeed.Set(this.Speed);
this.hasSpear = player.TryUseSpear();
this.Parent = player;
}


+ 2
- 2
logic/GameClass/GameObj/Character/Character.Skill.cs View File

@@ -31,12 +31,12 @@ namespace GameClass.GameObj
protected Character(XY initPos, int initRadius, CharacterType characterType) :
base(initPos, initRadius, GameObjType.Character)
{
this.ReSetCanMove(true);
this.CanMove.Set(true);
this.score = 0;
this.buffManager = new BuffManager();
this.occupation = OccupationFactory.FindIOccupation(characterType);
this.MaxHp = this.hp = Occupation.MaxHp;
this.MoveSpeed = this.orgMoveSpeed = Occupation.MoveSpeed;
this.MoveSpeed.Set(this.orgMoveSpeed = Occupation.MoveSpeed);
this.BulletOfPlayer = this.OriBulletOfPlayer = Occupation.InitBullet;
this.concealment = Occupation.Concealment;
this.alertnessRadius = Occupation.AlertnessRadius;


+ 3
- 3
logic/GameClass/GameObj/Character/Character.cs View File

@@ -107,7 +107,7 @@ namespace GameClass.GameObj
);
Bullet? bullet = BulletFactory.GetBullet(this, res, this.bulletOfPlayer);
if (bullet == null) return null;
if (TryAddAp()) bullet.AddAP(GameData.ApPropAdd);
if (TryAddAp()) bullet.AP.Add(GameData.ApPropAdd);
FacingDirection = new(angle, bullet.AttackDistance);
return bullet;
}
@@ -647,7 +647,7 @@ namespace GameClass.GameObj
{
if (SetPlayerState(RunningStateType.RunningForcibly, playerStateType) == -1) return false;
TryToRemove();
ReSetCanMove(false);
CanMove.Set(false);
position = GameData.PosWhoDie;
}
return true;
@@ -802,7 +802,7 @@ namespace GameClass.GameObj
}

public void AddMoveSpeed(int buffTime, double add = 1.0) => buffManager.AddMoveSpeed(add, buffTime, newVal =>
{ MoveSpeed = newVal < GameData.characterMaxSpeed ? newVal : GameData.characterMaxSpeed; },
{ MoveSpeed.Set(newVal < GameData.characterMaxSpeed ? newVal : GameData.characterMaxSpeed); },
OrgMoveSpeed);
public bool HasFasterSpeed => buffManager.HasFasterSpeed;



+ 2
- 11
logic/GameClass/GameObj/GameObj.cs View File

@@ -26,23 +26,14 @@ namespace GameClass.GameObj
protected XY position;
public abstract XY Position { get; }

public abstract bool CanMove { get; }

public abstract bool IsRigid { get; }

public abstract ShapeType Shape { get; }

protected int isRemoved = 0;
public bool IsRemoved
{
get
{
return (Interlocked.CompareExchange(ref isRemoved, 0, 0) == 1);
}
}
public AtomicBool IsRemoved { get; } = new AtomicBool(false);
public virtual bool TryToRemove()
{
return Interlocked.Exchange(ref isRemoved, 1) == 0;
return IsRemoved.TrySet(true);
}

public int Radius { get; }


+ 0
- 2
logic/GameClass/GameObj/Immovable.cs View File

@@ -7,8 +7,6 @@ namespace GameClass.GameObj

public override XY Position => position;

public override bool CanMove => false;

public Immovable(XY initPos, int initRadius, GameObjType initType) : base(initPos, initRadius, initType)
{
}


+ 4
- 32
logic/GameClass/GameObj/Moveable.cs View File

@@ -67,12 +67,7 @@ namespace GameClass.GameObj
}
}

private int isMoving = 0;
public bool IsMoving
{
get => (Interlocked.CompareExchange(ref isMoving, 0, 0) == 1);
set => Interlocked.Exchange(ref isMoving, value ? 1 : 0);
}
public AtomicBool IsMoving { get; } = new(false);

// 移动,改变坐标
public long MovingSetPos(XY moveVec, long stateNo)
@@ -99,37 +94,14 @@ namespace GameClass.GameObj
}
}

private int canMove;
public override bool CanMove
{
get => (Interlocked.CompareExchange(ref canMove, 0, 0) == 1);
}
public AtomicBool CanMove { get; }

public void ReSetCanMove(bool value)
{
Interlocked.Exchange(ref canMove, (value ? 1 : 0));
}
public bool IsAvailableForMove => !IsMoving && CanMove && !IsRemoved; // 是否能接收移动指令

public bool IsAvailableForMove // 是否能接收移动指令
{
get
{
lock (actionLock)
{
return !IsMoving && CanMove && !IsRemoved;
}
}
}

protected int moveSpeed;
/// <summary>
/// 移动速度
/// </summary>
public int MoveSpeed
{
get => Interlocked.CompareExchange(ref moveSpeed, 0, 0);
set => Interlocked.Exchange(ref moveSpeed, value);
}
public AtomicInt MoveSpeed { get; }
/// <summary>
/// 原初移动速度
/// </summary>


+ 2
- 2
logic/GameClass/GameObj/Prop/Gadget.cs View File

@@ -24,8 +24,8 @@ namespace GameClass.GameObj
public Gadget(XY initPos, int radius = GameData.propRadius) :
base(initPos, radius, GameObjType.Gadget)
{
this.ReSetCanMove(false);
this.MoveSpeed = GameData.propMoveSpeed;
this.CanMove.Set(false);
this.MoveSpeed.Set(GameData.propMoveSpeed);
}
}
public abstract class Tool : Gadget


+ 2
- 2
logic/GameClass/GameObj/Prop/Item.cs View File

@@ -17,8 +17,8 @@ namespace GameClass.GameObj
public Item(XY initPos, int radius = GameData.propRadius) :
base(initPos, radius, GameObjType.Item)
{
this.ReSetCanMove(false);
this.MoveSpeed = 0;
this.CanMove.Set(false);
this.MoveSpeed.Set(0);
}
}



+ 4
- 4
logic/GameEngine/MoveEngine.cs View File

@@ -102,7 +102,7 @@ namespace GameEngine
lock (obj.ActionLock)
{
if (!obj.IsAvailableForMove) { EndMove(obj); return; }
obj.IsMoving = true;
obj.IsMoving.Set(true);
}

new Thread
@@ -139,7 +139,7 @@ namespace GameEngine

if (isEnded)
{
obj.IsMoving = false;
obj.IsMoving.Set(false);
EndMove(obj);
return;
}
@@ -184,7 +184,7 @@ namespace GameEngine
}
if (isEnded)
{
obj.IsMoving = false;
obj.IsMoving.Set(false);
EndMove(obj);
return;
}
@@ -224,7 +224,7 @@ namespace GameEngine
}
} while (flag);
}
obj.IsMoving = false; // 结束移动
obj.IsMoving.Set(false); // 结束移动
EndMove(obj);
}
}


+ 2
- 2
logic/Gaming/ActionManager.cs View File

@@ -450,12 +450,12 @@ namespace Gaming
player.ReSetPos(windowToPlayer + windowForClimb.Position);
}

player.MoveSpeed = player.SpeedOfClimbingThroughWindows;
player.MoveSpeed.Set(player.SpeedOfClimbingThroughWindows);
moveEngine.MoveObj(player, (int)(GameData.numOfPosGridPerCell * 3 * 1000 / player.MoveSpeed / 2), (-1 * windowToPlayer).Angle(), stateNum);

Thread.Sleep((int)(GameData.numOfPosGridPerCell * 3 * 1000 / player.MoveSpeed / 2));

player.MoveSpeed = player.ReCalculateBuff(BuffType.AddSpeed, player.OrgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed);
player.MoveSpeed.Set(player.ReCalculateBuff(BuffType.AddSpeed, player.OrgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed));

lock (player.ActionLock)
{


+ 4
- 8
logic/Gaming/AttackManager.cs View File

@@ -33,7 +33,7 @@ namespace Gaming
Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64);
if (obj.CanMove && ((Bullet)obj).TypeOfBullet != BulletType.JumpyDumpty)
BulletBomb((Bullet)obj, null);
obj.ReSetCanMove(false);
obj.CanMove.Set(false);
}
);
this.characterManager = characterManager;
@@ -89,7 +89,7 @@ namespace Gaming
{
if (gameMap.Remove(bullet))
{
bullet.ReSetCanMove(false);
bullet.CanMove.Set(false);
if (bullet.BulletBombRange > 0)
{
BombedBullet bombedBullet = new(bullet);
@@ -255,16 +255,12 @@ namespace Gaming
}
if (bullet != null)
{
#if DEBUG
Console.WriteLine($"playerID:{player.ID} successfully attacked!");
#endif
Debugger.Output($"playerID:{player.ID} successfully attacked!");
return true;
}
else
{
#if DEBUG
Console.WriteLine($"playerID:{player.ID} has no bullets so that he can't attack!");
#endif
Debugger.Output($"playerID:{player.ID} has no bullets so that he can't attack!");
return false;
}
}


+ 0
- 10
logic/Gaming/CharacterManager.cs View File

@@ -306,9 +306,7 @@ namespace Gaming
/// <returns>人物在受到攻击后死了吗</returns>
public void BeAttacked(Student student, Bullet bullet)
{
#if DEBUG
Debugger.Output(student, "is being shot!");
#endif
if (!bullet.Parent!.IsGhost()) return;

if (student.CharacterType == CharacterType.StraightAStudent)
@@ -319,17 +317,13 @@ namespace Gaming

if (student.NoHp()) return; // 原来已经死了

#if DEBUG
Debugger.Output(bullet, " 's AP is " + bullet.AP.ToString());
#endif
if (student.TryUseShield())
{
if (bullet.HasSpear)
{
long subHp = student.SubHp(bullet.AP);
#if DEBUG
Debugger.Output(this, "is being shot! Now his hp is" + student.HP.ToString());
#endif
bullet.Parent.AddScore(GameData.TrickerScoreAttackStudent(subHp) + GameData.ScorePropUseSpear);
bullet.Parent.AddHP((long)bullet.Parent.Vampire * subHp);
}
@@ -341,16 +335,12 @@ namespace Gaming
if (bullet.HasSpear)
{
subHp = student.SubHp(bullet.AP + GameData.ApSpearAdd);
#if DEBUG
Debugger.Output(this, "is being shot with Spear! Now his hp is" + student.HP.ToString());
#endif
}
else
{
subHp = student.SubHp(bullet.AP);
#if DEBUG
Debugger.Output(this, "is being shot! Now his hp is" + student.HP.ToString());
#endif
}
bullet.Parent.AddScore(GameData.TrickerScoreAttackStudent(subHp));
if (student.CharacterType == CharacterType.Teacher)


+ 1
- 1
logic/Gaming/Game.cs View File

@@ -326,7 +326,7 @@ namespace Gaming
{
foreach (Character player in gameMap.GameObjDict[GameObjType.Character])
{
player.ReSetCanMove(false);
player.CanMove.Set(false);
}
}
gameMap.GameObjDict[keyValuePair.Key].Clear();


+ 1
- 1
logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs View File

@@ -196,7 +196,7 @@ namespace Gaming
}
if (homingMissile != null)
{
homingMissile.ReSetCanMove(true);
homingMissile.CanMove.Set(true);
attackManager.moveEngine.MoveObj(homingMissile, GameData.checkIntervalWhenSparksNSplash - 1, (whoAttacked.Position - homingMissile.Position).Angle(), ++homingMissile.StateNum);
}
},


+ 1
- 1
logic/Preparation/Interface/IGameObj.cs View File

@@ -8,8 +8,8 @@ namespace Preparation.Interface
public long ID { get; }
public XY Position { get; } // if Square, Pos equals the center
public bool IsRigid { get; }
public AtomicBool IsRemoved { get; }
public ShapeType Shape { get; }
public bool CanMove { get; }
public int Radius { get; } // if Square, Radius equals half length of one side
public bool IgnoreCollideExecutor(IGameObj targetObj); // 忽略碰撞,在具体类中实现
}


+ 3
- 4
logic/Preparation/Interface/IMoveable.cs View File

@@ -8,14 +8,13 @@ namespace Preparation.Interface
{
public XY FacingDirection { get; set; }
object ActionLock { get; }
public int MoveSpeed { get; }
public bool IsMoving { get; set; }
public bool IsRemoved { get; }
public AtomicInt MoveSpeed { get; }
public AtomicBool CanMove { get; }
public AtomicBool IsMoving { get; }
public bool IsAvailableForMove { get; }
public long StateNum { get; }
public Semaphore ThreadNum { get; }
public long MovingSetPos(XY moveVec, long stateNum);
public void ReSetCanMove(bool value);
public bool WillCollideWith(IGameObj? targetObj, XY nextPos) // 检查下一位置是否会和目标物碰撞
{
if (targetObj == null)


+ 51
- 0
logic/Preparation/Utility/LockedValue.cs View File

@@ -0,0 +1,51 @@
using System.Threading;

namespace Preparation.Utility
{
//理论上结构体最好不可变,这里采用了可变结构。
public struct AtomicInt
{
private int v;
public AtomicInt(int x)
{
v = x;
}
public override string ToString() => Interlocked.CompareExchange(ref v, -1, -1).ToString();
public int Get() => Interlocked.CompareExchange(ref v, -1, -1);
public static implicit operator int(AtomicInt aint) => Interlocked.CompareExchange(ref aint.v, -1, -1);
public int Set(int value) => Interlocked.Exchange(ref v, value);

public int Add(int x) => Interlocked.Add(ref v, x);
public int Sub(int x) => Interlocked.Add(ref v, -x);
public int Inc() => Interlocked.Increment(ref v);
public int Dec() => Interlocked.Decrement(ref v);

public void CompareExchange(int b, int c) => Interlocked.CompareExchange(ref v, b, c);
/// <returns>返回操作前的值</returns>
public int CompareExReturnOri(int b, int c) => Interlocked.CompareExchange(ref v, b, c);
}
public struct AtomicBool
{
private int v;//v==0为false,v!=0(v==1或v==-1)为true
public AtomicBool(bool x)
{
v = x ? 1 : 0;
}
public override string ToString() => (Interlocked.CompareExchange(ref v, -1, -1) == 0) ? "false" : "true";
public bool Get() => (Interlocked.CompareExchange(ref v, -1, -1) != 0);
public static implicit operator bool(AtomicBool abool) => (Interlocked.CompareExchange(ref abool.v, -1, -1) != 0);

public bool Set(bool value) => (Interlocked.Exchange(ref v, value ? 1 : 0) != 0);

/// <returns>赋值前的值是否与将赋予的值不相同</returns>
public bool TrySet(bool value)
{
int ori = Interlocked.CompareExchange(ref v, value ? 1 : 0, value ? 1 : 0);
return value ? (ori == 0) : (ori != 0);
}

public bool Invert() => Interlocked.Add(ref v, -1) != 0;
public bool And(bool x) => Interlocked.And(ref v, x ? 1 : 0) != 0;
public bool Or(bool x) => Interlocked.Or(ref v, x ? 1 : 0) != 0;
}
}

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

@@ -2,7 +2,6 @@

namespace Preparation.Utility
{

public struct XY
{
public int x;
@@ -89,7 +88,7 @@ namespace Preparation.Utility
return Math.Atan2(y, x);
}

public override bool Equals(object? obj) => obj is null || obj is XY ? false : this == (XY)obj;
public override bool Equals(object? obj) => obj is not null && obj is XY xy && this == xy;

public override int GetHashCode()
{


Loading…
Cancel
Save