壁を立てる

目次

はじめに

 HGIMG4向けにレースゲームのサーキットコースを作ってみます。 実際にHGIMG4で使用するときは、物理演算を使います。コースは起伏がない、円環状のコースとします。 コースアウトすると、地面の端から落下してしまったり、ショートカットできてしまったりして困るので、道路の両側には壁を設置します。 壁は、XZ平面(水平な地面)に垂直な板とします。

 完成予定図はこんな感じ。垂直の壁は、あとで非表示にするので見えなくなります。

完成予定図

 完成済みのデータを見ながらの方が分かりやすいと思うので、サンプルをダウンロードできるようにしておきました。
サンプルダウンロード(472 KB)

サーキットのテクスチャを準備

 平らな地面にテクスチャ画像を張り付けて、サーキットコースにします。

緑の背景に灰色の線を道路に見立てて引いてある。

ファイル名:map01.png

 簡単な画像ですが、見ての通りノイズを入れてあります。 同じ色で塗りつぶして作ると、ゲーム画面で表示したときに地面が動いている様子が分かりにくくなってしまいます。 走行していても、地面が動いていないかのように見えてしまいます。 地面にある程度情報量があると、地面が動いている様子が分かりやすくなります。

 リアルな草やアスファルトは、準備できなかったので砂模様のフィルタで代用。

Blenderを準備

 地形の作成には、Blender 3.2.2を使用します。バージョンが変わっても、操作はあまり変わらないと思います。

 起動するとシーンコレクションにCubeというのが作られているので、まず消します。

シーンコレクションのCubeを削除する。

右クリック > 削除

「Cube」オブジェクトが削除できました。

メニューバー:ファイル > 保存

適当な場所に「Blenderファイルを保存」で、ファイルに保存しておきます。 さて、準備が整いました。

床を作る

 今回のサンプルは、HGIMG4の物理演算を使用します。 平面の床をポリゴンで自作した場合、物理演算との相性がよくありません。 そこでHGIMG4で使用する際は、床はgpfloorを使用します。

 床以外のパーツは、Blenderで作成します。 今回はコースアウトを防止するための壁だけですが、山や客席、木や岩などがあれば、Blenderで作ります。 床なしでこれらを作るのは作業性が悪いので、床以外のパーツ作成・配置のための目印としての床を作ります。

オブジェクトモード
追加 > メッシュ > 平面

追加>メッシュ>平面

Nキーを押してサイドバーを表示
スケールを X=100、Y=100 に設定します。平面の寸法が200m×200mになります。 Nキーを押してサイドバーを閉じます。

サイドバーのアイテム

マテリアルプロパティを選択
「+新規」をクリック

マテリアルプロパティ

ベースカラー●>テクスチャ 画像テクスチャ

ベースカラー●>テクスチャ 画像テクスチャ

「開く」からテクスチャ画像「map01.png」を選択

 テクスチャが適用されました。 この状態では確認できないので、「3Dビューのシェーディング」を「マテリアルプレビューモード」に変更します。

マテリアルプレビューモード

 テクスチャが適用されていることが確認できました。

 地面ができましたが、オブジェクト名が「平面」では分かりにくいので、「地面」に変更しておきます。 シーンコレクションのオブジェクトの名前をダブルクリックすると変更できます。

オブジェクトの名前を平面から地面に変更

壁の下書きを作成

 灰色がアスファルトの道路、緑が芝生です。 車が道路を大きくはみ出してしまわないように、壁を設置します。 コースの内側と外側の2つの壁を作ります。どちらも作り方は同じですが、外側の壁から作ってみます。

 まずは、壁の下書きとなる線(カーブ)を描画します。 カーブを作ったあとに、カーブに沿って壁を作っていきます。

オブジェクトモード
追加 > カーブ > ベジェ(Shift + A)
画面中央に小さなベジェカーブが作成されます。

編集モード
オブジェクトモード > 編集モード(Tab)
Deleteキーを押す
今あるベジェカーブが削除されます。 ベジェカーブ オブジェクトの中身が空になりました。

シーンコレクションに「ベジエカーブ」ができているので、名前を「壁外側_カーブ」にしておきます。

テンキーの7を押す。
トップビューに切り替わります。

ツールバー:ドロー
フリーハンドで道路の外周をドラッグで囲む。外側の壁から作ります。
地面と水平にカーブが作成されます。

右クリック:ループ切り替え(Alt + C)
カーブの両端をつないで、閉じたカーブにします。

ツールバー:移動
カーブの頂点を移動して、きれいに整えます。

壁のメッシュを作成

 壁は、長方形の四角形の面を帯状に並べたもので作成します。 完成イメージは、こんな感じ。赤い部分が壁で、黒い線がメッシュです。

 すべてのメッシュを手で打つと大変なので、長方形メッシュ1個を作成し、増やして壁にします。 ということで、1メッシュ作ります。

オブジェクトモード
編集モード > オブジェクトモード(Tab)

追加 > メッシュ > 平面(Shift + A)
四角形の面が1個作成される。

シーンコレクションに「平面」オブジェクトができているので、名前を「壁外側_面」にしておきます。

