目次
はじめに
BPがある程度理解できたがC++はちょっと、、という人に向けて書いています。
ゲームでよく使うであろう”周囲のアクタから一番近いものを取得するノード”を作ってみるという内容の第3回です。
前回
投稿者の環境は以下の通りです
・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
更新処理も書きます。
DistanceFromActorToCheckに FVector::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のフォローなどしていただけるとありがたいです。
それではよきゲーム開発を。