top / 1 / 2 / 3 / 4 / ex1 / 5 / 6 / ex2 / 7 / 8 / 9 / 10 / 11 / ex3 / 12 / 13 / 14 /..../ 関数 / 覚え書き / 倉庫

第11回 【 スクリプトの基礎 】

「シドとマー君のスクリプト講座」

ついカッとなってやった。
スゲー疲れた。

聞きたいことがいくつかある。


他で聞け。俺は何でも知ってる訳じゃない。
ゾーンであれやこれや起こっている間、俺は一日中ここに座ってるのだからな。
STALKERで使えるスクリプトの基礎や、俺が使ったことのある機能についてなら少しは教えられるが。



変数について

「変数」について教えてくれ。


変数と言うのは、そうだな。「何でも入れる事ができる器」の様なもんだと思って構わない。


?さっぱり判らないぞ。


うーむ。 例えば、そうだな。お前は任務を受けたりした時、その内容を全て覚えておくか?


いや、必ずPDAを見るぞ。
忘れちまう事だってあるからな。


だろう?
スクリプトの世界でも、データをどうにかして覚えておく必要があるんだ。
そうだな、例えばお前が以前に作ったスクリプトでこんなものを使ったな?

if (xr_logic.pstor_retrieve(db.actor, "x_first_run", true) == true) then


ああ、確かゲーム開始フラグを取得する命令だった。


まあ、色々事情が合ったとして、だ。
もしも仮に、このゲーム開始フラグをまた取得する必要が出てきたらどうする?


もう一度このファンクションを呼び出すぞ。


1回や2回ならそれで良いかも知れんがな、もしかしたら100回も200回も取得する必要が出てくるかも知れんぞ?


呼び出される方はたまったもんじゃないな。
そのうち喧嘩が始まるぞ。


だろう?
だったら、最初に取得したフラグを「何でも入れる事ができる器」とやらに保管しておいて、2回目以降はその「器」の中を見たほうが、お互いに手間が省けるだろう。
この「器」こそが「変数」だ。

変数の使い方はそれだけじゃない。あらゆる場所で、そしてあらゆる用途で使われる。
まあ、こればっかりは体験してみるしかないな。


どうすれば良いんだ?


うむ。基本はこうだ。

local flggamestart

とりあえず判りやすいようにさっきの例で行くぞ。
名前は「flggamestart」、フラグゲームスタートと名付けた。これは、先ほど取得したゲーム開始フラグを入れる目的で作ったものだからな。
付ける名前は半角英数であれば基本的に自由だが、名前を見ただけでそれが何の目的で作られた器なのか判るようにしなければ、後で苦労するぞ。

「local」ってのは、このファンクションの中でしか使わないって意味だ。
まあ、相当ゾーンの奥地にまで踏み込まない限り、「local」以外の変数を使うことは無い。
基本的に変数の準備は「local 変数名」だ。これだけ覚えときゃ充分だ。
とにかく、これで器の準備は出来るってこった。


中身は?


慌てるな。今から入れる。
・・・そうだな、これを見ろ。何だか判るな?

function ngclordcheck() if (xr_logic.pstor_retrieve(db.actor, "x_first_run", true) == true) then ロケットランチャーを追加 ロケット弾を追加x5 ゲーム開始フラグを下ろす end end


俺が作ったファンクションだな。
随分と簡略化してあるが。


そうだ。変数の説明に必要ない部分は省略した。
この条件式の中で件のフラグを取得しているな?
これを少し変えてみるぞ。
まず、さっきの変数を書き込もう。変数を準備する事を「変数を定義する」と言う。
・・・よし、定義したぞ。

function ngclordcheck() local flggamestart if (xr_logic.pstor_retrieve(db.actor, "x_first_run", true) == true) then ロケットランチャーを追加 ロケット弾を追加x5 ゲーム開始フラグを下ろす end end


簡単だな。
これからフラグを入れるんだろう?


ああ。フラグを移すのは、こうだ。

flggamestart = xr_logic.pstor_retrieve(db.actor, "x_first_run", true)


イコールで結んだだけか?


そうだ。二つのデータをイコールで結べば、データは右から左へとコピーされる。
当然、左側――左辺と言うんだがな――、左辺に置くのは変数で無ければならない。
これをまとめると、

function ngclordcheck() local flggamestart flggamestart = xr_logic.pstor_retrieve(db.actor, "x_first_run", true) if (xr_logic.pstor_retrieve(db.actor, "x_first_run", true) == true) then ロケットランチャーを追加 ロケット弾を追加x5 ゲーム開始フラグを下ろす end end

こうなるな。


これでフラグが変数「flggamestart」に入ったのか?


そうだ。だが、これだけでは足りない。
判るか?


ああ、フラグが変数「flggamestart」に入ったのは良いが、それだけでは何の意味も無いな。


