2

私は compsci の学士号を取得するためのゲーム開発コースに参加しており、XNA ゲームを作成するプロジェクトを進めています。私たちは jrpg スタイルのゲームを作成しており、戦闘のクールなアイデアを思いつきました: スキルと選択した順序に基づいて、ターンごとに 3 つのスキルをキューに入れ、さまざまなボーナス効果を適用できます。攻撃と火の 2 つのスキルを持つ基本的なものを作成しました。

最初のスキルから始めて、次に選択した 2 番目と 3 番目のスキルを矢印で示します。2 番目と 3 番目のレベルのボックスは、その時点で追加された効果を示しています。

基本: 攻撃+攻撃 = 2 回目の攻撃のクリティカル率が高くなります。火+攻撃=攻撃の元のダメージに火のダメージを追加します。Fire+Fire = 火傷状態を適用

難しいのは、3 連続で攻撃するときです。これは一種の特殊攻撃になるためです。Attack は 1/4 の確率でクリティカルを発生させ、Fire は 2 倍のダメージを与える Fire 攻撃 (Fireball という名前) を行います。

これを if 文に実装すると、スキルが増えると苦労する可能性があります。if ステートメントの数は、1 から n までの n^n の合計に等しいので、6 つのスキルが必要な場合は、6+36+216=258 の if ステートメントを記述する必要があります。その多くは冗長でもあります! これは、フローチャートをコーディングするときに 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

すべてのコードを記述することを避けながら、さまざまな選択肢がプレーヤーに与える影響をカスタマイズする機能を引き続き必要としているようです。

これを行う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>

あなたはアイデアを得る。ユーザーの選択を処理するとき(ここでは推測しています)、たとえば、ユーザーが行うことを列挙型に保存できます。したがって、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 を生成し、ゲームのバランスをとるために値を微調整するのに役立つ単純なツールを作成できることを意味します。

テーブル上の 1 つのオプション。それが役立つことを願っています。

于 2012-11-15T05:18:14.883 に答える