こたつみかんが美味しい時期がやってまいりました。
この記事は https://qiita.com/advent-calendar/2022/ue の1の20日目の記事です。
UE・プログラミング初心者向けの記事となっております。上級者の方々の参考にはなりません。ご了承お願いいたします。最後の方にBPのスクショを載せているのでそれを見ていただければ…(震え)
又筆者も超初心者の為間違いっている・まどろっこしいやり方をしている場合がございます。
こたつでヌクヌクしながらのんびりお読みください。
目次
・準備
・レベルアップシステムを作る
・PlayerのBP編
・DataTableを作る
・CharacterBP編
・Projectile編
・BP_Weapon_Component編
・敵のBP編
・プレイしてみる
・あとがき
・スクショ集
準備
1.ファーストパーソンテンプレートでプロジェクトの作成
筆者の環境
・Windows10
・UE5.1.0
2.PostProcessVolumeの削除
UE5.1においてテンプレートマップや新しいメッシュをインポートした時にエディタ画面が白飛びする現象が確認されています。
もしファーストパーソンマップが白飛び・黒潰れしていたら、アウトライナーのLightingフォルダ内のPostProcessVolumeを削除してください。
左上の編集からプロジェクト設定を開き、プロジェクト▶マップ&モード▶デフォルトのゲームモードを「BP_FirstPersonGameMode」にしてください。
キチンとプレイできたら準備は完了です!
レベルアップシステムを作る
レベルアップシステムってどんな奴やねん、って感じなんですが、今回は敵を倒すと経験値が入り、経験値が一定数溜まるとレベルが上がるよく見るRPG的なやつを作っていこうと思います。
こんな感じのを組んでいきます。多分そんなに難しい内容ではない…ない…
PlayerのBP編
DataTableを作る
そもそもDataTableとは?という話なんですが(すごく大雑把に言うと)UE内で組める表みたいなもんです。
こういうのをUEの中で作っていきます。
適当なフォルダ内にブループリント>構造体というのがあるで構造体を追加してください。
これがExcelで言うところの「列」になります
開くとこんな感じになってると思います。
この構造体タブ内の▶MemberVar_0になってる所が列の名前で、その横にあるのがその列に入れることができる変数の形になります。
変数を追加から新しい列を作れるので
・攻撃力 Frote(浮動点少数)
・必要経験値 Frote or Integer (どっちでもいい)
という感じで列を作っていきます。(わかりやすいので日本語にしてますがプログラミングに日本語を使いたくない主義の方は適当に英語に変えてください)
汎用性とか考えた結果Froteにしてるだけなので整数しか使わねえわ!って人はIntegerでもまるで問題ありません。
今回は使いませんが、構造体タブの隣のデフォルト値のタブからは変数の初期値を変更することができます。
こんな感じのタブが出ると思うので、ドロップダウンの中から、先ほど自分が作成した構造体を選択してください。
開くとこんな感じのが出来ている筈です。
さて、本題のDataTableを組んでいくのですが、この状態でどうやってレベルを指定するのか、という話を先に書いておきます。
今回、DataTableの行を読み取るのにこのノードを使用するのですが、指定方法がName変数になっています。
つまり、DataTableの行の名前をレベル数にしてしまい、Playerのレベル変数IntgerをNameに変換してピンに渡してしまえば数字から直接行を指定できるぜ!という仕組みです。
では作っていきます。
追加から行を10個くらい追加します。
行の名前を数字に変更します。
下の行エディタから各レベルに合わせて攻撃力と必要な経験値量をざっくり決めて入れましょう。
行の名前の数字は半角にするのをお忘れなく!
これでDataTableは完成です。
CharacterBP編
続いてCharacterBPの方を触っていきます。
UE4までは弾の発射処理までCharacterに書いてあったんですが、UE5になってからSkeletal Mesh Componentが親クラスのActor Component??を使ったものに変わっていました。
↑おそらくこれのSkeletalMesh版…??
銃をとるとそのComponentに書いてるBPを指定されたActorに追加しますよ~見たいなやつらしい。武器ごとに性能が違うやつゲームを作る時に全部CharacterBPに描くのを防止できますよ~的な機能かと。よくわからん。詳しい人間違ってたら教えてください。
BP_FirstPersonCharacter編
FirstPerson>BluePrints下のBP_FirstPersonCharacterを開きます。
変数を追加します。
・プレイヤーのレベル Integer
・攻撃力 Frote
・累計経験値 Frote
・必要経験値 Frote
・連続レベルアップ Boolean
の5つです。もしDataTableで変数の型をIntegerにしていた人はそれに合わせて変えてください。
プレイヤーのレベルの初期値を1にしておいてください。
連続レベルアップのBooleanは経験値が一回の加算で2Lv以上アップできるときに困らないよう使います。
データテーブルの行の取得、のノードを出します。
ドロップダウンから先ほど作ったDataTableを選びます。
出力側にある外側の列から行の内容が吐き出されるのですが、Breakノードを挟むのが面倒なので構造体ピンを分割で直接変数を引っ張り出せるようにしてください。
行を指定する入力側のピンRowNameにプレイヤーのレベル変数を繋げたいのですがそのままではくっついてくれないのでToStringとToNameを挟んで無理矢理繋げます。
先ほど作った変数に、データテーブルからでてきた変数をセットします。
BeginPlayが別のところで使われているので、BeginPlayが繋がっているノードの最後のところから今作ったDataTableのBPに線を引っ張ってきます。
やらなくても大丈夫ですが適当にデバッグ用のノードを最後につけて実行するとこんな感じになるはずです。
これでデータを引っ張り出すところは組めたので次はレベルアップについて組んでいきます。
今回は汎用性大事ということでBluePrintInterfaceを使っていきます。
超適当な説明をするとCastしなくても使えるカスタムイベント的なやつなんですが厳密にいうと多分違うのでちゃんと知りたい方はこのへんの動画みてください。
ブループリントインターフェースを作ります。
名前は何でもいいですがノードの名前になるのでわかりやすいものにしておきましょう。
下のインプットに新しい変数を追加します。
・経験値 Flote
ここに敵の経験値がセットされます。
画面の上の方のクラスの設定を開きます。
右側のタブのインターフェース→継承インターフェースにあるドロップダウンから先ほど作成したインターフェースを選びます。
左側のタブのインターフェースのところに、先ほど作ったインターフェース内にある関数が追加されます。
右クリックしてイベントを実装を選んでください。
カスタムイベントに似たようなノードが出てきます。大体カスタムイベントと似たような機能です。
ここから繋げていきます。
先ほど出したイベントから経験値を引っ張り累計経験値に加算してセットします。
次に連続レベルアップ変数をTrueにします。これは次に来るLoopをオンにするためのイベントなので深い意味はありません。
WhileLoopでそれ以降LoopBodyに書かれた内容が連続レベルアップがTrueな限り繰り返されるようにします。
次にブランチで次のレベルアップに必要な経験値より今の累計経験値が多いかどうか判断します。
少なければ連続レベルアップをFalseにしレベルアップは行われません。
ここからはレベルアップが行われる場合の処理になります。PlayerLevelを+1して、累計経験値からレベルアップに必要な経験値を引きます。
最後にDataTableの処理に繋げて、新しいレベルでの行から取り出した変数にセットし直します。
ここまでの処理を例を出して言語化すると、
InterFaceを通じて敵から経験値300が送られてきたとします。累計経験値は300になります。Levelが1から2にアップするのに必要な経験値は100なのでブランチは当然Trueに進みます。
プレイヤーレベルは2になり、累計経験値から必要経験値100を差し引いて200が残ります。
データテーブルから攻撃力と必要経験値が更新されて攻撃力は110、必要経験値は120になります。
連続レベルアップイベントはTrueになっているのでWhileループに帰ってきます。
もう一度ブランチを通りますが累計経験値は200、必要経験値は120なのでTrueに進みレベル2から3に進む処理が行われます。データテーブルも更新され、累計経験値は80、必要経験値は150になります。
まだ連続レベルアップがTrueなのでWhileLoopからもう一度ブランチに処理が進みますが、今度は必要経験値150に対して累計経験値は80しかないのでブランチはFalseに進み、WhileLoopもオフになるのでレベルアップが終了します。
(文字にするとめちゃめちゃわかりにくいですね…)
Projectile編
続いてBP_FirstPersonProjectileの方にBPを書いていきます。
projectileMovementというシステムが追加された「スポーンすると指定されたスピードに従ってすっ飛んでいく」という代物で、既に物理挙動が追加されているのでぶっちゃけそこまですることはありません。
BP_FirstPersonProjectileを開きます。
ビューポートからコリジョンを選択してコリジョンプリセットをBlockAllにしておいてください。
変数に
攻撃力Flote
FirstPerson Object
を追加します。
FirstPersonは詳細タブから直接BP First Person Characterを検索してオブジェクト参照の変数にしてください。
Hit以降の部分には物理シミュレーションの処理が入っているのですが今回は使わないのとエラーの元になるのでDestroyActor以外全て決してしまいます。
イベントHitとDestroyActorの間にApplyDamageを挟みます。
イベントHitのOtherをApplyDamageに繋げます。このイベントHitのOtherには「projectilにHitされた(ぶつかられた)Actor」の情報が入っています。
後は先ほど作った攻撃力変数をBaseDamageに、FirstPersonをDamage Causerに繋げるだけです。
DamageCauserは実際にダメージを与えたactorの情報を渡すピンなので、ちょっと使い方が間違ってる気もしますが使えればセーフなので…
書いた内容としては当たったActorに攻撃力変数の数値とのダメージと攻撃したactorのを与える、以上!
なんて楽なんだ…
BP_Weapon_Component編
こいつに書く内容はただ一つ。
「CharacterBPの攻撃力変数を取り出してprojectileの攻撃力に渡す」
以上です。
UE4の方のFirstPersonテンプレートだとCharacterBPから直発射してたから直に数値渡すだけでよかったけどシステムが変わっちゃったからしょうがないね。
BP_Weapon_Componentを開きます。弾の発射関連が書いてあるのは
この辺の
こいつ(SpawnActor BP First Person Projectile)です。
では書いていきます。
SpawnActorのReturnValueから先ほど作ったProjectile内の攻撃力変数をSetで出します。
SpawnActorとPlaySoundの間くらいの使いやすい位置にでも繋げておきます。
実はこのBP_Weapon_ComponentはBeginPlayの時点でFirstPersonCharacterBPが変数化してあるので左側の変数のところのFirstPersonCharacterをGetで配置します。
このFirstPersonCharacterからGet攻撃力でCharacterBP側に入っている攻撃力変数を取り出します。
取り出してきた攻撃力をProjectileの攻撃力のSetにくっつけます
。
同じようにReturnValueから今度はFirstPerson変数をSetで出し、先ほど出したFirstPersonCharacterを直接繋げます。
これで
これが組みあがったということになります。
次は敵BPと敵BPからの経験値の送信の部分になります。
敵のBP編
敵のBPは最初から入っていないので自分で作っていきます。
Actorを追加します。
見た目用のStaticMeshと当たり判定用のコリジョンを追加します。
今回はHitで判定を取っているのでコリジョンプリセットをAllBrockにしておいてください。
イベントグラフに移動します。
変数にHP Floteを追加します。デフォルト値は適当に300くらいを入れておいてください。
書く処理はHP≦0になったら先ほど作ったブループリントインターフェースが送られるというものになります。
AnyDamageでprojectileからDamageを与えられたときにイベントを実行します。
自分のHPからDamageを引いてセットします。
引いた数字がHP≦0であればブランチがTrueに進みDamageCauserに入っているFirstPersonに向けてLevelUPを実行するメッセージを送ります。
送り終わったらDestroyActorでactorを削除します。
これで全機能が完成しました!
プレイしてみる
このままだとUIも何も組んでいないので適当にデバッグ用のPrintstringをCharacterBPのLevelUPの最後にくっつけておきます。
適当にBP_Enemyをレベル上に配置します。
プレイしてみます。
青がレベル、赤が攻撃力、緑が累計経験値です
ちゃんと機能していそうですね。
あとがき
いっけない~遅刻遅刻!!
というわけでクソ簡単なレベルアップシステムの作り方でした。
UIとかつけて見栄え良くしようとしたら時間足りませんでした。許してください。
ほんとは会話システムも書く予定だったんですがレベルアップシステムの時点でとんでもない量になっていたんです…
ではまたぷちコン映像編で会いましょう
─=≡Σ((( つ╹ω╹)つ シュバッ!!