8.アンカーポイントにおけるスクリプト仕様


8−1.隠された記述

「SpE4.exeの起動時に直接起動されるスクリプト」と「アンカーポイントに記述するスクリプト」とでグローバル変数の扱いに違いがありました。 これらの説明をする前に、アンカーポイントの内部仕様を説明します。今まで何度か登場しているこのスクリプト。

===============
extern int b=0;     //グローバル変数bを宣言しておく
function my_function(int a)
{
    b=a*2;          //引数aを2倍にしてbへ代入(bはグローバル変数なのでどこでも使用可能)
}
my_function(5);     //引数を2倍にする関数を呼ぶ
print_string(b);    //関数my_functionで2倍になった変数bを表示する。
===============

ラベル名「main」のアンカーポイントに記述していると思いますが、内部的には前後にこのようなものが付与されてコンパイル処理に入ります。

===============
#include "/spesystem/script/system.inc"     //←追加
#include "/spesystem/script/mission.inc"    //←追加
extern function main(int __unit_handle__)   //←追加
{                                           //←追加
    extern int b=0;     //グローバル変数bを宣言しておく
    function my_function(int a)
    {
        b=a*2;          //引数aを2倍にしてbへ代入(bはグローバル変数なのでどこでも使用可能)
    }
    my_function(5);     //引数を2倍にする関数を呼ぶ
    print_string(b);    //関数my_functionで2倍になった変数bを表示する。
}                                           //←追加
===============

最初4行と、最後の括弧の1行が追加されます。雰囲気的に「SpE4.exeの起動時に直接起動されるスクリプト」と同じになります。 関数の中に包まれてしまうので、書いた1行目からそのまま実行できたり、グローバル変数にexternが必要だったりするわけです。 また、#includeも自動的に付与されるので、わざわざ書く必要がありません。

「6−1.ローカル変数とグローバル変数」の説明で、アンカーポイントに書いたスクリプトではグローバル変数に「extern」の付与が必要だと書いたのはこういうことが理由です。 関数内なのでそのままだとローカル変数になってしまうからなんですね。

SphereScriptをゲームエンジンの中に埋め込み、イベント駆動させる仕組みにするため、このような拡張がされています。 普段意識することは無いですが、仕様について不可解なことが発生したら、このことをを思い出してください。


8−2.隠された引数

上記の自動的に挿入される部分の関数に「__unit_handle__」という引数があるのがお分かりになると思います。 ここには、アンカーポイントの「cmd」欄に設定した条件を満たした対象のユニットのハンドルが入ります。たとえば「19:Label[OP1]がロックオンされた」を設定したスクリプトを用意しておき、Labelには「Enemy」などと入れておいたとします。

===============
destroy(__unit_hanle__);
===============

上記のように書くと、「Enemy」をロックオンしたときにスクリプトが動くのですが、変数「__unit_hanle__」にはロックオンされたユニットのハンドルが入っていますので、ロックオンされたらそのまま爆破する動作をします。

このスクリプトでは「Enemy」というラベル名が分かっているので、一見すると、「destroy_label」関数を付けば同じことが出来そうな気がしますが、ラベル名「Enemy」と設定されたユニットが戦場にたくさんいる場合、どの「Enemy」か分からなくなってしまいます。 そこで、この仕組みを使うことで、動作の対象となるユニットを一発で判定できるようになります。

実際は「04:ユニットがこのパスに到着」と組み合わせてイベント制御に使うことが多いです。 カメラであってもハンドルを持ちますので、事前にカメラやユニットのパスを作っておいて、「カメラがココに到達したら徐々に停止する」というような使い方をします。


8−3.インクルード及びリンクとの関係

前章で「#include」と「#link」の意味と使い方を解説しました。アンカーポイント内に記述するスクリプトにおいても、これらの機能は利用可能ですが、注意することがあります。 インクルードするにしてもリンクするにしても、アンカーポイント内に記述したスクリプト「以外」のファイルには以下の記述は自動的に追加されません。

===============
#include "/spesystem/script/system.inc"
#include "/spesystem/script/mission.inc"
extern function ラベル名(int __unit_handle__)
{
(ここに自分で書いたスクリプトが入る)
}
===============

「#include」を使う場合は単なる挿入なので、勝手にインクルードや関数化を追加されると困ってしまうので当然です。 ただしこの場合は、そもそも元のスクリプトに必要なファイルが上記のように自動的にインクルードされているので、難しいことを考える必要がない、という面もあります。

一方で「#link」を使う場合も、インクルードや関数化はされませんが、独立した一つのスクリプトとして扱われるので、「#include」などをその都度書く必要があります。具体的にはこのようになります。

===============
(↓アンカーポイント「main」内に記述↓)
#link "test3.inc"
print_string("Test.");    //関数print_3を呼ぶ
(↑アンカーポイント「main」内に記述↑)

(↓「test3.inc」というファイルを作ってそこに記述↓)
#include "/spesystem/script/system.inc"
#include "/spesystem/script/mission.inc"
extern function print_3(string str)
{
	print_string(str + str + str + "\n");   // 3回表示して改行する機能
}
(↑「test3.inc」というファイルを作ってそこに記述↑)
===============

このインクルードが無いと、スクリプトのコンパイルをするときに「print_string関数とは何だ?」となってエラーになってしまいます。 このたった6行のスクリプトだと冗長な印象を受けますが、本来このリンクという機能はRS4thで実現しているような大規模なシステム記述を想定しているので、余計なお膳立てはあえて排しています。

ところで、このアンカーポイントに記述したスクリプトが複数ある場合、SphereEngineはこれを外部参照として扱います。そのため、#linkを使わずとも以下のスクリプトは正しく動作します。

===============
(↓アンカーポイント「main」内に記述↓)
print_string("Test.");    //関数print_3を呼ぶ
(↑アンカーポイント「main」内に記述↑)

(↓アンカーポイント「print」内に記述↓)
extern function print_3(string str)
{
	print_string(str + str + str + "\n");   // 3回表示して改行する機能
}
(↑アンカーポイント「print」内に記述↑)
===============

別のアンカーポイント内に記述した関数を呼んでいます。実際はこのような使い方より、externでグローバル変数(正確には外部参照変数)を定義しておき、いろいろなアンカーポイントから参照する、という使い方が可能です。 例えばこのような使い方です。「21:Label[OP1]がメイン武器を使用」を設定したアンカーポイントを用意します。

===============
extern missile_count=0;
missile_count++;    //  ミサイル発射累計数をカウントしていく
===============

ミサイルを発射するたびにこのスクリプトが呼ばれ、missile_countが加算されていくのですが、missile_countは外部参照変数なので、他のスクリプトから「missile_count」を読み込むとミサイル発射数が分かる、という仕組みです。 ちなみにexternを付与しないと、ローカル変数扱いになってしまうので、他のスクリプトからアクセスできないばかりか、何度ミサイルを撃っても「missile_count」は1より大きくなりません。


8−4.コンパイルと動作のタイミング

plcファイルを読み込んだときに、全てのアンカーポイント内のスクリプトがこれまでの説明のように展開及びコンパイルされ、準備されます。 そしてアンカーポイントの設定で「01:自動的に起動」を選んだものは関数が呼ばれて動作を開始します。「01:自動的に起動」が複数あった場合はスレッドに分かれて同時に動作します。 同様に、例えば「04:ユニットがこのパスに到着」が選択された場合は、パス上のユニットがアンカーポイントに到達したときに、新たにスレッドが自動的に作られて、スクリプトが起動します。


最初のページへ戻る