関数とSCRIPT

関数を使うとよりシンプルにACSを組み立てることができます。
関数を学ぶとSCRIPTもマスターしたも同然です。
まず関数を学んでいきましょう。


関数

はじめに

ACSで行う計算処理などを"関数"という形でまとめておくとより簡単に、見やすくACSを記述することができます。

数学で例えると、「ある値xを3乗する」関数f(x)を
f(x) = x*x*x
と定めることができますよね。(ACSの都合上累乗表現を使っていません。)
このように関数f(x)を定めておけば、今後ある値aを3乗した値を求めたいときには、
f(a)
と記述するだけでf(a)は目的の値となり、要所要所で
a*a*a
とわざわざ書く必要がありません。

また、f(x)の定義が間違っていて、実は関数f(x)の役割は「ある値xを4乗する」だったら
f(x)の定義文を
f(x) = x*x*x*x
と書き換えるだけで
f(a)
の部分を書き換える必要はありません。
(関数を使っていなければa*a*aの部分をすべてa*a*a*aに書き換えなければなりません。)

このように、関数という概念は非常に便利で、これをACSにも応用します。


関数の定義

ACSの関数の宣言は、C言語などの宣言とは異なっています。
ACSの関数の一般的な形は↓


function type function_name(type arg1 , type arg2 , ... , typen)
{

//関数の内容

return value;
}

//"関数の内容"の部分で演算の内容を記述しましょう。詳しくは具体例を参考にして下さい。


スペースで区切られている文字の塊をひとつの塊としてください。
まず、
function
の部分をみてみましょう。
これは、「次に記述する文章は関数の定義だ」
と宣言しています。

type
ではこの関数が結果として"返す"値の型(int型やstr型など)を指定します。
この関数が結果として返す値がint型の場合はこの部分にintと記述します。
この結果として返す値を戻り値(return value)と呼びます。
戻り値が存在しない場合(関数が結果として何も値を返す必要が無い場合)は、
void
と記述しましょう。

function_name
ここでは定義したい関数の名前を記述しましょう。
ただし、その3の最後で説明したように、名前の付け方にはルールがあります。

type arg1 , type arg2 , ... , typen
の部分は、仮引数(parameter)「かりひきすう」と呼ばれ、数学の関数で言う
f(x,y)
のx,yの部分に相当します。
arg1,arg2などには自由に名前を付けましょう。
その3の最後で説明したように、引数の名前の付け方にはルールがあります。
typeはそれぞれの仮引数の型(int型など)を指定しましょう。
また、複数仮引数を定義するときはそれぞれの仮引数の間に","(コロン)をはさみましょう。
ちなみに、これから、
arg1,arg2,arg3,...
を左から順番に
第一仮引数、第二仮引数、...
と呼んでいくことにします。

return
では、関数の結果として返す値(戻り値)を指定します。
例えば、結果として1という値を返したいなら
return 1;
と書きましょう。(先ほど指定した戻り値の型と一致するようにしましょう。)
変数xの値を返したいなら
return x;
と書きます。
また、戻り値が存在しない場合(typeがvoidの場合)は、
return;
書きます。
また、return文を関数が実行すると、そこで関数は終了します。
return文より後の部分に何か動作を持ってきても何も実行されません。

では、実際に関数を使ってみましょう。


#include "zcommon.acs"

//与えられた値の絶対値を求めます。
function int abs (int x){
if(x >= 0){

return x;
//xが0以上ならそのまま返す。
}
return -x;
//xが負なら符号を反転して返す。
}

Script 1 ENTER
{
int a = abs(2);
int b = abs(-3);

print(s:"a is ",d:a,s:". b is ",d:b,s:".");
}


と表示されます。

この例の赤い字の部分を詳しく見てみましょう。

function int abs (int x)
この部分では
関数absを宣言し、戻り値はint型、仮引数はint型のxと宣言しています。
if(x >= 0){
return x;
}

この部分では、仮引数xが0以上ならばそのまま戻り値として値を返し、関数absを終了します。
return -x;
この部分では、xは負の値なので、符号を反転して戻り値として値を返し、関数absを終了します。

では、次に青い字の部分を見てみましょう。

