挨拶
皆さんお体元気でしょうか。自分は12月の寒波で足先がホントに冷たくて、足先の感覚が一日の半分くらいは無くなってる気がします。
まあそんなことはおいといて、さっそく行きましょう。
状況
作成しているゲームの移動処理を書く際に、ブループリントで先に処理を作ってC++のコードに落とし込んでいました。
その時に陥ったLineTraceの種類間違いについてです。
環境はue4.27、VS2022、Windows10です。
1:最初はSingleLineTraceを使っていた。がしかし...
ブループリントでLineTraceByChannelを使っている場所があったので、とりあえず検索で 「ue4 LineTraceByChannel C++」 と検索しました。
検索の結果、同じ名前のC++関数はありませんでした。
なのでとりあえず名前が似ていて、検索上位に来たSingle Line Trace関数を最初は使用していました。
しかし、コードを書いていくうちに、
「なんか挙動がブループリントの時と一致しないな... しかもこれ、引数の数も場所も違いすぎね?」となりました。
2:ブループリントで確認すると?
あまりに違うためブループリントの方にカーソルを合わせて場所を確認したところ...
なんと全然違うクラスが表示されてる..!(カーソル合わせて出てくるの、教えてもらって初めて知りました)
なにはともあれ、Kismet System Libraryというところにあるのがわかったので、コード内部で検索を掛けて探しに行きました。
すると...
同じような処理を発見!
/**
* Does a collision trace along the given line and returns the first blocking hit encountered.
* This trace finds the objects that RESPONDS to the given TraceChannel
*
* @param WorldContext World context
* @param Start Start of line segment.
* @param End End of line segment.
* @param TraceChannel
* @param bTraceComplex True to test against complex collision, false to test against simplified collision.
* @param OutHit Properties of the trace hit.
* @return True if there was a hit, false otherwise.
*/
UFUNCTION(BlueprintCallable, Category="Collision", meta=(bIgnoreSelf="true", WorldContext="WorldContextObject", AutoCreateRefTerm="ActorsToIgnore", DisplayName="LineTraceByChannel", AdvancedDisplay="TraceColor,TraceHitColor,DrawTime", Keywords="raycast"))
static bool LineTraceSingle(const UObject* WorldContextObject, const FVector Start, const FVector End, ETraceTypeQuery TraceChannel, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, EDrawDebugTrace::Type DrawDebugType, FHitResult& OutHit, bool bIgnoreSelf, FLinearColor TraceColor = FLinearColor::Red, FLinearColor TraceHitColor = FLinearColor::Green, float DrawTime = 5.0f);
引数の数を見る感じ
#include "Kismet/KismetSystemLibrary.h"をincludeし、UKismetSystemLibrary::LineTraceSingleを使えば同じ処理が書けそうだと思いました。
3:コードを書いて挙動確認
使用してみたところ、レイを飛ばして当たっている場所がどうやらおかしく、ブループリントと挙動が違います!
具体的には、何にも当たっていないのにtrueになってしまう状態でした。
なぜだろうと2時間ぐらい調べたところ...
TArray<AActor*>{ },
ここの部分で自身のコリジョンに当たっているため、常にhitしてtrueが返ってくることが判明しました。
そこで、直す方法として
TArray<AActor*>{ this },
と書けば自身を無視してレイを飛ばしてくれるので、自分の中央からレイを飛ばしても自身に当たらずブループリントと同じ挙動になりちゃんと動きました!
良かった!
UKismetSystemLibrary::LineTraceSingle関数の例
一応使用した際のコードとパラメータの意味についてです。
ブループリントのLineTraceByChannelと大体の引数は一致しているので、間違えてはないはずですが、間違ってたらすいません。
ちなみにちゃんと.cppで#include "Kismet/KismetSystemLibrary.h"しないと動かないので注意!
//bHitTrace1はhitしていたらtrueを返す。
//bhitTrace1は、ヘッダーでbool bhitTrace1と宣言。
//hitF1はローカルでHitResult hitF1と宣言。
bHitTrace1 = UKismetSystemLibrary::LineTraceSingle(
GetWorld(), // ワールドへのポインタ
GetActorLocation(), // トレースの始点(アクターの現在の位置から)
GetActorLocation() + (GetNormalizeVector1() * 200.0f), // トレースの終点
UEngineTypes::ConvertToTraceType(ECC_Visibility), // トレースの対象となるコリジョン チャネル
false, // 詳細なコリジョン情報を得るかどうか (falseなら得ない)
TArray<AActor*>{ this }, // 自身を無視するために自身を配列に追加
EDrawDebugTrace::ForDuration, // デバッグ表示の設定
hitF1, // トレースの結果を格納するHitResult構造体
true, // ヒット情報を保持するかどうか (trueなら保持する)
FColor::Green, // 当たってない時の色
FColor::Red, // 当たっている時の色
-1.0f // レイの描画時間
);
これを参考にしてもらえればブループリントのLineTraceByChannelと同じような処理ができると思います。
感想
ブループリントにカーソルを合わせている時にクラス名が表示されるのを最初は知らず、他のことで質問をした際に教えてもらいました。
(おま環でブループリントをダブルクリックしてもC++コードに飛べないってことも、この時に知りました)
そもそもなんで同じ関数が用意されてないんでしょう。謎ですね..
以上です。私がQiitaを書くのはこれで2記事目です。
見出しとか初めて使ったので、見づらかったら次回から改善していきます。
日々精進、日々成長。
最後に
最後に一応公式のドキュメント貼っておきます。
自分の検索エンジンだと検索上位に来なかったので、同じ被害者の方を増やさないために貼っておきます
UKismetSystemLibrary::LineTraceSingleについて↓
https://docs.unrealengine.com/4.27/en-US/API/Runtime/Engine/Kismet/UKismetSystemLibrary/LineTraceSingle/
UKismetSystemLibraryについて↓
https://docs.unrealengine.com/4.27/en-US/API/Runtime/Engine/Kismet/UKismetSystemLibrary/