LoginSignup
10
4

More than 1 year has passed since last update.

DataTableで作るレベルアップシステム

Last updated at Posted at 2022-12-19

こたつみかんが美味しい時期がやってまいりました。
この記事は 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においてテンプレートマップや新しいメッシュをインポートした時にエディタ画面が白飛びする現象が確認されています。
スクリーンショット (865).png

もしファーストパーソンマップが白飛び・黒潰れしていたら、アウトライナーのLightingフォルダ内のPostProcessVolumeを削除してください。

左上の編集からプロジェクト設定を開き、プロジェクト▶マップ&モード▶デフォルトのゲームモードを「BP_FirstPersonGameMode」にしてください。
スクリーンショット (867).png

スクリーンショット (868).png

キチンとプレイできたら準備は完了です!

レベルアップシステムを作る

レベルアップシステムってどんな奴やねん、って感じなんですが、今回は敵を倒すと経験値が入り、経験値が一定数溜まるとレベルが上がるよく見るRPG的なやつを作っていこうと思います。

ざっくり説明するとこんなやつです
ブログ説明用.png

更に細かくプレイヤーの仕組みについて説明すると
ブログ用PlayerBP.png

こんな感じのを組んでいきます。多分そんなに難しい内容ではない…ない…

PlayerのBP編

DataTableを作る

そもそもDataTableとは?という話なんですが(すごく大雑把に言うと)UE内で組める表みたいなもんです。
スクリーンショット (880).png

こういうのをUEの中で作っていきます。

スクリーンショット (881).png

適当なフォルダ内にブループリント>構造体というのがあるで構造体を追加してください。
これがExcelで言うところの「列」になります
スクリーンショット (883).png
開くとこんな感じになってると思います。
この構造体タブ内の▶MemberVar_0になってる所が列の名前で、その横にあるのがその列に入れることができる変数の形になります。
スクリーンショット (885).png
変数を追加から新しい列を作れるので
スクリーンショット (890).png

・攻撃力   Frote(浮動点少数)
・必要経験値 Frote or Integer (どっちでもいい)

という感じで列を作っていきます。(わかりやすいので日本語にしてますがプログラミングに日本語を使いたくない主義の方は適当に英語に変えてください)
汎用性とか考えた結果Froteにしてるだけなので整数しか使わねえわ!って人はIntegerでもまるで問題ありません。
スクリーンショット (892).png
今回は使いませんが、構造体タブの隣のデフォルト値のタブからは変数の初期値を変更することができます。

次に肝心のDataTableの方を作っていきます。
スクリーンショット (882).png

その他>データテーブルを追加してください。
スクリーンショット (894).png

スクリーンショット (895).png

こんな感じのタブが出ると思うので、ドロップダウンの中から、先ほど自分が作成した構造体を選択してください。

開くとこんな感じのが出来ている筈です。

スクリーンショット (896).png

さて、本題のDataTableを組んでいくのですが、この状態でどうやってレベルを指定するのか、という話を先に書いておきます。

スクリーンショット (898).png
今回、DataTableの行を読み取るのにこのノードを使用するのですが、指定方法がName変数になっています。
つまり、DataTableの行の名前をレベル数にしてしまい、Playerのレベル変数IntgerをNameに変換してピンに渡してしまえば数字から直接行を指定できるぜ!という仕組みです。

では作っていきます。
スクリーンショット (903).png
追加から行を10個くらい追加します。
スクリーンショット (904).png
行の名前を数字に変更します。
スクリーンショット (905).png
下の行エディタから各レベルに合わせて攻撃力と必要な経験値量をざっくり決めて入れましょう。
行の名前の数字は半角にするのをお忘れなく!
これでDataTableは完成です。

CharacterBP編

続いてCharacterBPの方を触っていきます。
UE4までは弾の発射処理までCharacterに書いてあったんですが、UE5になってからSkeletal Mesh Componentが親クラスのActor Component??を使ったものに変わっていました。
スクリーンショット (907).png
↑おそらくこれのSkeletalMesh版…??