その通りだ。Marked one。
そもそもフラグを変数「flggamestart」に突っ込んだのは、それ自体が目的じゃない。
もう二度とゲーム開始フラグのファンクションを呼び出さないで済むようにする為だ。
2回目以降にフラグを見るときは、ファンクションを呼び出すのではなく、変数を見れば良い。
・・・こうだ。

function ngclordcheck() local flggamestart flggamestart = xr_logic.pstor_retrieve(db.actor, "x_first_run", true) if (flggamestart == true) then ロケットランチャーを追加 ロケット弾を追加x5 ゲーム開始フラグを下ろす end end


これでようやく変数「flggamestart」が役に立ったな。


このスクリプトは、以前にお前が作ったのと全く同じ動きをするわけだが、それだけじゃないぞ。
もしも仮にだ、このファンクションの中でもう1回、いや100回でも良い、このフラグを取得する必要が出来たら、いつでもこの変数を見ればそれで済むってわけだ。
どうだ、中々のスグレモノだろう?


ああ。使わない手は無いな。


他にも変数の使い道は山ほどある。その使い方でMODDERとしての技術が問われるってもんだ。
腕の良いMODDERならば、変数の使い方を一目見ただけでお前の実力を看破するだろう。
良いか。覚えておけ。変数をいかに効率よく使うかがファンクションの機能を高めるんだ。全てのスクリプトの基本にして最大の命題と言う奴だ。
・・・あるいは、スクリプトを作る中で、最も多く直面し、最も難解で・・・そして最も刺激的な部分かも知れないぞ。
何しろ「自分で正解を決められるパズル」を組み立てるようなものだからな!



関数について

「関数」について教えてくれ。数学は赤点だったんだが・・・。


関数か。あれは今お前が使っている「ファンクション」「命令」と同義語だと思って良いぞ。少なくとも、ゾーンにおいてはな。
例えばお前は「ngcloadcheck」と言うファンクションを作っただろう。
あるいは今まさに動かしている最中かも知れんな。
「ngcloadcheck」と言うのはファンクション名だ。そして、命令であり、関数名でもある。
ファンクション「ngcloadcheck」と言う代わりに関数「ngcloadcheck」と言う言い方も出来るってわけだな。


数学は関係ないのか?


ああ、少なくともゾーンにいる間は数学の事は忘れろ。命が幾つあっても足りないぞ。
しかし、何でまた「数」でも何でもないファンクションの事を「関数」なんて紛らわしい名前で呼ぶのか不思議だろう?


そう言えばそうだな。何でだ?


これは、スクリプトだけでなく全てのプログラムにに関わってくる事だから、覚えておいて損は無いぞ?
他にもさっき説明した「変数」だの、他にも「引数」だの、数でもないのに「数」と呼ばれるものが幾つかある。まあ、名前の由来はどれも同じようなものだ。

コンピュータにおける全ての情報は2進数で表現できると言うのは聞いた事があるだろう?
つまり、コンピュータにしてみれば、どんな形のデータであれ全て2進数、数字に見えてるってわけだ。
データの目的によって関数、引数、変数などと呼ばれている。


ふーむ。単に「数」と言う文字がついてるだけで、実際には数字にこだわる必要は無いって事か。
ところで、関数、つまりファンクションもデータなのか?


いい質問だ、Marked one。
さっきも例に出したゲーム開始フラグ取得のアレだが・・・。

xr_logic.pstor_retrieve(db.actor, "x_first_run", true)

これもファンクションであり、命令であり、関数だ。・・・そして、データとして扱う事もある。
お前はあたかも「xr_logic.pstor_retrieve(db.actor, "x_first_run", true)」と言う命令自体がフラグそのものであるかのように、「true」と比較したり、値を変数に移したりしていただろう。
ヘンだとは思わなかったか?


いや、そう言うものかと思ってた。


まあ、そう言うもんなんだがな。
・・・まず前提として、ファンクションには大きく分けて2種類あると思え。
「何かの処理をするだけのもの」「処理の結果を報告してくるもの」だ。


と言う事は、このファンクションは・・・。


うむ、この命令はそもそも「フラグを取って来る」と言う機能を持っていて、「取ってきたフラグを見せる」のが目的だ。
つまり、後者の「処理の結果を報告してくる」タイプのファンクションだと言う事だな。
問題は、どうやって報告するかだが・・・。


なるほど。
「true」とかと比較する事が出来るような「データ」として、この関数を「処理の結果そのもの」の様に扱う事ができるんだな。


うむ。
このタイプのファクションは、その内部の処理で「戻り値」と言うものを設定する。
ファンクションが終わる前に、呼び出し元に出力するべきデータを用意するわけだ。

