fc2ブログ

凛(kagring)のUE5/UE4とゲーム制作と雑記ブログ

2016 年から UE4 / 2021年から UE5 を触り始めました。勉強したもののメモ用ブログです。ゲーム制作に関するメモや雑記とか色々あります。C++ での Qt、Unity もほんの少しあります。

2022年05月 | ARCHIVE-SELECT | 2022年07月

| PAGE-SELECT | NEXT

≫ EDIT

UE5/UE4 C++でゲームモード(GameMode)を継承した独自のクラスを作る(AGameModeBase、UGameplayStatics::GetGameMode)

C++でゲームモード(GameMode)を継承した独自のクラスを作る方法です。

公式ドキュメントはこちら。

・AGameModeBase
https://docs.unrealengine.com/4.27/en-US/API/Runtime/Engine/GameFramework/AGameModeBase/

C++で独自のゲームモード(GameMode)クラスを作成する場合は「AGameModeBase」を継承します。
こんな感じですね。
#include "GameFramework/GameModeBase.h"

// AGameModeBaseを継承した独自のゲームモード(GameMode)クラスを作成
UCLASS()
class ANewGameMode: public AGameModeBase
{

GENERATED_BODY()
public:
// コンストラクタ
ANewGameMode();
};

あとは基本的に「AGameModeBase」に関するイベントを記述するだけなので難しいことはないのかなと思います。

この作成した独自のゲームモード(GameMode)クラスを取得するには
「UGameplayStatics::GetGameMode」関数を使います。

「UGameplayStatics::GetGameMode」関数は素の「AGameModeBase」を取得する関数なので
独自のゲームモード(GameMode)クラスにキャストしてあげます。

TObjectPtr< ANewGameMode> aGameMode = Cast< ANewGameMode>(UGameplayStatics::GetGameMode(this));

こんな感じの記述になります。

ゲームを作る時には独自のクラスを作ることは結構必須だと思うので覚えておきたいですね。

| UE5 | 10:00 | comments:0 | trackbacks:0 | TOP↑

≫ EDIT

UE5/UE4 C++でゲームインスタンス(GameInstance)を継承した独自のクラスを作る(UGameInstance、UGameplayStatics::GetGameInstance)

C++でゲームインスタンス(GameInstance)を継承した独自のクラスを作る方法です。

公式ドキュメントはこちら。

・UGameInstance
https://docs.unrealengine.com/5.0/en-US/API/Runtime/Engine/Engine/UGameInstance/

C++で独自のゲームインスタンス(GameInstance)クラスを作成する場合は「UGameInstance」を継承します。
こんな感じですね。
#include "Engine/GameInstance.h"

// UGameInstanceを継承した独自のゲームインスタンス(GameInstance)クラスを作成
UCLASS()
class UNewGameInstance: public UGameInstance
{

GENERATED_BODY()
public:
// コンストラクタ
UNewGameInstance();
};

あとは基本的に「UGameInstance」に関するイベントを記述するだけなので難しいことはないのかなと思います。

この作成した独自のゲームインスタンス(GameInstance)クラスを取得するには
「UGameplayStatics::GetGameInstance」関数を使います。

「UGameplayStatics::GetGameInstance」関数は素の「UGameInstance」を取得する関数なので
独自のゲームインスタンス(GameInstance)クラスにキャストしてあげます。

TObjectPtr< UNewGameInstance> aNewGameInstance = Cast< UNewGameInstance>(UGameplayStatics::GetGameInstance(this));

こんな感じの記述になります。

ゲームを作る時には独自のクラスを作ることは結構必須だと思うので覚えておきたいですね。

| UE5 | 10:00 | comments:0 | trackbacks:0 | TOP↑

≫ EDIT

UE5/UE4 「Float」型の値を一定数記録(サンプリング)してグラフで表示する(Debug Float History、Add Float History Sample、Draw Debug Float History Location、Draw Debug Float History Transform)

「Float」型の値を一定数記録(サンプリング)してグラフで表示する方法です。

こちらのツイートを見かけたので試してみました。

「Debug Float History」という機能を使うことでグラフ表示ができるようです。

