2006年10月23日

はじめに

 この「一週間で出来るVRMスクリプト」カテゴリは、VRMスクリプトの基礎をおぼえたいと思っている人のために書きました。ただし、読んでいただく前にひとつはっきりさせておきたいことがあります。

スクリプトを知らなくても、VRM4はVRM3と同程度以上のギミックは使えます。
スクリプトを知っていると、あなたの独自のギミックをVRM4で実現することができるかもしれません。


 要は、VRM4に「VRM3と同じくらいの機能」+「よりリアルな3D車両」を期待しているのであれば、スクリプトを覚える必要はないということです。

 また、スクリプトで行えるのは、編成、ポイント、信号などVRM4における可動部品の制御と決まっていて、それ以上でもそれ以下でもありません。ましてや魔法などではありません。

 このことを理解して、ぜひスクリプトに対する得体の知れない拒否感と、それにともなうVRM4への拒否感を解消していただきたいと思います。

 長くなるのは本意ではありません。ここで納得し、なおVRMスクリプトに興味がある方は、一日目を読み始めてください。

 こちらからどうぞ。

 未だ合点がいかない方は、続きを読んでください。
__________________________________________________

 自分が心配なのは、VRM4では、VRM3では簡単に使える機能にもいちいちスクリプトが必要なのに違いない、とVRM4を敬遠している方が多そうなことです。
 確かにそういう機能もありますが、これらは全て、スクリプトウィザードを使うことでスクリプトを目にしなくても設定できます。

0610scriptwizard.jpg
<スクリプトウィザード>

 もっと言えばこれは単純な機能に限りません。幾人かのネットVRMユーザーは、複雑な動作をウィザードだけで実現できるスクロール(ウィザードに表示される項目)を公開しています。これらを利用すれば、自動閉塞運転などのVRM3をはるかに凌駕するギミックを容易に得ることができます。

 それでは、VRMスクリプトを覚えるメリットはいったい何でしょうか。

 ウィザードで自動生成するスクリプトと、ユーザー自身が記述するスクリプトには大きな違いがあります。ウィザードはスクロールの製作者の提示した目的しか実現できませんが、スクリプトは組み合わせ次第でユーザーの「何かをしたい」という様々な目的にフィットし得る、ということです。

 あくまで程度の問題です。スクリプトはウィザードより命令の内容が細かいというだけで、スクリプトを持ってしても不可能なこともたくさんあります。
 しかしそれでも、定型文の組み合わせ的なウィザードよりは、スクリプトを直接記述するほうがずっと多彩なギミックが作れます。

 スクリプトを覚えるには、「スクリプトでアレやコレをやりたい!」という気持ちが「それなりに長いテキストを読む」というノルマを嫌う気持ちに勝っていなければなりません。

 逆に言えば、どんなにわかりやすい解説よりも修得に大切なのは、各人の「スクリプトでアレやコレをやりたい!」というモチベーションです。なんとなくスクリプトは覚えたほうがよさそう、というだけなら、たぶん単に「スクリプトは面倒くさい」という記憶が残るだけです。

 VRMスクリプトが特別なのではなく、自転車の乗り方からあなたの覚えている鉄道の知識まで、大抵のものはそうだと思います。VRMスクリプトに対してもそういうモチベーションのある方は、VRMスクリプトに取り組んでもきっと後悔しないはずです。


2005年11月05日

あとがき

 読んでくださった方どーもありがとうございました。もし文章が長いと感じてやめてしまった方がいたら、それは改行の多さとスクリプトと解説を併記したことによる単なる印象です。
 短い文章ではありませんが、実際読んでみればそれほど時間を要することはないはずです。

 それから、スクリプトはVRM4で絶対必要、これがないと運転できない!というものではありません。また、修得の程度も個人の必要に合わせたレベルでかまいません。とりあえずVRM3並みの操作がしたい方はカメラや列車をアクティヴにする方法を知ればよいですし、ライトのON/OFFも然りです(これらはウィザードを使ってもできますが)。

 でも、スクリプトの基本を覚えるのに一ヶ月かからないことは確かです。先月の頭に

>え?EF64のヘッドライトですか?いや、あれはスクリプトウィザードでちょいちょいとやりました。EF64-1000の入替標識もウィザードです。

 などと書いていた45-50sがスクリプトの解説を書くまでにこぎつけたことが何よりの証拠です。45-50sにできたのだから誰でもできるはずですよ、自慢でもなんでもなく。

2005年11月04日

七日目:スクリプトを書いてみるII

 最終日の今日は、簡単な自動運転スクリプトを書いてみましょう。

 どういうものかというと、待避線のある駅が1つの単線小判型ループに、2本のお互いに逆方向に走る列車を配置します。まずキーを押すと、信号が青になって1本が発車し、一周して戻ってきて停車します。すると今度は対向列車の信号が青になって自動で発車し、一周して戻ってきて停車。あとはこの繰り返しで、駅で2つの列車が交換を繰り返すというモノです。

 第2号をお持ちの方はこちらをダウンロードして実際に書いてみてください。このサンプルレイアウトでは、編成・信号・ポイント・センサーの名前は既に書き直してありますが、スクリプトは白紙状態です。

 さて、この「単線自動交換」を実現するにはどうすればよいでしょうか。まず使う部品を整理しましょう。

(1)編成
 なくてはならない、編成です。
 ここでは発車や減速〜停車をSetTimerVoltageを使って命令します。

(2)ポイント
 最初にデフォルトの編成が一周して駅についた後、自動でもう1本の編成が発車します。でもVRM4では間違った方向からポイントに進入すると編成が強制停止してしまうので、発車する前に駅のポイントを切り替えておかないと発車できませんね。ですからポイントにはポイントの向きを切り替えるメソッドを書いておくことが必要になります。

(3)信号
 おまけみたいなもので編成の制御には影響を及ぼしませんが、はじめは赤が点灯していて発車する直前に青になるようにすると面白いですよ。

