2

我正在为我的 compsci 学士开设游戏开发课程,我们的项目是制作 XNA 游戏。我们正在制作一款 jrpg 风格的游戏,并为战斗提出了一个很酷的想法:每回合你排队 3 个技能,根据技能和选择的顺序,可以应用各种奖励效果。我们制作了一个具有 2 个技能的基本技能:攻击和射击

您从第一个技能开始,然后箭头显示选择的第二个和第三个技能。第二层和第三层的方框显示了此时添加的效果。

基础:攻击+攻击=第二次攻击的暴击率更高。Fire+Attack = 在攻击的原始伤害上增加一些火焰伤害。Fire+Fire = 应用燃烧状态

更难的部分是当你连续击中 3 个时,因为它们会进行某种特殊攻击。攻击造成 1/4 几率暴击,火焰造成双倍伤害火焰攻击(称为火球)。

在 if 语句中实现这一点可能会因更多的技能而变得痛苦。if 语句的数量等于 n^n 从 1 到 n 的总和,所以如果我们想要 6 个技能,我们需要编写 6+36+216=258 个 if 语句!其中许多也是多余的!这很容易出错,因为我们必须煞费苦心地制作每个 if 语句,以便在我们编写流程图时它们处于正确的位置。

这就是为什么我们认为我们应该有一些具有静态效果的通用组合,如果可以累积的话,可能会增加一个计数器,然后当我们连续 3 个时调用具有该技能特殊攻击的函数。

首先想到的是有限状态机。除了我认为的特殊情况外,它可以处理所有情况。也许是下推式自动机?我的主要问题是我不知道如何在代码中实现它们。我学的课是理论课。

还有其他更有效或更容易编写/编码的方法吗?

4

2 回答 2

1

我会想出某种递归模型:

enum Outcomes { Crit, DoubleCrit, FireDMG, Burn, NoEffect }

abstract class Attack 
{ 
    public Attack() { Child = null; }

    List<Outcomes> GetOutcomes(); 
    protected virtual Attack Child; 
}
class Melee : Attack 
{ 
    public Melee() : base() { }
    public Melee(Attack child) : base() { Child = child; }

    List<Outcomes> GetOutcomes()
    {
        List<Outcomes> ret = new List<Outcomes>();
        if(Child != null) ret.Add(Child.GetOutcomes());

        if(ret.Contains(Outcomes.Crit))
            ret.Add(Outcomes.DoubleCrit);
        else
            ret.Add(Outcomes.Crit);

        return ret;
    }
}
class Fire : Attack 
{ 
    public Fire() : base() { }
    public Fire(Attack child) : base() { Child = child; }

    List<Outcomes> GetOutcomes()
    {
        List<Outcomes> ret = new List<Outcomes>();
        if(Child != null) ret.Add(Child.GetOutcomes());

        List<Outcomes> PossibleOutcomes = new List<Outcomes>();        

        PossibleOutcomes.Add(Outcomes.FireDMG);
        PossibleOutcomes.Add(Outcomes.Burn);

        if(ret.Contains(Outcomes.Burn)) PossibleOutcomes.Add(Outcomes.Fireball)
        if(ret.Contains(Outcomes.FireDMG)) PossibleOutcomes.Add(Outcomes.NoEffect);

        // Use some randomization method to select an item from PossibleOutcomes
        int rnd = 2; // Totally random number.
        ret.Add(PossibleOutcomes[rnd]);

        return ret;
    }
}

然后链式攻击只需使用:

Attack ChosenAttack = new Melee(new Fire(new Melee()));

或者假设用户选择了每个分支,您只需要保留最后一个分支并不断将其作为子分支添加到他们选择的下一个攻击中。

Attack ChosenAttack = new Melee();

// Some events occur...

ChosenAttack = new Fire(ChosenAttack);

// Some more...

ChosenAttack = new Melee(ChosenAttack);

如果我不太了解问题并且我的建议不起作用,我深表歉意。

于 2012-11-15T05:04:20.690 回答
1

听起来您确实希望仍然能够自定义不同选择将对玩家产生的影响,同时避免编写所有代码。

做到这一点的一种方法是创建一个数据结构,它将处理任何组合的结果,并使创建新组合的任务更容易处理潜在的大量可能性,而不是你必须重新编译的代码更容易更改的东西在 XML 中并根据用户的选择查询结果。

您可能有一个类似于以下的类来存储结果。

public class AttackResult
{
    public int ChanceToCrit { get;set; }
    public int ChanceToBurn { get;set; }
    public int FireDmg { get;set; }
}

至于 XML,你可能会有类似的东西,

<Options>
    <Attack>
        <AttackResult>
            <ChanceToCrit>5</ChanceToCrit>
        </AttackResult>
        <Attack>
            <AttackResult>
                <ChanceTCrit>10</ChanceToCrit>
            </AttackResult>
        </Attack>
    </Attack>
    <Fire>
    </Fire>
</Options>

你明白了。例如,在处理您的用户选择时(我只是在这里猜测),您可能会将他们所做的事情存储在 Enum 中。因此,要使用 XML,您可能会做一些类似的事情

public enum ActionType
{
    Attack,
    Fire,
    None
}

allActions 必须是为了让这个例子与你的游戏想法一起工作,我认为。

public ActionResult ProcessActions(List<ActionType> allActions)
{
    string xpathquery = "Options";

    foreach(var playerAction in allActions)
    {
        if(playerAction == ActionType.None)
           break;
        xpathquery += "/" + playerAction.ToString();
    }

    //Query xmldocument of all options
    var result = Singleton.ActionsDoc.SelectSingleNode(xpathquery);
    string attackRes = result.InnerXml;
    XmlSerializer serializer = new XmlSerializer(typeof(ActionResult))
    //Might need to prepend something to attackRes before deserializing, none of this is tested
    byte[] allBytes = Encoding.UTF8.GetBytes(attackRes);
    MemoryStream ms = new MemoryStream(allBytes);

    ActionResult result = (ActionResult)serializer.Deserialize(ms);

    return result;
}

此选项有其缺点,例如 XmlSerializer 非常慢,但这意味着您可以创建一个简单的工具来帮助生成所有选项所需的 xml,并非常简单地调整值以平衡游戏。

桌上的一个选项。希望有帮助。

于 2012-11-15T05:18:14.883 回答