まずは値を格納するための「Debug Float History」型の変数を用意します。
FloatHistory005.jpg
とりあえず中身の設定はそのままで問題ないようです。

次に「Add Float History Sample」ノードを使ってグラフにするための値を格納していきます。
FloatHistory001.jpg
「Value」には格納したい「Float」型の値を指定します。
「Float History」には先ほど作成した「Debug Float History」型の変数を指定します。

この「Add Float History Sample」で追加した値をグラフで表示します。
「Debug Float History Location」というノードがあり、これでグラフ表示をすることができます。
FloatHistory006.jpg
「Float History」には先ほど作成した「Debug Float History」型の変数を指定します。
「Draw Location」には表示位置を3D空間座標で指定します。
「Draw Size」には表示するグラフの幅と高さを指定します。
「Draw Colot」には表示する色を指定します。
「Duration」には表示する時間を指定します。毎フレームであれば「0.0」で問題ありません。
これについては他のデバッグ表示と同じ扱いですね。

というわけでこんな感じでノードを組んでみました。
FloatHistory000.jpg
操作キャラクターの位置の高さを毎フレーム登録して、その高さの値がどう変化するかをグラフで表示する。
といった処理になります。
キャラクターの位置と重なりを避けるために「Debug Float History Location」の位置を少しずらし、
横に長く表示したいのでグラフの幅を高さよりも大きくしています。

結果はこんな感じになりました。

無事サンプリングした値がグラフとして表示されているようです。

ちなみに「Debug Float History Location」ノードの他に
「Debug Float History Transform」という「Transform」を直接指定するノードもあります。
FloatHistory004.jpg

それと、今回は「Add Float History Sample」の値から自動でグラフの最小値と最大値を算出して表示しています。
(なので途中から最大値が変化している)
これは「Debug Float History」変数の詳細で変更できるようなので、こちらを指定するのが良いと思います。
FloatHistory003.jpg
「Max Samples」は保持するサンプル数を指定します。
「Min Value」はグラフの最小値を指定します。
「Max Value」はグラフの最大値を指定します。
「Auto Adjust Min Max」はグラフの最小値と最大値を入力された値から自動で変化させるか。といったものになります。

処理負荷だったり、なにかの密度だったりをリアルタイムで確認するのに結構向いているのかなと思います。
こういったデバッグ機能が増えてくれるのは嬉しいですね。

| UE5 | 10:00 | comments:0 | trackbacks:0 | TOP↑

≫ EDIT

UE5/UE4 C++でアクター(Actor)の「Tick」を実行しないようにする(PrimaryActorTick.bCanEverTick、PrimaryActorTick.bStartWithTickEnabled、AActor::SetActorTickEnabled)

C++でアクター(Actor)のTickを実行しないようにする方法です。

こちらを参考にさせていただきました。

・UE4/C++ Tick が来ない!そんなときのトラブルシュート備忘録
https://usagi.hatenablog.jp/entry/2017/07/05/164236

・UE4 無駄なTickを省く方法
https://papersloth.hatenablog.com/entry/2018/11/01/200000

公式ドキュメントはこちら。

・アクタのティック(Actor Ticking)
https://docs.unrealengine.com/4.27/ja/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/Actors/Ticking/

まずはアクターのコンストラクタの「PrimaryActorTick.bCanEverTick」で制御する方法です。
こんな感じで記述します。

// コンストラクタ
ANewActor::ANewActor()
{

// Tick が実行されないようにする
PrimaryActorTick.bCanEverTick = false;

}


参考サイトには以下のような注意点があります。

このActorを継承したBlueprintを作成しTickノードに何か処理を繋ぐとC++側もBlueprint側もTickが動いてしまいます。
ただし、Tickがゴーストノードの場合はTickが動くことはありません。

とはいえこんな不安な状態のまま開発を行いたくはありません。
その場合は、先程Blueprintで変更したのと同じ「StartWithTickEnabled」をC++側から「false」にしてやりましょう。


というわけで「 PrimaryActorTick.bStartWithTickEnabled」も合わせて設定します。