int a = abs(2);
この部分では、変数aを宣言し、値を「関数absの仮引数に2を渡して得た戻り値」で初期化しています。
つまり、結果的には
int a = 2;
となっています。
int b = abs(-3);
この部分では、先ほどの動作と同様にして、結果的には
int b = 3;
となっています。
ここで、abs(2),abs(-3)のように、関数を呼び出すときに使用する2,-3の部分を実引数(argument)と言います。
(このページでは仮引数と実引数を単に引数と呼んでいますが、状況によってどちらかは判断して下さい。)

このように、関数の呼び出しは
関数名(引数1,引数2,...)
といった感じで呼び出します。


また、関数を使用する行より前の行で関数を定義しなければ関数を使うことができません。


←イメージ


さきほどの例の文を書き換えて次の様なACSを作ってみましょう。


#include "zcommon.acs"

function int abs (int x){
if(x >= 0){
return x;
}
return -x;
}

Script 1 ENTER
{
int a = -2;
int b = abs(a);

print(s:"a is ",d:a,s:". b is ",d:b,s:".");
}


と表示されます。

このACSから、
実引数の値は関数の処理で変更されることはない。
ということがわかります。
(abs(a)としたのにaが2にならない。)
このように、実引数の値は変更されないという保証があるので、より安全にACSを作ることができます。
(勝手に実引数の値が変わってゲームがクラッシュしてしまうようなことはありません。)


関数に仮引数が必要ない場合があります。
次の様なACSを見てみましょう。


#include "zcommon.acs"

function void hello(void){
print(s:"hello!");
return;
}

Script 1 ENTER
{
hello();
}


と表示されます。

このように、仮引数が存在しない場合、
仮引数を宣言する部分では、
void
と書き、関数を呼び出すときは実引数は何も書きません。


関数とACS

さきほど、関数を紹介しました。
この関数という概念は非常に重要で、ACSは関数を使わなければ殆ど意味をなしません。
例えば、今までに紹介していた
print
やちらっと紹介した
sin
//正弦
も関数です。
これらはAction SpecialsとかBuilt-in ACS functions(備え付け関数)という関数の仲間と思われます。


Delay関数

関数という概念は非常に便利ですが、時間の経過という概念を扱うときだけ制限があります。
(というよりももともと関数は瞬時に計算する物だと思うので、時間の経過という概念は使ってはならないと思います。)
ACSにはdelay関数という備え付け関数があります。
この関数の役割は、「delay関数を実行したscriptは指定された時間だけ一時停止する」という役割を持っていますが、(こちらを参照)
関数(function)ではdelay関数を使うことができません。


SCRIPT

ACSはAction Code Scriptの略であるくらいなので、ScriptはACSの重要な構成単位です。
これがなければACSが存在できません。
しかし、Scriptは関数と非常に似ているため、関数をマスターすればすぐに理解できると思います。

まず、先ほどの絶対値の例を見てみましょう。


#include "zcommon.acs"

function int abs (int x){
if(x >= 0){
return x;
}
return -x;
}

Script 1 ENTER
{

int a = -2;
int b = abs(a);
print(s:"a is ",d:a,s:". b is ",d:b,s:".");
}


今回はこの赤い字の部分を見ていきます。


今までは例のように、

Script 1 ENTER

というフレーズを使っていました。この意味を調べてみましょう。

一般にScriptの定義方法が存在し、その方法は

Script 番号 起動条件
{
//内容
}

となっています。

つまり、今までの

Script 1 ENTER

は「Script番号が1で起動条件がENTERのScript」
と言う意味です。
まずScript番号を見ていきましょう。

Script番号は、Scriptを識別するために与えられる番号で、必ず1〜999の中の番号である必要があります。
また、1つのMAPにつき同じScript番号をもつScriptはただ一つのみで、複数存在できません。

次に、起動条件を見ていきましょう。

例のように、ENTERも起動条件の一種です。
起動条件の一覧を見てみましょう。

