毎回恒例の第24回UE5ぷちコンに参加しました。
本イベント開催中に第二子の出産予定日を迎えることが分かっていたので、それに伴っていつもより時間が取れないことを前提に、シンプルだけど楽しめるゲームを目指して制作しました。

テーマが「スピード」だったので、高速で正確なマウス操作が必要なゲームと解釈して、「SPEED SWITCH OPERATION ビッグステーション」というゲームを制作しました。
応募動画はこんな感じです。(ニューマシンにして、DaVinciResolveが正常にエクスポートできなくなってしまったので、ちょっと解像度が粗目の動画になってしまいました)
ゲーム説明

ビッグステーションを中心に、上下線には膨大なポイント切り替え線が配置されており、これをマウス操作でポチポチ切り替えていくことで、電車を正確なホームに導くゲームとなっています。

プレイ画面のカメラは上空に配置しており、マウスの右ドラッグで地面をスクロール(正確にはカメラを動かしている)、左クリックで地上に配置されたオブジェクトにアクションを発生させることができます。
また、カメラは平行投影でレンダリングしているので、奥行き感を感じない独特な雰囲気のゲームとなっています。(これには、奥行き感があると奥のホームが見にくいという点と、なるべくキャッチーなゲームにしたかったので、雰囲気に拘ったという理由があります)

マウスホイールで拡大・縮小にも対応しています。

ちなみに、レベル全体はこんな感じです。タイトル画面・メニュー画面・プレイ画面が全てこのレベル上で動いています。ゲーム中に見えない部分は滅茶苦茶省略しています。
初のマウスで操作するゲーム
今回、初めてマウスカーソルを使ったゲームを開発してみました。これだけポイント切り替えがあると、ゲームパッドによる操作は難しいという理由と、ゲームパッドだと今回のお題である「スピード」感を得られないと判断した為です。
ところが開発をしてみると、ゲームパッドとは作り方が大きく違うことに気が付きました。
今回は技術的にそのあたりの話題にフォーカスしたいと思います。
クリックされたオブジェクトを取得するには
本ゲームではマウスを使ってポイント切り替えのレバーや、電車をクリックすることができます。それぞれにBPにOnClickイベントのようなものを設定するのかと思っていたのですが、UnrealEngineではそのような実装方法ではなく、画面上のクリックしたポイントから直線的にLineTraceを発生させ、Lineに衝突したオブジェクトを判定というやり方で実装することが分かりました。
つまり、プレイ中のマウス操作のLineTraceを可視化してみると、こんな感じになっています。

空中から降り注ぐ赤い線が面白いですね。
まずは、画面上のクリックはレベル上のどこをクリックしたことになるのかを取得する処理が必要になりますが、”Convert Mouse Location To World Space”というノードを使えば一発で取得できます。

つまり、クリックイベント時の処理は以下のようになっています。

やっていることはすごく単純で、クリックしたレベル上の座標をLine Traceの開始地点とし、クリックされた方向(World Direction)に距離を掛けた値をLine Traceの終着地点としています。(Multi Line Traceを使うか、Line Traceを使うかで悩んだ形跡がありますが、ゲームではLine Traceを使うようにしました)
これによって、上述のような空から地上に向かってLineTraceが行われますので、あとは何と衝突したかを判定して、ポイント切り替えを動かしたり、電車のクリック判定を行っています。
余談ですが、Line Trace後の処理は以下のようになっています。クリックされる可能性のあるActorにはBluePrintInterfaceでOnClickイベントを設定しておくことで、クリックされたことをActor側で受信することができます。

マップのスクロール
マップは広大な為、右ドラッグで地面をスクロールさせることができます。ちょうど、UnrealEngineのBPエディタの操作感と同じですね。
このゲームの特徴として、カメラは常に上空(Z座標) 22865.0 に待機しており、右ドラッグされたときにドラッグされた移動量に合わせてカメラを移動させるだけで、マップがスクロールしているように見せています。

なお、先ほども説明した通り、本ゲームはマウスホイールでカメラの拡大・縮小ができますが、これはカメラのZ軸を移動させているのではなく、カメラが平行投影モードなのを利用して”Set Ortho Width”の値を更新するだけで実現させています。

そして、マウスドラッグによるマップスクロール処理は、たったこれだけで実装されています。

EnhancedInputを使って右クリックイベントを取得し”IsRightDragging”にフラグを立てながら、クリックされた座標を”Start Drag World Pos”に保存します。(細かい話しですが、この時マウスカーソルも”手で掴む”カーソルに変更しています。)
で、右クリックが離されたイベントでは”IsRightDragging”にフラグを倒し、マウスカーソルも元に戻しています。
上記の処理の中で、”Get Mouse Pos”と”Screen to World Orthographic”という関数をコールしていますが、それぞれの実装は以下の通りです。


なんとなく「クリックされたオブジェクトを取得するには」で解説した”Convert Mouse Location To World Space”ノードと似ていますが、拡大縮小等を考慮した結果、このような実装となっています。
これで右クリックした時のマップ上の座標を保存できたので、あとは右クリックしながらマウスを動かす処理に注目していきます。
とは言っても、ここも複雑なものではなく、ドラッグ開始前とドラッグ中の座標の差を”Drag Offset”として、その座標を”Move Camera”というノードに入れているだけです。

“Move Camera”の処理は単純に”Add Actor World Offset”ノードを呼び出しているだけです。(たったこれだけの処理なのに、カスタムイベント化されているのは、マップのスクロール制限(これ以上はスクロールさせない等)を掛けたかった為ですが、現在の実装ではどこまでもスクロールしてしまいますね。

これだけで、右ドラッグによるマップのスクロールを実現しています。このような視点のゲームを作りたい方のお力になれれば幸いです。
UMGも伸縮対応
今作から本気でUMGをレスポンシブ対応させています。
例えば、画面上部の時刻表ですが、レイアウト的に画面上部をすべて覆う必要があった為、どんな画面解像度(横幅)で表示しても列車名の部分が伸びてサイズの辻褄が合うようになっています。単純な拡大縮小なら簡単に実装できますが、それだと時刻や車両数の表示が間延びしてしまう為、間延びしても問題ない列車名部分のみが画面サイズに合わせて伸縮するようにUMGのみで組んでいます。



これで、第24回UE5ぷちコン振り返り記事は終了です。ここまで読んでいただきありがとうございました。
No responses yet