// コンストラクタ
ANewActor::ANewActor()
{

// Tick が実行されないようにする
PrimaryActorTick.bCanEverTick = false;
PrimaryActorTick.bStartWithTickEnabled = false;

}


ちなみに「PrimaryActorTick.bCanEverTick」なのですが、
コンストラクタで「false」に設定した後に、再度「true」設定しても「Tick」が動くことはないようです。

なので、一時的に「Tick」を止めたい。という場合には「SetActorTickEnabled」関数を使います。

// アクターのTickを一時的に止める
TObjectPtr< AActor> aActor;
aActor->SetActorTickEnabled(fasle);

// Tick を再開
aActor->SetActorTickEnabled(true);

上記一時的に止める場合は「PrimaryActorTick.bCanEverTick」は「True」である必要があるので注意ですね。

無駄に「Tick」が実行されると重くなる原因にもなるので注意して使っていきたいですね。

| UE5 | 10:00 | comments:0 | trackbacks:0 | TOP↑

≫ EDIT

UE5/UE4 Actor などの生成周りでのライフサイクルについて(Actor.h、Actor Lifecycle)

Actor などの生成周りでのライフサイクルについてのメモです。

とはいえ、「Actor.h」に記述されているのでそれの抜粋です。
詳しくは上記ファイルや公式ドキュメントを見てみたほうが良さそうです。

公式ドキュメントはこちら。

・アクタ(Actor)
https://docs.unrealengine.com/5.0/ja/unreal-engine-actors/

・アクタのライフサイクル(Actor Lifecycle)
https://docs.unrealengine.com/5.0/ja/unreal-engine-actor-lifecycle/

というわけでヘッダーの抜粋です。見やすいように成形しています。

・UObject::PostLoad:
For actors statically placed in a level, the normal UObject PostLoad gets called both in the editor and during gameplay.
This is not called for newly spawned actors.

・UActorComponent::OnComponentCreated:
When an actor is spawned in the editor or during gameplay, this gets called for any native components.
For blueprint-created components, this gets called during construction for that component.
This is not called for components loaded from a level.

・AActor::PreRegisterAllComponents:
For statically placed actors and spawned actors that have native root components, this gets called now.
For blueprint actors without a native root component, these registration functions get called later during construction.

・UActorComponent::RegisterComponent:
All components are registered in editor and at runtime, this creates their physical/visual representation.
These calls may be distributed over multiple frames, but are always after PreRegisterAllComponents.
This may also get called later on after an UnregisterComponent call removes it from the world.

・AActor::PostRegisterAllComponents:
Called for all actors both in the editor and in gameplay, this is the last function that is called in all cases.

・AActor::PostActorCreated:
When an actor is created in the editor or during gameplay, this gets called right before construction.
This is not called for components loaded from a level.

・AActor::UserConstructionScript:
Called for blueprints that implement a construction script.

・AActor::OnConstruction:
Called at the end of ExecuteConstruction, which calls the blueprint construction script.
This is called after all blueprint-created components are fully created and registered.
This is only called during gameplay for spawned actors, and may get rerun in the editor when changing blueprints.

・AActor::PreInitializeComponents:
Called before InitializeComponent is called on the actor's components.
This is only called during gameplay and in certain editor preview windows.

・UActorComponent::Activate:
This will be called only if the component has bAutoActivate set.
It will also got called later on if a component is manually activated.

・UActorComponent::InitializeComponent:
This will be called only if the component has bWantsInitializeComponentSet.
This only happens once per gameplay session.

・AActor::PostInitializeComponents:
Called after the actor's components have been initialized, only during gameplay and some editor previews.

・AActor::BeginPlay:
Called when the level starts ticking, only during actual gameplay.
This normally happens right after PostInitializeComponents but can be delayed for networked or child actors.


「Register Component」など、適切なタイミングで行わないとエラーになったりするので
こういったタイミング系の部分はちゃんと覚えておきたいところです。

| UE5 | 10:00 | comments:0 | trackbacks:0 | TOP↑

≫ EDIT

UE5/UE4 C++でコンストラクタ(Constructor)内でクラス(Class)を生成する(FObjectInitializer::CreateDefaultSubobject)

