-2

我想对如何实现基于刻度的系统提出一些想法。

玩家或非玩家执行的每个动作都有初始执行时间和冷却时间。一旦一个生物的冷却时间过去了,它就可以选择一个新的动作。如果玩家必须选择一个动作,游戏就会“暂停”。

例子:

1:玩家重击(50 刻执行,50 刻冷却)

2:游戏持续 50 刻。

3:NPC可以设置动作。

4:玩家挥动并冷却 50 刻。

5:NPC可以设置动作。

6:为玩家暂停游戏。

我目前拥有的工作但效率不高。我有一个类,每个动作都是静态方法。这些方法输出一个包含所有数据的结构。这将被传递给单个生物的动作提示。

如果玩家采取了行动,每个更新循环都会调用 cue 并开始倒计时攻击时间。一旦攻击被解决,我再次调用动作类中的静态方法。我开始倒计时冷却时间。

所以我应该拥有的可能是一个包含所有操作的列表,并对该列表进行排序,从而跳过不必要的时间/滴答声,然后直接进入下一个操作。但是会有不同类型的动作,比如移动、攻击、能力,我无法很好地实现这一点。

当一个生物进行基本攻击时,这被称为(攻击是生物自己的实例攻击结构)

attack = Actions.BasicAttack(this, player, rand);

这就是 Actions 类的样子。

public struct Attack
    {
        public int Damage;
        public string Type;
        public int Time;
        public int Cooldown;
        public Creature target;
        public bool solved;
    }




    public static Attack BasicAttack(Creature attacker, Creature defender, Random rand)
    {
        Attack attack = new Attack();

        attack.Damage = rand.Next(attacker.MinBaseDmg, attacker.MaxBaseDmg + 1);
        attack.Type = "Melee";
        attack.Time = 50;
        attack.Cooldown = 30;
        attack.target = defender;
        attack.solved = false;

        return attack;
    }

当玩家有动作提示时,它会在每个生物的更新方法中调用。如果玩家没有动作提示,Tick = 0,当玩家有动作提示时,Tick = 1。

protected void ActionCue(int tick)
    {
        if (attack.target != null)
        {
            if (attack.Time > 1)
            {
                Console.WriteLine(attack.Time);
                attack.Time -= tick;
                this.free = false;
            }
            else if (!attack.solved)
            {
                Actions.SolveAttack(attack.Damage, attack.Type, attack.target);
                attack.solved = true;
            }
            else if (attack.solved && attack.Cooldown > 1)
            {
                //Console.WriteLine(attack.Cooldown);
                attack.Cooldown -= tick;
            }
            else
                free = true;
        }
    }
4

2 回答 2

1

考虑这样的事情(我将使用伪代码 - 它远未优化等,但它可能足够快,或者让你开始优化你想要做的事情)

class CombatEventList
{
   public static AddEvent(CombatEvent event, int ticksTillHappens)   
}

virtual class CombatEvent
{
    public virtual void CombatAction()
}

class PlayerActionChoice : ComabtEvent
{
   public void CombatAction
   {
       var playerAction = GetUserDecision();//returns i.e CombatEvent PlayerMeeleAttack
       CombatEventList.AddEvent(playerAction, 0);
   }
}

class PlayerMeeleAttack : CombatEvent
{
   int cooldownInTicks = 50;

   public void CombatAction
   {
       MakeAttack()//damages the moster etc - all the stuff the attack is supposed to do
       var nextEvent = new PlayerActionChoice();
       CombatEventList.AddEvent(nextEvent, cooldownInTicks);
   }
}

那么,这是如何工作的呢?

我们得到了一个事件列表。

该列表检查所有现在应该发生的事件,并执行它们的 CombatAction。

在他们的 CombatAction 中,事件将新事件添加到列表中。例如,PlayerMeeleAttack 事件在适当的冷却时间后设置 PlayerActionChoice 事件,以便他稍后可以采取另一个行动。