種類の名前 このScriptの起動主(※) 起動する条件
OPEN World このScriptがあるMAPが読み込まれたらすぐに起動します。1つのMAPにつき1回だけ起動されます。
ENTER Player プレイヤーがゲームに参加したときにそれぞれのプレイヤーに対して1回ずつ起動します。
RETURN Player プレイヤーがhub設定で繋がっているMAPから戻ってきたときに起動します。
hubの詳しい説明はMAPINFOの解説を見て下さい。
RESPAWN Player プレイヤーがマルチプレイヤーゲームで復活したときに起動します。
DEATH Player プレイヤーが死んだときに起動します。
LIGHTNING World このScriptがあるMAPにlightning設定(稲妻が光る設定)がある場合、稲妻が光るたびにこのScriptが起動されます。
lightningの詳しい説明はMAPINFOの解説を見て下さい。
UNLOADING World このScriptがあるMAPが終了したとき(ゴールしたとき)起動します。何回でも起動できます。
DISCONNECT World マルチプレイヤーゲームでプレイヤーがゲームを終了したとき(サーバーから離れたとき)に起動します。引数をかならず一つ宣言しなければなりません。この引数に自動的に(プレイヤー番号 - 1)が代入されます。

※:Scriptを起動した物体を特定する関数などが存在し、その関数のために決められています。

DISCONNECTの時だけ特殊なので、例を挙げます。


Script 999 (int gone) DISCONNECT
{
PrintBold(s:"Player ", n:gone + 1, s:" quit the game");
//すべてのプレイヤーに
//"Player (プレイヤーの名前) quit the game"
//と表示されます。
}


起動条件が必要ないときは、起動条件の部分に
(void)
//括弧が必要
と入力しましょう。(起動条件が必要でない場合が多いです。)


Script 1 (void)
{
//内容...
}


こんな感じで書きます。

また、ここの
void
部分に関数の仮引数のときと同じように仮引数を持ってくることができます。
ただし、持ってくることのできる仮引数の数は3個までです。4個以上引数を持ってこないようにACSを工夫しましょう。
また、returnは使用できませんし、必要ありません。


Script 1 (int a,int b)
{
print(s:"a is ",d:a,s:". b is ",d:b,s:".");
//仮引数を定義したa,b,はScript内では変数として使うことができる。
}


こんな感じで書きます。

関数を実行するときは、関数名を書くだけで良かったですが、Scriptを実行するときは、Scriptを実行するために関数を使う必要があります。
ACS内で他のScriptが実行する方法と、ゲーム中にプレイヤーがScriptを実行する方法があります。

まず、前者(の一部)を紹介します。

ACS_Execute関数を使います。

一般的な形は

ACS_Execute (script, map, s_arg1, s_arg2, s_arg3);

で、scriptにScript番号を指定します。
引数mapは実行するScriptが含まれているMAP番号を指定します。同じMAPのScriptを使う場合は0を入力して下さい。(専ら0だと思います。)
引数s_arg○は実引数を入力して下さい。何も無ければ0を入力しましょう。

後者(の一部)も紹介します。

DeePseaの場合、Scriptを起動したいLine(スイッチ)の編集画面を開いて、
Type→D ACS Scripts→1 Script Run +Script-Map-Arg1-Arg2-Arg3[80]
と選び、実引数に値をACS_Execute関数と同様に入力すると、そのLineを起動すればそれに対応するScriptを実行させることができます。

具体例を示します。


#include "zcommon.acs"

Script 1 ENTER
{
int a = 3;
ACS_Execute(2,0,a,0,0);
}

Script 2 (int x)
{
print(d:x);
}


結果はご想像の通り、

です。


まとめ

・関数の定義のしかたは
function type function_name(type arg1 , type arg2 , ... , typen)
{

//関数の内容

return value;
}
赤い字の部分を仮引数と言う。
・return文を実行したら関数は終了する。
・関数の名前の付け方にはルールがある。
・関数は関数名と実引数を書くと実行できる。
・仮引数が必要ない場合はvoidと書き、実引数には何も書かない。
・Scriptの定義のしかたは
Script 番号 起動条件
{
//内容
}
・起動条件の代わりに(void)や仮引数を持ってくることができる。
・return文を書いてはならない。
・Script番号は1〜999までで、同じ物が同一MAPで複数回使われてはならない。
・Scriptを実行する方法は
ACS_Execute (script, map, s_arg1, s_arg2, s_arg3);
などがある。


Home Back Next