話を戻すぞ。「データそのものとして扱う事が出来る」と言う事は、コンピュータから見たら、この命令はそれ自体、一種の「数値」と変わらない。
だから関「数」と言うわけだ。



戻り値について

「戻り値」について教えてくれ。


今説明しただろう。Marked one。まだ判らないか?・・・まあいい。
「戻り値」と言うのは・・・そうか、お前はまだ使った事が無かったな。
では、さっきの例の続きだ。何度も出てるゲーム開始フラグ取得の関数だ。

xr_logic.pstor_retrieve(db.actor, "x_first_run", true)

このファンクションはフラグの状態を調べてお前に報告する義務がある。
この場合は「戻り値」はフラグそのものであり、「立ってるか」「下りてるか」を意味しているわけだな。
これが「戻り値」だ判るか?


すまん。すこしこんがらがってきた。
何となくは判るんだが・・・。


うーむ。それではこのファンクションを例にするのはしばらく止めておくか。
いいか?一旦、頭を空っぽにしろ。
・・・では、ちょっと長いが、これに見覚えはあるか?

function actor_binder:net_spawn(data) printf("actor net spawn") level.show_indicators() self.bCheckStart = true self.weapon_hide = false -- ?・?M 齏・D・A?韃 ・・?鈬AA・ weapon_hide = false -- ??粱鞣瑯・肭@琿・ 蒟?・A ?璢. if object_binder.net_spawn(self,data) == false then return false end db.add_actor(self.object) if self.st.disable_input_time == nil then level.enable_input() end self.weather_manager:reset() -- game_stats.initialize () if(actor_stats.add_to_ranking~=nil)then actor_stats.add_to_ranking(self.object:id()) end --' ヌ璢?赳褌 ??鳰・蓿@・ death_manager.init_drop_settings() ngc_mod.ngclordcheck() -- NGC_MOD ADDITIONAL return true end


ああ、それなら覚えている。
ゲーム開始時点でアイテムを持たせるファンクション「ngclordcheck」を突っ込んだ部分だ。
たしか、ゲームのロード時に必ず実行しているんだったな。


そうだ。
お前が一行ぶちこんだ部分のすぐ下を見ろ。
「return true」と書いてあるだろう。これが「戻り値」だ。
「処理の結果を報告する」タイプのファンクションは、必ず処理を終わる前にこの処理を行っている。
この記述では「true」の値を返しているな。


必ず「true」を返すのか?


いや、そうとも限らないぞ。
少し上を見てみろ。そう・・・真ん中よりちょっと上の辺りだ。こんな行があるだろう。

if object_binder.net_spawn(self,data) == false then return false end


if条件式だな。


このif条件式が何を判定しているのかは、実のところ俺にも判らない。
ゾーンを作り出したクソッタレ共には判っているんだろうがな。
ともかく、重要なのはそこじゃない。
この判定の結果、ある条件が成立したら、「return false」と言う処理をしているだろう。
この「return」と言う記述を実行すると、ファンクションは仕事を放り出しちまうのさ。例え戦闘の真っ最中でもな!


残りの処理はどうなる?


ハッ!そりゃ、無視されるのさ。
その場合、途中で仕事を放り出した場合には「false」「戻り値」として設定しているだろう?
これがどう言う意味だか正確には判らないが、何となく雰囲気は伝わってこないか?


ああ、何となく判るぜ。
「true」の場合は「任務完了」「false」の場合は「任務失敗」って事だ。


そうだ。確証は無いし確認する方法も無いが、まあ間違いなかろう。
どちらにしても、だ。このファンクションは、自分を呼び出した上位のファンクションに対して任務の結果を「戻り値」として報告する義務を持っているって事だな。


その戻り値は、俺の作った「ngclordcheck」には関係してこないのか?


ああ。ここでは関係ないな。
そもそもファクションには上下関係がある。「命令する側」「命令される側」だ。
「戻り値」と言うものは「命令された側」「命令した側」、つまり上官に対して報告するものだ。
その逆は決して無い。
お前のファンクション「ngclordcheck」は、ここでは呼び出される立場、つまり「命令される側」と言うわけだな。


ならば、俺の「ngclordcheck」「戻り値」を返すのか?
そんなスクリプトを組んだ記憶は無いが・・・。


さっき言ったろうが。チッ、もう一度だけ説明してやる。

ファンクションには大きく分けて2種類ある。
「何かの処理をするだけのもの」「処理の結果を報告してくるもの」だ。
もしもお前の作ったファンクションが複雑な動きをしていたら、場合によっては「任務失敗」に終わる事もあるだろう。


いや、俺は必ず任務を遂行するぞ。


やかましい。
例えば、お前が「誰かを守れ」って言う命令を受けたとする。
お前はその場に行く。しかし、その「誰か」はアノマリーのど真ん中に転がってた。それでも任務の遂行は可能か?

