ステートメントとは命令のひと塊のことです。
制御文以外のステートメントの区切りには「;」(セミコロン)が必要です。
「;」は区切りですので、最後の文には不要ですが、書くことを推奨します。
let r = 0; let px = GetPlayerX(); //↑のようにステートメントの最後には //「;」が必須です。
予約語に指定されている単語は、変数名やサブルーチン名に使えません。
以下の単語が予約語です。
alternative、ascent、break、case、descent、else、function、
if、in、local、loop、real、return、let、others、
sub、task、times、while、yield
また、次の変数やサブルーチンが、組み込みで用意されています。
これらも変数名やサブルーチン名に使わないようにしてください。
add、append、compare、concatenate、divide、false
index、length、multiply、not、negative、pi、power
predecessor、remainder、result、slice、
successor、subtract、true
a ~ b | concatenate(a, b) |
a + b | add(a, b) |
a - b | subtract(a, b) |
a * b | multiply(a, b) |
a / b | divide(a, b) |
a % b | remainder(a, b) |
a ^ b | power(a, b) |
a[b] | index(a, b), index!(a, b)←左辺値の時 |
a[b..c] | slice(a,b,c) |
! a | not(a) |
+ a | a |
- a | negative(a) |
a++ | a = successor(a) |
a-- | a = predcessor(a) |
(|a|) | a = absolute(a) |
true | 論理型の真を返す関数 |
false | 論理型の偽を返す関数 |
pi | πを返す |
変数とは数値等を入れておく箱のようなものです。
real, char, booleanまたそれらの配列が使えます。
realは数値です。
charは文字です。charの配列が文字列です。
booleanは真偽値です。
1, 1.0, 0.001, 100 …real型
true,false…boolean型
'a', 'b', 'あ' …char型(内部的にwchar_tで格納するため全角文字もOKです)
ただし、型を明示的に扱うことはできません。自動で判断されます。
変数宣言は「let」を用います。
「real」でも変数を宣言できますが実体は「let」と同じです。
let a; //aという変数を宣言 let a = 32; //aという変数を宣言(real型)して、32で初期化 let b = true; //bという変数を宣言(boolean型)して、trueで初期化 let str = "もじれつ";//strという変数を宣言(char型)して、"もじれつ"で初期化なお、C言語と違い並べて宣言することはできません。
let a,b; //×
変数を扱うとき、変数名1つにつき1つの値を割り当てられました。
ことろがこれでは10、20個など多くのデータを使うとき、
それだけの数の変数を準備する必要があり、宣言に手間がかかります。
そこで同じタイプの変数をまとめて扱うために配列というものが準備されています。
配列を使うときは次のように宣言します。
let a = [1,2,3];// …realの配列 let str = "文字列";// …charの配列以下に配列の使用例を示します。
//配列の宣言 let a = [2, 3, 5];//配列aを[2,3,5]で初期化 //配列へのアクセス //[x]で配列のx番目の値にアクセスします //添え字は0からです。 let b = a[0];//bは2になります a[0] = 9;//配列aは[9, 3, 5]になります。 let str = "あいうえお"[2];//strは'う'になります。 //配列の結合 //「~」演算子で配列の結合を行えます let c = [32, 64, 96]; a = a ~ c;//aは[9, 3, 5, 32, 64, 96]になります。 //配列のテーブルをループで作成する場合 //配列を結合しながらテーブルを作成できます let d = [];//dは配列 ascent(i in 0..100) {//配列dを[0 1 2 … 98 99]で初期化 d = d ~ [i];//配列の結合 i++; } //配列のスライシング //配列に対して[x..y]のようにかくと、 //要素のx番目からy番目を切り出します //ただしy番目の要素は含みません let e = [0, 1, 2, 3, 4]; let f = e[2..4];//fは[2,3]になります //配列を三項演算子の代わりに使う let g = [7, -5][b == 10];//bが10ならgは-5になります //配列のサイズを取得する let h = [1, 2, 3, 4, 5]; let i = length(h);//iは5になります //配列要素の削除 let j = [10, 20, 30, 40]; j = erase(j, 0);//最初の要素を削除します //j = [20, 30, 40]になります
配列のコンストラクタは定数に限りません。
if(a == 0){ b = c }else if(a == 1){ b = d }のような記述は、
aが0と1しか取らない場合に限り、b = [c, d][a]のように書けます。
突然"["を始めた時は配列の作成で、何かの後に続けた時は要素へのアクセスです。
JavaScript等は"+"演算子で結合も行いますが、
このスクリプトでは配列同士を足し算すると、
[1, 2, 3] + [4, 5, 6] == [5, 7, 9]のような演算になります。
全ての中括弧(「{...}」)はローカルスコープを導入します。
全ての中括弧において、中で宣言したものは外では使えません。
純粋にローカルスコープ「のみ」を利用したい場合にlocal文を用います。
いわば、何もしない制御文です。
(このスクリプトでは、C言語のように、突然中括弧を開始することはできません)
同名の変数を宣言しない限り、親の変数は全て触れます。
//ここで宣言した変数は全域で有効 let a;//変数aは全ての「@〜」内で有効」 @Initialize { a = 2;//変数aにはアクセスできる let x = 1;//ここで宣言すると@Initializeの最後まで有効 local { //ここで宣言したxはlocal文最後の「}」まで有効 let x = 3; //ここではxは3 a = x;//aには3が入る } //ここではxは1 let c = x;//cには1が入る } @MainLoop { a = 5;//変数aにはアクセスできる //ここでは変数xにアクセスできない } @Finalize { //while、loop、ifの「{...}」も同様にローカルスコープが導入される let d = 10; loop(5) { let e = d;//dにはアクセス可能 } //ここではeにアクセスできない }
変数に値を代入したり、式を記述するときには下記の記号が使えます。
なお「=」は比較ではなく、代入を表します。例えば
a = 2;
は「aは2に等しい」のではなく、「aに2を代入する」という意味です。
let a; let b; a = 32 + 2; //「+」で和を表します。aは34になります。 b = a - 30; //「-」で差を表します。bは4になります。 a = 2 * 3; //「*」で積を表します。aは6になります。 b = 72 / a; //「/」で商を表します。bは12になります。 a = 32 % 3; //「%」は商の余りです。aに32を3で割った余りを代入という意味になります。aは2になります。 b = a ^ 4; //「^」は累乗です。bにaの4乗を代入という意味になります。bは16になります。 b = 3 ^ 3 ^ 3; //「^」だけ、右結合の演算子です。3^3^3は3^(3^3)と解釈され729ではなく19683になります /* 演算子の優先順位は、 「( ... )」 > 「^」「[]」>「!」「+」「-」 (単項) >「*」「/」「%」 > 「~」「+」 「-」 (二項) です。 */ let c = ((b * 3 - 2)%(a + 2 ^ 2)) / 2;//cは2になります。 //以下のような書き方もできます a++;//a = a + 1と同じ a+=5;//a = a + 5と同じ
比較式は、「==」 「!=」 「>」 「>=」 「<」 「<=」が使えます。
ただし、異なる型同士を比較した場合エラーになります。
論理式は、「!」 「&&」 「||」が使えます。
「&&」と「||」はショートサーキット評価がなされます。
左辺だけで結果が確定した場合右辺は計算されません。
たとえば、0 == 1 && func(x)とすると、
0 == 1だけで真偽の偽なのは確定しますのでfuncは呼ばれません。
「!」は否定です。真なら偽、偽なら真を返します。
条件分岐です。与えられた条件によって処理を変えたいときに使います。
/* 基本的な条件式の記述 「a == b」 :aがbと等しい 「a > b」 :aがbより大きい 「a >= b」 :aがb以上 「a < b」 :aがbより小さい 「a <= b」 :aがb以下 */ //ifの使い方 if(a == 2 + b * 5) { //aが「2 + b * 5」であれば実行される部分 } //「&&」は論理積を表します。 if(a > 50 && b < 30) { //aが50より大きく、bが30より小さいときに実行される } //「||」は論理和を表します。 if(c >= 2 || b <= 30) { //cが2以上またはbが30以下のときに実行される } //else は「でなければ」といったような意味です if(c == 4) { //cが4であれば実行される } else if(d == 6) { //cが4ではなく、dが6の時実行される } //alternativeの使い方 //C言語のswitchに似た分岐構文です alternative(a) case(0) { //aが0の時に実行される } case(3, 5) { //aが3もしくは5の時に実行される } others { //それ以外の時実行される } //C言語と違いステートメントが1つでも「{」「}」の省略はできません。 //必ず「{」「}」で囲む必要があります。
処理を繰り返したいときに使います。
ループは予約語loopで構成し、while, times, ascent, descentなどのループ条件を付加できます。
構文は
loop(n){ }
times(n) loop{ }
while(条件) loop{ }
ascent(let i in x..y) loop{ }
descent(let i in x..y) loop{ }
です。times、while、ascent、descentのloopは省略できます。
//loopは、()の中に繰り返したい回数を記述します。 loop(10) { //10回繰り返します。 } //回数を省略すると無限ループします。 //必ずbreak、returnで抜けてください。 let a = 5; loop { if(a == 5) { break; } a++; } //timesも()の中に繰り返したい回数を記述します。 times(5) { //5回繰り返します。 } //whileは与えられた条件が真の間、範囲を繰り返し実行します。 let a = 0; while(a < 360) {//aが360より小さい間繰り返す。 a++; }; //while中が無限ループになると //アプリケーションが動かなくなるので注意してください。 while(true) { //常に条件が真になり、無限ループになるので危険 } //インデックス付きのループもつくれます //ascent(let i in x..y) loop{} //descent(let i in x..y) loop{} //i が x から y まで変化します。ただし y は含みません。 //ascentは値が増加、descentは減少します。 ascent( let a in 0..10) loop { //array[a] = xxx;配列にアクセスしたりするとき便利です } //ascent、descentともにlet とloopは省略可能です。 descent(a in 0..10) { }
breakは最も内側のwhile、loopから脱出します。
returnで最も内側のsub, function, taskから脱出します。
functionの中から以外では、値を伴うreturnはエラーになります。
let a = 0; while(true) {//aが5になったらループを抜ける if(a==5){break;}; a++; }
特定の動作をまとめるときに使います。
引数などは取れません。
BASICで言うGOSUB〜RETURNに相当します。
他の制御文と同様に、必要なだけ入れ子にできます。
sub xxx(xxxは任意の文字)でサブルーチン部分を記述します。
//サブルーチンのかき方例 sub Shot5Way {//5WAYサブルーチン let ex = ObjMove_GetX(objEnemy); let ey = ObjMove_GetY(objEnemy); let angle=-30; while(angle<=30) {//(angle=-30, -15, 0, 15, 30) CreateShotA1(ex, ey, 3, angle, DS_RICE_S_BLUE, 30); angle+=15; } } //サブルーチン呼び出し例 @MainLoop() { if(timer == 0) { Shot5Way;//5WAYサブルーチン呼び出し } }
ユーザー定義関数を導入します。
subとよく似ていますが、違いは、引数によって値を渡し、返値によって結果を返せることです。
返り値は「retuen 値;」で記述します。
もしくは「result」という名前の変数に特別な代入してください。
「result」変数は予め用意されていますので宣言の必要はありません。
やはり、他の制御文と同様に、必要なだけ入れ子にできます。
引数の無い関数を呼ぶ時は、括弧は付けても付けなくてもよいです。
仮引数のletは省略可能です。
//関数のかき方例 function nWayToPlayer(let nWayNum,let nWayInterval,let nWaySpeed,let nWayGraphic) {//自機方向へのnWay関数 //nWayNum:nWay //nWayInterval:弾の間隔 //nWaySpeed:弾の速度 //nWayGraphic:弾の画像 let ex = ObjMove_GetX(objEnemy); let ey = ObjMove_GetY(objEnemy); let sAngle =- nWayInterval*int(nWayNum/2); let eAngle = nWayInterval*int(nWayNum/2); while(sAngle <= eAngle) { CreateShotA1(ex, ey, nWaySpeed, sAngle, nWayGraphic, 30); sAngle+=nWayInterval; } } //関数の呼び出し例 @MainLoop() { if(timer == 0) {//関数呼び出し //5Way、弾間隔10°、弾速5、画像BLUE11 nWayToPlayer(5, 10, 5, DS_RICE_S_RED); } }
//返り値の例 function Double(let x) { return x * 2; } //〜〜〜 a = Double(10); //a = 20
functionに似ていますが、途中で戻ってくることができます。
複数のマイクロスレッドを並列して存在させ、順次yieldによって切り替える事で、
あたかも同時に複数のスクリプトが走っているような記述ができます。
@Initialize { TWork(); } @MainLoop { //毎ループタスクを実行 yield; } //---------------------------------------------------- //敵動作 //---------------------------------------------------- task TWork { let frame = 0; while(!Obj_IsDeleted(objEnemy)) { //敵が削除されるまで8フレーム毎に弾をだす。 let ex = ObjMove_GetX(objEnemy); let ey = ObjMove_GetY(objEnemy); if(frame % 8 == 0) { let i=0; while(i<360) { CreateShotA2(ex, ey, 7, i+frame,-0.4,4,DS_RICE_S_BLUE, 0);//弾を発射 i+=30; } } frame++; //他のタスクに制御を渡す。 yield; } }
コメント部分のスクリプトは、実行時に無視されます。
「//」は行末までコメントアウト、
また、「/*」〜「*/」では、その間がコメントアウトされます。
//←行末までコメントアウト /* この部分は実行されない */
他のスクリプトを読みこんで、他のスクリプトの記述したルーチンを呼び出せるようにする機能です。
「#include"〜〜〜"」で別のスクリプトを取り込みます。
//----TestA.txt---------------------------- let valueA = 0; function FuncA() { //〜〜〜 } //----TestB.txt---------------------------- //TestA.txtを取り込みます。 //「./」ではじめたパスはこのスクリプトからの相対パスになります。 //「./」がない場合は、実行ファイルディレクトリからの相対パスになります。 #include"./TestA.txt" function FuncB() { //#includeでTestA.txtを取り込んでいるため //valueAにアクセスできる。 let valueB = valueA; //TestA.txtを取り込んでいるため //FuncAを呼び出せる。 FuncA(); }