チュートリアル 4
ワールドの座標と基本的なオブジェクト
TransportXにおける座標の取り扱いを学び、ワールドに背景や地面などのオブジェクト(3Dモデル)を配置してみましょう。
チャンクと座標
3Dモデルをワールドへ設置する方法を説明する前に、TransportXの座標系は少し特殊なため、この取り扱いについて理解する必要があります。
TransportXは左手系の絶対座標系を採用しています。 ワールドのとある場所に原点(X座標、Y座標、Z座標が全て0の点)が存在し、例えば原点から東へ100m進んだ点を(100,0,0)、そこから更に北へ200m、天空へ3m進んだ点を(100,3,200)と表します。
ここまでは普通なのですが、これに加えて、TransportXにはチャンクという概念が存在します。ワールド全体を250m四方の領域に区切っていき、その一つ一つをチャンクと呼びます。 各チャンクには番号が振られており、例えば
- X座標が0~250、Z座標が0~250の領域 → チャンク(0,0)
- X座標が500~750、Z座標が0~250の領域 → チャンク(2,0)
- X座標が500~750、Z座標が-500~-250の領域 → チャンク(2,-2)
となります。
ワールドファイルでオブジェクトを設置するときなど、ワールド上の位置を指定することはこの先よくあります。 その際、位置は原点(0,0,0)からの絶対座標ではなく、チャンクの番号と、チャンクの基準点からの相対座標(チャンク内座標)の組み合わせで指定するのが基本となります。例えば、
- 絶対座標(300,0,200) → チャンク(1,0)、チャンク内座標(50,0,200)
- 絶対座標(100,0,200) → チャンク(0,0)、チャンク内座標(100,0,200)
- 絶対座標(100,0,-600) → チャンク(0,-3)、チャンク内座標(100,0,150)
と計算できます。
このような仕様となっている理由は、数十km単位の広さのワールドを作ったときに、絶対座標で表現しようとすると例えば(50012.3,20,31400)などと非常に大きな数値になってしまうためです。 これは人間にとって読みづらいだけではなく、コンピュータにとっても扱いづらいため、整数部分をチャンクとして可能な限り分離しているわけです。
基本的なオブジェクトの種類
1章で述べたように、オブジェクトには背景や地面、建物に加えて、道路、道路ネットワーク上を動く自動車など、様々なものが含まれるのでした。 これらのオブジェクトは、ワールドへ設置する方法によって次の3種類へと厳密に区別することができます。
- 背景
- プロップ
- 交通
背景
背景はその名の通り、ワールドの背景として描画されるオブジェクトです。空や遠景のテクスチャを背景として設置するのが一般的です。 この背景ですが、他の全てのオブジェクトと全く異なる2つの特徴を持っています。それは、カメラからの距離が常に固定されていること、他のオブジェクトよりも常に裏側へ描画されることです。
背景の位置は常にカメラの位置に等しいですが、その一方で描画される角度はワールド基準となります。 そのため、カメラがどれだけ移動しようとカメラから背景の距離が変動することはありませんが、カメラを回せば向きは変化することとなります。
また、背景は地面や道路、自動車などの他のオブジェクトよりも常に裏側へ描画されます。 この性質により、「背景モデルよりも外側に行ってしまった遠方の建物が描画されない」などのような現象が発生することはありません。
プロップ
プロップは、ワールド上に固定されて動かない物体全般を表現するオブジェクトです。地面や建物、道路、信号機などが該当します。
プロップは、その中でも更に次の3種類へ区別することができます。
- 位置を直接指定して設置するプロップ
- ネットワークに紐づくプロップ
- プラグインを介して設置されるプロップ
位置を直接指定して設置するプロップは、例えば「チャンク番号(0,1)、チャンク内座標(50,0,25)に3Dモデル "Hoge" を設置する」というような位置を直接指定するスクリプトによって設置するプロップを指します。
特別な機能を持たせることはできず、最もシンプルなプロップです。
ネットワークに紐づくプロップは、直線・曲線道路や交差点などのネットワークの敷設位置を基準として設置するプロップを指します。 例えば「半径400mの曲線道路を敷設し、それに合わせて道路の3Dモデルを設置したい」というのはよくあるケースですが、この場合は「スプラインプロップ」と呼ばれるこの種類の設置方法が便利です。 詳しい設置方法は、TransportXにおける道路などのネットワークの敷設方法について理解している必要があるので、ネットワークについて説明した後に解説します。
プラグインを介して設置されるプロップは、ユーザーが作成したプラグインと呼ばれるプログラムを介して設置するプロップを指します。 ここまでに説明した2種類のプロップは、いずれも「ただ設置して、無条件にその場へ描画する」だけのシンプルなものでした。 表示が変化する信号機や、風速計等の簡単な動きを伴う物体、電光掲示板など、プロップ自身に何らかの特別な機能を持たせる必要がある場合は、どのようなルールで動くのかプログラミングすることとなります。 また、ワールド上に設置するためのスクリプト(構文)についてもプラグイン側で定義することとなります。
プラグインの作り方についてはまだ説明しませんが、TransportX公式のサンプルワールドに設置されている信号機はまさにプラグインとして実装されたプロップですので、この設置方法はこの先の近い章で解説します。
交通
背景、プロップの他に、自動車やプレイヤー操作のバスといった交通もオブジェクトの一種です。 交通について1章に補足して説明するようなことはまだありませんが、交通はプロップなどと並んでオブジェクトのひとつである、ということだけ把握しておいていただければ現時点では大丈夫です。
地面を設置する
ここまでの長い勉強、大変お疲れ様でした。いよいよ初めてのオブジェクト設置です。 最もシンプルなオブジェクトである「位置を直接指定して設置するプロップ」の代表例として、地面を設置してみましょう。
プロップの位置を直接指定して設置するには、ワールドファイルへ次の構文を記述します。
Chunks[チャンクX, チャンクZ].PutProp("モデルキー", X座標, Y座標, Z座標);
チャンクX、チャンクZにはプロップを設置するチャンク番号を、モデルキーにはモデルリストで定義したキーを、X座標、Y座標、Z座標にはプロップを設置する座標を指定します。
前章で3Dモデルを準備し、モデルリストをワールドファイルから読み込まれるようにしました。モデルリストを参照すれば、地面の3Dモデルには Grass というキーを割り当てているはずです。
チャンク(0,0)、チャンク内座標(0,0,0)にモデル Grass を設置してください。スクリプトは次のようになります。
Chunks[0, 0].PutProp("Grass", 0, 0, 0);
現時点でのワールドファイル全体は次のようになっているはずです。
Models.LoadList("Models.txt");
Chunks[0, 0].PutProp("Grass", 0, 0, 0);
注意点として、Chunks.PutProp 構文は必ず Models.LoadList 構文よりも下に記述してください。
Models.LoadList 構文よりも上に記述してしまった場合、モデルを読み込むよりも前に設置しようとしていることとなり、「モデル Grass が見つかりません」とエラーになってしまいます。
ここまでできたら、前章と同様に bin\TransportX.Player.exe を実行し、ワールドを動作確認してみましょう。次のような画面が表示されたら成功です。

