ゲーム開発備忘録

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

【UE4・UE5】〈UnrealC++入門〉③ BPで作った関数をC++ノード化してみよう ~最短アクタ計算~

目次

 

はじめに

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

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

 

前回

namiton.hatenablog.jp

 

 

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

・Windows11

・Rider2022.3.1

・UE5.1.1

解説

➀OutHitsから当たったアクタを取り出そう

前回MultiSphereTraceを利用して当たった情報の構造体の配列OutHitsが取れました。

BPで使ったこともあるかと思いますがこの構造体です。

 

配列から一個一個の要素を取り出して、Hit Actorを取り出す動作をC++で書いてみましょう。

 

SampleBlueprintFunctionLibrary.cppを拡張します。

if (!UKismetSystemLibrary::
SphereTraceMulti(WorldContextObject, Origin, Origin, TraceDistance,
TraceChannel, bTraceComplex, ActorsToIgnore,
DrawDebugType, OutHits, bIgnoreSelf))
{
return false;
}
// 追加
// ヒットしたActorの解析
for (FHitResult HitResult : OutHits)
{
     AActor* HitActor = HitResult.GetActor();

// アクターが特定できない場合はスキップ
if (!HitActor)
{
continue;
}
}
// ここまで
return true;

 

まず、OutHitsの構造体を使ってC++11から使えるforeachを使います。

このように書くことで配列の要素を抽出して要素の数だけループしてくれます。

for (auto 要素 : 配列)
{
要素を使って計算
}

 

アクタを受け取る定数 AActor* HitActorを用意して、構造体FHitResultからGetActorを呼んでアクタを取得します。FHitResultがBPで見た構造体なのでBP上で見れたピンはすべてC++からでも取れます。※逆にこの構造体をBPは公開している。

 

HitActorが何も取得できていない場合はcontinueで次の要素にスキップします。

// アクターが特定できない場合はスキップ
if (!HitActor)
{
continue;
}

 

② 最短計算をする

SampleBlueprintFunctionLibrary.cppを拡張します。

BPだと値の初期化をC++で書きます。

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

// 追加
// 距離検索用キャッシュfloat  
float DistanceFromNearestActor = TNumericLimits<float>::Max();

// 初期化
NearestActor = nullptr;

// ここまで

if (!UKismetSystemLibrary::
SphereTraceMulti

 

更新処理も書きます。

 

DistanceFromActorToCheckFVector::DistSquared(Origin, HitActor->GetActorLocation())を直接if文の中に書くことができますが見やすさ重視で分けています。

    // アクターが特定できない場合はスキップ
if (!HitActor)
{
continue;
}

// 追加
// 距離を計測して更新
const float DistanceFromActorToCheck = FVector::DistSquared(Origin, HitActor->GetActorLocation());

if (DistanceFromActorToCheck < DistanceFromNearestActor)
{
NearestActor = HitActor;
DistanceFromNearestActor = DistanceFromActorToCheck;
}
// ここまで
}
return true;

 

これで処理は完成です!ビルドしてみましょう。

お疲れ様でした!

 

全文

SampleBlueprintFunctionLibrary.h

// namiton.hatenablog @koituwasugee 

#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"
, meta=(ExpandBoolAsExecs = "ReturnValue"
, AutoCreateRefTerm="ActorsToIgnore"
, WorldContext = "WorldContextObject"))
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

// namiton.hatenablog @koituwasugee 
#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)
{
// ヒットした構造体群を受け取る
TArray<FHitResult> OutHits;

// 距離検索用キャッシュfloat  
float DistanceFromNearestActor = TNumericLimits<float>::Max();

// 初期化
NearestActor = nullptr;


if (!UKismetSystemLibrary::
SphereTraceMulti(WorldContextObject, Origin, Origin, TraceDistance,
TraceChannel, bTraceComplex, ActorsToIgnore,
DrawDebugType, OutHits, bIgnoreSelf))
{
return false;
}
// ヒットしたActorの解析
for (FHitResult HitResult : OutHits)
{
AActor* HitActor = HitResult.GetActor();

// アクターが特定できない場合はスキップ
if (!HitActor)
{
continue;
}

// 距離を計測して更新
const float DistanceFromActorToCheck = FVector::DistSquared(Origin, HitActor->GetActorLocation());

if (DistanceFromActorToCheck < DistanceFromNearestActor)
{
NearestActor = HitActor;
DistanceFromNearestActor = DistanceFromActorToCheck;
}
}
return true;
}

最後に

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

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

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

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

投げ銭を投げる