Celowin - パート 2: ローカル変数

前置き


この一連のレッスンの目的は、全くの初心者をプログラミングの世界に誘い、モジュールを作成するためにNWNのスクリプトをどのように使うかを教えることです。初めの 部分のレッスンはとても基本的なものになると思われるので、何かのプログラムを書いたことがある人は飛ばしても構わないでしょう。これらのレッスンの最終目的は、プログラムと聞いただけで身震いするような人々でも学べる場を提供することです。


これらのレッスンをフォーラムに掲示したり、印刷したり、修正を加えることは大いに構いません。しかし、その際には私が作成したということをどこかで触れて下さい。良い悪いを含めて、これらのレッスンについて何かコメントがあれば私に送って下さい。Celowin.


これらのレッスンは、オーロラツールセットをある程度触っている人を想定して書かれています。これらのレッスンにおいて解りにくい部分があるという意見が多数寄せられれば、必要な部分をさらに詳しく説明することも考えています。


イントロダクション


このレッスンは、前のレッスンよりは少し長くなるでしょう。そして、もう少し高度な概念を扱います。どのようにすれば上手く説明できるか自信がないので、何か分からないことがあったら質問して下さい。あなたが分からないことに対して、きっと他に5人は同じように分からないと思っているでしょう。


前回作ったモジュールに手を加えてみましょう。ツールセットでモジュールを開いて下さい。


配置したNPC上で右クリックをして、プロパティを選択します。そして、スクリプトタブを選択します。


今回は2つのスクリプトを作成します。両方とも短いスクリプトです。


最初のスクリプトは、OnSpawnスロットに設定します。


void main()
{
  SetLocalInt(OBJECT_SELF, "SINGER_COUNT", 0);
}

スクリプトをtm_singer_os ('os' はOnSpawnという意味です)という名前で保存します。


たった1行のスクリプトですが、一度もスクリプトを書いたことのない人にとっては不安に感じるものです。したがって、「真の」スクリプト作成に入る前に、このスクリプトについて説明をしようと思います。


まず第一に、このスクリプトを、以前に扱ったイベントスロットとは異なったスロットに設定していることに注意して下さい。OnSpawnスロットに設定されているスクリプトは、NPCがゲームにロードされた時に1回だけ実行されます。従って、我々がここで行っているように、何かを初期化するのに理想的です。


この1行のスクリプトは、ある変数を設定しています。あなたの最後の数学の授業を思い出して下さい。変数とは何でしたか?それは、数字を表す文字です。1文字ではなく長い名前を付けていることを除いては、ここでいう変数は数学で習った変数とほとんど一緒です。


SetLocalInt関数は、ローカル変数を設定する関数で、コンマで区切られた3つの入力情報を必要とします。


ここで、2番目と3番目の入力情報は意味が分かると思います。変数名をSINGER_COUNTとして、それに0という値を与えています。最初の入力情報について、もう少し説明をします。


モジュール内にあるものは、ほとんど全てがオブジェクトです。NPC、配置可能物、ウェイポイントもオブジェクトですが、PC自身でさえもオブジェクトです。モジュール内にはとても多くのオブジェクトが存在しているので、その中から正しいものを参照する時にちょっとややこしくなります。


OBJECT_SELF は、オブジェクトを参照する時の最も便利な方法の1つです。OBJECT_SELF は、スクリプトを呼び出したオブジェクトを参照するので、今回の場合、スクリプトはNPCに設定されたのでOBJECT_SELFはNPCを意味しているということが推測できます。


まとめると、この1行のスクリプトは、 SINGER_COUNTという変数を定義し、それに0という値を代入して、NPC SINGERに保管するということを行っています。


SetLocalInt関数の「Int」は「Integer(整数)」を意味しているということにも注意して下さい。4、0、–35といった値は設定できますが、例えば3.8といった値は設定できません。


さて、次のスクリプトに移りましょう。前回OnHeartbeatスロットに設定したスクリプトを上書きしたいと思います。


int nCount=GetLocalInt(OBJECT_SELF, "SINGER_COUNT");
void main()
{
    nCount = nCount+1;
    ActionSpeakString("私は "+IntToString(nCount)+" 回話しました。");
    SetLocalInt(OBJECT_SELF, "SINGER_COUNT", nCount);
}

名前はtm_singer_hbのままで保存します。


説明の前に、このスクリプトが実際に何を行うかを見た方がいいでしょう。よって、スクリプトエディタを閉じて、OKを押してNPCのプロパティ画面を閉じて下さい。そして、モジュールを保存します。モジュールを起動してNPCがどんな行動するか確認して下さい。


このスクリプトで初めて、void main()の前にコードを書いています。これについて説明しなければならないでしょう。main関数の前に書かれているコードは全て、スクリプトの「初期化」と呼ばれています。基本的に、そこで設定したものはスクリプトから参照できます。前に扱ったローカル変数とは違って、nCountは、スクリプトが実行されている間だけ保持されます。スクリプトが終了すると、nCountは破棄されます。このため、このように使用される変数は、「一時変数」と呼ばれています。


