記事一覧

キレイなスクリプトの書き方

スクリプトを書いていらっしゃる方が沢山来ていただいているようで、スクリプターとしては嬉しい限りです。
それに加え、スクリプトの質問をされる方も多くなってきました。
書き方のことで質問された方もいるので、いい機会に勝手ながらアドバイスをさせてもらいます。

※久しぶりに開発者よりの日記です。興味ない方ごめんなさいorz

-

最近のスクリプトを見てお気付きの方もいらっしゃると思いますが、menu・gotoなど、ラベルを使う命令を一切排除しています。
これは去年の1月からしているNo more "goto" Good bye "goto"運動(AthenaDevさんにて命名?)によるもので、スクリプトの見直し・整形を行いました。
実際に見てみると、最新のAthenaデフォルトではsampleスクリプトを除き、gotoは使われていないと思います。

なぜgotoやmenuがいけないのか、答えはswitch、selectなどで綺麗に簡潔に代用できるからです。
実際に昔のスクリプトと改修後のスクリプトを見てみると、

lou_fild01.gat,175,173,4scriptクエン ホ819,{
    if(Lou_que1 == 4) goto L_OK2;
    if(Lou_que1 == 3) goto L_OK1;
    mes "[クエン ホ]";
    mes "ここは危険だ。帰れよ。";
    close2;
    warp "lou_fild01.gat",200,174;
    end;
L_OK1:
    emotion 18;
    mes "[クエン ホ]";
    mes "どうだい、素敵だろ~。";
    mes "落ち込んだり元気がなくなると";
    mes "ここに来るんだ。";
    mes "ここからじっと景色を眺めてると";
    mes "落ち着くんだよ。";
    next;
~~~~~略~~~~~
L_OK2:
    mes "[クエン ホ]";
    mes "どうする?";
    next;
    menu "叫ぶ",-,"帰る",L_CANCEL;
    mes "[クエン ホ]";
    mes "おし、叫んでみて!";
    next;
    input @annouce$;
    announce "「"+strcharinfo(0)+"」の叫び : "+@annouce$,0x01;
    mes "["+strcharinfo(0)+"]";
    mes @annouce$;
    next;
    mes "[クエン ホ]";
    mes "どう?すっきりした?";
    mes "また叫びたくなったら来なよ。";
    close;
L_CANCEL:
    mes "[クエン ホ]";
    mes "うん、じゃあまたね。";
    close2;
    warp "lou_fild01.gat",200,174;
    end;
}

改修前の龍乃城NPC、クエン ホです。
まだフラグが少ないNPCなので何とか目で追っていけますが、もしもクエストフラグが何十にも及ぶと大変ですね。

一方改修後は

lou_fild01.gat,175,173,4scriptクエン ホ819,{
    switch(LOU_1QUE) {
    default: //3,4以外のとき
        mes "[クエン ホ]";
        mes "ここは危険だ。帰れよ。";
        close2;
        warp "lou_fild01.gat",200,174;
        end;
    case 3:
        emotion 18;
        mes "[クエン ホ]";
        mes "どうだい、素敵だろ~。";
        mes "落ち込んだり元気がなくなると";
        mes "ここに来るんだ。";
        mes "ここからじっと景色を眺めてると";
        mes "落ち着くんだよ。";
        next;
~~~~~略~~~~~
    case 4:
        mes "[クエン ホ]";
        mes "どうする?";
        next;
        if(select("叫ぶ","帰る")==2) {
            mes "[クエン ホ]";
            mes "うん、じゃあまたね。";
            close2;
            warp "lou_fild01.gat",200,174;
            end;
        }
        mes "[クエン ホ]";
        mes "おし、叫んでみて!";
        break;
    }
    next;
    input '@word$;
    announce "「"+strcharinfo(0)+"」の叫び : " +'@word$,1,0x9BFD00;
    mes "["+strcharinfo(0)+"]";
    mes '@word$;
    next;
    if(LOU_1QUE == 3) {
        mes "[クエン ホ]";
        mes "どう?すっきりしたかな?へへ。";
        mes "ここには、好きに来ていいよ。";
        mes "今日は本当にありがとう!";
        set LOU_1QUE,4;
    }
    else {
        mes "[クエン ホ]";
        mes "どう?すっきりした?";
        mes "また叫びたくなったら来なよ。";
    }
    close;
}

フラグの状況と進行具合が目で追って分かりやすいです。
breakなどによる共通部分の処理も気軽に出来る点も魅力です。
またラベルを使っていないので、衝突を意識する必要もありません。
この大改修でほとんどのスクリプトが見やすくなり、また後から手を加える人にとって大変ありがたい偉業となりました。



スクリプトを書く際少なくとも私はこの点に注意し、見た目的に分かりやすく美しく、を追求しています。
まだまだ未熟な部分もありますが・・・orz
「スクリプトなんて動けばいいじゃん」と思う方もいらっしゃるかもしれません。
ですがプログラムも然り、それを見る人・手を加える人がいる限り整合の必要性があります。

