ゲーム開発備忘録

ゲームプログラマー UE4・5向けの記事を書いておりますので見ていただけるとありがたいです。

【UE4・UE5】〈UnrealC++入門〉② BPで作った関数をC++ノード化してみよう ~MultiSphereTraceの組み込みとmeta指定子~

目次

 

はじめに

BPがある程度理解できたがC++はちょっと、、という人に向けて書いています。

ゲームでよく使うであろう”周囲のアクタから一番近いものを取得するノード”を作ってみるという内容の第2回です。

 

前回

namiton.hatenablog.jp

 

この話では必要なピンを表示するところまでやります。

 

投稿者の環境は以下の通りです

・Windows11

・Rider2022.3.1

・UE5.1.1

解説

➀MultiSphereTraceの中身を見てみよう

UEC++を学習する上で一番良いのは、既存のノードの中身を見てみることです。ネットで調べるより直接見たほうが動作も分かるのでお勧めです。

 

MultiSphereTraceをダブルクリックするとコードエディタで実装に飛べます。(※UEと連携している場合のみ)


▼該当実装

bool UKismetSystemLibrary::SphereTraceMulti(const UObject* WorldContextObject, const FVector Start, const FVector End, float Radius, ETraceTypeQuery TraceChannel, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, EDrawDebugTrace::Type DrawDebugType, TArray<FHitResult>& OutHits, bool bIgnoreSelf, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime)
{
ECollisionChannel CollisionChannel = UEngineTypes::ConvertToCollisionChannel(TraceChannel);

static const FName SphereTraceMultiName(TEXT("SphereTraceMulti"));
FCollisionQueryParams Params = ConfigureCollisionParams(SphereTraceMultiName, bTraceComplex, ActorsToIgnore, bIgnoreSelf, WorldContextObject);

UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
bool const bHit = World ? World->SweepMultiByChannel(OutHits, Start, End, FQuat::Identity, CollisionChannel, FCollisionShape::MakeSphere(Radius), Params) : false;

#if ENABLE_DRAW_DEBUG
DrawDebugSphereTraceMulti(World, Start, End, Radius, DrawDebugType, bHit, OutHits, TraceColor, TraceHitColor, DrawTime);
#endif

return bHit;
}

 

いろいろやってますが、ぱっと見れば以下のことが分かります。

➀UKismetSystemLibraryの中に作成されたSphereTraceMultiという名前の関数である。

②returnでbHitを返している。

③当たったものの情報はOutHitsというFHitResultという構造体を配列で持っている。

 

以上を踏まえてこの関数を自作関数の中で使ってみましょう。

 

②MultiSphereTraceの引数を自作ノードから指定できるようにする

SampleBlueprintFunctionLibrary.hの関数を拡張します。

const とは定数で内部での書き換えを禁止します。これを指定すると入力ピンになります。ないと出力ピンになります。

関数の引数はSphereTraceMultiの中身と同じものを用意しています。

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "Kismet/KismetSystemLibrary.h" // 追加
#include "SampleBlueprintFunctionLibrary.generated.h"

/**
*
*/
UCLASS()
class USampleBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()

public:
UFUNCTION(BlueprintCallable, Category="CustomFunction")
static bool FindNearestActor(const UObject* WorldContextObject,
const FVector Origin,
const ETraceTypeQuery TraceChannel,
const float TraceDistance,
AActor*& NearestActor,
const bool bTraceComplex,
const TArray<AActor*>& ActorsToIgnore,
const bool bIgnoreSelf,
const EDrawDebugTrace::Type DrawDebugType);

 

SampleBlueprintFunctionLibrary.cppも同様に変更します。

#include "SampleBlueprintFunctionLibrary.h"

bool USampleBlueprintFunctionLibrary
::FindNearestActor(const UObject* WorldContextObject,
const FVector Origin,
const ETraceTypeQuery TraceChannel,
const float TraceDistance,
AActor*& NearestActor,
const bool bTraceComplex,
const TArray<AActor*>& ActorsToIgnore,
const bool bIgnoreSelf,
const EDrawDebugTrace::Type DrawDebugType)
{
return true;
}

