UE4.25 中有各种Trace,最常用的就是 LIneTrace,即发射线看打到谁。

一、World.h 中的 Trace

  在引擎 World.h 中,

  • Trace 类型有两种:LineTrace、SweepTrace(射线方式、扫掠方式);
  • Trace 数量有两种: TraceSingle、TraceMulti(也就是射到一个就停止,还是可以射穿多个);
  • Trace 方式有三种:ByChannelByObjectTypeByProfile通过不同方式选择哪些东西可以Trace)。

  下边这个函数就是 “射线方式、射一个停止、通过 Channel查找射到谁” 的一个 LineTrace 方法。

/**
	 *  Trace a ray against the world using a specific channel and return the first blocking hit
	 *  @param  OutHit          First blocking hit found
	 *  @param  Start           Start location of the ray
	 *  @param  End             End location of the ray
	 *  @param  TraceChannel    The 'channel' that this ray is in, used to determine which components to hit
	 *  @param  Params          Additional parameters used for the trace
	 * 	@param 	ResponseParam	ResponseContainer to be used for this trace	 
	 *  @return TRUE if a blocking hit is found
	 */
	bool LineTraceSingleByChannel(struct FHitResult& OutHit,const FVector& Start,const FVector& End,ECollisionChannel TraceChannel,const FCollisionQueryParams& Params = FCollisionQueryParams::DefaultQueryParam, const FCollisionResponseParams& ResponseParam = FCollisionResponseParams::DefaultResponseParam) const;

  重点分析上边第三条:Trace 的方式。

1. ByChannel

  这个名称比较迷惑,通过 Channel 来控制那些东西可以 Trace,比如想只 Trace WorldStatic 的 Object,但其实 TraceChannel 参数不是 “只与 WorldStatic 交互” 的意思,而是 The 'channel' that this ray is in(源码注释),也就是这根射线的 Collision Type 是 WorldStatic,所有与 WorldStatic 类型有Block的,都会挡住射线,就会出现想发出一根只与 WorldStatic Object 交互的射线,但是却被怪物挡住的情况!
  上边这种需求应该用下边这种 ByObjectType 的 LineTrace 方法。

2. ByObjectType

  如果想发出射线,与碰到场景(一般地面、不动的物体等场景物体都是 WorldStatic)就停止,可以用

FHitResult HitResult;
GetWorld()->LineTraceSingleByObjectType(HitResult, Location, FVector(Location.X, Location.Y, 0), ECC_WorldStatic);

  这样的射线,只在碰到 WorldStatic Object 时停止,会穿过怪物、人物等 Dynamic物体。上边这个函数就可以从 Location 位置向世界坐标系的 Z 轴负方向(一般就是朝下)发射线,遇到地面等静态物体停止,再通过 Location.Z - HitResult.Location.Z 就可以算出 Location 位置距离地面的高度了。

3. ByProfile

  看参数和注释应该是通过 FName ProfileName 确定射线会射到的物体,还没用过,用到再说~

二、UKismetSystemLibrary 中的 Trace

  UKismetSystemLibrary 中的 Trace 有 LineTrace、BoxTrace、SphereTrace、CapsuleTrace 四种类型,每种又分为 xxxTraceSingle、xxxTraceMulti 两种(同上)。
  举例说明:

bool UKismetSystemLibrary::LineTraceSingle(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 TraceHitColor, float DrawTime)
{
	ECollisionChannel CollisionChannel = UEngineTypes::ConvertToCollisionChannel(TraceChannel);

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

	UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
	bool const bHit = World ? World->LineTraceSingleByChannel(OutHit, Start, End, CollisionChannel, Params) : false;

#if ENABLE_DRAW_DEBUG
	DrawDebugLineTraceSingle(World, Start, End, DrawDebugType, bHit, OutHit, TraceColor, TraceHitColor, DrawTime);
#endif

	return bHit;
}

  可以看到,其实最后还是调的 World->LineTraceSingleByChannel,UKismetSystemLibrary 里的 Trace 都是调用的 World 里的 Trace。从代码上看,调用对应关系如下(Single 和 Multi 对应关系显然):

UKismetSystemLibrary World
LineTraceSingle / LineTraceMulti LineTraceSingleByChannel / LineTraceMultiByChannel
BoxTraceSingle SweepSingleByChannel
SphereTraceSingle SweepSingleByChannel
CapsuleTraceSingle SweepSingleByChannel

  也就是 UKismetSystemLibrary 里默认是 ByChannel,也有对应其他方式的,比如 UKismetSystemLibrary::LineTraceSingleForObjects 对应 World->LineTraceSingleByObjectType,其他同理。
  即 Line 对应 Line,其他对应 Sweep。
  UKismetSystemLibrary 的好处就是可以直接画出 Trace的起点、终点以及 Trace 的线:

  e.g.

if (UKismetSystemLibrary::LineTraceSingleForObjects(
	GetWorld(),
	Location,								/** Start			*/
	FVector(Location.X, Location.Y, 0),		/** End				*/
	TArray<TEnumAsByte<EObjectTypeQuery>>{ UEngineTypes::ConvertToObjectType(ECC_WorldStatic) },
	false,									/** bTraceComplex	*/
	{},										/** ActorsToIgnore	*/
	EDrawDebugTrace::Persistent,			/** DrawDebugType	*/
	OUT HitResult,							/** OutHit			*/
	true))									/** bIgnoreSelf		*/
{
	if (HitResult.bBlockingHit)
	{
		TargetLocation = HitResult.Location;
	}
}
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