(4)センサー
 編成の停車位置にセンサーを置き、それを一周して戻ってきた編成が踏んだときにもう一方の編成の発車メソッドをcallすれば「一方の編成が進入して停車するともう一方の編成が発車する」という挙動を再現できます。
 また、停車位置の手前にも踏んだ編成の減速メソッドをcallするセンサーを置きます。

 これら4種類の部品を以下のように配置します。直近の単語は部品につけた名前です。センサーの名前は込み入るので、離して記してあります。

samplepicture.jpg

<動作の流れ>
 デフォルトの編成は「ED75」です。最初にAキーを押すと信号「WestSignal」が青になり、「ED75」は自動で加速します。一周して駅に戻るとセンサー「SlowdownED75」を踏んで減速し、このとき同時に信号「WestSignal」を赤に戻します。停車位置には「StartED75jr」が置かれていて「ED75」は停車直前にそれを踏みます。

 すると今度は信号「EastSignal」が青になった後「ED75jr」が加速を始めます。一周して駅に戻るとセンサー「SlowdownED75jr」を踏んで減速し、このとき同時に信号「EastSignal」を赤に戻します。そして停車位置には「StartED75」が置かれていて「ED75jr」が踏めば再び「WestSignal」が青になり「ED75」が発車します。

 これの繰り返しです。フライスルーカメラにして駅周辺で待っていれば、貨物列車が交換を繰り返す様を眺めることができます。

<使用する命令>
 今回、前述の4種類の部品で使う命令は以下のようになります。

(1)編成(と車両)

SetTimerVoltage 0.0〜1.0 待ち時間

 駅発車と停車の両方に使えますね。編成の速度制御は今回この命令に全て任せます。

SetHeadlight/SetTaillight 0又は1

 ライトが点いているとそれだけでもかっこいい!

(2)ポイント

SetPointBranch 0又は1

 branchは「分岐」の意味ですね。0は直進側、1は分岐側に設定します。

(3)信号

SetSignal 1〜6

 今回は2灯式信号を使用するので、現示は「停止」「進行」の2種類だけです。停止のときは変数を1、進行のときは6にします。2〜5は「警戒」や「注意」などがある信号で使います。詳しくはリファレンスを参照してください。

イベント系統の命令

SetEventSensor 呼ぶメソッドの名前 グローバル変数
SetEventKey 呼ぶメソッドの場所 呼ぶメソッドの名前 グローバル変数 キー
call 呼ぶメソッドの場所 呼ぶメソッドの名前

 この3つは紹介済みですし説明はいりませんね。もう1つ、callに似ているけれどちょっと違うこの命令を使います。

SetEventAfter 呼ぶメソッドの場所 呼ぶメソッドの名前 グローバル変数 時間

 callは即座にメソッドを呼びますが、この命令は任意の時間後に呼ぶことができます。よく見てください、右側に書き入れる変数はcallにグローバル変数と待ち時間が加わっただけですね(そういう意味ではSetEventKeyもcallにグローバル変数とキーが加わっただけです)。
 なお、時間はSetTimerVoltageと同じく1000分の1秒で書き入れます。
____________________

 まず初期設定を書いてしまいましょう。BeginFuncとEndFuncで挟まない命令は最初に実行されるのでしたね。最初から実行されていてほしい命令と言えば…

 まず車両のスクリプトエディター(編成のではありません!)にライト類を点灯させろ!と書いてしまいましょう。

<車両のスクリプトエディター>

SetHeadlight 1
SetTaillight 1

 2両のED75に書いてください。これでビュアーを起動したときからライトが光り続けます。

 信号機も消えていてはおかしいですね。とりあえずはじめは全部赤現示で。

<2灯式信号のスクリプトエディター>

SetSignal 1

 東西2基の信号に書けましたね。これで初期設定はOKです。つぎに速度制御のメソッドを書きますが、速度ですから編成のスクリプトエディターに書きます。

<編成のスクリプトエディター>

BeginFunc LetsGo
SetTimerVoltage 0.7 3000
EndFunc

BeginFunc StopTrain
SetTimerVoltage 0.0 5000
EndFunc

 これは2つの編成共通ですから、両方に書いてください。
 発車用メソッドLetsGoの加速に要する時間はあなたの自由にしてかまいませんが、他の値は変えないでください。変えると、一周して駅に戻ったときに正しい位置に停車できません。
 内容は見ればわかる通り、加速用メソッドと停車用メソッドです。

 さて、編成の速度制御に連動して動作させたい動きがまだ2つありましたね。信号の現示とポイントの向きです。これらもメソッドだけ部品に書いておきましょう。

<2灯式信号のスクリプトエディター>

BeginFunc Green
SetSignal 6
EndFunc

BeginFunc Red
SetSignal 1
EndFunc


<ポイントのスクリプトエディター>

BeginFunc Straight
SetPointBranch 0
EndFunc

BeginFunc Curve
SetPointBranch 1
EndFunc

 これらもそれぞれ2つの信号、ポイントの両方に書いてください。信号に書くときは、さっき書いた初期設定用のSetSignal 1を消しちゃわないように注意。

 これで「何を」やるかは一通り書けました。あとは的確なタイミングでメソッドを呼んでやるだけです。
 順番に、まずはAキーを押すと信号「WestSignal」が青になり編成「ED75」が加速するというのを書きましょう。

<レイアウトのスクリプトエディター>

Var AHO
Var MANUKE

SetEventKey this CallLetsGo AHO a

BeginFunc CallLetsGo
call WestSIGNAL Green
SetEventAfter ED75 LetsGo MANUKE 1000
EndFunc

 冒頭で宣言した2つの変数のうちAHOはSetEventKey、MANUKEはSetEventAfterで使うためのものです。下半分のメソッド「CallLetsGo」は中継用メソッドですね。Aキーを押すとCallLetsGoが呼ばれ、そのCallLetsGoがWestSIGNALのGreenとED75のLetsGoを呼びます。

 日本語で書くと、WestSignalを青にして1秒後にED75を加速するということですね。

 次に、ED75が一周して戻ってきてはじめて踏むセンサー「SlowdownED75」です。