この状態でビルドしてみましょう。

画像のようにピンが増えました。

③MultiSphereTraceを使ってみる

SampleBlueprintFunctionLibrary.cppのFindNearestActor中を書いていきます。

先ほど見た通りSphereTraceMultiの返り値はbool型なのでif文の条件式の中で利用できます。

頭に!を付けることで条件を反転できるので当たったものがなかったら中に入るようにします。

{
// ヒットした構造体群を受け取る
TArray<FHitResult> OutHits;

if (!UKismetSystemLibrary::
SphereTraceMulti(WorldContextObject, Origin, Origin, TraceDistance,
TraceChannel,bTraceComplex,ActorsToIgnore,
DrawDebugType, OutHits, bIgnoreSelf))
{
return false;
}
return true;
}

 

実行すると当たっているときにはTrue,何もないときはFalseが返ってきます。

 

④Return Valueを実行ピンで表示する

よくブループリントでbool型の実行結果をブランチノードで分岐することが想定されるノードの場合は実行ピンで表現したほうが使いやすいのでやってみましょう。

 

関数や変数に追加の情報を付与するメタデータ指定子というものを使います。

docs.unrealengine.com

 

SampleBlueprintFunctionLibrary.hのみにExpandBoolAsExecsを追加します。

これをすることで関数の戻り値のbool型を実行ピンに変化させることができます。

public:
UFUNCTION(BlueprintCallable, Category="CustomFunction"
, meta=(ExpandBoolAsExecs = "ReturnValue")) // 追加
static bool FindNearestActor(const UObject* WorldContextObject,
const FVector Origin,

 

追記したら再度ビルドしてみましょう。

bool型のReturnValueが消えて実行ピンが増えました。これでブランチを置く手間が減りました。

 

特定の表示名にしたり複数のピンを使用したい場合はExpandEnumAsExecsを使いましょう。

この解説は過去にしているのでこちらからよんでみてください。

namiton.hatenablog.jp

 

⑤配列など未接続のピンがあるとエラーが出る問題を修正する

Actors to Ignoreなど配列の中身がない場合、いちいち空の配列を作るのは大変です。

 

そこで自動的に空のものを値を作ってくれるmeta指定子AutoCreateRefTermを付けてこの手間を省きます。

 

再度SampleBlueprintFunctionLibrary.hのみに追加します。

public:
UFUNCTION(BlueprintCallable, Category="CustomFunction"
, meta=(ExpandBoolAsExecs = "ReturnValue"
, AutoCreateRefTerm="ActorsToIgnore")) // 追加
static bool FindNearestActor(const UObject* WorldContextObject,
const FVector Origin,

 

ビルドしてみましょう。なにもつながってなくても自動で空の配列が作られてエラーが出なくなります。

 

⑥WorldContextObjectを非表示にしたい

WorldContextObjectとはこのノードを実行するときにどのワールドで実行するというかということを決定します。

詳しく知りたい方はこちらの記事が参考になりましたので共有いたします。

qiita.com

現在の用途では不要なパラメータですのでWorldContext =”引数名”で入力ピンとして表示しないようにします。

public:
UFUNCTION(BlueprintCallable, Category="CustomFunction"
, meta=(ExpandBoolAsExecs = "ReturnValue"
, AutoCreateRefTerm="ActorsToIgnore"
, WorldContext = "WorldContextObject")) // 追加
static bool FindNearestActor(const UObject* WorldContextObject,
const FVector Origin,

 

ビルドしてノードを更新するとピンが非表示になりました。

 

次回はOutHitsを使って最も近いアクタの検出処理を実装します。

最後に

UE4やUE5向けの記事を書いています。

皆様の応援が投稿のモチベーションになりますので

コメントやTwitterのフォローなどしていただけるとありがたいです。

それではよきゲーム開発を。

投げ銭を投げる