使用代码添加/删除标签

在上一篇文章中,当雕塑 Actor 进入 Box 组件范围,然后触发重叠事件之后,会被 AttachToComponent() 立刻夺走控制权,然后触发门下降。即使物体还是抓取着、没有释放的状态。

在这篇文章中,我们完善一下逻辑,只有当物体释放了,才会触发门下降。

这就需要我们能获取物体的抓取状态,判断物体是否被抓取。我们可以通过标签机制来实现。标签的基本概念,在之前的文章 《标签》 中,已经讲解过了。之前是在编辑器中手动设置标签,现在我们可以通过代码动态添加和删除标签。

Actor 下的标签存在 TArray 结构体中。如代码清单 1 所示,我们可以调用成员函数 Add()Remove() 对标签进行添加和删除。在抓取时,我们添加“Grabbed”标签;在释放时,我们删除“Grabbed”标签。

代码清单 1 添加/删除标签
  1. void UGrabber::Grab()
  2. {
  3.     if (PhysicsHandle != NULL)
  4.     {
  5.         FHitResult HitResult;
  6.         bool HasHit = GetGrabbableInReach(HitResult);
  7.  
  8.         if (HasHit)
  9.         {
  10.             UPrimitiveComponent* HitComponent = HitResult.GetComponent();
  11.             HitComponent->WakeAllRigidBodies();
  12.  
  13.             HitResult.GetActor()->Tags.Add("Grabbed");
  14.  
  15.             PhysicsHandle->GrabComponentAtLocationWithRotation(
  16.                 HitComponent,
  17.                 NAME_None,
  18.                 HitResult.ImpactPoint,
  19.                 GetComponentRotation()
  20.             );
  21.         }
  22.     }
  23. }
  24.  
  25. void UGrabber::Release()
  26. {
  27.     UE_LOG(LogTemp, Display, TEXT("Released grabber"));
  28.     if (PhysicsHandle != NULL)
  29.     {
  30.         UPrimitiveComponent* GrabbedComponent = PhysicsHandle->GetGrabbedComponent();
  31.         if (GrabbedComponent != NULL)
  32.         {
  33.             AActor* GrabbedActor = GrabbedComponent->GetOwner();
  34.             GrabbedActor->Tags.Remove("Grabbed");
  35.             GrabbedComponent->WakeAllRigidBodies();
  36.             PhysicsHandle->ReleaseComponent();
  37.         }
  38.     }
  39. }

运行程序。我们抓取物体,然后按 F8 键弹出。如图 1 所示,雕塑的标签里的确添加了“Grabbed”标签。释放后,再弹出,能确认删除了“Grabbed”标签。

图1 标签

标签的逻辑实现和验证好之后,我们继续完善门的触发逻辑。之前的逻辑是,只要有指定的物体标签发生重叠,就返回对应的 Actor 指针,进而触发门的移动。现在,如代码清单 2 所示,我们不仅需要物体有指定的物体标签,而且还不能有“Grabbed”标签(即物体没有被抓取)。这样,我们才返回非空的 Actor 指针,才触发门的移动。

代码清单 2 判断
  1. AActor* UTriggerComponent::GetAcceptableActor() const
  2. {
  3.     TArray<AActor*> Actors;
  4.     GetOverlappingActors(Actors);
  5.  
  6.     for (int32 i = 0; i < Actors.Num(); i++)
  7.     {
  8.         bool HasAcceptableTag = Actors[i]->ActorHasTag(AcceptableActorTag);
  9.         bool IsGrabbed = Actors[i]->ActorHasTag("Grabbed");
  10.         if (HasAcceptableTag && !IsGrabbed)
  11.         {
  12.             return Actors[i];
  13.         }
  14.     }
  15.  
  16.     return NULL;
  17. }

最后的效果如下方视频所示,抓着雕塑进入门的重叠区域后,门不会下降。只有释放了物体之后,门才会下降。