編集モード
オブジェクトモード > 編集モード(Tab)

面を長方形に整形してください。方法はいくつかありますが、最終的に以下のような大きさにします。
X軸方向 … 1m (壁の高さ)
Y軸方向 … 5m (壁の1メッシュ幅)

ツールバー>スケール
X,Y方向に伸ばして、面を長方形にする。

辺選択モード
ツールバー:移動
辺を選択。見た目で移動するか、サイドバーのアイテム(N)で数値を入力する。
もう一度Nキーを押すとサイドバーは閉じます。

モディファイアーで壁を作成

 作ったメッシュを並べて、壁を作ります。 手作業でコピーして並べるのは大変なので、モディファイアーを使用します。 モディファイアーは、お絵描きツールでいうところのフィルターのような機能で、3Dモデルに対して非破壊の加工を加えてくれます。 非破壊なので、後から変更ができるので便利です。

シーンコレクションで、「壁外側_面」を選択します。

モディファイアー プロパティを選択。

配列

作成した面をカーブと同じ長さ分だけ並べて配置します。

モディファイアーを追加 > 生成 配列
 モディファイアーに「配列」が追加されます。

次のように設定します。

適合する種類カーブに合わせる
カーブ壁外側_カーブ
オフセット(倍率)有効
係数0.0, 1.0, 0.0
マージ有効

 面をカーブと同じ長さ分まで並べたものができました。

※ オブジェクトモードのスケールで面の大きさを変えていると、長くなりすぎてしまいます。 このような場合は、「定数で指定」で適当な数値を指定してください。

カーブ

長く並べた面をカーブに沿って配置します。

モディファイアーを追加 > 変形 カーブ
 モディファイアーに「カーブ」が追加されます。

次のように設定します。

カーブオブジェクト壁外側_カーブ
変形軸Y

 よく見ると、面が重なっている部分があります。 カーブの長さが面の幅の整数倍になることはほとんどあり得ないので、始点と終点でこのように重なってしまいます。 重なっていなくても、始点と終点の頂点はつながっていないので、隙間が空いた状態です。

溶接

隙間は完全にふさいでおかないと、すり抜けなど思わぬ動作を引き起こしてしまう可能性があります。 頂点をくっつけて、ループにします。

モディファイアーを追加 > 生成 溶接
 モディファイアーに「溶接」が追加されます。

次のように設定します。

モード全て
距離メッシュ幅より短く、重なっている幅より長い値

 「溶接」を適用前と適用後では下図のようになります。指定の距離以下の近い頂点が、溶接(頂点が結合)されています。 これで隙間はなくなりました。

ディスプレイス

地面に半分めり込んだ状態なので、壁の下端を地表近くまで移動します。

モディファイアーを追加 > 変形 ディスプレイス
 モディファイアーに「ディスプレイス」が追加されます。

次のように設定します。

方向Z
強さ2 (結果を見て調整、地面に少し埋もれる程度にする。)
中間レベル0

 これで壁ができました。 色が白のままだと後で消すのを忘れそうなので、最後に目立つ色に変えておきます。

マテリアル プロパティ > 新規 > サーフェス
ベースカラー:赤

内側の壁を作成

 同じ要領で、サーキットコース内側の壁も作ります。

 出来ました。オブジェクト名は、「壁内側_面」にしておきます。

マージ

 この状態で「壁内側_面」と「壁外側_面」の2つのオブジェクトを1個のファイルに出力しても、HGIMG4では衝突判定が正しく行われません。 解決方法は、二通りあります。

 1つは、オブジェクト1個ずつを2ファイルに出力する方法。 HGIMG4で利用する際に、2ファイルを読み込ませます。 壁の数が増えると面倒そうです。

 もう1つは、2つのオブジェクトをマージして1個のオブジェクトにして出力する方法です。 少し手間ですが、1ファイルになるので、HGIMG4で利用する際は1ファイル読み込むだけになります。 これらなら壁の数が増えても大丈夫です。

 ということで、後者の方法、オブジェクトのマージをやってみます。 単純に2つのオブジェクトを結合させてしまうと、モディファイアーを使っているので思ったような結果にはなりません。 結合前にモディファイアー後の形状を実際の頂点データに変換(メッシュ化)して、モディファイアーを使わない状態にしておく必要があります。

オブジェクトモード
 この操作は戻せなくなるので、必ずコピーを作って行ったほうがよさそうです。ということで、コピーを作ります。 シーンコレクションで、「壁内側_面」と「壁外側_面」をコピー(Ctrl+C)して貼り付け(Ctrl+V)します。

後ろに「.001」とついたオブジェクトが作成されます。

「壁内側_面.001」を選択します。

オブジェクト > 適用(Ctrl+A) > 表示の形状をメッシュ化
 「壁内側_面.001」の形状がメッシュ化され、モディファイアーがすべて削除されます。

「壁外側_面.001」も同様にメッシュ化します。
 メッシュ化後は、「壁内側_カーブ.001」「壁外側_カーブ.001」は不要なので削除してかまいません。

シーンコレクションで、「壁内側_面.001」と「壁外側_面.001」を選択します。
 Ctrlキーを押しながらクリックすると複数選択できます。