いいか、スクリプトの世界ではどんな事が起きるか判らない。
そんな複雑なファンクションを作るときには、「任務成功」「任務失敗」の両方の「戻り値」を用意する必要もあるって事だ。
で、お前の作ったファンクション「ngclordcheck」はだな、失敗するはずもない簡単なファンクションだったから、「戻り値」は必要なかったってわけだ。


(あれで簡単だったのか・・・)


まあ、ファンクションはこんな具合に「true」だの「false」だの、場合によっては計算した結果の数値を返すこともあるってわけだ。
で、最初の話に戻るわけだが・・・。
あれだ、ゲーム開始フラグ取得の関数の話だ。もう一度同じ事を言うぞ。

xr_logic.pstor_retrieve(db.actor, "x_first_run", true)

このファンクションはフラグの状態を調べてお前に報告する義務がある。
この場合は「戻り値」はフラグそのものであり、「立ってるか」「下りてるか」を意味しているな。
言ってみれば、お前のファンクション「ngclordcheck」はその報告を受ける「上官」ってわけだ。


なるほど!今度は判ったぞ。


どうだ。戻り値ってものが理解できたか?


ああ、多分な。


まあ、お前が作れるスクリプトではそう複雑なものは出来まい。
もしかしたら、戻り値を使う機会は一生無いかも知れんな。
だが、覚えておく必要はあるぞ。既存の関数を使う時や、他人の作ったスクリプトを解析する時には絶対に避けては通れないものだからな。

他に知りたい事はあるか?



引数について

「引数」について教えてくれ。


「引数」ってのは、ファンクションを呼び出す時に一緒に渡すデータだ。
ちなみに「いんすう」じゃないぞ?「ひきすう」と読め。
ファンクションには上下関係があると言ったのを覚えているな?Marked one。


ああ。「命令する側」「命令される側」だな。


そうだ。例えば俺がお前に「ぶっ殺せ」って命令をしたとしよう。
どうする?


それだけじゃ判らないぞ。
何処で誰を殺せば良いんだ?


だろう?
つまり「ぶっ殺せ」と言う命令を実行するためには、その命令と一緒に二つのデータを渡してやらにゃならん。「相手の名前」「相手の居場所」だ。
これが「引数」だ。


ファンクションにするとどうなる?


こんな感じだな。

ぶっ殺せ(名前, 居場所)

もう少しリアルに書いてやろう。
俺がお前に「命令する側」のファンクションだったとする。
俺のファンクションの中にはお前を呼び出す為に、こんな命令文が書かれることになる。

local flgresult flgresult = kill_stalker("wolf", "cordon")

こんな感じだな。
「flgresult」は、任務の結果、つまり「戻り値」を入れるべき変数だ。
flgと言うのはフラグの略だ。「結果フラグ」って意味だな。
つまりお前は成功したら「true」、失敗したら「false」と言う戻り値を用意しなければならない。
・・・まあ、この辺は「戻り値」の話だから置いとこう。今は「引数」の話だったな。

ここでは殺すべき相手の名前「"wolf"」と、その居場所「"cordon"」「引数」になっているわけだ。


俺はどんなファンクションを作れば?


まず、ファンクション名はそのままだ。
引数は、適当な名前をつけて構わない。


うーん、良く判らないが、こんな感じか?

function kill_stalker(name, place) end


上出来だ、Marked one。
お前は今、「name」「place」と書いたが、これは、そのまま変数として機能する。


変数の定義をしていないぞ。
「local name」「local place」を書かなくて良いのか?


ああ、引数ってのは、ファンクションが呼び出された時点で、既にデータを受け取っているからな。
その後にノロノロと変数を用意しても遅いのさ。
つまり、

function kill_stalker(name, place)

こう書いた時点で、お前は「name」「place」と言う二つの変数を定義し終わっていて、しかもその中身を上官から受け取り済みとして行動して良い。
試しに「name」の中を見てみろ。


おお、本当だ。「"wolf"」と書いてあるぞ。
早速殺してこよう。


待て!これは物の例えだ!
・・・まったく物騒な奴だ・・・。

ともかくだ、「引数」呼び出し元では「渡すデータそのもの」を、呼び出される側では「受け取るべき器」を記述してやる必要があるって事だな。

他に知りたい事はあるか?


いや、もうない。ありがとう。


そうか。取りあえず今回教えた事はPDA・・・じゃない、覚え書きに書いておいたぞ。
判らなくなったらいつでもそれを見るんだ。


わかったよ。じゃあな。


グッハンティンストーカー。





top / 1 / 2 / 3 / 4 / ex1 / 5 / 6 / ex2 / 7 / 8 / 9 / 10 / 11 / ex3 / 12 / 13 / 14 /..../ 関数 / 覚え書き / 倉庫
ニャギ茶★SPOT --工作部屋--