最終更新:ID:mwMxqS/DQQ 2018年06月27日(水) 23:56:28履歴
ERB構文講座 | |
前編 | 基本、変数、表示 |
後編 | 分岐と反復、関数と関数呼び出し、ラベルとキー入力、その他 |
特別編 | ビット演算について |
参考 | ERBファイルの作成や改造時によくあるミスについてのQ&A |
条件式は変数と変数、変数と数値の大小などを比較し、それが正しいかどうかを判定します。
その比較に使われるのが比較演算子で、==, !=, <, >, <=, >= などがあります。
== は等しい、!= は等しくない、不等号はそれぞれそのままの意味です。
例えば、A = 0, B = 1, C = 0 のとき
また、比較演算子を使った条件式の代わりに0かそれ以外の数字を書くことでも
真偽を表すことができます。
この場合、0が偽、それ以外が真です。
(関連記事:ERB編集における代表的なエラー#!= 0は-1も含まれる)
その比較に使われるのが比較演算子で、==, !=, <, >, <=, >= などがあります。
== は等しい、!= は等しくない、不等号はそれぞれそのままの意味です。
例えば、A = 0, B = 1, C = 0 のとき
式 | 真偽 |
---|---|
A == B | 偽(正しくない) |
A == C | 真(正しい) |
A != C | 偽 |
A > B | 偽 |
B > C | 真 |
B <= A | 偽 |
A >= C | 真 |
また、比較演算子を使った条件式の代わりに0かそれ以外の数字を書くことでも
真偽を表すことができます。
この場合、0が偽、それ以外が真です。
(関連記事:ERB編集における代表的なエラー#!= 0は-1も含まれる)
Emueraでは、比較演算子の他に否定演算子というものがあり、!(感嘆符)で表します。
これには、直後の条件式の結果を逆転させる効果があります。上の例で言えば、
!(A > B) は真、!(A <= C) は偽になります。
これには、直後の条件式の結果を逆転させる効果があります。上の例で言えば、
!(A > B) は真、!(A <= C) は偽になります。
複数の条件式を使う場合は、条件式と条件式の間に && や || を記述します。
&& は「○○かつ××」に使用し、|| は「○○または××」に使用します。
例えば、変数Aが0かつ変数Bが1という条件の場合は
変数Aが0または変数Bが0という条件なら
もっと複雑に、変数Aが0で変数Bが1、または変数Aが0で変数Cが1なら
&& は「○○かつ××」に使用し、|| は「○○または××」に使用します。
例えば、変数Aが0かつ変数Bが1という条件の場合は
A == 0 && B == 1となります。
変数Aが0または変数Bが0という条件なら
A == 0 || B == 0となります。
もっと複雑に、変数Aが0で変数Bが1、または変数Aが0で変数Cが1なら
(A == 0 && B == 1) || (A == 0 && C == 1) もしくは A == 0 && (B == 1 || C == 1)となります。
よく使われる条件式の中に、キャラの能力や素質を判断するものがあります。
例えば、調教中のキャラが処女の時、TALENT:TARGET:0 == 1 が成立します。
素質は持っている状態が1、持っていない状態が0となるため、
条件式に単に TALENT:TARGET:0 と書いた場合、「調教中のキャラが処女である」
という条件と同じ意味になります。
逆に、TALENT:TARGET:0 == 0(あるいは !TALENT:TARGET:0)と書いた場合には、
「調教中のキャラが処女ではない」という意味になります。
調教中のキャラの従順がLv3以上の時は、ABL:TARGET:0 >= 3 が成立します。
能力や刻印はLvがそのまま数値となります。
体力や経験などレベルで表されない能力は、値がそのまま使用されます。
調教中のキャラのV経験が10以上であるという条件を表すなら、
EXP:TARGET:0 >= 10 となります。
例えば、調教中のキャラが処女の時、TALENT:TARGET:0 == 1 が成立します。
素質は持っている状態が1、持っていない状態が0となるため、
条件式に単に TALENT:TARGET:0 と書いた場合、「調教中のキャラが処女である」
という条件と同じ意味になります。
逆に、TALENT:TARGET:0 == 0(あるいは !TALENT:TARGET:0)と書いた場合には、
「調教中のキャラが処女ではない」という意味になります。
調教中のキャラの従順がLv3以上の時は、ABL:TARGET:0 >= 3 が成立します。
能力や刻印はLvがそのまま数値となります。
体力や経験などレベルで表されない能力は、値がそのまま使用されます。
調教中のキャラのV経験が10以上であるという条件を表すなら、
EXP:TARGET:0 >= 10 となります。
RAND:(数値もしくは数値変数)と記述することで、一定の範囲の中から
ランダムで数値を決定することができます。
例えば、A = RAND:10 と記述した場合、変数Aは0から9(= 10 - 1)までの
いずれかの整数になります。また、
(関連記事:ERB編集における代表的なエラー#RANDの使い方)
ランダムで数値を決定することができます。
例えば、A = RAND:10 と記述した場合、変数Aは0から9(= 10 - 1)までの
いずれかの整数になります。また、
A = 5 B = RAND:Aの場合、変数Bは0から4(= A - 1 = 5 - 1)までのいずれかの整数になります。
(関連記事:ERB編集における代表的なエラー#RANDの使い方)
もし○○ならば、という処理に最もよく使われる構文です。
条件の成立した部分の直後の処理のみを行います。
上の例文では処理の部分が1行ずつしかありませんが、実際には
次の ELSEIF, ELSE, ENDIF までの処理が全て行われます。
処理4と5、どちらも不成立の時は処理6のみが行われる)
判定したい条件が3つ以上ある場合は、ELSEIF を増やしていくことができます。
ENDIF の書き忘れはエラーの原因になりますので注意しましょう。
(関連記事:ERB編集における代表的なエラー#ELSEIF を ELSE としてしまう/ ELSE IF としてしまう)
(関連記事:ERB編集における代表的なエラー#お前はもう死んでいる分岐)
IF A == 0 PRINTFORML 変数Aは0です。 ELSEIF B == 0 PRINTFORML 変数Aは0でなく、変数Bは0です。 ELSE PRINTFORML 変数Aは0でなく、変数Bも0ではありません。 ENDIF上が IF - ELSEIF - ELSE - ENDIF 構文の基本的な形です。上の構文は
- もし変数Aが0ならば(IF A == 0)、『変数Aは0です。』と表示します。
- 変数Aが0でなく変数Bが0ならば(ELSEIF B == 0)、『変数Aは0でなく、変数Bは0です。』と表示します。
- いずれの条件にも当てはまらないならば(ELSE)、『変数Aは0でなく、変数Bも0ではありません。』と表示します。
条件の成立した部分の直後の処理のみを行います。
上の例文では処理の部分が1行ずつしかありませんが、実際には
次の ELSEIF, ELSE, ENDIF までの処理が全て行われます。
IF 条件式1 処理1 処理2 処理3 ELSEIF 条件式2 処理4 処理5 ELSE 処理6 ENDIF(条件式1が成立の時は処理1〜3、条件式1が不成立で条件式2が成立の時は
処理4と5、どちらも不成立の時は処理6のみが行われる)
判定したい条件が3つ以上ある場合は、ELSEIF を増やしていくことができます。
IF A == 0 PRINTFORML 変数Aは0です。 ELSEIF B == 0 PRINTFORML 変数Aは0でなく、変数Bは0です。 ELSEIF C == 0 PRINTFORML 変数A、Bは0でなく、変数Cは0です。 ELSE PRINTFORML 変数A、B、Cはいずれも0ではありません。 ENDIF判定したい条件が1つの場合は、ELSEIF 以下の部分はなくても構いません。
IF A == 0 PRINTFORML 変数Aは0です。 ELSE PRINTFORML 変数Aは0ではありません。 ENDIF条件を満たさない時何もしない場合、ELSE 以下の部分はなくても構いません。
IF A == 0 PRINTFORML 変数Aは0です。 ELSEIF B == 0 PRINTFORML 変数Aは0でなく、変数Bは0です。 ENDIFIF と ENDIF は絶対に必要です。
ENDIF の書き忘れはエラーの原因になりますので注意しましょう。
(関連記事:ERB編集における代表的なエラー#ELSEIF を ELSE としてしまう/ ELSE IF としてしまう)
(関連記事:ERB編集における代表的なエラー#お前はもう死んでいる分岐)
上の IF - ENDIF を簡略化したのがSIFになります。
直後の1行しか実行できない、などの特徴があります。例えば
注意しましょう。
2つ以上の処理を行う時は上の IF - ELSEIF - ELSE - ENDIF を使いましょう。
(関連記事:ERB編集における代表的なエラー#SIF文に複数の行を収めようとしてしまう)
また、eramakerでは
(Emueraではコメント行がきちんと無視されるので、条件式が真であるときのみ処理1が実行されます。)
(関連記事:ERB編集における代表的なエラー#SIFの直後にコメントを置くのは危険)
・IF と SIF の組み合わせ
条件式2だけが成立する時は処理2と3のみを実行します。
(条件式1が偽の場合は「IF 条件式2」の行だけを読み飛ばすので、「ENDIF が変な場所にある!」というエラーになる)
SIF の直後の行に IF や SIF などの分岐や反復を行う文は書かないようにしましょう。
SIF A == 0 PRINTFORML 変数Aは0です。SIF には ENDIF が必要ない、ELSEIF や ELSE が使用できない、
直後の1行しか実行できない、などの特徴があります。例えば
SIF 条件式 処理1 処理2と記述すると、条件式の真偽に関わらず処理2は実行されてしまうので
注意しましょう。
2つ以上の処理を行う時は上の IF - ELSEIF - ELSE - ENDIF を使いましょう。
(関連記事:ERB編集における代表的なエラー#SIF文に複数の行を収めようとしてしまう)
また、eramakerでは
SIF 条件式 ;コメント 処理1のように、SIF の直後にコメント行を入れると、必ず処理1が実行されてしまいますので、これも注意が必要です。
(Emueraではコメント行がきちんと無視されるので、条件式が真であるときのみ処理1が実行されます。)
(関連記事:ERB編集における代表的なエラー#SIFの直後にコメントを置くのは危険)
・IF と SIF の組み合わせ
IF 条件式1 SIF 条件式2 処理1 処理2 処理3 ENDIFと記述すると、条件式1と条件式2の両方が真である場合は処理1から3を全て実行し、
条件式2だけが成立する時は処理2と3のみを実行します。
SIF 条件式1 IF 条件式2 処理1 処理2 ENDIF逆にこう記述すると、条件式1が成立しない時にエラーが発生します。
(条件式1が偽の場合は「IF 条件式2」の行だけを読み飛ばすので、「ENDIF が変な場所にある!」というエラーになる)
SIF の直後の行に IF や SIF などの分岐や反復を行う文は書かないようにしましょう。
IF 文と似た機能を持つ構文として SELECTCASE - CASE - CASEELSE - ENDSELECT があります。
1つの数値変数の値によって処理を分岐させる時に使います。
例えば乱数によって処理を分岐させる時に便利な構文です。
CASE については次のような書き方をすることもできます。
CASE IS >= X は、数値変数が X 以上の場合に真となります。
また、CASE に書く条件は、カンマで区切って複数指定することができます。
よってこの SELECTCASE 文は、次の IF 文と同じ意味を持ちます。
1つの数値変数の値によって処理を分岐させる時に使います。
例えば乱数によって処理を分岐させる時に便利な構文です。
SELECTCASE A CASE 0 PRINTFORML 変数Aは0です。 CASE 1 PRINTFORML 変数Aは1です。 CASEELSE PRINTFORML 変数Aは0でも1でもありません。 ENDSELECTこれは、次の IF 文と同じ意味を持ちます。
IF A == 0 PRINTFORML 変数Aは0です。 ELSEIF A == 1 PRINTFORML 変数Aは1です。 ELSE PRINTFORML 変数Aは0でも1でもありません。 ENDIFSELECTCASE 文は、CASE の後ろに書かれた数値が SELECTCASE の直後に書かれた数値変数(この場合は A)と等しいかどうかを判定して分岐します。
CASE については次のような書き方をすることもできます。
SELECTCASE A CASE 1, 2, 3 PRINTFORML 変数Aは1、2、3のいずれかです。 CASE 4 TO 9 PRINTFORML 変数Aは4以上9以下です。 CASE IS >= 50 PRINTFORML 変数Aは50以上です。 CASE 10 TO 20, IS >= 40 PRINTFORML 変数Aは50以上ではありません。 PRINTFORML 変数Aは10以上20以下、あるいは40以上(かつ49以下)です。 CASEELSE PRINTFORML 変数Aは0以下(上の条件のいずれも満たさない)です。 ENDSELECTCASE X TO Y は、数値変数が X 以上 Y 以下の場合に真となります。
CASE IS >= X は、数値変数が X 以上の場合に真となります。
また、CASE に書く条件は、カンマで区切って複数指定することができます。
よってこの SELECTCASE 文は、次の IF 文と同じ意味を持ちます。
IF A == 1 || A == 2 || A == 3 PRINTFORML 変数Aは1、2、3のいずれかです。 ELSEIF A >= 4 && A <= 9 PRINTFORML 変数Aは4以上9以下です。 ELSEIF A >= 50 PRINTFORML 変数Aは50以上です。 ELSEIF (A >= 10 && A <= 20) || A >= 40 PRINTFORML 変数Aは50以上ではありません。 PRINTFORML 変数Aは10以上20以下、あるいは40以上(かつ49以下)です。 ELSE PRINTFORML 変数Aは0以下(上の条件のいずれも満たさない)です。 ENDIF(関連記事:Emueraについての補足#IFを使うべきかSELECTCASEを使うべきか)
三項演算子は、正確に言えば分岐構文ではありませんが、IF 文から派生してできた演算子なので、ここで説明します。
三項演算子は、次のような形を取ります。
TALENT:TARGET:0 が0の時に『(TARGETの呼び名)は処女ではありません。』と出力します。
三項演算子は、次のような形を取ります。
<代入先変数> = <条件式> ? <真の場合の代入値> # <偽の場合の代入値>例えば、変数 A が3以上の時に1、そうでない場合に0を変数 B に代入する操作は、IF 文を使うと次のようになります。
IF A >= 3 B = 1 ELSE B = 0 ENDIFこれを三項演算子で表現すると、次のように1行で書けます。
B = A >= 3 ? 1 # 0三項演算子は文字列変数に対しても使用できます。文字列を扱う場合は、三項演算子を ¥@ 〜 ¥@ で囲みます。
PRINTFORML %CALLNAME:TARGET%は\@ TALENT:0 ? 処女です。 # 処女ではありません。 \@上の文は、TALENT:TARGET:0 が0以外の時に『(TARGETの呼び名)は処女です。』と出力し、
TALENT:TARGET:0 が0の時に『(TARGETの呼び名)は処女ではありません。』と出力します。
REPEAT 数式 処理 RENDREPEAT - REND 間の処理を繰り返し実行します。
繰り返す回数はREPEATの直後にある数値、または数値変数に代入されている値です。A + 1 などの数式を置くこともできます。
例えば、
REPEAT 10 PRINTFORML あ RENDと記述すると、『あ』が10行表示されます。
・COUNT
変数 COUNT は、現在までに何回繰り返しを行ったかを格納しています。
REPEAT - REND 内の処理を最初に行う時はまだ1回目の繰り返しの途中(1回目の繰り返しが完了していない)なので
REPEAT 10 PRINTFORML 現在{COUNT}回目です。 RENDこう記述した場合、表示されるのは0回目から9回目となります。
COUNT がとる値は 0 から REPEAT の直後の数値 - 1 までと覚えておきましょう。
また、COUNTに数値を代入するのはエラーの原因となるので注意しましょう。
(関連記事:ERB編集における代表的なエラー#REPEATループに注意)
・REPEAT と IF, SIF の組み合わせ
REPEAT - REND の間にも IF や SIF を使用することができます。
REPEAT 10 IF COUNT == 5 PRINTFORML 6回目です? ELSE PRINTFORML {COUNT + 1}回目です ENDIF RENDと記述すると、COUNTが5、つまり6回目のみ最後に?が表示されます。
また、REPEAT - REND の間にもう一つ REPEAT - REND を使用する(入れ子にする)ことは
可能ですが、COUNT の値が2つ目の REPEAT - REND によって変更されてしまうため
そのままでは正常に動作しません。
REPEAT - REND を入れ子にしたい場合は、内側の REPEAT - REND の前後に COUNT の値を
退避・返還する処理を行うなどの工夫をするか、
(Emueraを使う場合は)後で説明する FOR - NEXT で代用する必要があります。
;REPEAT を入れ子にする例 REPEAT 10 COUNT:1 = COUNT REPEAT 10 処理 REND COUNT = COUNT:1 REND(関連記事:ERB編集における代表的なエラー#二重REPEAT文)
・CONTINUE と BREAK
REPEAT - REND 間で、以降の処理を行わずに次の繰り返しに入る場合には CONTINUE を、
以降の処理を行わず、繰り返し自体を終了させる場合には BREAK を使用します。
REPEAT 10 A = COUNT IF A == 5 CONTINUE ENDIF PRINTFORM {A}: RENDこれを実行すると、COUNT が5の時に CONTINUE が実行されるので、実際に表示されるのは
0:1:2:3:4:6:7:8:9:となります。また、
REPEAT 10 A = COUNT IF A == 5 BREAK ENDIF PRINTFORM {A}: RENDを実行すると、COUNT が5の時に BREAK が実行され REPEAT - REND から抜けるので、実際に表示されるのは
0:1:2:3:4:までになります。
FOR <カウンタ数値変数>, <数式>, <数式>[, <数式>] 処理 NEXTREPEAT - REND の機能強化版が FOR - NEXT です。
例えば、次の2つのスクリプトは全く同じ動作をします。
FOR COUNT, 0, 10 PRINTFORML {COUNT}回目 NEXT
REPEAT 10 PRINTFORML {COUNT}回目 RENDFOR の直後の<カウンタ数値変数>は REPEAT でいう COUNT に相当します。
REPEAT では繰り返しの回数を数える変数は COUNT に固定されていましたが、FOR ではこの変数を好きな変数に設定することができます。
カウンタ変数を別にすることで、REPEAT では面倒だったループの入れ子を簡単に実現できます。
;入れ子の例 FOR A, 0, 10 FOR B, 0, 10 処理 NEXT NEXTFOR の後ろに来る2番目の<数式>は、繰り返しを始める<カウンタ数値変数>の値を設定します。
3番目の<数式>で、繰り返しを終わる<カウンタ数値変数>の値を指定します。
例えば、
FOR COUNT, 3, 8 PRINTFORM {COUNT}: NEXTを実行すると、
3:4:5:6:7:と表示されます。
FOR の後ろの4番目の<数式>は、ループを1回繰り返すごとにカウンタ変数に加算される値を設定できます。省略すると自動的に1が設定されます。
例えば、
FOR COUNT, 0, 10, 2 PRINTFORM {COUNT}: NEXTを実行すると、
0:2:4:6:8:と表示されます。
なお、REPEAT - REND と同様に CONTINUE と BREAK も使用できます。
WHILE 条件式 処理 WEND条件式が真である間、ループを繰り返します。
例えば、次のスクリプトは「あ」を10行表示します。
A = 0 WHILE A < 10 PRINTFORML あ A += 1 WENDこのとき、「A += 1」の行を書き忘れると、変数Aの値は0のままになってしまうので、
A < 10 はいつまでも真のままとなり、無限ループに陥ってしまいますので注意が必要です。
WHILE - WEND でも CONTINUE と BREAK を使用できます。
DO 処理 LOOP 条件式条件式が真である間、ループを繰り返します。
WHILE - WEND との見た目の違いは条件式の位置が違う程度ですが、最初の繰り返しが必ず実行されるという特徴があります。
次の2つのスクリプトを見比べてみてください。
A = 0 WHILE A < 0 PRINTFORML あ WEND
A = 0 DO PRINTFORML あ LOOP A < 0WHILE 文はループの最初に条件式が真かどうか評価するので、この場合は PRINTFORML は一度も実行されません。
一方 DO - LOOP はループの最後に条件式を評価するので、この例では PRINTFORML が1回実行され、その後に式が評価されてループを抜けます。
(関連記事:Emueraについての補足#DO〜LOOP命令)
また、DO - LOOP 内で CONTINUE 文を呼ぶと、DO ではなく LOOP に飛ぶことにも注意してください。
次のスクリプトは(DO → CONTINUE → DO ではなく)DO → CONTINUE → LOOP 0 の順に実行されるので、無限ループにはなりません。
DO CONTINUE LOOP 0(関連記事:Emueraについての補足#CONTINUEの処理に関して)
いくつかの決まった処理を行わせたい時、それを予め別の場所に記述しておいて、
任意の場所から使えるようにしたものを関数と言います。
例として、変数Aの値を10倍にする関数を作ってみましょう。
それ以降の処理が関数で行う内容となります。
この結果、上は『変数Aは0です。』下は『変数Aは50です。』と表示されます。
また、関数を呼び出すのに JUMP <関数名> を使うこともあります。
CALL と JUMP の違いは関数での処理を実行した後、元の場所に戻るかどうかで、
CALL は戻る、JUMP は戻らないようになっています。
なお、同じ名前の関数が複数ある時はどれか1つだけが呼び出されます(イベント関数という特殊な関数を除く)。
関数の名前は他と同じにならないよう注意しましょう。
(関連記事:ERB編集における代表的なエラー#(関数が)かぶった!?)
任意の場所から使えるようにしたものを関数と言います。
例として、変数Aの値を10倍にする関数を作ってみましょう。
@A_TEN_TIMES A = A * 10@の後に半角英数と_(アンダーバー)で関数の名前を付けることができます。
それ以降の処理が関数で行う内容となります。
A = 0 CALL A_TEN_TIMES PRINTFORML 変数Aは{A}です。 A = 5 CALL A_TEN_TIMES PRINTFORML 変数Aは{A}です。作った関数を利用する(呼び出す)には CALL <関数名> と記述します。
この結果、上は『変数Aは0です。』下は『変数Aは50です。』と表示されます。
また、関数を呼び出すのに JUMP <関数名> を使うこともあります。
CALL と JUMP の違いは関数での処理を実行した後、元の場所に戻るかどうかで、
CALL は戻る、JUMP は戻らないようになっています。
なお、同じ名前の関数が複数ある時はどれか1つだけが呼び出されます(イベント関数という特殊な関数を除く)。
関数の名前は他と同じにならないよう注意しましょう。
(関連記事:ERB編集における代表的なエラー#(関数が)かぶった!?)
ある条件を満たした時、関数を途中で終わらせたいという場合は
RETURN <数値> と記述します。
また、RETURN 文で関数を終了し元の場所に戻ってくると、変数 RESULT が RETURN で指定された数値に書き変えられます。
この時、RESULT を関数の戻り値(返り値)といいます。
例えば、
なおEmueraでは、RETURN 文に数値変数や数式を指定できるほか、カンマで区切って複数の戻り値を指定することもできます。
RETURN <数値> と記述します。
@TEST SIF A == 0 RETURN 0 A = A * 5この場合、関数TESTを呼び出した時 A が0なら何も行われず、そうでなければ A が5倍されます。
また、RETURN 文で関数を終了し元の場所に戻ってくると、変数 RESULT が RETURN で指定された数値に書き変えられます。
この時、RESULT を関数の戻り値(返り値)といいます。
例えば、
@TEST2 IF A == 0 RETURN 0 ELSEIF A == 1 RETURN 1 ELSEIF A == 2 RETURN 2 ELSE RETURN 9 ENDIFという関数を作り、別の場所から呼び出すと
A = 0 CALL TEST2 PRINTFORML {RESULT} A = 2 CALL TEST2 PRINTFORML {RESULT} A = 3 CALL TEST2 PRINTFORML {RESULT}上から順に0, 2, 9が表示されます。
なおEmueraでは、RETURN 文に数値変数や数式を指定できるほか、カンマで区切って複数の戻り値を指定することもできます。
Emueraでは、関数は引数を取ることができます。引数とは、関数を CALL で呼び出す時に関数に渡すことのできる変数です。
上に書いた関数 @TEST2 を、引数を取るように書き換えたのが次の例文です。
引数は複数取ることができ、そのような場合は ARG, ARG:1, ARG:2, …のように定義します。
上に書いた関数 @TEST2 を、引数を取るように書き換えたのが次の例文です。
@TEST2, ARG IF ARG == 0 RETURN 0 ELSEIF ARG == 1 RETURN 1 ELSEIF ARG == 2 RETURN 2 ELSE RETURN 9 ENDIF呼び出すときは次のようにします。
CALL TEST2, 0 PRINTFORML {RESULT} CALL TEST2, 2 PRINTFORML {RESULT} CALL TEST2, 3 PRINTFORML {RESULT}CALL TEST2, 0 を実行すると、ARG に0が代入され、関数内で ARG を参照することができます。
引数は複数取ることができ、そのような場合は ARG, ARG:1, ARG:2, …のように定義します。
@TEST3, ARG, ARG:1, ARG:2 (略)
CALL TEST3, 0, 7, 3引数には文字列変数も取ることができ、その場合は ARGS を使います。
A, B などの一文字変数や COUNT など多くの変数は、プログラム全体で同時に一つの変数を共通で使用します。
ですが、それが原因でバグが発生することがあります。
この例では FUNC 内の FOR ループのカウンタ変数を COUNT:1 にすれば問題は解決しますが、
1つのバリアント内で使われる関数は1000個を軽く超えるので、どこかで必ずこういった問題が発生します。
そこで、ある関数の中でしか使えない変数(ローカル変数)を用意すれば、この問題は解決するはずです。
そのローカル変数が LOCAL と LOCALS です。次の例を見てください。
「EVENTFIRST の中で使っている LOCAL」と「FUNC001 の中で使っている LOCAL」は別物として扱われるので、
PRINTFORML 文の結果は「123」と出力されます。
なお、LOCALS は LOCAL の文字列変数バージョンです。
先に説明した ARG と ARGS もローカル変数として扱われます。
ですが、それが原因でバグが発生することがあります。
@MAIN FOR COUNT, 0, 10 CALL FUNC NEXT @FUNC FOR COUNT, 0, 3 (何か処理) NEXT上の例文で MAIN 関数を実行すると、FUNC が呼ばれるたびに COUNT が3にセットされるので、無限ループに陥ります。
この例では FUNC 内の FOR ループのカウンタ変数を COUNT:1 にすれば問題は解決しますが、
1つのバリアント内で使われる関数は1000個を軽く超えるので、どこかで必ずこういった問題が発生します。
そこで、ある関数の中でしか使えない変数(ローカル変数)を用意すれば、この問題は解決するはずです。
そのローカル変数が LOCAL と LOCALS です。次の例を見てください。
@EVENTFIRST LOCAL = 123 CALL FUNC001 PRINTFORML {LOCAL} @FUNC001 LOCAL = 567 RETURN一見すると LOCAL という同じ変数に数値を代入しているように見えますが、
「EVENTFIRST の中で使っている LOCAL」と「FUNC001 の中で使っている LOCAL」は別物として扱われるので、
PRINTFORML 文の結果は「123」と出力されます。
なお、LOCALS は LOCAL の文字列変数バージョンです。
先に説明した ARG と ARGS もローカル変数として扱われます。
他の言語でプログラミングをしたことのある人には特に注意して頂きたいのですが、
・LOCAL や ARG は関数が呼び出されたタイミングで初期化されない
・関数が呼び出されるたびに同じ LOCAL, ARG を使いまわす
の2点に気をつける必要があります。
この特徴は、関数の再帰などを利用した場合に注意が必要です。
「LOCAL はローカル変数で呼び出し時に0に初期化されるので、LOCAL は1のままで無限ループになり、そのうちスタックが溢れるはず」
と思われるかもしれません。しかし実際に SAMPLE を呼び出すと、
最初の外部からの呼び出しでは SAMPLE が9回再帰呼び出しされ、2回目以降は再帰呼び出しがされません。
なぜかといえば、最初の呼び出しで LOCAL に1が代入されると、次に再帰で呼び出された時に LOCAL が0で初期化されず、1という値が保持されるからです。
また再帰が完了して SAMPLE 関数から抜けた後も、LOCAL の最終的な値である10が保持され続けるので、これ以降は外部から呼び出されても再帰はされません。
ARG についても同様です。
(関連記事:Emueraについての補足#LOCAL変数であっても避けるべきこと)
・LOCAL や ARG は関数が呼び出されたタイミングで初期化されない
・関数が呼び出されるたびに同じ LOCAL, ARG を使いまわす
の2点に気をつける必要があります。
この特徴は、関数の再帰などを利用した場合に注意が必要です。
@SAMPLE LOCAL += 1 IF LOCAL < 10 CALL SAMPLE ENDIF上のコードは、プログラミング経験のある人からしてみれば
「LOCAL はローカル変数で呼び出し時に0に初期化されるので、LOCAL は1のままで無限ループになり、そのうちスタックが溢れるはず」
と思われるかもしれません。しかし実際に SAMPLE を呼び出すと、
最初の外部からの呼び出しでは SAMPLE が9回再帰呼び出しされ、2回目以降は再帰呼び出しがされません。
なぜかといえば、最初の呼び出しで LOCAL に1が代入されると、次に再帰で呼び出された時に LOCAL が0で初期化されず、1という値が保持されるからです。
また再帰が完了して SAMPLE 関数から抜けた後も、LOCAL の最終的な値である10が保持され続けるので、これ以降は外部から呼び出されても再帰はされません。
ARG についても同様です。
@SAMPLE2, ARG SIF ARG >= 10 RETURN CALL SAMPLE2, ARG + 1 PRINTVL ARG上のコードを書き、CALL SAMPLE2, 0 と呼び出すと10が10回表示されます。
(関連記事:Emueraについての補足#LOCAL変数であっても避けるべきこと)
erabasicにおいて、値を返す命令の戻り値は RESULT を経由して受け取ります。
例えば、与えられた数式の絶対値を返す ABS という命令を使って、
変数A の絶対値を LOCAL に格納するには次のように記述します。
式中関数では、引数を (A) のように丸括弧で囲んで呼び出します。
引数が複数ある場合は (A, B, C) のように丸括弧の中でカンマで区切って書きます。
逆に引数がない場合は () と丸括弧だけを書きます。引数がなくても丸括弧は省略できません。
文字列を返す命令でも、同様の書き方ができます。
式中関数の一覧はEmuera Wikiで確認できます。
例えば、与えられた数式の絶対値を返す ABS という命令を使って、
変数A の絶対値を LOCAL に格納するには次のように記述します。
ABS A LOCAL = RESULTこれに対し、ABS という名前の「式中で使える関数(以下「式中関数」と書きます)」を使うと、上のスクリプトを次のように書くことができます。
LOCAL = ABS(A)「式中関数」の名前通り、代入式の中から直接関数を呼び出し、RESULT を介さずに戻り値を LOCAL に代入することができます。
式中関数では、引数を (A) のように丸括弧で囲んで呼び出します。
引数が複数ある場合は (A, B, C) のように丸括弧の中でカンマで区切って書きます。
逆に引数がない場合は () と丸括弧だけを書きます。引数がなくても丸括弧は省略できません。
文字列を返す命令でも、同様の書き方ができます。
STRLENS STR:0 IF RESULT > A SUBSTRING STR:0, A, 1 LOCALS:0 = %RESULTS:0% ENDIF
IF STRLENS(STR:0) > A LOCALS:0 = %SUBSTRING(STR:0, A, 1)% ENDIF上の2つの例文は、同じ動作をします。
式中関数の一覧はEmuera Wikiで確認できます。
式中関数は自分で定義することができます。
関数を定義する @ 行の直後に #FUNCTION と書き、RETURN を RETURNF に置換するだけで、その関数は式中関数になります。
ただし、RETURNF の書き方が他の命令(PRINTFORM など)とは異なるので注意してください。
(関連記事:Emueraについての補足#文字列とRETURNFに関する面妖な仕様)
関数を定義する @ 行の直後に #FUNCTION と書き、RETURN を RETURNF に置換するだけで、その関数は式中関数になります。
;下の行は @TEST2, ARG と書いてもよいが、慣習的にこう書くことが多い @TEST2(ARG) #FUNCTION IF ARG == 0 RETURNF 0 ELSEIF ARG == 1 RETURNF 1 ELSEIF ARG == 2 RETURNF 2 ELSE RETURNF 9 ENDIF呼び出すときは次のようにします。
PRINTFORML {TEST2(0)} PRINTFORML {TEST2(2)} PRINTFORML {TEST2(3)}文字列を返す式中関数を作りたい場合は、#FUNCTIONS と書きます。
ただし、RETURNF の書き方が他の命令(PRINTFORM など)とは異なるので注意してください。
(関連記事:Emueraについての補足#文字列とRETURNFに関する面妖な仕様)
主に選択肢による分岐で使用されるのがラベルとキー入力です。
この場合、0を入力すれば処理1、1を入力すれば処理2を実行します。
0でも1でもない数値を入力した場合、RESULT != 0 && RESULT != 1 が
成立するため GOTO INPUT_LOOP が実行されます。
GOTO (ラベル名)は $(ラベル名)の処理に移動するもので、CALL や JUMP と @ との
関係に似ていますが、GOTO と $ に関しては同じ関数内にある必要があります。
GOTO INPUT_LOOP で $INPUT_LOOP に移動すると再び INPUT を実行するため、
この一連の処理は0か1かを入力するまで繰り返されることになります。
また、一つの関数内で複数の $ と GOTO の組み合わせを使用すると
『IF に対応しない ELSEIF, ELSE, ENDIF が〜』というエラーが発生することがあります。
この場合、2つ目の入力処理を別の関数に移すなどの工夫をしましょう。
(関連記事:ERB編集における代表的なエラー#GOTOで飛ぶと自分がいた場所を忘れます。)
(関連記事:ERB編集における代表的なエラー#同じGOTOラベル名は使わない。(INPUT_LOOPに関するバグ))
PRINTFORML 選択してください PRINTFORML [0] 選択肢1 PRINTFORML [1] 選択肢2 ;Emueraは上のような[ ]で囲まれた数字を見つけると自動的にボタンに変換してくれます $INPUT_LOOP INPUT IF RESULT != 0 && RESULT != 1 GOTO INPUT_LOOP ELSEIF RESULT == 0 処理1 ELSEIF RESULT == 1 処理2 ENDIFINPUT はキー入力(またはボタン操作)を待ち、入力された数値を RESULT に格納します。
この場合、0を入力すれば処理1、1を入力すれば処理2を実行します。
0でも1でもない数値を入力した場合、RESULT != 0 && RESULT != 1 が
成立するため GOTO INPUT_LOOP が実行されます。
GOTO (ラベル名)は $(ラベル名)の処理に移動するもので、CALL や JUMP と @ との
関係に似ていますが、GOTO と $ に関しては同じ関数内にある必要があります。
GOTO INPUT_LOOP で $INPUT_LOOP に移動すると再び INPUT を実行するため、
この一連の処理は0か1かを入力するまで繰り返されることになります。
また、一つの関数内で複数の $ と GOTO の組み合わせを使用すると
『IF に対応しない ELSEIF, ELSE, ENDIF が〜』というエラーが発生することがあります。
この場合、2つ目の入力処理を別の関数に移すなどの工夫をしましょう。
(関連記事:ERB編集における代表的なエラー#GOTOで飛ぶと自分がいた場所を忘れます。)
(関連記事:ERB編集における代表的なエラー#同じGOTOラベル名は使わない。(INPUT_LOOPに関するバグ))
キャラの追加と削除には、ADDCHARA と DELCHARA を使用します。
ここまでの処理でキャラ番号1、5、9のキャラが追加され、
次に登録番号3番、つまりキャラ番号9のキャラが削除、
その後登録番号1番、つまりキャラ番号1番のキャラが削除され、
キャラ番号5番のキャラのみが残る状態になります。
DELCHARAを続けて使用する際には、削除された登録番号より後のキャラは
それぞれ前に詰められることに注意しましょう。
また、キャラの追加・削除をする場合は調教中のキャラ、助手などの状態を
確認しましょう。例えば助手をやっていたキャラがDELCHARAで削除されても
助手の登録番号を保存しているASSIは変化しません。しかし全体の登録番号は
前にずれてしまうため、助手になる条件を満たしていないキャラが助手に
なってしまうこともあります。
ADDCHARA 1 ADDCHARA 5 ADDCHARA 9Emueraでは次のように書くことができます。
ADDCHARA 1, 5, 9ADDCHARAではCSVにあるキャラ番号が参照されます。
DELCHARA 3 DELCHARA 1DELCHARAではキャラ番号ではなく、キャラの登録番号が参照されます。
ここまでの処理でキャラ番号1、5、9のキャラが追加され、
次に登録番号3番、つまりキャラ番号9のキャラが削除、
その後登録番号1番、つまりキャラ番号1番のキャラが削除され、
キャラ番号5番のキャラのみが残る状態になります。
DELCHARAを続けて使用する際には、削除された登録番号より後のキャラは
それぞれ前に詰められることに注意しましょう。
また、キャラの追加・削除をする場合は調教中のキャラ、助手などの状態を
確認しましょう。例えば助手をやっていたキャラがDELCHARAで削除されても
助手の登録番号を保存しているASSIは変化しません。しかし全体の登録番号は
前にずれてしまうため、助手になる条件を満たしていないキャラが助手に
なってしまうこともあります。
BAR(BARL)を使用することで数値の表示を視覚的に行うことができます。
BAR (数値or変数),(数値or変数),(グラフの長さ)のように記述し
Aに現在の値、Bにその最大値を入れることで、現在の値が最大値の
どのくらいの割合かを示す際によく使用されます。
BARLでは表示後に改行されることも覚えておきましょう。
BAR (数値or変数),(数値or変数),(グラフの長さ)のように記述し
A = 80 B = 100 BAR A, B, 10では
[********..]と表示されます。
Aに現在の値、Bにその最大値を入れることで、現在の値が最大値の
どのくらいの割合かを示す際によく使用されます。
BARLでは表示後に改行されることも覚えておきましょう。
era basicでは変数などは全て整数で処理されますが、例外として
TIMESを使用することで小数の計算を行うことができます。
なお、TIMESを使用した結果が小数になっても整数に丸められます。
TIMESを使用することで小数の計算を行うことができます。
A = 1000 TIMES A, 1.5これで変数Aは1000×1.5の1500となります。
なお、TIMESを使用した結果が小数になっても整数に丸められます。