Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/silverlight/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 实施基于滴答/轮回的作战系统_C#_Xna - Fatal编程技术网

C# 实施基于滴答/轮回的作战系统

C# 实施基于滴答/轮回的作战系统,c#,xna,C#,Xna,我想了解一些关于如何实现基于tick的系统的想法 玩家或非玩家的每个动作都有一个初始执行时间和冷却时间。一旦生物冷却时间过去,它就可以选择一个新动作。如果玩家必须选择一个动作,游戏将“暂停” 例如: 1:球员挥杆过大(执行50次,冷却50次) 2:游戏持续50分钟 3:人大可以采取行动 4:玩家摆动并冷却50次 5:人大可以采取行动 6:游戏为玩家暂停 我目前拥有的东西可以工作,但效率不高。我有一个类,每个动作都是静态方法。这些方法输出一个包含所有数据的结构。这将传递给单个生物的动作提示 每次更

我想了解一些关于如何实现基于tick的系统的想法

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

例如:

1:球员挥杆过大(执行50次,冷却50次)

2:游戏持续50分钟

3:人大可以采取行动

4:玩家摆动并冷却50次

5:人大可以采取行动

6:游戏为玩家暂停

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

每次更新循环调用提示,并开始倒计时攻击时间,如果玩家已采取行动。一旦攻击得到解决,我再次调用actions类中的静态方法。我开始倒计时

因此,我应该有一个包含所有操作的列表,并对该列表进行排序,跳过不必要的时间/滴答声,直接进入下一个操作。但是会有不同类型的动作,比如移动、攻击、能力,我不能把我的头脑集中在一个好的实现上

当一个生物执行一个基本攻击时,该攻击被调用(攻击是该生物自己的实例攻击结构)

这就是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;
    }
当玩家有一个动作提示时,在每个生物的更新方法中都会调用它。如果玩家没有动作提示,则勾选=0;如果玩家有动作提示,则勾选=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;
        }
    }

考虑这样的事情(我将使用伪代码——它远没有被优化,等等,但它可能足够快,或者让你开始优化你正在尝试做的事情)

那么,这是怎么回事

我们有一份活动清单

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

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

解决所有当前CombatEvents并将其自己的CombatEvents添加到列表后,列表将检查下一个事件(最低延迟)

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

这是一个循环

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


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

好的,几个小时后,我似乎可以解决这个问题了。这是给任何需要它的人的代码。我也愿意接受反馈

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

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");
    }
这就是大部分魔法发生的地方。在主类中,如果玩家不是“自由”的,则每次更新都会调用此方法。我在对下一行任务执行任何操作之前更新所有任务,因为我不想在更新其状态后编辑其统计信息

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

粘贴代码。从一个甚至不使用实际类名的描述中推断你在做什么是一件痛苦的事,我很可能需要一种完全不同的方法来做。但我试着粘贴一些代码,让你们看到我现在拥有的东西。当我需要移动等不同的动作时,我也遇到了问题。我需要一种让事情变得更灵活的方法来获得提示并直接计算下一步要执行的动作。@MennoGouw-所以创建一个基本动作类并继承它。你的问题不清楚。很明显,你在项目中做得不够远,我们无法帮助你。到底是什么问题?你说当前的系统可以工作。非常感谢你,我对我的新方法很在行,但是它看起来比你的代码更混乱。从未参与过活动,所以现在正是这样做的好时机。这看起来很清楚,谢谢!为了清楚起见,我使用名为Events的类,但它们实际上不是Events(语言结构)。这可能有点误会-抱歉。当然,您可以使用实际事件来实现这一点!但这不是必须的;)是的,我明白了,我知道类/方法的名称和实际事件之间的区别,但感谢您澄清:D
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");
    }
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;
        }
    }