【ゲーム開発のためのC#入門講座・基礎拡張編】複数条件分岐を使ってみよう【#3】

2.0_C#基礎拡張編

例えば求める選択肢が二択じゃなかったら

例えば会話イベントでプレイヤーに選択肢を求める場合、その選択肢が「はい」と「いいえ」のふたつだけならif文で実装できますよね。

if (choosedOption == "はい")
{
    System.Console.WriteLine("「はい」が選択されたよ!");
}
else 
{
    System.Console.WriteLine("「はい」が選択されなかったよ!");
}

でも場合によっては、

  • そう かんけいないね
  • 殺してでも うばいとる
  • ゆずってくれ たのむ!!

なんて、3つ以上の選択肢を求めたい場合もありますよね。

こういう時はif文をふたつ以上組み合わせることで実装することができます。

if (choosedOption == "そう かんけいないね")
{
    ……処理……
}
else 
{
    if (choosedOption == "殺してでも うばいとる")
    {
        ……ねんがんのアイスソードを手に入れる処理……
    }
    else
    {
        ……処理……
    }
}

今までも自然体でそうしてきたのですが、「{}」で囲んでいる部分の内側にさらに「{}」で囲む処理が入る場合はちょっとしたルールがあります。どこからどこまでがその範囲なのかわかりやすくするため、その階層の深さに応じて行頭に半角スペースを一定数追加する、というものです(大半の開発ツールで自動で設定されます。今回活用しているWebサービスも自動設定)。

この階層のことをプログラミングの世界ではネスト(入れ子の意味)といいます。

もしこのネストがなかったら、めちゃくちゃ見辛いプログラムになります。

if (choosedOption == "そう かんけいないね")
{
……処理……
}
else 
{
if (choosedOption == "殺してでも うばいとる")
{
……ねんがんのアイスソードを手に入れる処理……
}
else
{
……処理……
}
}

