概要
Opcodeは中間言語です。
C言語やBASICなどの高級言語と機械語の中間の言語です。
高級言語のような読みやすさがあり、ソースコードを復元しやすいのが特徴です。
Opcodeの構成要素
変数 … 0@ , $300 等、変化する値
定数 … 10 , 3.14 等、変化しない値
関数 … 02F6: 0@ = sine 1@ 等、データを渡すと何らかの仕事をし、値を返す要素
配列 … &0(0@,1i) 等、同じ性質の変数を並べた物
制御文 … if , jump 等、プログラムの流れを制御する要素
演算子 … + , - 等、変数などに対して働きかける要素
コメント … //~ 等、ソースプログラムの中に書き込める注釈
それでは簡単に説明をしていきます。
コードの例
00A5: 0@ = create_car #PONY at 1.0 2.0 3.0
- 00A5:
コード番号 と言えばいいのでしょうか?
コードにはこのような4桁の16進数が付いています。これは変更できません。
命令の種類を表す重要な部分です。「付く物」と覚えておいてください。
一部Sanny Builderで省略することが出来る物もあります。
比較などの場合、先頭の0を8に変えると否定の意味になります。
番号が分からないという方、Sanny Builderにちゃんとあります。
ツールバー Tools → IDE tools → Opcode Search (Ctrl+Alt+2)
- = create_car #PONY at 1.0 2.0 3.0
「= create_car , at」の部分は飾りです。全て省いて「00A5: 0@ #PONY 1.0 2.0 3.0」でも機能しますが、これではわかりにくいので付けられています。
#PONY の部分で生成する車を指定しています。
後ろの 1.0 2.0 3.0 は座標で、大抵の場合はX,Y,Zの順に書かれています。
- 0@
変数 0@ に右式を代入。
この場合、座標 [1.0, 2.0, 3.0] に出した#PONYが代入されます。
つまり、このコードは
「座標X1.0, Y2.0, Z3.0に#PONYを出せ」という命令になります。
この命令のあとに
020B: explode_car 0@ // versionA
と命令してやることで0@、つまり上で代入したPonyが爆発するわけです。
定数・変数
文字通り、「変化する数」です。
演算したり 関数の引数、分岐のための比較など とても重要な働きをします。
Opcodeの変数には4種類あり、整数、小数、短文字列、長文字列を指定できます。
定数 | ローカル変数 | グローバル変数 | メモリ変数 | |
---|---|---|---|---|
整数 | 10 | 0@ | $100 | &100 |
小数 | 3.14 | |||
短文字列 | 'ABC' | 0@s | s$100 | s&100 |
長文字列 | "This is a pen." | 0@v | v$100 | v&100 |
定数
整数 | -2147483648~2147483647 |
---|---|
少数 | -3.402823466E+38~3.402823466E+38 |
短文字列 | 7文字まで |
長文字列 | 15文字まで |
ローカル変数
0@~31@まで利用可。その他にタイマー変数32@と33@が存在し、これらには1フレームの時間*1が加算されていく。
ミッションスレッドでは1023@まで使用可能。
どちらも同スレッド内のみで利用可能。
グローバル変数
$0~$65535まで利用可。
配列を使えば$-2147483648 - $2147549182まで参照可能。
main.scmを含む全スレッドで共通。そのため、main.scmと重複するとエラーが出る可能性がある。
→main.scmで使用する主なグローバル変数
整数(int)・小数(float)
Opcodeでは整数と少数は別物です。
計算する場合は、整数または小数同士に揃えなければ計算できません。
またその都合上、変数同士の代入・計算・比較は必ずOpcodeを表記しなければいけません。
(片方が定数であればOpcodeを省略して表記することもできる)
文字列
短文字列と長文字列があります。
短文字列は7文字まで、長文字列は15文字まで使用可能です。
ただし、短文字列変数は変数を2つ分、長文字列変数では変数を4つ分使用する点に注意。
例えば0@sは0@~1@を、0@vは0@~3@を使用するため、気をつけて使わないと変数を上書きしてしまったり、逆に文字列を壊してしまいます。
関数 (ここでは演算に関する関数を記述します。)
使用可能な関数
無い物は自分で関数を作成する必要がある。
- sine
- 02F6, 02F8など。
古いバージョンのSBのOpcodeSearchではcosineとなっているが、間違い。 - cosine
- 02F7, 02F9など。
こちらも古いバージョンのSBのOpcodeSearchではsineとなっているが、間違い。 - 平方根
- 01FBなど。
- 整数・小数の絶対値
- 0094など。
- 単位変換(メートル→フィート)
- 0425 と 042D の2つ存在する。前者がfloat用、後者がint用。
「meters to_feet」「metric to_imperial」と何故か微妙に表記揺れしているが意味は同じ。 - 乱数生成
- 0208, 0209など。
配列
全ての変数は配列として扱うことが出来ます。
配列について詳しいことはこちらへ→配列について
書式
配列名(インデックス変数,サイズ 型) &0(0@,1i) 型 i …4バイト整数 f …4バイト小数 s …8バイト短文字列 v …16バイト長文字列
Sanny Builderは配列宣言もできるようです。
書式
var 配列名: array サイズ of 型 end
制御文
プログラムの流れを変える要素。構文も交えて説明します。
ラベル・ジャンプ・サブルーチン
ラベル
:label
スクリプトの特定場所に名前を付けます。
これ自体は何もしませんが、ジャンプ命令やサブルーチン命令でその場所へと飛んでこれるようになります。
ジャンプ
jump @label
指定したラベルへと移動し、そこから処理を続けます。
サブルーチン
gosub @label
ジャンプ命令と同じですが、移動する前に現在の場所を記憶しておきます。
飛んだ先の処理でreturn命令を使う事によって記憶していた元の場所へと戻り、そこから処理を再開できます。
条件分岐
if (条件)
指定した条件が真であるかどうかによって処理を分岐させられます。
条件には比較演算やチェックコードが入ります。
- 書式1
if <N> 条件1 条件2 : 条件8 jf @ラベル名 (偽処理) 真処理
<N>には or または and を指定でき、指定した場合は一つのifに最大8つまで条件を指定できるようになります。
or: 指定した条件のうち、どれか一つでも真ならば真処理を行う。
and: 指定した条件の全てが真の時にのみ真処理を行う。一つでも偽なら偽処理に飛ぶ。
jf @ラベル名: 偽ならば<ラベル名>へジャンプする。
- 書式2 (if-then-else-end)
- この書式はSanny Builder3独自のものであるため、コンパイルした物をデコンパイルしたとき同じ形に戻りません。
if <N> 条件 then 条件が真の場合の処理 else 条件が偽の場合の処理 end
elseと偽の場合の処理は省略できます。
例
:START : if and 0039: 0@ == 1 0449: actor $PLAYER_ACTOR in_a_car jf @START 03C0: 10@ = actor $PLAYER_ACTOR car 04BA: set_car 10@ speed_to 100.0 :
「もし、変数0@の中身が整数の1で かつ $PLAYER_ACTORが乗り物に乗っていたら、変数10@に$PLAYER_ACTORが乗っている乗り物を代入し、その乗り物のスピードを100m/sにする。
変数0@が1ではなかったり、$PLAYER_ACTORが乗り物に乗っていなければラベルSTARTへジャンプする。」
というプログラムになります。
and/orの注意点
and や or を指定したifではそれ以外の判定ができません。
つまり「条件1と2のどちらか、及び条件3を満たした場合」みたいなことができません。
どうしてもやりたい場合は、以下のようにまずどちらか一方の判定をし、その後でもう片方を判定するように書く必要があります。
if or 条件1 条件2 then if 条件3 then 真処理 end end
ループ処理
for-end
一定の回数、同じ処理を繰り返します。
この書式はSanny Builder3独自のものであるため、コンパイルした物をデコンパイルしたとき同じ形に戻りません。
書式
for 変数 = 初期値 to(downto) 終値 step 増加数 処理 (break) end
変数に初期値を代入し、増加数分を変数に加算しつづけ、終値に達した場合に処理を抜けます。
stepは省略可能で、省略した場合は1になります。
toでは増加数が加算され、downtoでは増加数分減算されます。
例
for 0@ = 0 to 4 020C: create_explosion_with_radius 0 at 0.0 0.0 0.0 0001: wait 0 end
1ループ目 0@に0を代入。座標 0.0 0.0 0.0に爆発作成 0@は0なので戻る。
2ループ目 0@に1を加算。座標 0.0 0.0 0.0に爆発作成 0@は1なので戻る。
3ループ目 0@に1を加算。座標 0.0 0.0 0.0に爆発作成 0@は2なので戻る。
4ループ目 0@に1を加算。座標 0.0 0.0 0.0に爆発作成 0@は3なので戻る。
5ループ目 0@に1を加算。座標 0.0 0.0 0.0に爆発作成 0@は4なので戻らずループを抜ける。
結果として、座標 0.0 0.0 0.0に5回爆発作成する。
while-end
条件が真の間、同じ処理を繰り返します。
この書式はSanny Builder3独自のものであるため、コンパイルした物をデコンパイルしたとき同じ形に戻りません。
''書式
while 条件 処理 end
条件として true を指定する事もできます。
この場合無限ループとなり、中で jump や break を使用して自分で脱出しない限りずっとループし続けることになります。
例
while 8248: not model #AK47 available 0001: wait 0 end
「8248: not model #AK47 available」
これは#AK47 が読み込めていると真を返す「0248: model #AK47 available」の否定形で、つまり #AK47 が読み込めていない時に真を返します。
つまり、この例文は「モデル#AK47が読み込まれるまでwait 0をし続ける」という意味になります。
repeat-until
条件が偽の間、同じ処理を繰り返します。
条件の真偽がwhileと逆なので注意。
この書式はSanny Builder3独自のものであるため、コンパイルした物をデコンパイルしたとき同じ形に戻りません。
書式
repeat 処理 until 条件
見ての通り、中の処理を行った後に条件判定を行うため、必ず一度は処理がなされるというのがwhileとの大きな違いです。
例
repeat 0001: wait 0 ms until 0248: model #AK47 available
上記のwhileの例文と同じく「モデル#AK47が読み込まれるまでwait 0をし続ける」という意味。
whileとは条件が逆になる(真になった時にループを抜ける)点に注意。
演算子
計算をするために必要な記号
整数または小数同士でなければ計算不可能。
プログラム上では、「=」は等しいという意味ではありません。
殆どのプログラム言語では左に変数 右に変数または定数を置き、左式に右式を代入という意味になります。
0006: 0@ = 1 ならば、0@に1を代入という意味です。
また、定数を小数で扱いたい場合は「1」と表記するのではなく「1.0」と表記して下さい。
演算 | 演算子 | 比較 | 演算子 | |
---|---|---|---|---|
代入 | = | 等しい | a == b | |
加算 | += | 大なり | a > b | |
減算 | -= | 小なり | b > a | |
乗算 | *= | 以上 | a >= b | |
除算 | /= | 以下 | b >= a |
上の表を見て「アレッ?」と思った方もいるでしょう。
実はOpcodeの比較命令には「等しい(==)」「大なり(>)」「以上(>=)」の3つしか存在しません。
そのため、それ以外の比較をしたい場合は左式と右式を入れ替えたり、Opcodeの先頭を 8 に変えて真偽を反転させたり等する必要があります。
コメント
何がしたいか、その処理に何の意味があるかといった注釈を入れたい場合に使います。
コンパイル時には無視されるため、デコンパイルした後のソースコードにはコメントは残りません。
書式1
//注釈 //「//」を記述した後ろ一行はすべて注釈として扱われます。 //基本的にはこちらを使います。
書式2
{ 注釈 複数行を一度にコメント化したい場合はこちらを使うと楽です。 }
書式3
/* 注釈 書式2と同じですが、コメント内に } を含めたい場合はこちらを使うと良いでしょう。 */