銃をとるとそのComponentに書いてるBPを指定されたActorに追加しますよ~見たいなやつらしい。武器ごとに性能が違うやつゲームを作る時に全部CharacterBPに描くのを防止できますよ~的な機能かと。よくわからん。詳しい人間違ってたら教えてください。

BP_FirstPersonCharacter編

FirstPerson>BluePrints下のBP_FirstPersonCharacterを開きます。
変数を追加します。
スクリーンショット (943).png

・プレイヤーのレベル Integer
・攻撃力 Frote
・累計経験値 Frote
・必要経験値 Frote
・連続レベルアップ Boolean

の5つです。もしDataTableで変数の型をIntegerにしていた人はそれに合わせて変えてください。
プレイヤーのレベルの初期値を1にしておいてください。
連続レベルアップのBooleanは経験値が一回の加算で2Lv以上アップできるときに困らないよう使います。
スクリーンショット (910).png
データテーブルの行の取得、のノードを出します。
スクリーンショット (911).png
ドロップダウンから先ほど作ったDataTableを選びます。
スクリーンショット (915).png
出力側にある外側の列から行の内容が吐き出されるのですが、Breakノードを挟むのが面倒なので構造体ピンを分割で直接変数を引っ張り出せるようにしてください。
スクリーンショット (914).png

行を指定する入力側のピンRowNameにプレイヤーのレベル変数を繋げたいのですがそのままではくっついてくれないのでToStringとToNameを挟んで無理矢理繋げます。
スクリーンショット (920).png
先ほど作った変数に、データテーブルからでてきた変数をセットします。
スクリーンショット (923).png
BeginPlayが別のところで使われているので、BeginPlayが繋がっているノードの最後のところから今作ったDataTableのBPに線を引っ張ってきます。
スクリーンショット (926).png
やらなくても大丈夫ですが適当にデバッグ用のノードを最後につけて実行するとこんな感じになるはずです。
スクリーンショット (927).png

これでデータを引っ張り出すところは組めたので次はレベルアップについて組んでいきます。
今回は汎用性大事ということでBluePrintInterfaceを使っていきます。
超適当な説明をするとCastしなくても使えるカスタムイベント的なやつなんですが厳密にいうと多分違うのでちゃんと知りたい方はこのへんの動画みてください。

スクリーンショット (930).png

ブループリントインターフェースを作ります。
スクリーンショット (932).png
名前は何でもいいですがノードの名前になるのでわかりやすいものにしておきましょう。
下のインプットに新しい変数を追加します。
・経験値 Flote
ここに敵の経験値がセットされます。

BP_FirstPersonCharacterに戻ります。
スクリーンショット (935).png

画面の上の方のクラスの設定を開きます。
右側のタブのインターフェース→継承インターフェースにあるドロップダウンから先ほど作成したインターフェースを選びます。
スクリーンショット (938).png
左側のタブのインターフェースのところに、先ほど作ったインターフェース内にある関数が追加されます。
右クリックしてイベントを実装を選んでください。
スクリーンショット (940).png
カスタムイベントに似たようなノードが出てきます。大体カスタムイベントと似たような機能です。
ここから繋げていきます。

スクリーンショット (946).png
先に全体像を乗っけておきます。
細かい解説に移ります↓
スクリーンショット (952).png

先ほど出したイベントから経験値を引っ張り累計経験値に加算してセットします。
次に連続レベルアップ変数をTrueにします。これは次に来るLoopをオンにするためのイベントなので深い意味はありません。
スクリーンショット (953).png
WhileLoopでそれ以降LoopBodyに書かれた内容が連続レベルアップがTrueな限り繰り返されるようにします。
次にブランチで次のレベルアップに必要な経験値より今の累計経験値が多いかどうか判断します。
少なければ連続レベルアップをFalseにしレベルアップは行われません。
スクリーンショット (954).png
ここからはレベルアップが行われる場合の処理になります。PlayerLevelを+1して、累計経験値からレベルアップに必要な経験値を引きます。
スクリーンショット (956).png
最後に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を開きます。
スクリーンショット (1009).png

