几何体扫掠检测
在这篇文章中,我们开始实现扫掠检测。扫掠检测的概念在之前的文章中已经了解过:可以想象成一个几何体(比如球体)从一个起点沿着某个路径“拖动”或“扫过”,并检测它在这个过程中是否与其他物体发生碰撞。
此处,我们使用 Unreal Engine 中的 SweepSingleByChannel() 函数,它用于单次几何体碰撞检测。
Single 单次的意思是,只关心第一次碰撞的物体。
与之对应的有 SweepMultiByChannel,它会检查路径上所有可能的碰撞。
SweepSingleByChannel 的函数定义如下:
- bool UWorld::SweepSingleByChannel(struct FHitResult& OutHit,
- const FVector& Start,
- const FVector& End,
- const FQuat& Rot,
- ECollisionChannel TraceChannel,
- const FCollisionShape& CollisionShape,
- const FCollisionQueryParams& Params /* = FCollisionQueryParams::DefaultQueryParam */,
- const FCollisionResponseParams& ResponseParam /* = FCollisionResponseParams::DefaultResponseParam */) const;
OutHit 是一个输出参数,用于存储碰撞检测的结果。
Start 指定要扫掠的起始位置;End 指定要扫掠的目标位置。
Rot 指定扫掠物体的旋转信息。
TraceChannel 指定碰撞通道。
CollisionShape 指定进行扫掠检测的几何体形状。
Params 指定查询参数,用于定制碰撞检测的行为。有默认值。
ResponseParam 指定碰撞响应的行为。有默认值。
返回值是布尔值,表示是否发生了碰撞。
在了解了 SweepSingleByChannel 各个参数的含义之后,我们实现以下功能:使用球体沿着相机视线的方向扫掠,打印出碰撞的物体信息。
如代码清单 1 所示,我们使用 FCollisionShape::MakeSphere 创建一个球体。球体不需要旋转,旋转信息使用 FQuat::Identity,当然球体即使旋转了也没有区别。扫掠的起始点和终点,在上一篇文章中已经可视化看过。
- // Called every frame
- void UGrabber::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
- {
- Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
- FVector Start = GetComponentLocation();
- FVector End = Start + GetForwardVector() * MaxGrabDistance;
- DrawDebugLine(GetWorld(), Start, End, FColor::Red);
- FCollisionShape Sphere = FCollisionShape::MakeSphere(GrabRadius);
- FHitResult HitResult;
- bool HasHit = GetWorld()->SweepSingleByChannel(HitResult,
- Start, End,
- FQuat::Identity,
- ECC_GameTraceChannel2,
- Sphere);
- if (HasHit)
- {
- AActor* HitActor = HitResult.GetActor();
- UE_LOG(LogTemp, Display, TEXT("Hit actor: %s"), *HitActor->GetActorNameOrLabel());
- }
- else
- {
- UE_LOG(LogTemp, Display, TEXT("No actor hit"));
- }
- }
SweepSingleByChannel 函数中的通道指定需要注意。函数中通道是一个枚举值,我们想要将通道指定为之前自己创建的 Grabber 通道,该如何指定呢?
我们可以打开项目根目录下的 Config\DefaultEngine.ini 文件,搜索 Grabber。可以看到如下项,填写其中的 Channel 值即可。
- +DefaultChannelResponses=(Channel=ECC_GameTraceChannel2,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="Grabber")
运行程序。当我们视角对着雕塑的时候,如图 1 所示,可以看到日志里打印了雕塑物体的名称。
