使用代码添加/删除标签
在上一篇文章中,当雕塑 Actor 进入 Box 组件范围,然后触发重叠事件之后,会被 AttachToComponent() 立刻夺走控制权,然后触发门下降。即使物体还是抓取着、没有释放的状态。
在这篇文章中,我们完善一下逻辑,只有当物体释放了,才会触发门下降。
这就需要我们能获取物体的抓取状态,判断物体是否被抓取。我们可以通过标签机制来实现。标签的基本概念,在之前的文章 《标签》 中,已经讲解过了。之前是在编辑器中手动设置标签,现在我们可以通过代码动态添加和删除标签。
Actor 下的标签存在 TArray 结构体中。如代码清单 1 所示,我们可以调用成员函数 Add() 和 Remove() 对标签进行添加和删除。在抓取时,我们添加“Grabbed”标签;在释放时,我们删除“Grabbed”标签。
- void UGrabber::Grab()
- {
- if (PhysicsHandle != NULL)
- {
- FHitResult HitResult;
- bool HasHit = GetGrabbableInReach(HitResult);
- if (HasHit)
- {
- UPrimitiveComponent* HitComponent = HitResult.GetComponent();
- HitComponent->WakeAllRigidBodies();
- HitResult.GetActor()->Tags.Add("Grabbed");
- PhysicsHandle->GrabComponentAtLocationWithRotation(
- HitComponent,
- NAME_None,
- HitResult.ImpactPoint,
- GetComponentRotation()
- );
- }
- }
- }
- void UGrabber::Release()
- {
- UE_LOG(LogTemp, Display, TEXT("Released grabber"));
- if (PhysicsHandle != NULL)
- {
- UPrimitiveComponent* GrabbedComponent = PhysicsHandle->GetGrabbedComponent();
- if (GrabbedComponent != NULL)
- {
- AActor* GrabbedActor = GrabbedComponent->GetOwner();
- GrabbedActor->Tags.Remove("Grabbed");
- GrabbedComponent->WakeAllRigidBodies();
- PhysicsHandle->ReleaseComponent();
- }
- }
- }
运行程序。我们抓取物体,然后按 F8 键弹出。如图 1 所示,雕塑的标签里的确添加了“Grabbed”标签。释放后,再弹出,能确认删除了“Grabbed”标签。

标签的逻辑实现和验证好之后,我们继续完善门的触发逻辑。之前的逻辑是,只要有指定的物体标签发生重叠,就返回对应的 Actor 指针,进而触发门的移动。现在,如代码清单 2 所示,我们不仅需要物体有指定的物体标签,而且还不能有“Grabbed”标签(即物体没有被抓取)。这样,我们才返回非空的 Actor 指针,才触发门的移动。
- AActor* UTriggerComponent::GetAcceptableActor() const
- {
- TArray<AActor*> Actors;
- GetOverlappingActors(Actors);
- for (int32 i = 0; i < Actors.Num(); i++)
- {
- bool HasAcceptableTag = Actors[i]->ActorHasTag(AcceptableActorTag);
- bool IsGrabbed = Actors[i]->ActorHasTag("Grabbed");
- if (HasAcceptableTag && !IsGrabbed)
- {
- return Actors[i];
- }
- }
- return NULL;
- }
最后的效果如下方视频所示,抓着雕塑进入门的重叠区域后,门不会下降。只有释放了物体之后,门才会下降。