右クリック:統合(Ctrl+J)
 2つのオブジェクトが1つに統合(結合)されます。

名前を「壁_面(統合)」にしておきます。

FBXへのエクスポート

 Blenderから直接HGIMG4で使用できる形式(.gpb)に変換することはできません。 FBXにエクスポートしたのちに、専用ツールでgpbファイルに変換する必要があります。 また、複数のオブジェクトを一度に出力すると、衝突判定が正しく動作しないようです。 出力するオブジェクトは1つだけにする必要があります。

「壁_面(統合)」以外を非表示にします。

メニュー:ファイル > エクスポート > FBX(.fbx)

内容可視オブジェクト有効
トランスフォームスケール1.00
スケールを適用すべてFBX
前方-Zが前方
Yが上
トランスフォームを適用有効

 FBXファイルが出力されます。 作成したFBXファイルは、Windows付属の「3D ビューアー」で見ることができます。

GPBファイルに変換

 先ほど作成したFBXファイルを、作業用フォルダに移動します。 作業用フォルダのパスは、日本語文字列を含まないフォルダにしてください。

HSP3エディタを開きます。

メニュー:ツール > HGIMG4ツールを開く
 GPB converterが起動します。

モデルデータにFBXファイルを指定して、「変換」をクリック。

 変換が成功すると、同じ作業フォルダ内にgpbフィルとmaterialファイルが作成されます。 プレビューで、変換がうまくいったか確認してください。

 このままでは裏面が表示されません。作業する際に少し不便なので、両面表示にしておきます。

GPB converterの「マテリアル」をクリックします。

「colored」を選択。

「cullFace」を「false」にします。

「変更」ボタンをクリック。
 これで、両面表示になりました。

作成した壁データがビューワーに表示されている。

HGIMG4で表示

 作成したgpbフィルとmaterialファイルをresフォルダに入れて、HGIMG4で表示させてみます。 衝突判定の確認のため、物理設定を行った箱を設置しました。カーソルキーで動かせます。

作成したサーキットコースを箱が走行している。壁は赤く表示されている。


  ;	カーソルキーで箱を動かすことができます
  ;
  #include "hgimg4.as"
  title "HGIMG4 Test"
  
  ;	環境構築
  gpreset
  setcls CLSMODE_SOLID, $8080FF
  setcls CLSMODE_SOLID, $A0D8EF
  setpos GPOBJ_CAMERA, 0, 50,100
  
  ;	箱ノード
  ; 自機
  gptexmat id_texmat, "res/qbox.png"
  gpbox   id_box, 3, -1, id_texmat
  setpos  id_box,	-22, 2, 75
  gppbind id_box, 1, 0.5
  
  ;	床ノード
  gptexmat id_texmap, "res/map01.png"
  gpfloor id_floor, 200,200,, id_texmap
  gppbind id_floor, 0, , GPPBIND_MESH
  
  ;	壁ノード
  ; コースアウトを防止するための壁です。
  gpload     id_kabe, "res/circuit"
  gppbind    id_kabe, 0, , GPPBIND_MESH
  ;setobjmode id_kabe, OBJ_HIDE, 0
  
  
  *main
    stick key,15
    if key&128 : end
  
    ;	カーソルキーで箱を動かす
    f = 0.3
    if key&1 : gppapply id_box, GPPAPPLY_IMPULSE, -f, 0,  0
    if key&4 : gppapply id_box, GPPAPPLY_IMPULSE,  f, 0,  0
    if key&8 : gppapply id_box, GPPAPPLY_IMPULSE,  0, 0,  f
    if key&2 : gppapply id_box, GPPAPPLY_IMPULSE,  0, 0, -f
  
    ;	カメラ操作
    getpos id_box,dx,dy,dz
    gplookat GPOBJ_CAMERA, dx,dy,dz
  
    ;	描画
    redraw 0
      gpdraw
  
      color
      pos 8,8:mes "HGIMG4 sample"
  
    redraw 1
    await 1000/60
  
    goto *main

 床については、自作すると物理演算との相性があまりよくないので、gpfloorで読み込んでいます。

 また、コメントにしているOBJ_HIDEの行を有効にすると、壁が非表示になります。見えなくても存在はしているので、衝突させることができます。 実際にゲームで使用する場合は、非表示にした方がいいでしょう。


  gpload     id_kabe, "res/circuit"
  gppbind    id_kabe, 0, , GPPBIND_MESH
  setobjmode id_kabe, OBJ_HIDE, 0

まとめ

 ということで、Blenderで壁を作ってHGIMG4で利用する手順でした。 サーキットコース以外でも、いろいろと応用が利きそうですね。 手順さえわかれば難しくはない作業だと思います。

 しかし、今回は単純な形状だったので何も問題ありませんでしたが、入り組んだ壁の場合は、衝突判定が正しく動作しないケースがあるかもしれません。 そのような場合は、壁を複数のファイルに分けて読み込むことも検討してください。

関連記事

  1. 地形データの制限  床面といえばgpfloorなのですが、ポリゴンを使って複雑な地形とか作りたい! 今まで適当に作った...