UE4随笔 Landscape动态Attach之后没有碰撞怎么解决?

32 篇文章 43 订阅
4 篇文章 0 订阅

本帖纯属个人原创,如有转载请注明出处

很多时候需求是这样的,想达到场景中所有的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逻辑。

下一篇写,如何巧妙的解决旋转整体模型带来的帧率下降。

希望能帮助到大家。谢谢。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WhiteTian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值