计时器似乎在命令行战斗模拟器中发射两次

时间:2014-06-16 19:24:42

标签: c# .net linq timer

我尝试使用System.Timers.Timer对象创建一个实现攻击和接收来自攻击者的攻击的基类来触发攻击事件,目标通过减少其HP来响应,并发出信号。被毁了。

奇怪的是,计时器似乎连续两次触发AttackTarget经过的处理程序,但只有当它会导致目标被销毁时才会出现。

我做的测试对于前4次攻击看起来很好,然后紧接着(没有1000ms延迟),第5次攻击以某种方式发生,并且破坏的消息出现,即使目标在第4次攻击后仍然有1马力

我在AttackTarget方法上设置了一个断点,我也可以从输出中看到,AttackTarget事件只为野蛮人发射4次,这应该让目标保持1马力,但目标似乎响应TakeDamage 5次,报告被破坏。

我可能能够减少重现问题所需的代码,但是如果您想要测试它并试图找出我和#的话,它应该很容易将代码粘贴到一个项目中。 39;我做错了。

样本输出

Barbarian attacking at 1005 time elapsed
Goblin attacking at 1006 time elapsed
Goblin took 8 damage from Barbarian. 25 hp remaining.
Barbarian took 11 damage from Goblin. 45 hp remaining.
Barbarian attacking at 2000 time elapsed
Goblin took 8 damage from Barbarian. 17 hp remaining.
Goblin attacking at 2000 time elapsed
Barbarian took 11 damage from Goblin. 34 hp remaining.
Barbarian attacking at 3000 time elapsed
Goblin took 8 damage from Barbarian. 9 hp remaining.
Goblin attacking at 3001 time elapsed
Barbarian took 11 damage from Goblin. 23 hp remaining.
Barbarian attacking at 4001 time elapsed
Goblin took 8 damage from Barbarian. 1 hp remaining.
Goblin attacking at 4001 time elapsed
Barbarian took 11 damage from Goblin. 12 hp remaining.
Barbarian did 8 damage to Goblin and destroyed it!
Goblin destroyed at 4003 time elapsed

我的测试程序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ClashOfClans.Units.Troops;

namespace TestClashOfClans
{
    public class Program
    {
        public static void Main()
        {
            var b1 = new Goblin(1);
            var a1 = new Goblin(1);
            b1.EngageTarget(a1);
            a1.EngageTarget(b1);
            Console.ReadLine();
        }
    }
}

这3个文件位于类库项目中

抽象TroopBase类

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Timers;

namespace ClashOfClans.Units.Troops
{
    public abstract class TroopBase : IAttackable
    {
        public int HP { get; private set; }
        public int Damage { get; private set; }
        public int CostToCreate { get; private set; }
        public Stopwatch TimeAttacking = new Stopwatch();

        public abstract int MoveSpeed { get; }
        public abstract int AttackSpeedMS { get; }
        public abstract double AttackRangeTiles { get; }
        public abstract string Name { get; }

        public int Level { get; set; }

        protected static Dictionary<int, StatStick> LevelStats;

        protected void ApplyStatStick(StatStick stick)
        {
            this.HP = stick.HP;
            this.Damage = stick.Damage;
            this.CostToCreate = stick.Cost;
        }

        protected TroopBase(int level)
        {
            ApplyStatStick(LevelStats[level]);
            AttackTimer = new Timer(this.AttackSpeedMS);
            AttackTimer.Elapsed += AttackTarget;
            this.Level = level;
        }

        public IAttackable Target;

        protected Timer AttackTimer { get; private set; }

        public void EngageTarget(IAttackable target)
        {
            this.Target = target;
            AttackTimer.Start();
            target.Destroyed += TargetDestroyed;
            TimeAttacking.Start();
        }

        protected void AttackTarget(object sender, EventArgs e)
        {
            Target.TakeDamage(this, new AttackEventArgs(this.Damage));
            Console.WriteLine("{1} attacking at {0} time elapsed", TimeAttacking.ElapsedMilliseconds, this.Name);
        }

        public void TakeDamage(object sender, AttackEventArgs e)
        {
            Console.WriteLine("{0} took {1} damage from {2}. {3} hp remaining.",
                this.Name, e.Damage, ((TroopBase)sender).Name, this.HP);
            this.HP -= e.Damage;
            if (HP <= 0)
            {
                OnDestroyed();
            }
        }

        public event Delegates.DestroyedDelegate Destroyed;

        public void OnDestroyed()
        {
            if (Destroyed != null)
            {
                Destroyed(EventArgs.Empty);
            }
            this.AttackTimer.Stop();
            Console.WriteLine("{0} destroyed at {1} time elapsed", this.Name, this.TimeAttacking.ElapsedMilliseconds);
        }

        public void TargetDestroyed(EventArgs e)
        {
            this.AttackTimer.Stop();
            Console.WriteLine("{0} did {1} damage to {2} and destroyed it!",
                this.Name, this.Damage, (Target as TroopBase).Name);
        }
    }

    public class AttackEventArgs : EventArgs
    {
        public int Damage { get; set; }

        public AttackEventArgs(int damage)
        {
            this.Damage = damage;
        }
    }
    public delegate void AttackDelegate(object sender, AttackEventArgs e);

    public class StatStick
    {
        public int HP { get; set; }
        public int Damage { get; set; }
        public int Cost { get; set; }
    }
}

地精

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClashOfClans.Units.Troops
{
    public class Goblin : TroopBase
    {
        public Goblin(int level) : base(level) { }

        public override int MoveSpeed
        {
            get { return 32; }
        }
        public override double AttackRangeTiles
        {
            get { return 0.4D; }
        }
        public override int AttackSpeedMS
        {
            get { return 1000; }
        }
        public override string Name
        {
            get { return "Goblin"; }
        }

        static Goblin()
        {
            LevelStats = new Dictionary<int, StatStick>()
            {
                {1, new StatStick{ HP=25, Damage=11, Cost=25}},
                {2, new StatStick{ HP=30, Damage=14, Cost=40}},
                {3, new StatStick{ HP=36, Damage=19, Cost=60}},
                {4, new StatStick{ HP=43, Damage=24, Cost=80}},
                {5, new StatStick{ HP=52, Damage=32, Cost=100}},
                {6, new StatStick{ HP=68, Damage=42, Cost=150}},
            };
        }
    }
}

IAttackable

using ClashOfClans.Units.Troops;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClashOfClans.Units
{
    public class Delegates
    {
        public delegate void DestroyedDelegate(EventArgs e);
    }
    public interface IAttackable
    {
        void TakeDamage(object sender, AttackEventArgs e);
        event Delegates.DestroyedDelegate Destroyed;
    }
}

1 个答案:

答案 0 :(得分:2)

您的TakeDamage方法就是问题所在。在计算损坏之前,您需要打印this.HP。第一次攻击不会在1 HP左侧结果,当1 HP离开时就会发生。

  1. Goblin剩下1 HP。野蛮人的攻击。<​​/ li>
  2. 打印出攻击详情(包括当前1 HP)。
  3. 计算新HP(-7)。
  4. 新HP小于0.请致电OnDestroyed