【Minecraft】(Java未経験者対応)Bukkit/Spigot対応プラグインの作り方講座【基礎編③】
閉じる
閉じる

新しい記事を投稿しました。シェアして読者に伝えましょう

×

【Minecraft】(Java未経験者対応)Bukkit/Spigot対応プラグインの作り方講座【基礎編③】

2016-02-17 16:27
    さて、いよいよやってきました。プログラムをする上で使わないことはまずない
    条件分岐
    のお時間です。

    条件分岐には主に2つの構文があります。
    ①if文
    ifは日本語にするともし~なら、的な意味合いを持ちます。
    条件分岐におけるifも似たような意味で、if()の()内に記述した条件に当てはまった場合のみ次の処理を実行します。

    記述例①
    if (条件) {
     条件に合致する場合の処理
    }
    これは条件に一致するときのみ処理を実行し、それ以外はなにもしない場合の記述法です。


    記述例②
    if (条件) {
     条件に合致する場合の処理
    }
    else {
     条件に合致しない場合の処理
    }
    これは条件に一致するときと、そうでないときで処理の方法を変えたい場合に使う記述法です。
    else は「それ以外」といった意味合いを持ちます。


    記述例③
    if (条件①) {
     条件①に合致する場合の処理
    }
    else if (条件②) {
     条件②に合致する場合の処理
    }

    ...

    else {
     条件①、条件②のどちらにも合致する場合の処理
    }
    これは、条件分岐が3つ以上になる場合につかう記述法です。
    条件判定は上から順番に行われるので、優先したい条件を上に持ってくる必要があります。


    条件式の記述法
    if文の()内には true や false を記述するか、条件式を記述します。
    条件式は、次のような形で書かれます。
    ①AとBは等しい if(A == B)
    ②AとBは等しくない if(A != B)
    ③AはBより大きい if(A > B)
    ④AはBより小さい if(A < B)
    ⑤AはB以上である if(A >= B)
    ⑥AはB以下である if(A <= B)
    ⑦AかつB if(A && B)
    ⑧AまたはB if(A || B)
    ⑨Aでない if(!A)

    これらを複合することもできます。
    例:AとBは等しい かつ AとCは等しい
    if( A==B && A==C)

    例:AとBは等しい または AとCは等しい
    if( A==B || A==C)

    例:AとBは等しくない ②の変化形
    if( !(A==B) )

    例:AはBまたはCの少なくともどちらか一方と等しい
    if( A==B || A==C )
    if( !( A!=B && A!=C ) )

    なんだか難しいと感じるかもしれませんが、プログラムをするうちに慣れてくると思います(@@;)

    例題:AとBは等しいが、AとCは等しくない
    答え→下を反転
    if ( A==B && A!=C) または if( A==B && !(A==C) )
    これ以外にもありますが、望ましい書き方は上の2つのどちらかだと思います。


    ②switch文
    普段のプログラムだとあまり存在感のないようなこの文ですが、マイクラでプログラムのソースをスッキリさせるためにはこの文をよく使ったりします。
    記述法は以下のとおりです。
    switch(引数){
     case 値1:
      引数が値1だったときの処理
      break;

     case 値2:
      引数が値2だったときの処理
      break;

     ...

     default:
      上の条件全てに当てはまらない場合の処理
      break;
    }
    ちょっと記述の仕方を見るとわかりにくいのですが、実際にこれから使用するので、それを見てイメージしてもらえればいいかと思います。




    さて、実際にこの条件分岐を使ってプラグインを作成したいと思います。
    コマンドと処理の内容を以下のようにしたいと思います。

    ①コマンドのみ

    /tutorial
    →自分にダイヤモンドが渡る


    ②コマンド+引数1つ
    /tutorial 1
    /tutorial 2
    /tutorial 3
    /tutorial ab
    →数字が1のとき:自分にダイヤモンドが渡る
    →数字が2のとき:自分にエメラルドが渡る
    →それ以外のとき:自分に鉄インゴットが渡る

    ③コマンド+引数2つ以上
    /tutorial 1 aaa bbb
    /tutorial c d e f g
    →コマンドが不正ですというメッセージを送る



    switch文の実装
    前回のプログラムを立ち上げ、sender.sendMessage("...")の下にswitch文を以下のように実装します。

    switch文の()内に入っている args.length は、String[]型のargsに入っている変数の数を表します。
    例えば前回の例のような
    /give player diamond 1
    だと args[0]に"player"、args[1]に"diamond"、args[2]に"1"が入っています。
    この場合、3つの変数がargsに入っていることになるので、args.length == 3になります。
    ちょっとややこしいのが、args[n]のnの最大値と、args.lengthの値は違うということです。
    つまり args.length == 5 ならば、 変数はargs[4]までですし、
    args.lenght == 1ならば、変数はargs[0]しかありません。

    /tutorial
    この場合、String型のlabelに"tutorial"が入りますが、他の引数がないのでargsは空です。
    なので、args.length == 0 となり、 case 0: の処理をすることになります。
    /tutorial 1
    /tutorial 2
    /tutorial 3
    /tutorial ab
    この場合、args[0]に"1"か"2"か"3"か"ab"が入ることになるので、args[0]のみ存在し
    args.length == 1 となり、case 1: の処理をすることになります。
    /tutorial 1 aaa bbb
    /tutorial c d e f g
    前者が args.lenght == 3、後者が args == 5 になります。
    この場合、case 0: にも case 1: にも合致しないので、default: の処理が行われます。

    各caseやdefaultにある
    break;
    という文は、「ここまで処理したらあとswitch文の{}内は全部無視していいよ」という意味あいです。
    case 0: やcase 1: でこれを省略してしまうと、default:の処理まで行われてしまいます。
    (default: は値に関係なく実行するという意味です)



    case 0: の処理を実装

    args.length == 0の場合、コマンドを実行したプレイヤーにダイヤを渡すので
    前回記述したプログラムをそのままコピー&ペーストしてあげるだけでいいです。
    ただし、break;より下は前述通り全て無視されてしまうので、case 0: と break;の間に4行の処理を入れてあげましょう。



    default: の処理を実装
    args.lengthが0でも1もない場合は、コマンドが不正ですとメッセージを送るので
    default: と break; の間に
    sender.sendMessage("コマンドが不正です");
    という命令文を書いたら処理は終了です。


    case 1: の処理を実装
    case 1: も、基本的な命令はcase 0:と大差ないので、下の4行をコピー&ペーストします。
    ペーストしたら、橙で囲った下の4行の文章はもう不要なので、消してしまいましょう。


    ここで、case 1: の変数名playerとitemに赤線が引かれています。
    これは、case 0: で変数の宣言が行われているためなので、宣言部分であるPlayerとItemStackを消してしまい、ただの代入にしてしまいます。


    では、いよいよargs[0]の記述による条件分岐を実装していきます。
    args[0]は0か1か2の数字が入っていますが、String型なので、単純な数字比較ができません。
    例えば、int型の変数であれば
    if( integer == 1 )
    のように記述できますが、
    if( args[0] == 1 )
    と記述するとエラーになります。また、文字列はダウルクォーテーション("")で囲うことで表現できますが
    if( args[0] == "1" )
    は真(true)ではなく偽(false)になってしまい通りません。

    本当はこのString型の数字をint型の数字に変換するのが一番なのですが、
    そうすると「例外処理」というものが必要になってくるため、今回は避けたいです。

    文字列の比較は、以下のメソッドで行えます。
    args[0].equals("文字列");   //大文字小文字を区別する場合
    args[0].equalsIgnoreCase("文字列");   //大文字小文字を区別しない場合
    文字列の後に .equals("a"); や .equalsIgnoreCase("a"); をつければよいだけなので
    if( "aaa".equals("aaa") ) という文も成り立ちます。(この場合trueです)

    今回は1, 2, 3のときに処理をしたいので
    if ( args[0].equalsIgnoreCase("1") ){
     文字列が1の場合の処理(itemにダイヤをセット)
    }
    else if ( args[0].equalsIgnoreCase("2") ){
     文字列が2の場合の処理(itemにエメラルドをセット)
    }
    else {
     それ以外の処理(itemに鉄インゴットをセット)
    }
    と記述します。

    よって、以下のようになります。



    …なんかスッキリしませんね。見にくいです。

    実は、if文による記述の場合、各条件に対する命令文が1つの場合、{}を省略することができます。例えば、
    if( A == 5) System.out.println("Aは5です.");
    else if ( A == 8 ) System.out.println("Aは8です.");
    else System.out.println("Aは5でも8でもありません.");
    といった感じです。ただし、各条件に対して命令文が2つ以上ある場合は、{}で囲わなければなりません。
    if(A==5) System.out.println("Aは5です.");  条件に対して1つで{}省略可
    else if(A==3 || B==8) {
     System.out.println("Aは3です.");   条件に対して2つの命令文なので
     System.out.println("Bは8です.");     {}は省略できない
    }
    こういう書き方もできます。
    if( args[0].equalsIgnoreCase("1") )
       item = new ItemStack(Material.DIAMOND);
    else if( args[0].equalsIgnoreCase("2") )
       item = new ItemStack(Material.EMERALD);
    else
       item = new ItemStack(Material.IRON_INGOT);

    こういった省略技法を知っておくと、ソースコードが綺麗にまとまるので、もし余裕がある方はこういったものも調べて覚えておくといいかもしれません。
    ただ、場合によっては省略可能でもあったほうが見やすい場合もあります。実際に書いてみて、省略するか省略しないかを個々で判断してみてください。



    動作確認
    完成したプログラムをエクスポートし、サーバーを起動します。

    /tutorial


    /tutorial 2


    /tutorial abc


    /tutorial ab cd ef




    期待通りの操作ができたでしょうか。

    次回はコマンド制御専用のクラスを用意するとともに、「ループ処理」について解説します。
    今回の条件分岐と次回のループ処理さえ覚えれば脱基礎編ですので、頑張って勉強しましょう。




    広告
    コメントを書く
    コメントをするには、
    ログインして下さい。