【问题标题】:Unreal Engine: How can I create UStaticMeshComponent in a loop?虚幻引擎:如何循环创建 UStaticMeshComponent?
【发布时间】:2019-03-13 17:50:00
【问题描述】:

我正在尝试使用 for 循环创建多个 UStaticMeshComponent,但虚幻引擎不断在 Object.h 中的 CreateDefaultSubobject 上触发断点(不在我的代码中,它来自 UE4 核心 API)。当我创建单个组件时,它工作正常。我对 UnrealEngine 和 C++ 很陌生,所以我可能会做一些愚蠢的事情,但请放轻松:)

非常感谢您的帮助。

标题

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "FlowSphere.generated.h"

UCLASS()
class CPP_PRACTICE_3_API AFlowSphere : public AActor
{
    GENERATED_BODY()

public: 
    // Sets default values for this actor's properties
    AFlowSphere();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public: 
    // Called every frame
    virtual void Tick(float DeltaTime) override;

private:
    //UPROPERTY()
    //TArray<UStaticMeshComponent*> StaticMeshComponents;

    UStaticMeshComponent* test;

};

C++

#include "FlowSphere.h"

// Sets default values
AFlowSphere::AFlowSphere()
{
    int32 amount = 100;

    RootComponent = CreateDefaultSubobject<USceneComponent>("SceneComponent");

    for (int32 i = 0; i < amount; i++) {

        //WHEN I INCLUDE THE LINE BELOW, UE4 START MAKING BREAKPOINT
        UStaticMeshComponent* item = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Sphere"));
        item.AttachTo(this->RootComponent);

    }

    //THIS WORKS FINE
    this->test = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("HELLO")); 
    PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AFlowSphere::BeginPlay()
{
    Super::BeginPlay();

}

// Called every frame
void AFlowSphere::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

}

它在 UE4 API 的 Object.h 上触发断点

    /**
    * Create a component or subobject
    * @param    TReturnType                 class of return type, all overrides must be of this type
    * @param    SubobjectName               name of the new component
    * @param    bTransient                  true if the component is being assigned to a transient property. This does not make the component itself transient, but does stop it from inheriting parent defaults
    */
    template<class TReturnType>
    TReturnType* CreateDefaultSubobject(FName SubobjectName, bool bTransient = false)
    {
        UClass* ReturnType = TReturnType::StaticClass();
        return static_cast<TReturnType*>(CreateDefaultSubobject(SubobjectName, ReturnType, ReturnType, /*bIsRequired =*/ true, /*bIsAbstract =*/ false, bTransient));
    }

【问题讨论】:

    标签: c++ unreal-engine4


    【解决方案1】:

    所以我最近不得不做同样的事情并遇到了很多问题,但要解决的两个主要问题是:

    1. 使用 UInstancedStaticMesh 代替 UStaticMesh。
    2. 为您的静态网格添加一个属性。

    下面是正确的代码。

    #include "FlowSphere.h"
    #include "Components/StaticMeshComponent.h"
    #include "UObject/ConstructorHelpers.h"
    
    // Sets default values
    AFlowSphere::AFlowSphere()
    {
        int32 amount = 100;
    
        RootComponent = CreateDefaultSubobject<USceneComponent>("SceneComponent");
    
        for (int32 i = 0; i < amount; i++) {
    
            FName name = *FString::Printf(TEXT("Sphere %i"), i);
            FName c_name = *FString::Printf(TEXT("ChildSceneComponent %i"), i);
    
            UPROPERTY(EditAnywhere)
                USceneComponent* ChildSceneComponent
                = CreateDefaultSubobject<USceneComponent>(c_name);
    
            // instead of the regular static mesh, create and instance static mesh object with name assigned
            UInstancedStaticMeshComponent* item = CreateDefaultSubobject<UStaticMeshComponent>(name);
            item->RegisterComponent();
    
            // assign property to mesh if not you'll get a static mesh null property error like i did 
            auto MeshAsset = ConstructorHelpers::FObjectFinder<UStaticMesh>(TEXT("StaticMesh'/Engine/BasicShapes/Sphere.Sphere'"));
    
            if (MeshAsset.Object != nullptr)
            {
                item->SetStaticMesh(MeshAsset.Object);
            }
            item->SetFlags(RF_Transactional);
    
            // add instance to actor level
            this->AddInstanceComponent(item);
    
            // make the scene component for the mesh to be visible
            RootComponent = Root;
    
            // attach mesh to the scene component of the actor in form of a Hierarchy
    
            item->AttachToComponent(ChildSceneComponent, FAttachmentTransformRules::KeepWorldTransform, m_name);
            ChildSceneComponent->AttachToComponent(Root, FAttachmentTransformRules::KeepWorldTransform, c_name);
    
            // set mesh transform based on the ith position
            FTransform t(FVector(250 * i, i, i));
    
            // activate the new copy of the mesh
            Mesh->AddInstance(t);
    
            // Offset and scale the child scene from the root scene as a precaution
            ChildSceneComponent->SetRelativeTransform(
                FTransform(FRotator(0, 0, 0),
                    FVector(250 * i, i, i),
                    FVector(0.1f))
            );
    
    
        }
    
    
        PrimaryActorTick.bCanEverTick = true;
    
    }
    
    
    
        
    

    【讨论】:

      【解决方案2】:

      您在两次不同的 CreateDefaultSubobject 调用中使用了相同的名称。

      我在一个新的 UE4 C++ 项目中运行您的代码并收到以下错误消息:

      致命错误: [文件:D:\Build++UE4\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\UObjectGlobals.cpp] [Line: 3755] 默认子对象 StaticMeshComponent Sphere 已经 FlowSphere /Script/MyProject.Default__FlowSphere 存在。

      另外,您发布的代码没有编译。

      item.AttachTo(this->RootComponent);
      

      应该是:

      item->AttachTo(this->RootComponent);
      

      您还需要包含“Components/StaticMeshComponent.h”。这是更正后的代码:

      #include "FlowSphere.h"
      #include "Components/StaticMeshComponent.h"
      
      // Sets default values
      AFlowSphere::AFlowSphere()
      {
          int32 amount = 100;
      
          RootComponent = CreateDefaultSubobject<USceneComponent>("SceneComponent");
      
          for (int32 i = 0; i < amount; i++) {
      
              FName name = *FString::Printf(TEXT("Sphere %i"), i);
              UStaticMeshComponent* item = CreateDefaultSubobject<UStaticMeshComponent>(name);
              item->AttachTo(this->RootComponent);
      
          }
      
          this->test = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("HELLO"));
          PrimaryActorTick.bCanEverTick = true;
      
      }
      

      【讨论】:

        猜你喜欢
        • 2022-06-13
        • 1970-01-01
        • 1970-01-01
        • 2021-03-23
        • 2016-03-07
        • 1970-01-01
        • 2014-04-26
        • 2018-06-24
        • 1970-01-01
        相关资源
        最近更新 更多