C++でコンストラクタ(Constructor)内でクラス(Class)を生成する方法です。

基礎の基礎ではあるのですが、忘れないようにメモということで…。
こちらを参考にさせていただきました。

・Unreal Engine C++ 逆引きメモ
https://edom18.hateblo.jp/entry/2018/03/16/105506

どうやら、コンストラクタ内では上記のNewObjectは使えないようです。(使うとクラッシュする)

ではどうするかというと、FObjectInitializer::CreateDefaultSubobjectを利用します。
FObjectInitializerは、コンストラクタ引数に指定しておくと、UEシステムが適切に渡してくれるようになっています。


というわけで、C++でコンストラクタ内でクラスを生成する場合は「CreateDefaultSubobject」関数を使って以下のように記述します。

// コンストラクタ
UTestClass::UTestClass()
{

// クラス生成
TObjectPtr< UNewClass > aInstance = CreateDefaultSubobject< UNewClass >(TEXT("Name"));
}


参考サイトさんでも書かれていますが、上記は簡略化された記述となっていて(問題はないですが)
本来は以下のようなコンストラクタとクラス生成の記述になります。

// コンストラクタ
UTestClass::UTestClass(const class FObjectInitializer& ObjectInitializer)

: Super(ObjectInitializer)
{
// クラス生成
TObjectPtr< UNewClass > aInstance = ObjectInitializer.CreateDefaultSubobject< UNewClass >(TEXT("Name"));
}


上記記述の差ですが

なおこのコンストラクタに引数を指定した場合としない場合の挙動の差ですが、UEシステムが自動的に生成する****.generated.h内にてマクロが生成され、コンストラクタの定義に応じて書き換わるよういなっているようです。

とあります。

こちらについても下記のサイトさんが参考になるようです。

・[UE4] ObjectInitializerでコンポーネント生成を制御する
http://historia.co.jp/archives/6587/

初歩的なことでもかなり知らないことは多いですね…。

| UE5 | 10:00 | comments:0 | trackbacks:0 | TOP↑

≫ EDIT

UE5/UE4 C++でクラス(Class)を生成する(NewObject)

C++でクラス(Class)を生成する方法です。

基礎の基礎ではあるのですが、忘れないようにメモということで…。
こちらを参考にさせていただきました。

・Unreal Engine C++ 逆引きメモ
https://edom18.hateblo.jp/entry/2018/03/16/105506

通常のC++では、newを用いてインスタンスを生成します。
しかし、UE C++ではインスタンスの生成方法に違いがあります。理由は前述のように、GC対象として管理するためです。
最近ではスマートポインタを使ったりしますが、それと似た感じですね。


というわけで、C++でクラスを生成する場合は「NewObject」関数を使って以下のように記述します。

TObjectPtr< UTestClass > aTestClass = NewObject< UTestClass >();


オーナーを指定する場合は引数に入れるようです。使い方の用途としてはこちらの方が多い気がします。

TObjectPtr< UTestClass > aTestClass = NewObject< UTestClass >(this);

UE のクラス内で生成する場合はだいたいは「this」を入れるような構成になるのかなと思います。

| UE5 | 10:00 | comments:0 | trackbacks:0 | TOP↑

≫ EDIT

UE5 C++で「Gameplay Ability System」をキャンセルする(UAbilitySystemComponent、CancelAllAbilities)

C++で「Gameplay Ability System」をキャンセルする方法です。

「Gameplay Ability System」については下記のサイトさんがまとめてくれています。
情報はこちらを詳しくみるのが良いと思います。

・【UE4】Gameplay Ability System を使い始めたい人向けの情報
https://qiita.com/sentyaanko/items/314ee39feb62ce67b885

公式ドキュメントはこちら。

・ゲームプレイ アビリティ システム(Gameplay Ability System)
https://docs.unrealengine.com/4.27/ja/InteractiveExperiences/GameplayAbilitySystem/

「Gameplay Ability System」をキャンセルするには
「UAbilitySystemComponent」の「CancelAllAbilities」関数
を使います。