<センサー「SlowdownED75」のスクリプトエディター>

Var AHO

SetEventSensor CallStopTrain AHO

BeginFunc CallStopTrain
call WestSIGNAL Red
call ED75 StopTrain
EndFunc

 これも構造的にはSetEventKeyのものと変わらないですね。SetEventSensorに呼ばれた中継用メソッド「CallStopTrain」がWestSIGNALのRedとED75のStopTrainを呼ぶ。すなわち「センサーを踏んだら信号が赤になって列車が減速〜停車する」という内容です。

 さて、減速し停車するED75が踏むのが次のセンサー「StartED75jr」です。このタイミングで信号「EastSIGNAL」を青にして対向の編成「ED75jr」を発車すればまさに列車交換ですね。ただ、ED75が駅に滑り込んだ瞬間ED75jrが発車するのは少し焦りすぎというか不自然ですから、SetEventAfterで時間差を作ってやるわけです。

<センサー「StartED75jr」のスクリプトエディター>

Var AHO
Var MANUKE

SetEventSensor CalljrLetsGo AHO

BeginFunc CalljrLetsGo
call EastSIGNAL Green
call WestPOINT Curve
call EastPOINT Curve
SetEventAfter ED75jr LetsGo MANUKE 3000
EndFunc

 今度の中継用メソッドが担う役割は「対向の信号を青にして、しばらく経ったらED75jrを発車する」ですね。ただし忘れてならないのはポイントの切替えです。2つのポイントを切り替えないと、発車するときか一周して戻ってくるときに強制停止の憂き目にあいます。
 ついでに、3つ以上のポイントがあってcall命令がずらっと並んでヤダなぁというときはこんな方法もあります。

 さあED75jrが発車していきました。あとは同じです。戻ってきたED75jrが最初に踏むセンサー「SlowdownED75jr」で、今度はEastSIGNALを赤にしたうえでED75jrを減速します。そして次に踏むセンサーでWestSIGNALを青にしてポイントの向きを直進に戻し、時間差でED75を発車させれば、無限ループの完成です。
 具体的には以下のようになりますが、解説はしませんよ。

<センサー「SlowdownED75jr」のスクリプトエディター>

Var AHO

SetEventSensor CallStopTrain AHO

BeginFunc CallStopTrain
call EastSIGNAL Red
call ED75jr StopTrain
EndFunc


<センサー「StartED75」のスクリプトエディター>

Var AHO
Var MANUKE

SetEventSensor CallLetsGo AHO

BeginFunc CallLetsGo
call WestSIGNAL Green
call WestPOINT Straight
call EastPOINT Straight
SetEventAfter ED75 LetsGo MANUKE 3000
EndFunc

 あー、1つだけ。このスクリプトは簡単のため、ここに書いたとおりに書けばうまいこと停車位置とセンサーが重なるようにしてあります。さっき速度制御用メソッドはいじらないで、と書いたのはそのためです。もちろん手動の速度操作を封じたり、色々な速度からでも一定の位置に停車する方法はありますが、今回はあくまでサンプルと言うことでやってません。
 ですからこのレイアウトで遊ぶときは眺めるだけにして、手動の速度操作は一切しないでください。