いきなりswitchやselectなんて・・・という方、私も最初はそうでしたorz
が、いざやってみるとゴチャゴチャしていた物がキレイになっていく感じで意外とハマり、無駄な処理・不要な部分という物が見えてきます。
それを排除していくことでより一層綺麗に仕上がると思います。


スクリプトを作ってる方、まずはgoto・menuの排除に挑戦してみてはいかがでしょうか。

コメント一覧

Cocoa (02/14 00:27) 編集・削除

スクリプト公開所の濃縮エルNPCでgoto使ってたorz
ちょっくら書き直してくるぜ!
λ=3......

らの字 (02/14 06:08) 編集・削除

確かにswitchのほうが高性能だけど、
個人的にはmenuとラベルのように
各処理部分をはっきり分けられて
初心者にわかりやすいところが好きです。

はっきりとmenuとラベルをスクリプトから排除するより
場合によって使い分けすべきではないかと考えてます。

こより (02/14 17:26) 編集・削除

好みの問題だからなぁ。
ボクはswitchのほうが好き。

C寄りの考え方に慣れてくると、多分switch派になるんじゃないかなぁ。

Blaze (02/15 02:19) 編集・削除

個人的にラベルはイベント時やcallsub等呼び出しのみの使用と考えています。
汎用性が低いもの、例えばcancel時はラベル呼び出しよりもその条件分岐地点にぶら下げる形がスマートだと思いますので・・・

私では現状の改修後のカタチに慣れてしまいましたが、やはり人それぞれ使いやすいカタチがありますよね。
自主的な概念を強要するつもりはありませんので、人それぞれの書きやすいカタチで書いていくのも個性的でいいかもですね。

Gokismith (02/17 12:43) 編集・削除

swicthは便利だとは思うのですが、menuは全部排除となると躊躇します。

なぜならswicthだけだと、ラベルの全部が「CASE 数字」になってしまうので、mes文を読まないと
「これをしたのはNPCプログラムのどこだったっけ・・・?」
となってしまうから。

たとえば上のものだとLOU_1QUEが何の関数だったか忘れると一貫の終わりなわけで・・・

ラベルにそれこそLOWZENYとか具体的に書いてあればお金の足りない時の処理どうだったっけ・・・?を言葉で検索できますが、CASEだと全部読まないとムリになっちゃう。

明らかにBASIC臭い考えかただなぁと自分でも思いますけど orz

menuとラベルがAthenaから消えると自分はプログラム書くのきつくなっちゃいそうです。

elseif (02/22 00:54) 編集・削除

goto,menuはあまり使わない派だけど、テストNPCを書くときはmenuやgoto使います
それにAthenaのスクリプトは普通書き捨てなので、使っていってかまわないと考えています
Gokismithさんの言うように、switch,select時は戻り値が整数になるので分岐を増やすと追いかけづらくなりますしね

個人的には饒舌なNPCだとmes命令が冗長になるのと、永続キャラクター変数に何も修飾されないのが辛いです

ナナ氏 (03/06 11:28) 編集・削除

さすがBlazeさん。
この考えはダイクストラが唱えた構造化定理の提案と同じ考えですね。
「いかなる制御を行なうプログラムも、補助的なスイッチなどを用いればgoto文のないプログラム(gotoless program)を記述できる」ていうもの。

プログラマーとしてはこの構造化定理に沿って記述していくのが筋。
「gotoの方が使い易い」という人はまだ使い熟していない証拠でしょう。

バレンタインイベント

ファイル 240-1.jpg

今日からRO本鯖でバレンタインイベントが開始されます。
事前から調べがついているので(前日記参照)あとはメッセージの取得とかのみ。
事前調査すると楽だなぁ。今度からなるべく調べてから調査してみよう。

バレンタイン間近だし、1週間で終わるかなと思ってましたが、今年はホワイトデーと兼用のようで3月20日までの開催。長っ!
他国では1週間で終了がほとんどのようで、思い切ったな~日鯖。
調査する側としてはタイムリミットが伸びたので嬉しい限り。のんびり調査していきます。

さて、移動距離が長い今イベント。
調査用キャラでウンバラ⇔コモド⇔アルベルタと往来しております。
しかし、そうこうしているうちに・・・
調査用キャラの所持金が尽きたorz
残金2,093zeny(苦笑)

メインからお金を渡そうとしましたが、2PC環境を整えるのに面倒なので久方にポタ屋をすることに。
事前に調査してウンバラ・ジュノーポタを取っておいたのでイベントに便乗してポタ屋開催。
結果2,093zeny→316,893zeny、めっちゃ儲かりました!
他から見れば微々たるものかもしれません。
ですが、昔もポタ屋でコツコツとしてたのであまりの懐かしさにちょっと感動。そんな時代もあったなぁ。

調査の方は順調です。ショコラクエストは終了かな?
問題はメインクエストの方で、性別によってクエスト分岐される所。
久しぶりに♀垢の出番となりそうです。