本帖纯属个人原创,如有转载请注明出处
很多时候需求是这样的,想达到场景中所有的Actor统一旋转的功能。纯代码无观赏性,大家有实际需求的自然能看懂。
接到这样的需求,大家就会想将所有的actor全部都attach到一个父节点上,编辑器中Landscape无法进行Attach, 并且InstancedFoliageActor场景中也没有。那么就需要我们在代码中动态的进行Attach。
下面的支点Actor就是父节点, RootActor。
//将LandscapeActor Attach到支点Actor void LandscapeAttachToPivotActor(); //将InstancedFoliage Attach到支点Actor void InstancedFoliageAttachToPivotActor(); //将LandscapeActor Attach到支点Actor void USPDynamicDataComponent::LandscapeAttachToPivotActor() { //Landscape类型的Actor比较特殊, 需要将这种类型的Actor代码挂接到支点Actor上 //(为什么说比较特殊, 和其他的相比, 这种Actor不能看到子控件, 不能调整移动性, 故不能像其他Actor在编辑器中调整) //地形 TArray<AActor*> LandScapesActors; UGameplayStatics::GetAllActorsOfClass(this, ALandscape::StaticClass(), LandScapesActors); for (auto LandScapeActor : LandScapesActors) { //不处理level streaming的资源 bool bLevelStreamingAssest = false; for (FName tag : LandScapeActor->Tags) { bLevelStreamingAssest = tag.ToString().Contains("LevelStreamingAssest"); BREAK_IF_TRUE(bLevelStreamingAssest); } if (bLevelStreamingAssest) continue; if (LandScapeActor->GetAttachParentActor() != SPPivotMeshActor) { //线设置成Movable才可以attach int32 LandScapeComponentsNum = LandScapeActor->GetComponents().Array().Num(); for (int j = 0; j < LandScapeComponentsNum; j++) { UActorComponent* pAC = LandScapeActor->GetComponents().Array()[j]; USceneComponent* pSC = Cast<USceneComponent>(pAC); if (!pSC) continue; pSC->SetMobility(EComponentMobility::Movable); } LandScapeActor->AttachToActor(SPPivotMeshActor, FAttachmentTransformRules::KeepWorldTransform); } } } //将InstancedFoliage Attach到支点Actor void USPDynamicDataComponent::InstancedFoliageAttachToPivotActor() { //地表 TArray<AActor*> InstancedFoliageActors; UGameplayStatics::GetAllActorsOfClass(this, AInstancedFoliageActor::StaticClass(), InstancedFoliageActors); AActor* pActor = nullptr; TArray<AActor*> LandScapesActors; UGameplayStatics::GetAllActorsOfClass(this, ALandscape::StaticClass(), LandScapesActors); if (LandScapesActors.Num() > 0) { pActor = LandScapesActors[0]; } else { pActor = SPPivotMeshActor; } for (auto InstancedFoliageActor : InstancedFoliageActors) { if (InstancedFoliageActor->GetAttachParentActor() != pActor) { int32 LandScapeComponentsNum = InstancedFoliageActor->GetComponents().Array().Num(); for (int j = 0; j < LandScapeComponentsNum; j++) { UActorComponent* pAC = InstancedFoliageActor->GetComponents().Array()[j]; USceneComponent* pSC = Cast<USceneComponent>(pAC); if (!pSC) continue; pSC->SetMobility(EComponentMobility::Movable); } InstancedFoliageActor->AttachToActor(pActor, FAttachmentTransformRules::KeepWorldTransform); } } }通过上面的方法我们就能将地表和刷的植被附加到RootActor/ParentActor上了。
此时行走在LandScape上会发现地表并没有碰撞,通过如下方式解决即可。
//将LandscapeActor Detach从Actor, 为什么要Detach?这个地形不能从属其他actor, 否则没有碰撞 void LandscapeDetachToPivotActor(); //将LandscapeActor Detach从Actor, 为什么要Detach?这个地形不能从属其他actor, 否则没有碰撞 void USPDynamicDataComponent::LandscapeDetachToPivotActor() { TArray<AActor*> LandScapesActors; UGameplayStatics::GetAllActorsOfClass(this, ALandscape::StaticClass(), LandScapesActors); for (auto LandScapeActor : LandScapesActors) { if (LandScapeActor->GetAttachParentActor() == SPPivotMeshActor) { //相反attach不同的是, 需要先detach再设置静态 FDetachmentTransformRules detachmentRules(EDetachmentRule::KeepWorld, false); LandScapeActor->DetachFromActor(detachmentRules); LandScapeActor->SetActorEnableCollision(true); int32 LandScapeComponentsNum = LandScapeActor->GetComponents().Array().Num(); for (int j = 0; j < LandScapeComponentsNum; j++) { UActorComponent* pAC = LandScapeActor->GetComponents().Array()[j]; USceneComponent* pSC = Cast<USceneComponent>(pAC); if (!pSC) continue; pSC->SetMobility(EComponentMobility::Static); } } } }通过调用上面的方法,即可解决没有碰撞的问题,当我们需要实现旋转逻辑时, 调用Attach。当我们需要行走在地表上时,再调用Detatch逻辑。
下一篇写,如何巧妙的解决旋转整体模型带来的帧率下降。
希望能帮助到大家。谢谢。