____________________

 はい、終わりです。どうでしたか?何となくでもわかった気がしてきませんか?

 本当はif命令やSetEventTimer、KillEventなんかもやりたかったんですが…。まあ今のあなたなら自力で答えにたどり着けるか。
 もしわからないところがあったら遠慮なくコメント欄に質問ください。自分にわかる範囲ならお答えしますし、わからないところでもたぶん暇な人が見つけてフォローしてくれるでしょう(ぉぃ

 よっしゃ!スクリプト楽勝!

他の日へはこちら

2005年11月03日

六日目:スクリプトの所在

 これまでスクリプトを書くたびに「このスクリプトはどこに書くか」ということも併記してきました。まとめると

(1)SetVoltageなどの命令はその命令をするオブジェクト(部品)に書く。

  例:SetVoltage →編成オブジェクト
    SetHeadlight→車両オブジェクト

(2)変数はメソッドの中に宣言するか外に宣言するかで性質が異なる。

  例:メソッドの中ならローカル変数。そのメソッドでしか使わない変数。
    メソッドの外ならグローバル変数。レイアウト全体で使える変数。

 (1)は間違うと、スクリプト自体が正しくても動作してくれません。VRMもビュアー起動時に自動でエラーチェックしてくれますが、スクリプト自体の正誤を確認するだけなので、所在はチェックしてくれないようです。
 「センサーを踏んだら速度を○○にする」というスクリプトを書くとき、うっかり速度制御メソッドまでセンサーに書いたりしないようにしましょう。

 (2)を間違うとどうなるでしょうか。ローカル変数を間違えてグローバル変数として宣言しても特段支障はありません。
 しかしグローバル変数でなければいけないところをローカル変数としてしまうと、他のメソッドやイベントからその変数を呼び出そうとしても呼び出せなくなります。そうなるとやはり意図した動作が起こらず悩むことになります。

 構造上「ここに書かねばならない」というスクリプトもありますが、そうでないものもあります。しかしそういうスクリプトもきちんと書く場所を意識しないと「アレ?あのスクリプトどこに書いたっけ」という事態に何度も陥りますから気をつけましょう。
 ここで1つ新しい命令を紹介します。

DrawMessage "表示内容"

 ビュアー左下のログウィンドウにMessageをDraw(描く)します。""でくくられた中身が表示されますので"出発進行"でも"第三閉塞進行"でも何でも良いです。
 BeginFuncとEndFuncで挟まなければ最初から表示され、メソッドの中に書けばcall命令やSetEventKeyなどで呼ばれたときに表示されます。

 自分は、この命令はレイアウトのスクリプトエディターに書くようにしています。

<レイアウトのスクリプトエディター>

BeginFunc Start
DrawMessage "出発進行"
EndFunc

BeginFunc NextA
DrawMessage "次はA駅です"
EndFunc

BeginFunc NextB
DrawMessage "次はB駅です"
EndFunc

 とでもメソッドを列挙しておきます。これでcall命令を使えば駅出発メソッド全てにDrawMessage命令を書く手間が省けますし、書き換えたいときにも「メッセージ関係はレイアウトに書いた」と知っていれば探さなくてもすぐできますね。

 そういうわけで、スクリプトの所在は常に意識するようにしましょう。

 明日は最終日。簡単な自動運転でも書いてみましょうか。

他の日へはこちら

2005年11月02日

五日目:スクリプトの構造III(変数の操作)

 昨日は変数は命令の「○○」の部分、つまり情報を担うのだということを書きました。今回は、

>センサーを踏んだ編成がどの編成なのかという情報を変数に持たせ、中継用メソッドのcall命令にその変数を書き入れればよいのです。

 コレを具体的に解説するわけですが、その前に変数の操作の仕方と変数の種類を知っておきましょう。ちょっとこちらのスクリプトをご覧ください。

Var AHO

set AHO 1

SetHeadlight AHO

 まず「AHOという名前の変数を使うぞ!」と宣言していますね。そのあと見慣れないsetという命令が書かれた行があり、最後に昨日紹介したSetHeadlightがあります。

 まて、なんだSetHeadlight AHOってのは。

 0なら消灯、1なら点灯、じゃあAHOなら…やっぱり「Headlightをアホにしろ」ってことか?と思った人、残念。SetHeadlightは昨日書いたとおり0か1という変数しか受け付けません。
 ハイそこで、さっき読み飛ばした「set AHO 1」という部分に目を移してください。

 ここでなされた操作は、まさに見ての如く「AHOを1にsetする」、もっと言えば「AHOを1にする」という操作です。よってこれ以降、AHOをいじらない限りAHO = 1が成立します。ということは当然、

SetHeadlight AHO = SetHeadlight 1

 ですね。ですから上のスクリプトはSetHeadlight 1と書いたのと同じことなのです。面倒ですか?だったらSetHeadlight 1でいーじゃん、と思われますか。

 実はSetHeadlightの右側に直接0か1を書き込めるようになったのはVRMスクリプトの実装からしばらく経ってからのことです。そのウラにはこういう理由があるらしいですが、それに加えてこの方法にはset命令を使うという手間をかけるだけのメリットがあります。それが件の「センサーを踏んだ編成がどの編成なのかという情報を変数に持たせ、中継用メソッドのcall命令にその変数を書き入れればよいのです」云々です。

 しかしそのことを解説するには、変数にも種類があることも書いておかねばならないでしょう。もう少しご辛抱ください。

 「Var」で宣言できる変数はただの「変数」です。これは冒頭に書いたように、SetVoltageやSetHeadlightなどにおいて速度や点灯状態などの情報を担当したり、SetEventSensorなどにおいてイベントIDという情報を担当します。

 そしてVarの仲間に「VarTrain」「VarLayout」のような「Varなんとか」があります。これら「Varなんとか」は部品自体を担当します。見ての如くVarTrainは編成名、VarLayoutはレイアウトを保持することができ、他にもVarPointやらVarSignalやら、制御可能な部品にはみんな専用の変数があります。
 これらを総称してオブジェクト変数と呼びます。ここでついでに、VRMスクリプトにおいては部品のことをオブジェクトと呼ぶことを覚えてください。

 さて、例えばTrain変数MANUKEに編成「TRAIN」を設定したいときは下のように書きます。

VarTrain MANUKE

get MANUKE TRAIN

 これでOKです。オブジェクト変数にオブジェクトを設定するときは、先ほど出てきたsetではなくgetを使います。setとgetの違いは、setが整数を扱うのに対しgetはオブジェクトの名前を扱うという点です。ところでgetに似たこんな命令があります。

GetSenseTrain Train変数

 これは「センサーを踏んだ編成をTrain変数にgetする」、つまり「センサーを踏んだ編成=Train変数とする」という命令です。ならばTrain変数とこの命令を使えばセンサーを踏んだ編成を特定できるではありませんか。

 早速書いてみましょう。センサーを踏んだとき、例えば

・編成「485series」は警笛を鳴らして3秒かけて速度を最高速度にする
・編成「EF64」は警笛を鳴らす

 というようにそれぞれに違う動作をさせたいケースを考えます。ちなみに「警笛を鳴らせ!」という命令はPlayHornを使います。変数は伴わない簡単な命令です。

 まず2本の編成に、センサーを踏んだときに実行したいメソッドを書きます。このとき大事なのは、2つのメソッドを同じ名前にすることです。
 いいんです。別の編成にあればお互いに顔が見えませんから、メソッドの名前は被っても支障ありません。

<編成「485series」に書く>

BeginFunc FUNDARA
PlayHorn
SetTimerVoltage 1.0 3000
EndFunc

<編成「EF64」に書く>

BeginFunc FUNDARA
PlayHorn
EndFunc

 どちらもセンサーを踏んだら起こしたいのでFUNDARAとでもしてみました。皆さんも、名前は何でもいいですからとにかく同じにしましょう。やりたい方はメソッドの中身もお好きに変えて結構です。

 お次はセンサーです。こちらが肝心ですよ。編成のほうはメソッドがあるだけで、踏んだ編成を区別するギミックはこちらに書きますからね。よく読んでください。

<センサーに書く>

Var AHO
VarTrain MANUKE

SetEventSensor CallFUNDARA AHO

BeginFunc CallFUNDARA
GetSenseTrain MANUKE
call MANUKE FUNDARA
EndFunc

 スクリプトの冒頭でまとめてここで使う変数を宣言しています。SetEventSensorに用いる変数AHOと今回のキモのGetSenseTrainに使うTrain変数MANUKEですね。
 そのあとSetEventSensorで「センサーを踏んだら(中継用メソッドの)CallFUNDARAを実行せよ」と書きます。これは説明不要でしょう。

 最後にいよいよCallFUNDARAを書きます。BeginFuncとEndFuncで挟まれた部分に書く2つの命令が具体的な中身ですが、まず

GetSenseTrain MANUKE

 と書いて冒頭で宣言したTrain変数MANUKEに、このセンサーを踏んだ編成の名前を登録するようにします。そしてその後です。今までなら

call 485series FUNDARA

 とか

call EF64 FUNDARA

 と「呼ぶメソッドの場所」には具体的な編成名を書いていましたが、今回は

call MANUKE FUNDARA

 として編成名の代わりにTrain変数MANUKEを書き入れます。先ほどGetSenseTrainを使ってMANUKE=センサーを踏んだ編成という状態にしていますから、これは

call センサーを踏んだ編成 FUNDARA

 と同義です。これで485seriesが通過したときは485seriesのメソッド「FUNDARA」が実行され、EF64が通過したときはEF64のメソッド「FUNDARA」が実行されます。
 これならいくつの編成を運転しても、メソッドの名前さえ統一すればそれぞれにユニークな動作をさせることができますね。
_____

 変数の操作はset、get、GetSenseTrainだけでなく、setを小数に対応させたsetfやレイアウト参照に特化したgetlayoutなどまだいくつかバラエティがあります。
 また、数値を取得した変数は四則演算(+−×÷)も可能ですから、要は変数は煮るなり焼くなりあなたの好きなようにしていいってことです。
 興味がある方はスクリプトリファレンスの「変数操作」「演算」の項をご覧ください。オブジェクト変数の種類も「変数宣言」の項に列挙されています。

 いかがでしょう。最初は難しく感じるかもしれませんが、変数を使ってスクリプトを書いているうちに苦でもなくなると思います。大事なのは実際に自分で書くことですよ。

他の日へはこちら

2005年11月01日

四日目:スクリプトの構造II(命令と変数)

 昨日ちょっとだけ言葉が出てきた「変数」についてもう少し解説します。

 例えばSetVoltageは「編成の速度を○○にしろ!」という命令でしたが、この「○○」を担うのが変数の役割の1つです。

 昨日書いたメソッド「LetsGo」で

SetVoltage 0.8

 と書きましたね。この「0.8」という数値が変数です。このように数値の変数を命令の右側に書き入れる命令をいくつか見てみましょう。

SetHeadlight 0又は1

 見ての通りHeadlight(ヘッドライト)をSetします。感覚的にわかると思いますが、0が消灯、1が点灯です。ちなみに、これは車両ごとに設定できますから車両のスクリプトエディターに書きましょう。

SetTaillight 0又は1

 SetHeadlightの兄弟のような命令で、Taillight(テールライト)をSetします。命令のかたちはSetHeadlightと全く同じです。これも車両のスクリプトエディターに書くのはわかりますね。

SetTimerVoltage 設定速度 設定時間

 これは書き入れる変数が2つありますね。「設定速度」と「設定時間」です。
 SetVoltageは変数が設定速度だけだったので、命令が実行されると即座に設定速度に変わります。もし本物なら、下手したら乗客が壁に押し付けられてせんべいになってしまいますね。
 これに対して、SetTimerVoltageはTimer(タイマー)が加えられています。設定時間後に設定速度になるようになめらかに速度が変化しますから、リアルに速度制御をすることができるのです。
 なおSetTimerVoltageは設定速度に使う変数はSetVoltageと同じ0.0〜1.0の小数ですが、設定時間に使う変数は単位がms(1000分の1秒)です。
 つまり1000と書けば1.000秒、3500と書けば3.500秒です。
_____

 さて、変"数"と言っても見た目が数値とは限りません。昨日センサーに書いたイベントの冒頭で変数AHOを使うよ!と宣言したのを思い出してください。

<AHOという名前の変数を使うよ!という宣言の仕方>

Var AHO

 このように簡単なのですが、宣言する場所を少し考慮する必要があります。それは、メソッドの中に宣言するか、それとも外に宣言するかという違いです。

 メソッドの中に宣言された変数はローカル変数と呼びます。この変数は宣言されたメソッドの中でしか使えません。代わりにメソッドの外とは隔絶されていますから、他のメソッドの中にあるローカル変数と名前が重複してもいっこうにかまいません
 メソッドの中限定とは、確かにローカルな変数ですね。

 それに対してメソッドの外に宣言された変数はグローバル変数と呼び、レイアウト全体からアクセスすることができます。それゆえ、名前の重複には気をつけねばなりません
 どこからでもアクセスできるからグローバル。もちろんレイアウトの中での話ですが。

 昨日使った変数AHOはグローバル変数です。もしローカル変数だと、ローカル変数は外から隔絶されているために「この命令と他の命令とを区別する」というここでの目的を成し得ません。ですから変数AHOはグローバル変数でなければならないのです。

 では、このようにVRMが命令を区別するためのグローバル変数が必要な命令を紹介します。

SetEventSensor 呼ぶメソッドの名前 グローバル変数

 ハイ、もうお馴染みですね。中継用メソッドを呼ぶことが目的の命令ですから、呼ぶメソッドの場所は書くまでもなくこの命令が書かれたセンサーです。ですからまずそのメソッドの名前を書き、その隣に、あらかじめ宣言しておいたグローバル変数を書き入れます。これでVRM君がこの命令を他と区別できます。

SetEventKey 呼ぶメソッドの場所 呼ぶメソッドの名前 グローバル変数 キー

 あるKeyを押したら○○を起こせ!というEventをSetします。つまり「Aキーを押したら〜」という命令です。右側に4つも項目があってちょっと面倒くさいですが、順番に書けば簡単です。まずキーを押したら呼ぶメソッドの場所と名前を書き、宣言しておいたグローバル変数を書いたら最後に設定したいキーを書き入れます。
 ちょっと例を示しましょうか。小判型の線路に編成を1つ置いて、書いてみてください。線より上がレイアウトのスクリプトエディター、下が編成「TRAIN」のスクリプトエディターに書くスクリプトです。

<Zキーを押したら編成「TRAIN」を停車する>

Var beatles

SetEventKey TRAIN Stop beatles z
_____

SetVoltage 1.0

BeginFunc Stop
SetTimerVoltage 0.0 3000
EndFunc

 まずレイアウトのスクリプトエディターでは、グローバル変数を宣言します。名前は何でも良いですからbeatlesにしました。そしてSetEventKeyの右側に、呼ぶメソッドの場所TRAIN、呼ぶメソッドの名前Stop、宣言したグローバル変数beatles、設定するキーzの順に書き入れます。

 これだけではダメですね。肝心のメソッドStopを編成に書かねばなりません。BeginFuncとEndFuncの中身は先ほど紹介したSetTimerVoltageです。停車したいのですから設定速度は0.0とします。設定時間は好みですが、とりあえず3秒にしてみました。

 さて、メソッドとは別にSetVoltage 1.0とも書かれていますね。二日目のはじめにポイントを使って説明したことを思い出してください。

>まず、単純にポイントに「切り替われ!」というスクリプトを書いたとしましょう。
>そしてビュアーを起動するとどうなるでしょうか。
>起動した瞬間VRMはそのスクリプトを読み、即座にポイントが切り替わります。

 つまり今書いたSetVoltage 1.0はビュアーを起動した瞬間実行され、はじめから編成は最高速度で走り出します。このように、BeginFuncとEndFuncに挟まれていない裸の命令ははじめに実行されるので初期設定に使います。覚えておきましょう。

 さて、書けたらビュアーを起動しましょう。いきなり編成が最高速度で突っ走っていますが、Zキーを押すと3秒かけて列車が停車します。昨日のSetVoltageと比べてグッとリアルな挙動ですね。
 これで「センサーを踏んだら」ともう1つ、「○キーを押したら」というイベントを設定することができるようになりました。

 今日はいくつかの新しい命令を紹介しつつ、変数について解説をしました。
 変数に関しては、速度やライトの点灯状態などを設定するために変数を用いること、グローバル変数とローカル変数の違いの2点を理解してください。

 ところがッ!!!

 変数にはまだもう1つ重要な役割があるのです。だって皆さん、今までのサンプルでは編成が1つだったから良いですが、レイアウトを作るとなったら特急も急行も普通も貨物列車も走らせたいでしょ?

 もっと具体的に書きましょうか。あるセンサーを踏んだとき、特急1は100km/hにして、特急2は90km/hにして、急行1と普通3は70km/hにして、貨物列車1は警笛を鳴らしたい、そんでもってあの列車は…なんてときに、今のままではセンサーに下のように書くしかないですね。

<このセンサーを踏んだ15本の列車に動作をさせたいとき(悪い例)>

Var AHO

SetEventSensor chukei AHO

BeginFunc chukei
call TOKKYU1 Set100km
call TOKKYU2 Set90km
call KYUKO1 Set70km
call KYUKO2 Set75km
call KYUKO3 Horn
call FUTSU1 Set65km
call FUTSU2 Horn
call FUTSU3 Set70km
call FUTSU4 Set70km
call FUTSU5 Horn
call FUTSU6 Set55km
call FUTSU7 Set60km
call KAMOTSU1 Horn
call KAMOTSU2 Set60km
call KAMOTSU3 Set55km
EndFunc

 中継用メソッドでは、15本の編成にあるメソッド全てに対してcallをかけています。こうすれば確かに今運転している編成がセンサーを踏んだときにも希望のメソッドが実行されます、が、これでは15本のうちどれかの編成がこのセンサーを踏むたびに全編成のメソッドが実行されてしまいます!しかも長すぎ。

 嗚呼!センサーを踏んだ編成だけのメソッドを実行するにはどうすればいいんだ!

 とまあそこで変数の登場というわけです。センサーを踏んだ編成がどの編成なのかという情報を変数に持たせ、中継用メソッドのcall命令にその変数を書き入れればよいのです。

 もちろんそんなこと言われてもどうすればいいのかわからないでしょう。ですから明日はこのことを具体的に解説します。ここまで理解できれば、スクリプトはおおむねOKですよ!

他の日へはこちら

2005年10月31日

三日目:スクリプトを書いてみるI

 一日目に<命令の例>として2つの命令を紹介ましたが、今日はそれを使ってイベントとメソッドを使ったスクリプトを書いてみましょう。

 2つの単語をもう一度記しますと、

SetEventSensor:(この)センサーを踏んだら○○してくれ!
SetVoltage:編成の速度(電圧)を○○にしてくれ!

 でしたね。これを見ると、SetEventSensorが「いつ」、SetVoltageが「何を」を担当することがわかります。ですからこの2つを使えば「このセンサーを踏んだら、編成の速度を○○にしてくれ!」というスクリプトが書けますね。

 サンプルレイアウト(第2号使用)を出しますので、ぜひ書いてみてください。小判型の線路に編成とセンサーが1つずつ置かれ、センサーの隣には目印のヤード照明灯が立ててあります。
 第2号をお持ちでない方も下図を参考に作ってみてください。
 サンプルレイアウトはこちら

koban.JPG

 まず考えるべきはスクリプトを書く場所です。VRMスクリプトは色々な場所に書くことができます。レイアウトにはじまって、センサー、ポイント、信号、編成、車両などスクリプトで制御できる部品なら全て、エディター内にスクリプトエディターという項目を持っています。

 SetEventSensorを含むイベントは「このセンサーを踏んだら」ですから、反応させたいセンサーのスクリプトエディターに書かなければいけません。別のセンサーに書いたらそのセンサーが反応してしまいますし、センサー以外の部品に書いても機能してくれません。
 同様にSetVoltageを含むメソッドは「編成の速度を○○にしてくれ!」ですから、速度制御をしたい編成に書きましょう。
 この「スクリプトをどこに書くべきか」というお話は、後日もう少し書くつもりです。

 次に少しだけ下準備です。編成とセンサーの名前を決めます。部品を置いた時点では編成は「TRAIN+通し番号」、センサーは「SENSOR+通し番号」という名前(サンプルではそれぞれTRAIN14、SENSOR12)になっていますが、これではあとからどれがどれだか把握しにくいので、わかりやすい名前をつけてあげましょう。
 ここでは編成・センサー共に1つしかないので、編成は「TRAIN」、センサーは「SENSOR」という名前にすればよいでしょう。

changename.JPG

 編成センサー、両方の名前を変更できましたか?いよいよスクリプトを書きましょう。イベントとメソッドのどちらを先に書くかは場合によりますが、ここではメソッドから書いてみましょう。
 先に完成形を示してから説明しますので、いきなりアルファベットの羅列が出てきても驚かないでくださいね。

<「編成の速度を○○にしてくれ!」というメソッド>

BeginFunc LetsGo
SetVoltage 0.8
EndFunc


 くどいようですが、これは編成のスクリプトエディターに書きます。さて、SetVoltageだけでなく色々くっついていますね。これを順番に説明しましょう。

 まず青字の「BeginFunc」「EndFunc」という2つの単語に注目してください。この2つはメソッドを書くのになくてはならない単語です。メソッドを書くからには、どこからどこまでがメソッドなのかをハッキリさせなければなりません。
 Beginは始める、Endは終えるという意味ですね。「メソッドがここから始まるよ!」とメソッドの冒頭には「BeginFunc」と書き、「メソッドはここまでだよ!」とメソッドの最後に「EndFunc」と書くのを忘れないようにしましょう。

 赤字部分に目を転じると「LetsGo」と書かれていますが、これはこのメソッドの名前です。「BeginFunc」の隣にメソッドの名前を付けてあげるのです。
 他と重複しなければ何でも良いので、「ahondara-」とか「manuke」とかでも結構です。でもあんまり関係ない名前にするとあとで混乱しますヨ。

 BeginFuncとEndFuncにはさまれているのが、メソッドの具体的な中身です。ここに、このメソッドがどのような命令を担当しているのかを書きます。

 ここであのSetVoltageが出てきましたね。後ろに0.8という数値が書かれています。これは「編成の速度を○○にしてくれ!」の「○○」にあたります。0.0から1.0までの好きな数字に置き換えることで、設定速度を変更できます。

 なお、この数字は設定速度の最高速度との比を表します。上の例では0.8ですから、最高速度が100km/hなら設定速度は100×0.8=80km/hです。「SetVoltage 0.0〜1.0の小数」で速度が設定できると知っておきましょう。

 これらの説明を理解すればアルファベットの羅列に見えていたあのメソッドも、何だかVRM君と話をするための言語に見えてきませんか?


BeginFunc LetsGo メソッド「LetsGo」のはじまりだッ!
SetVoltage 0.8 速度を最高速度×0.8にしてくれ!
EndFunc メソッドおわり!


 とまあこんな風にハイテンションに解釈する必要はありませんが、日本語部分だけを叫んでみれば実はものすごく単純なことを書いているに過ぎないことがわかると思います。ほら叫んで叫んで。恥ずかしがっちゃダメですよ。え?自分ですか?(逃走)

 さてとりあえずメソッドは書けました。しかしこれでは「何を」するか定めただけであり、「いつ」そのメソッドを実行するのか設定しなければ相変わらず何も起きません。というわけでイベントの解説に入ります。トイレ、休憩などなさる方は今のうちに。

2005年10月30日

二日目:スクリプトの構造I(イベントとメソッド)

 今日ははじめに、スクリプトでポイントを切り替える場合について少し考えます。それを踏み台にスクリプトの構造を見てみましょう。

 まず、単純にポイントに「切り替われ!」というスクリプトを書いたとしましょう。そしてビュアーを起動するとどうなるでしょうか。起動した瞬間VRMはそのスクリプトを読み、即座にポイントが切り替わります。

 それだけです。あとは何も起きません。

 でも我々がポイントを使って行いたいのはそんなことではないですよね。例えば「特急が来たら自動で直進に切り替えたい」とか「信号が赤になったら分岐に切り替えたい」といったことでしょう。

 これを実現するには「切り替われ!」と書くだけではなく、いつ切り替わるのかをハッキリさせなければなりません。

 そのためにスクリプトには「イベント」と「メソッド」という仕組みがあります。

 例えば「特急が来たら直進に切り替えろ!」と命令するときは、イベントは「特急が来たら」、メソッドは「直進に切り替えろ!」という命令をそれぞれ担当します。

 つまりイベントは「いつ」、メソッドは「何を」するのかを定めるわけですね。しかしなぜひとまとめにして「特急が来たら直進に切り替えろ!」と命令しないのでしょうか。

 それは「いつ」と「何を」を分けたほうが、少ないスクリプトでたくさんの種類の命令を実現でき、のちのちの修正もラクだからです。

 ピンときませんか。それでは、次のようなときはどうでしょうか。

・Aキーを押したら
 「駅前方のポイントを直進に切り替える」
 「駅後方のポイントを直進に切り替える」
 「信号を青にする」
 という3つの動作を同時に起こす。

・Bキーを押したら
 「駅前方のポイントを直進に切り替える」
 「駅後方のポイントを直進に切り替える」
 「信号を赤にする」
 という3つの動作を同時に起こす。


 という命令を書きたいとしましょう。AキーとBキーで異なるのは、信号の色だけですね。

 このとき、命令をひとまとめにして
 「Aキーを押したら駅前方のポイントを直進に切り替えて駅後方のポイントを直進に切り替えて信号を青にせよ!」
 「Bキーを押したら駅前方のポイントを直進に切り替えて駅後方のポイントを直進に切り替えて信号を赤にせよ!」
 とがんばって書くのはムダが多いです。両方の命令に「駅前方のポイントを直進に切り替えて駅後方のポイントを直進に切り替えて」なる大変長い重複がありますね。また、長いと書き間違いが発生するリスクも高まりますし、後で確認するのも大変です。
 しかも後から「あっやっぱりCキーも設定したいなぁ」なんて思いついた日には、また同じように長い命令をCキー用に書かねばなりません。

 そこで「いつ」の部分をイベントとして書きます。ここでは

1:Aキーを押したら
2:Bキーを押したら


 の2つですね。

 そして「何を」の部分をメソッドとして

イ:駅前方のポイントを直進にする
ロ:駅後方のポイントを直進にする
ハ:信号を青にする
ニ:信号を赤にする


 と書きます。

 あとはイ・ロ・ハイ・ロ・ニをそれぞれつなげれば、短いスクリプトの組み合わせで煩雑な動作を実現することができます(昨日も書きましたね)。

 書き換えもラクです。「やっぱりCキーも設定したいなぁ」という発作が起きても

3:Cキーを押したら

 というイベントを新たに設定して、イ〜ニのお好みのメソッドとつなげればよいわけです。

 イメージをつかむための一例として、下図をご覧ください。

normalsize.jpg

※イベント・メソッドの内容は本文と異なっています。

 こうすれば「いつ」を変えたいときにはイベントを、「何を」ならメソッドを書き換えるだけですぐにできますし、つなげ方を変えるだけでも修正が出来ますね。それに命令自体が短くて済みます。

 とはいってもイベントとメソッドをどうやってつなげるのか、そもそもイベントやメソッドはどうやって書けばいいのかといった疑問がありますね。ですから明日は、簡単なイベントとメソッドを書いてみましょう。

 今日のポイントは、イベントは「いつ」、メソッドは「何を」するのかを定める、ということでした。

他の日へはこちら

2005年10月29日

一日目:スクリプトで何が出来るか

 今日から一週間、スクリプトの類を全然知らずにVRM4を手にした人のために、スクリプトの解説をしてみたいと思います。

 お前がやるな、て声が聞こえてきそうですが。でも、今のところどのVRMサイトを見ても「白紙からできるVRMスクリプト」というコンテンツが無いようなので、ここは自分がビギナーの目線でやってみたいと思います。

 というわけで難しいことはやりません(できませんとも言う)。そもそもスクリプトで何が出来るのかということからはじめて、一週間でghostさんのスクリプト禅問答に何を書かれているかが理解でき、かつ自分でスクリプトが書けるようになるまでを目指します。

 そう、来週の土曜日にはそこのアナタも自分でスクリプトが書ける!という画期的な企画です(笑
 ただし3分でできるインスタントラーメンではありませんから、やってみようと思う方はよく読んでくださいね。また、45-50sのスクリプトのやり方にどうも納得できない、賛成できないという方はもちろん無理することなく、ご自分の方法で極めてください。

 ときに誤謬も含まれているかもしれません。もしスクリプトに詳しい方々がご覧になっていて誤謬に気づかれたら、遠慮なく教えていただければ幸いです。

 なお、これ以降文中でスクリプトと言うときには、特記なき場合すべてVRM4のスクリプトのことを指します。

 はいまえがき終わりです。

一日目:スクリプトで何が出来るか

 スクリプトで何が出来るでしょう?漠然と「自動運転」とか「何でもできそう」と思っておられる方が多いのではないでしょうか。

 スクリプトはVRMの部品に対して「あーせいこーせい」と命令を下すときに使う言葉です。しかし言葉である以上、その語彙以上のことは命令できません。あらかじめ存在している命令を組み合わせて、結果的に啓明さんやghostさんたちの行っているような「自動運転」とか「自動信号」なんかを実現しているのです。
 ですから、「自動運転してくれ」なんていう都合のいいスクリプトはありません。命令の一つ一つは単純なものです。例えば以下のように。

<命令の例>
SetVoltage:車両の速度(電圧)を○○にしてくれ!
SetEventSensor:センサーを踏んだら○○してくれ!


 SetVoltageは文字通りVoltage(電圧)をSetします。SetEventSensorSensor(センサー)を踏んだら○○を起こせ!というEventSetするわけですね。
 カタカナ語があふれている我が国ですから、英語を知らなくてもなんとなく想像できるでしょう。他にも様々な命令があり、これらは皆VRM4のスクリプトリファレンスに書かれています。

 今は「○○の部分はどうするんだ?」とか「命令なのはわかるけどじゃあそれをどこに書けばいいんだ?」とか色々疑問があるとも思いますが、大丈夫!来週の土曜日にはそれらの疑問は氷解しているはずです。

 で、ここで重要なことがあります。よほど記憶力に自信のある方は別として、命令の一つ一つを覚えるよりもスクリプトの構造を覚えて自分で書いてみたほうが、よほど修得が早いということです。
 自分もまだスクリプトリファレンスに書かれている全ての命令を覚えているわけではありません。しかしやりたいことに合わせてリファレンスを斜め読みしているうちに、よく使う種類の命令は覚えてしまいます。

 先ほど「自動運転してくれ」なんていう都合のいいスクリプトは無いのだと書きましたが、そのおかげで、ありとあらゆる命令を意のままに組み合わせることで「自動運転してくれ」などと言うよりはるかに色々なことができるようになります。例えばおみくじとか、いやいやなんでもないです。

 今日はまずスクリプトは決して魔法ではなく、言うなれば“VRM語”なのだと思ってください。

 最後に、こんな記事を読まずともスクリプトなんぞできるようになったるわい!とお思いの方々のために、比較的易しいスクリプトの解説をなさっているサイトをご紹介します。

ぶいあ〜るえむ(KZさん):スクリプト関連のコンテンツはTutorialのスクリプト(基礎編)以外は工事中のようですが、はじめての方ならスクリプト(基礎編)が好適だと思います。 ←お休み中のようです。

keimei KIHA-POST(啓明さん):啓明さん自身文中で中級者向けと仰っているように、この記事やKZさんのTutorialでスクリプトに少し慣れたら読んでみるとよいでしょう。
 逆に言えば、この記事は啓明さんのVRM4チップスがどうにも難しいと感じる方のために書かれていると思ってください。

 明日はスクリプトの構造の説明をします。と言ってもスクリプト自体は出てこないので安心してください。ではどこかに読者がいることを願いつつ、今日はこの辺で。
他の日へはこちら
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。