こんな感じで記述します。

// 全てのアビリティをキャンセル
TObjectPtr< UAbilitySystemComponent> aAbilitySystemComponent;
aAbilitySystemComponent->CancelAllAbilities();

「Gameplay Ability」を直接指定してキャンセルする関数もあるのですが
保持の仕方など考えないといけないのと、キャンセルしたい場合はとりあえず全部で問題ないのかなというところでのメモです。

「Gameplay Ability System」の使い方についてはまだ全然わかっていないので
少しづつ使い方を覚えていこうと思います。

| UE5 | 10:00 | comments:0 | trackbacks:0 | TOP↑

≫ EDIT

UE5/UE4 BPでマウスカーソルの画像をUMGのウィジェット(Widget)に変更する(Set Mouse Cursor Widget)

BPでマウスカーソルの画像をUMGのウィジェット(Widget)に変更する方法です。

こちらのツイートを見かけたので試してみました。

「Set Mouse Cursor Widget」ノードを使ってマウスカーソルの画像を変更
できるようです。
マウスカーソルをウィジェットに変更001
「Target」には「PlayerController」を指定します。
「Cursor」にはどの状態のカーソルを変更するかを指定します。
「Cursor Widget」には変更したい画像のウィジェット(Widget)を指定します。

というわけでこんな感じでノードを組んでみました。
マウスカーソルをウィジェットに変更000
「Cursor」の初期値が「None」になっているため「Default」に設定しました。
「None」だと画像が切り替わらないようなので注意が必要そうです。

結果はこんな感じに。

無事マウスカーソルが指定したウィジェットとして動いているようです。

あとは、こちらのツイートにもありますが
用途別に画像を変更できたりもするので、結構便利な使い方ができそうです。

ウィジェットの作り方についてはツイートに記載されているこちらが参考になると思います。

・UE4 マウスカーソルを自作アイコンにする
https://papersloth.hatenablog.com/entry/2018/02/06/220632

| UE5 | 10:00 | comments:0 | trackbacks:0 | TOP↑

≫ EDIT

UE5/UE4 C++でカスタムコンポーネント(Custom Component)をブループリント(Blueprint)でカテゴリ(ClassGropu)や名前(DisplayName)をクラス指定子(Class Specifiers)を使って追加して使えるようにする(meta=(BlueprintSpawnableComponent)、meta=(DisplayName)、ClassGroup)

C++でカスタムコンポーネント(Custom Component)をブループリント(Blueprint)でカテゴリ(ClassGropu)や名前(DisplayName)をクラス指定子(Class Specifiers)を使って追加して使えるようにする方法です。

こちらを参考にさせていただきました。

・Unreal Engine C++ 逆引きメモ
https://edom18.hateblo.jp/entry/2018/03/16/105506

まずこんな感じでコンポーネント(Component)を作成します。

UCLASS(Blueprintable, ClassGroup="Debug", meta=(DisplayName="Debug Test"))
class UDebugActorComponent : public UActorComponent

{

GENERATED_BODY()

};

「ClassGroup="Debug"」という記述で「Debug」というカテゴリに。
「meta=(DisplayName="Debug Test")」という記述で「Debug Test」という名前で登録するようにしてみました。

ただ、これを実行してみるとこんな感じに。
カスタムコンポーネントを表示させる001
先ほど作成したコンポーネントは追加されていないようです。

参考にさせていただいたサイトによると
「meta=BlueprintSpawnableComponent」を記述すると一覧に追加されるようです。

というわけで記述を追加してみました。

UCLASS(Blueprintable, ClassGroup="Debug", meta=(DisplayName="Debug Test", BlueprintSpawnableComponent))
class UDebugActorComponent : public UActorComponent

{

GENERATED_BODY()
};


結果はこんな感じに。
カスタムコンポーネントを表示させる000
無事「Debug」カテゴリに「Debug Test」という名前でカスタムコンポーネントが登録されました。

ここらへんは知識として知っていないとなんで?ってなりそうですね。

| UE5 | 10:00 | comments:0 | trackbacks:0 | TOP↑

| PAGE-SELECT | NEXT