画面下部に見えているのが地面の3Dモデルです。太陽光源を設定していないため、夜のように暗く描画されています。 ワールド内を動き回ってみれば、設置した地面プロップが確かに250m四方であることが分かるかと思います。

同様に、チャンク(0,1)にも地面を設置してみましょう。次のスクリプトを追加で記述してください。
Chunks[0, 1].PutProp("Grass", 0, 0, 0);
F5キーを押下して再読込すると、追加した地面が前方に描画されているはずです。

バス停標柱を設置する
地面と同じ要領でバス停標柱のモデルも設置してみましょう。次のスクリプトを記述します。
Chunks[0, 0].PutProp("BusStop", 125, 0, 150);
F5キーを押下して再読込すると、チャンク(0,0)のチャンク内座標(125,0,150)にバス停標柱が確認できるはずです。

やはり太陽光源を設定していないため真っ黒になってしまっていますが、設置することができました。
なお、ここまでプロップの位置のみを指定してきましたが、設置する角度を指定することもできます。構文は次の通りです。
Chunks[チャンクX, チャンクZ].PutProp("モデルキー", X座標, Y座標, Z座標, X回転, Y回転, Z回転);
X回転にはX軸まわりに回転する角度を、Y回転にはY軸まわりに回転する角度を、Z回転にはZ軸まわりに回転する角度をそれぞれ度数法で指定します。 例えば、X軸まわりに90°回転させて設置したい場合は、次のように記述します。
Chunks[0, 0].PutProp("BusStop", 125, 0, 150, 90, 0, 0);
この構文で設置したバス停標柱が次の画像です。

後方へ倒して設置することができました。
背景を設置する
ここまでは背景オブジェクトを設置していなかったため、地面プロップの裏は灰色一色で描画されていました。次は背景オブジェクトを設置してみましょう。
背景オブジェクトを設置するには、次の構文を記述します。
Background.Add("モデルキー");
モデルキーはプロップを設置するスクリプトと同様に指定します。前章で用意した背景モデルのキーは Background でしたので、スクリプトは次のようになります。
Background.Add("Background");
現時点でのワールドファイル全体は次のようになっているはずです。
Models.LoadList("Models.txt");
Background.Add("Background");
Chunks[0, 0].PutProp("Grass", 0, 0, 0);
Chunks[0, 1].PutProp("Grass", 0, 0, 0);
ここまでできたら、F5キーを押下して再読込してみましょう。

背景が灰色一色から空に変化しましたが、太陽光源を設定していないため、地面は依然として暗いままです(なお、背景モデルには自己発光を設定しているため、太陽光源がなくても明るく描画されています)。 次章では太陽光源を設定した上でプレイヤー車両を追加し、ワールド内を運転できるようにします。
付録
付録として、この章の完成データを配布しています。どうしても動かないときなどの参考にお使いください。