碰撞检测备忘录

重点

碰撞结果的计算都可以根据该表进行.

前提

为什么我使用的LineTraceMulti只返回一个对象?

答案: UKismetSystemLibrary.LineTraceMulti函数会返回所有它Overlap的对象, 并且在检测到第一个Block对象的时候停止.

1
Multiline trace will return all objects that overlap, and will stop the trace when it sees at least one blocking hit. In your case you’ll probably want to use a channel other than visibility so that you can have objects that allow for bullet penetration to be marked as overlap instead of blocking.

使用解析

思考一下下图, 后面都会围绕该如讲解.

可以将UE的碰撞检测类型分成三种:

  1. 基于TraceType的射线检测(注意, 该类型是)

  2. 基于ObjectType的射线检测

  1. 基于Profile的射线检测

image-20240508202044423

基于TraceType的射线检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
bool UKismetSystemLibrary::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 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;
}

LineTraceSingle为例, 其中使用了Trace的类型为ETraceTypeQuery, 然后UE会将其转换成ECollisionChannel, 最终调用UWorld.LineTraceSingleByChannel. 而ECollisionChannel具体类型为:

而ObjectType和TraceType的区分方式为:

所以, 在配置中定义的无论TraceChannels还是ObjectChannels, 其实都是ECollisionChannel.

重点: 可以将LineTrace理解为, 1对所有类型都Block, 那么Ignore/Overlap/Block与否, 取决于Component本身的Collision配置. 下图中Cube1配置的是Overlap, 则他们二者最终的结果就是Overlap.

即:

基于ObjectType的射线检测

基于TraceType的射线检测, 这里就不赘述了.

基于Profile的射线检测

通过传入的Profile, 对场景中的物体进行碰撞检测.

例如在Profile(TestTraceMulti)中, 自身类型为1, 对WorldStatic的检测类型为Overlap. 而场景中物体对1的碰撞类型为Block, 则最终结果为Overlap

二者交互类型为Overlap.

总结

使用Profile相当于双向指定, 所以推荐新增类型都为ObjectType(LineTrace不能双向指定, 因为Profile类型只能指定为ObjectType). 双向指定可以得到更多可定制的情形, 可以更好的使用变化的场景.

EObjectTypeQuery转换成ECollisionChannel.

1
ECollisionChannel UEngineTypes::ConvertToCollisionChannel(EObjectTypeQuery ObjectType)

ETraceTypeQuery转换成ECollisionChannel.

1
ECollisionChannel UEngineTypes::ConvertToCollisionChannel(ETraceTypeQuery TraceType)

ECollisionChannel转换成EObjectTypeQuery.

1
EObjectTypeQuery UEngineTypes::ConvertToObjectType(ECollisionChannel CollisionChannel)

ECollisionChannel转换成ETraceTypeQuery.

1
ETraceTypeQuery UEngineTypes::ConvertToTraceType(ECollisionChannel CollisionChannel)

引用

  1. Unreal4碰撞检测-中文版

  2. Unreal4碰撞检测-英文版

  3. LineTraceMulti为何只返回一个对象