main関数の中で、nCountが何回使われているかに注意して下さい。nCountを使う代わりに、毎回GetLocalInt(OBJECT_SELF, "SINGER_COUNT")を書いていたら、スクリプトがどんなに長く、ややこしいものになるか想像してみて下さい。うんざりしますよね?


ここで、nCountという名前は、ある種の標準化を用いています。一時変数を宣言するときは、変数名の最初の1文字から、この変数が保持している値の種類が分かるようにします。「n」は整数を表しています。変数にはどんな名前をつけることもできますが、この方法を使えば、変数が整数値を持っているに違いないとすぐに知ることができます。「Count」の部分で、この変数が何のために使われるのかをある程度知ることができます。


intは、整数値を定義しているという意味です。「=」は「値を代入する」という意味です。GetLocalInt関数は、変数SINGER_COUNTに保管されている値を取り出します。これに似た関数があったことを思い出して下さい。前回、SetLocalInt関数を使ってローカル変数に値を保管しました。GetLocalInt関数は、その値を取り出すために使われます。


したがって、最初の1行は多くのことを行っています。スクリプトが使用できる一時変数nCountを作成し、それにNPC上の変数SINGER_COUNTに保管されている値を代入しています。OnSpawnスロットに設定したスクリプトにおいて、SINGER_COUNTには0という値を設定したので、最初にこの行が実行されるとnCountには 0という値が代入されます。


1行のコードとしては、説明が多すぎるのというのは分かっていますし、みんなが1回で理解できるとは思っていません。もう一度じっくり読んでみて下さい。仮に分からなくても心配しすぎる必要はありません。この種のコードは、いくつかの例を扱えばより理解できるようになります。


main関数の本体の説明に移りましょう。最初の行について考えてみて下さい。


nCount = nCount+1;


これは、一時変数に1を加えた値を、再度同じ変数に代入しています。このような表現の場合、頭に「set」という言葉を付けて考えると分かりやすい人もいるようです。言葉に言い換えると、「nCountに1を加えた値をnCountに設定する」という感じになります。


もしnCountが9という値であれば、新しい10という値が設定されます。


(付け加えると、NWNスクリプトでは以下のような表現もできます。


nCount++;


[++]は 「インクリメント(増加)」を表しており、値を1つ増加させます。一度使えば便利な表現ですが、一般的に、スクリプト初心者にとっては少しとまどいを感じる表現だといえます。)


2行目はActionSpeakString関数ですが、中身がちょっと変わっています。まず第一に、+ 記号で区切られた3つの部分から成り立っていることに注目して下さい。文字列に使用する時、+記号は一方をもう一方に接続します。簡単な例を挙げると、「これは文字列です。」と、「これは」+「文字列です。」は全く同じものになります。


上のような表現にした理由は特にありませんが、真ん中の表現IntToString(nCount)を使うときに便利になります。この関数は正にその名前通りのことを行います。nCountは整数ですので、数字を文字列に変換します。


この方法は、プログラムを書いたことの無い人をちょっと混乱させると思うので、説明させて下さい。私が「象がチュチュを着ている」というような変なことを言っていると仮定して下さい。あなたは、すぐに頭の中にその絵が浮かび、私が言った文章を構成する個々の単語についてまでは考えないでしょう。文字に書くときだけ、象が...というように文字を考え始めます。


コンピュータも同じです。変数に値を保管している時は、それをどのように「文字に書く」かについては考えていません。IntToString関数は、NPCが話すことができるように、値を文字列に変換するようにコンピュータに伝えます。


最後の行も理解する必要があります。ここでは、新しいnCountの値をローカル変数に戻しています。nCountは一時的なものであり、スクリプトが終了すると破棄されることを思い出して下さい。したがって、NPC上の変数を更新したいときには、再度値を保管する必要があります。


レッスン3のプレビュー


レッスン2は、長いので元々2回か3回に渡って説明するつもりでしたが、別のレッスンに分けたいと思います。しかしここで、最後のスクリプトにあるちょっとした失敗を見逃す訳にはいきません。


あなたが細かい人なら、最初にスクリプトをテストしたときにおやっと思ったかもしれません。NPCが一番最初に話す言葉は、「私は1回話しました。」です。どういう意味かは簡単に分かりますが、文章表現が上手くないですね。

この問題を避けるには、「条件」や「if文」を用いる方法があります。レッスン3まで説明するつもりはありませんが、問題を解決したスクリプトを書いておきます。OnHeartBeatスロットに設定したスクリプトを以下のスクリプトに置き換えるだけです。


int nCount=GetLocalInt(OBJECT_SELF, "SINGER_COUNT");
void main()
{
  nCount = nCount + 1;
  if (nCount == 1)
  {
    ActionSpeakString("今初めて話しました。");
  }
  else
  {
    ActionSpeakString("私は " + IntToString(nCount) + " 回話しました。");
  }
  SetLocalInt(OBJECT_SELF, "SINGER_COUNT", nCount);
}

説明無しでもいくらか理解できると期待しています。実際、このスクリプトを完全に理解したら、自分自身のスクリプトを書く方法を80% は理解していると言ってもいいでしょう。





 author: Celowin, editor: Iskander Merriman, JP team: katsu794
 Send comments on this topic.