UE5でFPSゲーム制作 Part20-WorldSubsystem
Subsystemの内容が多すぎるので詳しい説明は調べてください。
Subsystemは自身を管理しているものと同じタイミングで生成、破棄されるため、手動で生成、破棄をする必要がなく管理が楽という利点があります。
生成されていればどこからでもアクセスが可能であり、レベル上のステータスを管理するManagerクラス等を作るのに役に立ちます。
World Subsystem
新規C++クラス→すべてのクラスからWorld Subsystemを選択し、Battle Manager Subsystemと名付けます。
BattleManagerSubsystem.h
BattleManagerSubsystem.cpp
イニシャライズ等以外の部分でやったことはEnemy Countという変数の追加と、その取扱いのための関数追加です。
次に新規C++クラスからWorld Settingsを選択し、TutoWorldSettingsと名付けます。
TutoWorldSettings.h
TutoWorldSettings.cpp
#include "TutoWorldSettings.h"
ここまで出来たらコンパイルして、プロジェクト設定を開きます。
基本設定のワールドセッティングクラスをTutoWorldSettingsに変更して再起動します。
これでエディタ上からワールドセッティングスの項目にUse Battle Managerの使用のオンオフができるようになりました。基本的にゲームステージではオンであり、タイトル画面などのところはオフにします。
これでWorld Subsystemを使用する準備はできました。
UE5でFPSゲーム制作 Part19-武器の残弾を表示する
UIに武器の弾数等を表示する
UIに武器の名前やマガジンの弾数を表示できるようにしたいと思います。今までやってきたことから、自分が持っている武器はCurrent Weaponという変数に格納しているので、Current Weaponから引っ張ってくるだけで済みます。
WeaponBase.h
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "WeaponInfo")
FString WeaponName;
UFUNCTION(BlueprintPure, Category = "WeaponInfo")
FString GetWeaponName();
WeaponBase.cpp
FString AWeaponBase::GetWeaponName()
{
return WeaponName;
}
を追加します。
BP_WeaponBaseにWeapon Nameという変数ができたので、名前を付けておきます。Assalt Rifleと名付けました。
WBP_MianHUD
WBP_MainHUDに新しくVertical Boxを追加します。Overlayの中にImageを入れてBackColorと名付けます。あとは必要なTextウィジェットを図のような階層構造で入れます。
BackColorはTintから薄い黒色にします。
例えばApex Legendsのようなゲームでは、ここを武器の種類に応じた背景色にしたりなどしていますね。
Textの"Weapon Name"からバインディングを作成します。
Textの"99"からバインディングを作成します。
Truncateは小数点以下を全部切り捨ててInt型に変換するノードです。
同じようにTextの"999"からバインディングを作成します。
これで画面に武器の名前やマガジンの弾、所持弾数を表示することができました。
UE5でFPSゲーム制作 Part18-UIの作成
UIの作成はWidgetブループリントを使って行います。
体力の表示
ユーザーインターフェースから新規ウィジェットブループリントを作成します。WBP_MainHUDと名付けます。
WBP_MainHUD
Canvas Panelを配置します。
体力を表示させるにはProgress Barを使用します。
Vertical Boxの中にTextとProgress Barを配置します。TextはHPとします。
右上からグラフに切り替えて、イベントConstructからBP_PlayerCharacter型の変数をキャストして作成します。
Progress BarのPercentからバインディングを作成します。
BP_PlayerCharacterのStatusから体力を計算します。
BP_PlayerCharacter
BP_PlayerCharacterにSequenceを追加し、WBP_MianHUDウィジェットを作成し、Add to Viewportで表示します。
これでHPの表示が出来ました。
UE5でFPSゲーム制作 Part17-ADS
ADSとはAim DOwn Sightの略で、銃をのぞき込んで撃つことです。
ADS
PlayerCharacter.h
ADSに関する関数を作成していきます。bIsAiming、IsAiming、SetAiming、FOV、GetFOVを作成します。
PlayerCharacter.cpp
入力アクションから新しくIA_RightActionをDigitalで作成しIMC_FPSに登録します。TriggersはPressedとReleasedに設定します。
新しくGameplayEffectを作成し、GE_MaxSpeedAdsと名付けます。
GE_MaxSpeedAds
ADS中は移動速度を下げたいのでMaxSpeedを200に設定します。
次に新しいGameplay Abilityを作成しGA_Adsと名付けます。
GA_Ads
Gameplay Abilityがアクティベートされたら、GameEffectとPlayerCharacterのSet Aiming関数を呼びます。Ability.Action.Ads.Cancelタグが呼ばれるとEnd Abilityが呼ばれます。
ADS中はダッシュができないようにしたいので、Cancel Abilities with TagとBlock Abilities with TagにAbility.Action.Dashを設定しておきます。
WeaponBaseクラスにADS時のズーム倍率を変数として作成します。
WeaponBase.h
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Weapon")
float ZoomScale;
UFUNCTION(BlueprintPure, Category = "Weapon")
float GetZoomScale();
WeaponBase.cpp
ZoomScale = 0.95f;
float AWeaponBase::GetZoomScale()
{
return ZoomScale;
}
BP_PlayerCharacter
GA_AdsをBP_PlayerCharacterに登録したら、IA_RightActionからアビリティを呼びます。アビリティが成功ならSet Aiming関数が呼ばれるはずです。
新しくタイムラインノードを作成しT_Adsと名付けます。キー補間はお好みで設定します。値は0.0~1.0に設定します。
Set Field Of View関数は視野角を変更する変数になります。この視野角をタイムラインノードを通して小さくすることでズームを表現することになります。例えば2倍のズームならCurrent WeaponのZoom Scaleは0.5fになります。
腰だめの時は弾が拡散し、ADS時は正面に飛ぶように変更したいと思います。
BP_WeaponBase
FireAction関数のLineTraceByChannel以降を関数に折りたたみます。Line Trace by Enemyと名前とつけます。
AsPlayerCharacterがIsAiming状態であるかどうかを判断し、IsAimingがFalseなら拡散するようにします。
Random Unit Vector in Cone in Degreesは比率に応じてランダムに拡散させることができます。BP_Weaponに作成したFire Spread変数で拡散率を変更できます。
これでADSが完成しました。
ここまででプレイヤーに必要なアクションはだいたい完成したと思います。ゲームによってはグレネードと回復アイテム、弾薬パックなどが必要になってくるでしょうか。
次はUIを作成していきたいと思います。
UE5でFPSゲーム制作 Part16-武器を拾う②
前回、インターフェースを通してBP_WeaponBaseのPickup Weapon関数とPickup Inventory関数で銃の所持者であるAs Player Character変数を登録できるようにしました。
Part12-銃を作る③の最後で、銃の所持者をBegin Playで登録していましたが、BPI_Weaponを通して行うことができるようになったのでBegin Playの部分はすべて削除します。
武器を拾う
入力アクションからIA_InteractをDigital(bool)で作成します。IMC_FPSでキーボードのFに割り当てます。TriggersはPressedです。
BP_PlayerCharacter
前回視線の先にあるオブジェクトを認識できるようになったので、Hit Itemが存在するならアイテムを判断して取得します。Cast to WeaponBaseは右クリックから純粋キャストに変換します。
Inventory Weapon_0がIs Not Validなら武器を拾ってCurrent Weaponに設定し、Hit Itemをなくします。
Inventory Weapon_0があってInventory Weapon_1がないとき(武器が1本しかないとき)は2本目の武器として拾い、インベントリへ格納します。
武器が2本ともある時には、手持ちの武器を捨てて、武器を拾います。Detach From ActorはソケットにアタッチされているActorを外すことができます。Keep Worldにしておかないと、足元にドロップされません。
落とした武器はインターフェースを通してBP_Weaponのコリジョンを戻します。
武器を捨てたら、Hit Itemを手持ちの武器としてCurrent Weaponに登録しアタッチします。
これで武器を拾って交換することができるようになりました。
UE5でFPSゲーム制作 Part15-武器を拾う①
最終的には今持っている武器を捨てて、落ちてる武器を拾い上げるようにしたいと思います。
武器を拾う
まずは落ちてるアイテムを認識できるようにします。
WeaponBase.h
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Weapon", meta = (AllowPrivateAccess = "true"))
class UBoxComponent* TraceBox;
FORCEINLINE class UBoxComponent* GetBox() const { return TraceBox; }
WeaponBase.cpp
TraceBox = CreateDefaultSubobject<UBoxComponent>(TEXT("HitBox"));
TraceBox->SetupAttachment(Mesh);
を追加し、銃にBoxCollisionを追加します。
プロジェクト設定→コリジョンからTrace Channelsを追加します。TraceItemと名付け、デフォルト応答をIgnoreにします。
BPI_Weaponに新しい関数を4つ作ります。
PickupWeaponとPickupInventoryという関数を作り、インプットにPlayer Characterを追加します。Drop WeaponとTraceHitItem関数は何も追加しません。
BP_PlayerCharacter
新しくカスタムイベントを追加し、UpdateShowItemInfoと名付けます。自分のカメラからLine Trace By Channelを取得します。Trace ChannelはTraceItemにします。
Actor型のHitItemという変数を作成します。自分の視点先にTraceItemのトレース応答がある場合、そのActorをHIt Itemとして取得します。
BP_WeaponBase
銃のメッシュとボックスコリジョンのコリジョンを変更しておきます。
重力で落下させたいのでMeshはSimulate PhysicsをTrueにし、CollisionEnabledはQuery and Physicsにします。
(逆にSimulate PhysicsがFalseでCollisionEnabledがQuery Onlyなら重力の影響を受けないので、壁に飾ってあったり、立てかけてあったりといった配置ができます。)
BoxコリジョンはBP_PlayerCharacterのLine Trace By Channelにのみ反応するようにします。また、CollisionEnabledはQuery Onlyにします。ここがNo Collisionになっているとトレース応答をブロックにしても反応しません。(ここで10分くらい迷った)
Pickup WeaponイベントとPickup Inventoryイベントは銃を拾う際に発生するイベントになります。要は拾った銃は物理演算や当たり判定を削除してキャラの手にアタッチするだけです。
別の銃を拾って、今の銃を捨てる際には、Drop Weaponイベントを呼び、再度物理演算や当たり判定を再開します。
次にBP_PlayerCharacterのBegin Playを編集します。
BP_PlayerCharacter
Set Timer by EventではUpdateShowItemInfoを一定時間ごとに呼び出しています。
また、最初に生成していた2本の銃はそれぞれ手持ちをPickup Weapon、もう一本はPickup Inventoryを呼び出します。
ここまででとりあえずマップに落ちている武器を認識することができました。
UE5でFPSゲーム制作 Part14-武器の持ち替え
BP_WeaponBaseを継承して子BPを作ります。すべての銃はこのBP_WeaponBaseを継承しており、基本的にステータスをいじるだけで武器の種類を増やすことができます。
武器の持ち替え
2つ以上の武器を装備している時、キーボードの1、2番やホイールで変更できるようにしていきます。
入力アクションからIA_SwapWeapon_0、IA_SwapWeapon_1、IA_SwapWeaponWheelを作成します。Value TypeはIA_SwapWeapon_0、IA_SwapWeapon_1はDigital(bool)、IA_SwapWeaponWheelはAxis1D(float)に設定します。
IMC_FPSにキーボード1番、2番、マウスホイール軸に設定します。IA_SwapWeaponWheelはModifiersをNagateにします。
BP_PlayerCharacterにWeaponBase型のInventoryWeapon_0とInventoryWeapon_1を作成します。Int型のCurrentWeaponIndexを作成します。
PlayerCharacter.hに
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "Action")
void SwapWeapon(int Value);
を追加します。
新しいGameplay Abilityを作成し、GA_SwapWeapon_Slot1と名付けます。
GA_SwapWeapon_Slot1
Ability TagとActivation Owned TagsはAbility.Action.Swapと設定します。
やっていることはアニメーションモンタージュを使用して、モンタージュ終了時にPlatyer CharacterのSwapWeapon関数を呼び出すだけです。
Swap Weapon関数のValueは0にします。これと同じものをGA_SwapWeapon_Slot2と名付けてもう一つ用意します。こちらはSwap Weapon関数のValueを1にします。
BP_PlayerCharacter
現在の武器であるCurrent WeaponとInventory Weaponが同じかどうかを判断して、違っていたらカスタムイベントからGameplay Abilityが呼ばれます。
武器の持ち替えに成功したら、Current Weaponをもう片方の武器に設定し、表示非表示を変更しています。
BeginPlayから銃を生成していた部分に新たにInventoryWeaponをセットし、2本目の武器は非表示にしておきます。
これで武器の持ち替えができるようになりました。