在所有当前的 CombatEvents 都被解决并将它们自己的 CombatEvents 添加到列表后,列表会检查下一个 Event(最低延迟)

该列表休眠指定数量的滴答声(下一个事件的延迟)。一旦完成睡眠,它将所有事件的冷却时间降低适当的量,并处理所有当前事件(那些刚刚达到 0 延迟的事件)

这是一个循环

该列表以 CombatStartEvent 开头,这将立即发生(延迟 0)。它在 CombatAction 方法中设置 PlayerActionChoice 和 MonsterActionChoice 事件。

当然,这远非最佳,它只是一个草图,或者一个供你思考的想法。可能有更好的想法,我没有过多考虑这个问题 - 但这显然比您当前的解决方案更有效:)

于 2012-10-11T13:20:32.283 回答
0

好的,几个小时后,我似乎得到了这个工作。这是任何需要它的人的代码。我也愿意接受反馈。

这是能力类,需要的东西都可以在这里添加。对于基于刻度的系统,时间变量很重要。

public string AbilityName { get; private set; }
    public int minDamage { get; private set; }
    public int maxDamage { get; private set; }

    public int ActivationTime { get; private set; }
    public int CooldownTime { get; private set; }
    public int Timer;

    public Ability(string AbilityName)
    {
        if (AbilityName == "attack")
        {
            this.AbilityName = AbilityName;
            minDamage = 10;
            maxDamage = 20;
            ActivationTime = 20;
            CooldownTime = 30;
            Timer = ActivationTime;

            iconPath = "ability/icon/attack";
        }
    }

这是任务类,能力、攻击者和目标作为参数传递,能力名称或类型可用于执行不同种类/类型的能力,例如移动与攻击。

public Ability ability { get; private set; }
    public bool onCooldown;

    public Creature attacker { get; private set; }
    List<Creature> targets = new List<Creature>();

    /// <summary>
    /// Initiates a attack task
    /// </summary>
    /// <param name="attacker"></param>
    /// <param name="defender"></param>
    public Task(Creature attacker, List<Creature> targets, Ability ability)
    {
        this.ability = ability;
        this.attacker = attacker;
        this.targets = targets;

        onCooldown = false;
    }

    public void Perform()
    {
        //performce abilty
        Console.WriteLine(attacker.Name + " performce ability");
    }

玩家或 AI 现在可以使用他们拥有的能力创建任务,如下所示:

targets.Add(player); //This is just a basic attack so only one "creature" gets in the list
                task = new Task(this, targets, abilityList[0]); //Task is created
                taskList.Add(task); //Task is added to a list i manage in a main class
                free = false; //creature is put on hold and cant do anything till task is completed

这是大多数魔术发生的地方。在主类中,如果播放器不是“免费”的,则每次更新都会调用此方法。在对下一个任务执行任何操作之前,我会更新所有任务,因为我不想在更新其状态后编辑其统计信息。

private void TaskHandler()
    {
        int ticksToAdvance = 0;
        // get the next task requiring a action
        taskList.Sort((x, y) => x.ability.Timer.CompareTo(y.ability.Timer));

        //get the amount of cooldown left
        ticksToAdvance = taskList[0].ability.Timer;

        //Update all tasks
        foreach (Task t in taskList)
        {
            t.ability.Timer -= ticksToAdvance;
        }

        //check if this task is on cooldown
        if (taskList[0].onCooldown)
        {
            //Reset ability timer, free creature and remove task from the list.
            taskList[0].ability.Timer = taskList[0].ability.ActivationTime;
            taskList[0].attacker.free = true;
            taskList.RemoveAt(0);
        }
        else
        {
            //perform ability
            taskList[0].Perform();
            //set timer to cooldown
            taskList[0].onCooldown = true;
            taskList[0].ability.Timer = taskList[0].ability.CooldownTime;
        }
    }
于 2012-10-11T17:13:58.620 回答