見出し画像

初めてのUnreal Engine 5でオクトパストラベラーみたいなゲームを作りたい!~技術編~(更新中備忘録)

はじめに

はじめまして。12月に入ってからUE5を触り始めたほぼ無職です。
今回は「手に職をつけようと思って(邪念)」&「自分でゲームを作ってみたいと思って」触り始めたUE5について綴っていこうと思います。
なお、内容は後から書いてるものなので、いつの間にか覚えててすっとばすこともあると思いますが、基本的には自分が詰まったとこを書いていくつもりです。(これが正解というわけではないのでご容赦を)
あ、あとからちょこちょこ追記するつもりなので多分クソ長くなります。
あ、それからゲームの内容についてはまた別の記事にするつもりです。


なぜUE5を使おうとしたのか

もともとはゲームエンジンを使わずに0から始めようと考えたのですが、
DirextX辺りで「よくわかんねー!」ってなってやめました。
まあ作りたいのはゲームであってゲームエンジンじゃないからね。
そんな主は元々「Unity」というゲームエンジンをゲーム以外の目的で使っていたのですが…
まあせっかくなら世に出てるゲームでよく使われてるUEを使おうかな!なったわけですと。軽いね!

なぜUE5(4)を使うのか?
:開発はめっちゃ売れなきゃ無料
:(Unityはc#っぽいのだったから)
 c++書けないけどブループリントでなんとかなる
:Unityを卒論で使ってトラウマになった(個人の感想)
:なんかよく使われててきれいなイメージがある

というわけで選定理由はなんとなくです。なんとなく。
案外こんなノリのほうがうまくいきます。たぶん。
ちなみにUE4の機能はだいたいUE5にもあるので、わからないとこを検索するときはUE4で検索すると出るかもです!

インストールとかはネットに腐るほどあるので適当に調べてください。
それでまあ実際に開いてみるわけですが、当然なんにもわかりません。
3Dゲームに関してはチュートリアルがいっぱいあるのですが、私は「なんか2Dゲームをつくりたい」という感じだったので、とりあえず検索検索っ♪してました。そして神のようなyoutubeチャンネルに出会ったわけです。

神のYoutubeチャンネル

この方の動画はチュートリアルとして大変ピッタリだったので、正直2D3D関係なくオススメしたいです。
ほんとに初心者でこんな記事読んでる暇あったらこの人の動画見よう!
んでまあ一通りやってから、自分好みのゲーム作成にとりかかるわけですが…
調べることや調べてもわからないことが多い!
ので、この記事では自分が当たった壁についてつらつら書いていこうと思います。

そもそもどんなゲームが作りたかったのか

オクトパストラベラーみたいなHD2Dゲームを自分で作りたい!
大雑把ですが、ようはHD2Dっぽいコマンド選択RPGをオリジナル要素を入れて作ってみたかったんですな。


ToDo

・素材の確保
・オクトパストラベラーみたいなマップ作製
⇒2D素材を3D空間に配置する逆オクトラ手法でやる
・コマンド選択バトルの実装
最初は大雑把にこんな感じでした。


こういうの、紙とかに書き出すのが結構大事です。
この画面からこういう風に遷移しよう、とか。
この段階ではUE5の機能を知らない状態なので実際に実装できるかはさておき、イメージだけでも練っておくと後から実装するときに時短になります。

まあどうせ後から頭悩ませるんだけどね!はっはっはー

素材をどうするか

最初は自分で作ろうと思ったのですが、
時間がかかりすぎるので大人しくほかの方の素材をお借りしましょう。

自分がいいな~って思ったとこ挙げときますね。

2Dマップチップから3Dマップを作る

サイトから引っ張ってきた無料のマップチップなので載せることはできないのですが、

マップチップをタイルセットに変換、タイルセットから切り出したいサイズに合わせて「ボックスを追加」「ポリゴンを追加」することで、タイルそれぞれにブロックの判定を持たせます

そこからタイルマップを作製し、自分の好きなようにタイルを並べ、完成したタイルマップを3D空間上に配置することで、タイトルの作業を行うことができます。

文字だけでごめんね…

PaperZDを扱う

PaperZDについて

2Dアニメーションを3Dのアニメーションのように扱えるようになるプラグインです。日本語の記事や動画が無さ過ぎて無理~になります。
Tickを多用するのは精神衛生上よろしくないので渋々採用することに。

基本的にはこの方の記事がとても参考になります。

StateMachineについて

「out」が初期状態です。「Idle」とか「Jump」とか書いてるのが「どんな動きをさせるか」です。まあそれぞれに設定されたFlipbookの動きを格納してるとでも思っておけばいいです。ちなみにループの可否も決めれます。

そして「Air」とか「attack_1」とか書いてるのがJumpノードです。
これは、他のクラスのブループリント上から「Jump to Node」というノードを使うことで、指定したJumpノードに移行することができます。
Aボタンを押したら「Attack_1」に飛んでその先を処理する~みたいな。

んで、それぞれのノード間に矢印があって、その矢印の上下に双方向の矢印マークがあります。これには遷移する条件を指定できます。
「攻撃モーションが完了したら~」とか「x方向に動いたら~」とか。

StateEvent(Callback)について

次はStateEventについてでしょうか。
先ほどのStateMachineの中にあるJump_1というノードに注目します。

Callbacksという欄に、EnterとExitの2つの入力欄があります。(デフォはNone) これは、同じPaperZDAnimBPのイベントグラフ上に、入力欄に入れた名前と同じカスタムイベントを作ることで、対象のノードに格納された動作の開始時か終了時に、そのイベントを発生させることができます。

Eventとアニメーション再現

このEventに続いてアニメーションについても書きます。
PaperZDはアニメーションシーケンサーでも使えるよ!とか公式には書いてたけど使い方がよくわかんねー!だったのと、PaperZDAnimBP上でタイムラインが使えなかったので…

あくまで開発中のスパゲッティですが、こんな感じでDelayを挟んでちまちま動かすことでアニメーションを再現することにしました。(この例は一定の高さになるまでキャラクターの高さをちまちま変えてるだけ)

そして、このイベントは先ほどのJump_1ノードの開始時に発生するので、
Jump_1に格納されたジャンプのモーションをとりながら、キャラクターが少しずつ上昇していくというアニメーションの再現となります。

レベルをまたいでやりとりしたい

そもそも「レベル」というのは実際のゲームにおける「場面」「画面」「ステージ」等の遷移するものを指します。(「ワールド」ともいえるかも?)

この世界一つ一つがレベル!

それで、異なるレベル間で変数等をやりとりしたくなったりするのですが、
基本的にレベルを切り替えるとレベル及びレベルに配置されたアクタが持つ変数はすべて初期化されてしまいます。
(これに気が付くのに2日かかった)

一応、ブループリントからレベルをOpenする時のOptionに値を入れることで実現できたりはするのですが、多くの情報をやり取りする場合に、いちいち文字列を区切って…とかは大変です。

そこで、私が3日かけてたどり着いたものが「サブレベル」と「ブループリントインターフェース」です!!!!

サブレベルとブループリントインターフェースを用いたやりとり

サブレベルは調べればいくらでもでてくるので詳細は割愛しますが、
今回の用途については
あるパーシスタントレベルの中で複数のサブレベルを用意しておけば、
変数をパーシスタントレベルに保持させた上でサブレベルを切り替えることができるといった感じです。すげー!

ウィンドウ⇒レベル からレベルタブを開き、ここでサブレベルとかを設定するよ

そしてめちゃくちゃ便利なブループリントインターフェースくん。
これは、inputとoutputを持たせることのできる関数をイベントとして作成できるもの、と私は認識しています。

セッター
ゲッター

こんな感じでゲッターとセッターを作成して、
パーシスタントレベルのクラス設定からインターフェースに追加しておき、

パーシスタントレベルからゲッターのグラフを作成

パーシスタントレベルでゲッターのグラフを作成しておくと、
ゲッターやセッターを通してレベルに設定した変数を自由に扱うことができます。

また、inputやoutputを設定しなくても使えるので、イベントディスパッチャーの変わりに、イベント&イベント通知として扱うこともできます。
(これもまた便利なんだな…しみじみ…700個分のちから…)

TargetPointは便利

キャラクターを指定した場所に移動させる時や、
アクタを指定した場所にスポーンさせる時などにおいて、
その場所を指定するのに便利なのがTragetPointです。

いかにも「ターゲットをこわせ!」って感じがする(今の子には伝わらないってマジ?)

この子は位置情報を保持しているうえ、ゲーム上には表示されないので大変扱いやすい「位置指定」の元として重宝します。

そこにあるんかい!!!

そんなTargetPointは「全てのクラス」の中にあります。
私はここで2時間使いました。バカですね…

ちなみに、ゲームを作る中でワープポイント等を作る際、ワープ先はTargetPointでいいと思いますが、ワープ元はTriggerBox等でイベントを発生させたほうがいいと思います。

一時停止的な機能をつける

ゲームにはよく「STARTボタンを押したら一時停止/メニュー」みたいなのがよくあります。あれを作りたくなっちゃったんですね。
なお、すでに停止時のUIはWidgetで作成しているものとします。
(UIを作るWidgetについても調べればわんさかでてくるよ!!!)

プレイヤーが操作するブループリントにて、TABキーを押すとUIを出して一時停止する機能
Widgetブループリントにて、UI表示時にTABキーを押すとUIを消して一時停止を解除する機能

これが正解というわけではないですが、あるWidgetがフォーカスされてるときにのみ受け付ける操作の仕組みはメニュー画面等でも使えると思いますので一応載せておきました。

Jsonを扱いたい

男の子にはね。あるんだよ。Jsonでいろいろ管理したい時がさ。
まあ正直に言うとUE5内での「キャラ」「敵」「技」「武器」とかの多数の情報を扱う手段を知らなかったので、最初からある程度はJsonでやろうと決めていたわけですな。
Jsonが何かって?
…調べよっか!(⋈◍>◡<◍)。✧♡

このサイト様がかなり参考になるので、正直私が書くまでもないのですが…

予めJsonに合わせた構造体を作っておく
ブループリントでの処理

「MakeFilepath」でJsonファイルのある個所をパスで指定し、
「LoadJsonFromFile」でファイルをもとにJsonオブジェクトを生成します。
「GetField」で指定したFieldの値を配列に格納し、
「ForEachLoop」と「break」でそれぞれの値を扱っています。

Jsonファイルの中身
技の情報を格納した技選択ボタン

まだ開発中ですが、私はJsonファイルのパーサーとWidgetを合わせて、
このように技を選択するボタンを作成しました。これらの情報はボタン以外のことにも使えるので、とりあえず技やアイテムなどのデータベース化できる情報はいったんJsonで扱おうと考えています。

レベルを切り替えたときのスポーン

RPGでバトルが終わったら、マップの元の位置に戻りたいじゃないですか?
でもマップとバトルのレベルは別だから、バトルが終わった後にマップのレベルを呼び出すと位置も初期化されちゃって…
なんとかなれー!で触ってみたのがGameInstanceです。
(ちいかわだとハチワレがすき)
私も詳しくは理解していませんが、1ゲーム内で共通して使える(初期化されない)便利なクラス?だと考えています。
某マリオのコインやらメダルやらとかね。

gameinstanceに変数を追加

ブループリントクラスから親クラスをGameInstanceにして作成。
GI内にずっと保持しておきたい変数を追加します。
今回はバトル開始時(敵に触れたとき)の位置を保存したいので、Vector型

触れたときの処理にセッターをつなげる

そうして、敵に触れた際にGIの変数にアクセスして値をセットします。

マップ起動時の処理

あとはマップに遷移した際に、ゲッターから引っ張ってプレイヤーの位置を変えれば完成!
初期値を最初のスポーン時の位置と同じにしておけば、特に変な動作もしないので安心です。たぶん。後から悪さしたらかなしい…なえぽよになるな…

更新中なのでご容赦をば…

UE5でゲームを作成し始めて一ヵ月ちょっと経った記念に、自分が詰まったとこを思い出せる範囲で書いてみました。
何かあればまた更新するので「こういうやり方もあるんだな~」くらいで見て頂ければいいと思います。
(もしかしたら忘れてて更新しなくなるかもだけど、
    まあ誰も見てないしいっか!w)

今作っているゲームの内容についても、
またいつか別の記事でかければいいな~と考えています。
長々と読んでいただきありがとうございます。

さいごに

実際にゲームを作ってみて実感したのですが(まだ一ヵ月だけど)
思ったより進捗が全然生まれません。
大きい会社ですら数年単位で開発してるので、私個人では「クオリティ」や「ゲーム性」にもよりますが5年くらいかかるんじゃね?とか思ってます。

…果たして大卒ニートはいつ就職できるのでしょうか…!?

この記事が気に入ったらサポートをしてみませんか?