ビューポートからコリジョンを選択してコリジョンプリセットをBlockAllにしておいてください。

スクリーンショット (979).png
変数に
攻撃力Flote
FirstPerson Object
を追加します。
スクリーンショット (980).png
FirstPersonは詳細タブから直接BP First Person Characterを検索してオブジェクト参照の変数にしてください。

スクリーンショット (1002).png
Hit以降の部分には物理シミュレーションの処理が入っているのですが今回は使わないのとエラーの元になるのでDestroyActor以外全て決してしまいます。

イベントHitとDestroyActorの間にApplyDamageを挟みます。
スクリーンショット (1003).png
イベント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を開きます。弾の発射関連が書いてあるのは
スクリーンショット (967).png
この辺の
スクリーンショット (968).png
こいつ(SpawnActor BP First Person Projectile)です。
では書いていきます。
スクリーンショット (969).png
SpawnActorのReturnValueから先ほど作ったProjectile内の攻撃力変数をSetで出します。
SpawnActorとPlaySoundの間くらいの使いやすい位置にでも繋げておきます。
実はこのBP_Weapon_ComponentはBeginPlayの時点でFirstPersonCharacterBPが変数化してあるので左側の変数のところのFirstPersonCharacterをGetで配置します。
スクリーンショット (973).png
このFirstPersonCharacterからGet攻撃力でCharacterBP側に入っている攻撃力変数を取り出します。
スクリーンショット (976).png
取り出してきた攻撃力をProjectileの攻撃力のSetにくっつけます
スクリーンショット (984).png

同じようにReturnValueから今度はFirstPerson変数をSetで出し、先ほど出したFirstPersonCharacterを直接繋げます。
これで
ブログ用PlayerBP.png

これが組みあがったということになります。
次は敵BPと敵BPからの経験値の送信の部分になります。

敵のBP編

敵のBPは最初から入っていないので自分で作っていきます。
スクリーンショット (989).png
Actorを追加します。
スクリーンショット (991).png
見た目用のStaticMeshと当たり判定用のコリジョンを追加します。
スクリーンショット (986).png
今回はHitで判定を取っているのでコリジョンプリセットをAllBrockにしておいてください。
イベントグラフに移動します。
スクリーンショット (994).png
変数にHP Floteを追加します。デフォルト値は適当に300くらいを入れておいてください。
書く処理はHP≦0になったら先ほど作ったブループリントインターフェースが送られるというものになります。
スクリーンショット (998).png
AnyDamageでprojectileからDamageを与えられたときにイベントを実行します。
自分のHPからDamageを引いてセットします。
引いた数字がHP≦0であればブランチがTrueに進みDamageCauserに入っているFirstPersonに向けてLevelUPを実行するメッセージを送ります。
送り終わったらDestroyActorでactorを削除します。

これで全機能が完成しました!

プレイしてみる

このままだとUIも何も組んでいないので適当にデバッグ用のPrintstringをCharacterBPのLevelUPの最後にくっつけておきます。
スクリーンショット (1004).png
適当にBP_Enemyをレベル上に配置します。
スクリーンショット (1007).png

プレイしてみます。
青がレベル、赤が攻撃力、緑が累計経験値です

ちゃんと機能していそうですね。

あとがき

いっけない~遅刻遅刻!!
というわけでクソ簡単なレベルアップシステムの作り方でした。
UIとかつけて見栄え良くしようとしたら時間足りませんでした。許してください。
ほんとは会話システムも書く予定だったんですがレベルアップシステムの時点でとんでもない量になっていたんです…
ではまたぷちコン映像編で会いましょう
─=≡Σ((( つ╹ω╹)つ シュバッ!!

スクショ集

CharacterBP
スクリーンショット (1011).png
Projectile
スクリーンショット (1008).png
Wepon
スクリーンショット (1013).png
BP_Enemy
スクリーンショット (1012).png

10
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
4