うーん、これは見る気が失せますね(白目

ネストのおかげで階層構造は非常に見やすくなります。ただ、このネストがどんどん深くなっていくと、それはそれですごく見辛くなってきます。

if (choosedOption == "そう かんけいないね")
{
    ……処理……
}
else 
{
    if (choosedOption == "殺してでも うばいとる")
    {
        ……ねんがんのアイスソードを手に入れる処理……
    }
    else
    {
        if (playerStatus == "悪人") 
        {
            if (partyStatus == "悪人") 
            {
                ……きさまらのような悪人に渡さない処理……
            }
            else
            {
                ……きさまのような悪人に渡さない処理……    
            }
        }
        else 
        {
            ……おれもいっしょにいく処理……
        }
    }
}

色々とごちゃごちゃしてきましたね。

プログラムの見やすさのことを可読性といいます。

可読性が低いプログラムというのはバグを生みやすいです。

理由は処理の範囲や意味を誤認してしまうリスクが高まるからですね。

例えそのプログラムを作った時は把握出来ていても、数か月後自分が見返した時「意味がわからん……」なんてことにもなりかねません(慣れないうちはよくある)。

そこで、ネストを深くしなくても済む方法をいくつかご紹介しましょう。

else ifを活用しよう

実はif文は、複数の条件分岐を同じネストレベルで書けるようになっています。

elseのあとに直接またif文を記述すればよいのです。

if (choosedOption == "そう かんけいないね")
{
    ……処理……
}
else if (choosedOption == "殺してでも うばいとる")
{
    ……ねんがんのアイスソードを手に入れる処理……
}
else
{
    ……処理……
}
<構文>
if (条件1)
{
    ……条件1を満たす場合のみ実行する処理……
}
else if (条件2)
{
    ……条件2を満たす場合のみ実行する処理……
}
else {
    ……条件を満たさない場合のみ実行する処理……
}

この「else if」はいくつ続けても問題ないので、選択肢や処理のパターンがどんなに増えても対応可能です。

注意していただきたいのは条件1を満たした時点で条件2以降の判定や処理は行われないということです。

なので、例えば条件1と条件2両方を満たす場合であっても、条件1の処理しか実行されません。

もし「条件1と2のいずれかを満たすなら」のように複合的な条件をまとめて判定したい場合は、これからご説明する論理演算子を活用する必要があります。

論理演算子って?

論理演算子は「AかつB」や「AまたはB」といった、条件同士の組み合わせを判定する演算子です。

また、条件の結果を反転させる論理否定演算子というものもあります。

演算子命令使用例結果
&&AかつBかどうか判定(両方trueか)1 == 1 && 1 == 2false
||AまたはBかどうか判定(どちらかtrueか)1 == 1 || 1 == 2true
!判定結果を反転!(1 == 1)false
// &&演算子の使用例
if (playerStatus == "悪人" && partyStatus == "悪人") 
{
    ……きさまらのような悪人に渡さない処理……
}   
else if (playerStatus == "悪人")
{
    ……きさまのような悪人に渡さない処理……      
}
else 
{
    ……おれもいっしょにいく処理……
}

「&&」演算子と「||」演算子は「and」と「or」の意味なのでわかりやすいかと思いますが、論理否定演算子は使い方がいまいち想像しにくいことでしょう。

これは基礎拡張編の最後に改めて解説予定なので、今回はそういうのもあるんだなってことだけ覚えていただければと思います。

改めて条件分岐を組んでみよう

それでは、改めて先程の条件分岐を見てみます。

if (choosedOption == "そう かんけいないね")
{
    ……処理……
}
else 
{
    if (choosedOption == "殺してでも うばいとる")
    {
        ……ねんがんのアイスソードを手に入れる処理……
    }
    else
    {
        if (playerStatus == "悪人") 
        {
            if (partyStatus == "悪人") 
            {
                ……きさまらのような悪人に渡さない処理……
            }
            else
            {
                ……きさまのような悪人に渡さない処理……    
            }
        }
        else 
        {
            ……おれもいっしょにいく処理……
        }
    }
}

うーん、やっぱりネストが深くて読み辛いですね。

それでは、else ifと論理演算子を使って組み直してみましょう。

if (choosedOption == "そう かんけいないね")
{
    ……処理……
}
else if (choosedOption == "殺してでも うばいとる")
{
    ……ねんがんのアイスソードを手に入れる処理……
}
else
{
    if (playerStatus == "悪人" && partyStatus == "悪人") 
    {
        ……きさまらのような悪人に渡さない処理……
    }   
    else if (playerStatus == "悪人")
    {
        ……きさまのような悪人に渡さない処理……      
    }
    else 
    {
        ……おれもいっしょにいく処理……
    }
}

どうでしょうか。

ネストが浅くなったのと、条件が多少ひとまとめになったので、さっきより読みやすくなったのではないかなと思います。

他の人と共同制作する場合や、未来の自分が見返した時に地獄を見ないよう、読みやすいコード作りを心掛けていきたいですね!

Unityでの活躍ポイント

今回も解説の時点で活躍ポイントが想像できる内容になっているかと思いますので、割愛させていただきます。

某有名RPGの会話イベントをモチーフに使わせてもらいましたが、条件分岐を使えばああいうことも実装できるようになる、ということですね。

実践演習

それでは学習した条件分岐と論理演算子を使ってみましょう。

演習①

仕様

変数「totalAmount」が、

①変数「money」を上回る場合、出力エリアに「お金たんないよ!」と表示する
②変数「money」と同じ場合、出力エリアに「全財産とは豪気な!」と表示する
③変数「money」未満の場合、出力エリアに「まいど!」と表示する

テンプレート
public class Hello{
    public static void Main(){
        int totalAmount = 300;
        int money = 300;
        // ↓ここに条件分岐を実装しよう!
        
        // ↑ここまで
    }
}

演習②

仕様

①変数「isDead」がtrue、かつ変数「skillName」が"リザレクション"の場合、出力エリアに「蘇生しました」と表示する
②上記条件を満たさない場合、出力エリアに「死亡しているキャラには使えません」と表示する

テンプレート
public class Hello{
    public static void Main(){
        bool isDead = true;
        string skillName = "アイテムなぞ使ってんじゃねえ!";
        // ↓ここに条件分岐を実装しよう!
        
        // ↑ここまで
    }
}

答え合わせ

演習①の答え

public class Hello{
    public static void Main(){
        int totalAmount = 300;
        int money = 300;
        // ↓ここに条件分岐を実装しよう!
        if (totalAmount > money) {
            System.Console.WriteLine("お金たんないよ!");
        }
        else if (totalAmount == money) {
            System.Console.WriteLine("全財産とは豪気な!");
        }
        else 
        {
            System.Console.WriteLine("まいど!");
        }
        // ↑ここまで
    }
}
出力エリア

全財産とは豪気な!

演習②の答え

public class Hello{
    public static void Main(){
        bool isDead = true;
        string skillName = "アイテムなぞ使ってんじゃねえ!";
        // ↓ここに条件分岐を実装しよう!
        if (isDead && skillName == "リザレクション") {
            System.Console.WriteLine("蘇生しました");
        }
        else 
        {
            System.Console.WriteLine("死亡しているキャラには使えません");
        }
        // ↑ここまで
    }
}
出力エリア

死亡しているキャラには使えません

まとめ

  • プログラムの階層のことをネストという
  • else ifを使うと複数の条件分岐をまとめて記述できる
  • 論理演算子を使うと「AかつB」や「AまたはB」などの条件を判定できる
  • else ifや論理演算子を使うとネストが浅くなり、プログラムの可読性が向上する

それでは、今回もお疲れ様でした!

また次の記事でお会いしましょう!

Posted by 夕目紅