User Tag List

Results 1 to 19 of 19

Thread: What is the correct way to create and add components at runtime ?

  1. #1
    0

    What is the correct way to create and add components at runtime ?

    What is the correct way to add components to actors outside constructors ?

    I can't find any function to do so.

  2. #2
    3
    The Rainbow Warrior



    Join Date
    Mar 2014
    Posts
    2,627

    Red face

    Creating and Registering Components During Runtime

    Code:
    //in some AActor class
    
    void AYourActor::CreateComponent(UClass* CompClass,const FVector& Location, const FRotator& Rotation, const FName& AttachSocket=NAME_None)
    {
      FName YourObjectName("Hiiii");
    
      //CompClass can be a BP
      UPrimitiveComponent* NewComp = ConstructObject<UPrimitiveComponent>( CompClass, this, YourObjectName);
      if(!NewComp) 
     {
        return NULL;
     }
     //~~~~~~~~~~~~~
    
      NewComp->RegisterComponent();        //You must ConstructObject with a valid Outer that has world, see above	 
      NewComp->SetWorldLocation(Location); 
      NewComp->SetWorldRotation(Rotation); 
      NewComp->AttachTo(GetRootComponent(),SocketName,EAttachLocation::KeepWorldPosition); 
       //could use different than Root Comp
    }


    The most notable line is this

    Code:
    UPrimitiveComponent* NewComp = ConstructObject<UPrimitiveComponent>( CompClass, this, YourObjectName);
    in this case, "this" is the owning Actor that is creating its own component, and I am passing in "this" to ConstructObject

    NewComp->RegisterComponent() will not work unless "this" is valid and has a valid world associated with itself, as most AActors will

    ~~~

    Attach Location

    Keep in mind you could use SnapToTarget or KeepRelativePosition

    I am choosing here to specify world space starting location and THEN attach.

    You could always use Root Comp or add parameter to specify which component to attach to.

    You'll probably want to use "Mesh" for any Character

    It's up to you!

    Enjoy!

    Rama
    Last edited by Rama; 11-23-2014 at 12:33 AM.
    100+ UE4 C++ Tutorials on the UE4 Code Wiki, including UE4 Multi-Threading!

    UE4 Marketplace: Melee Weapon Plugin & Compressed Binary Save System Plugin | Rama's C++ AI Jumping Videos | Vertex Snap Editor Plugin

    Visit www.ue4code.com to see lots of videos about my C++ Creations! ♥ Rama

  3. #3
    0
    Hi Rama!

    Thanks for your answer.

    Actually I'm already using a very similar code to the one you posted.
    However I noticed that InitializeComponent doesn't gets called when components are created that way (even if bWantsInitializeComponent is set to true), which made me think that maybe there's some other steps missing too and made me unconfident to follow that method.

    That's why I was asking for the "correct way" or some kind of built-in function.

    My fault for not being more explicit in my answer. Sorry.

  4. #4
    0
    Strictly speaking, InitializeComponent is actually concept of actor initialization, not component initialization. It's a sort of contract that lets the component do basic initialization stuff at a time where state is mostly initialized, compared to the constructor where your component won't even know its parent actor. As such, it is called automatically when actors initialize their child components, and this is why it's not getting called automatically in this case.

    Outside of that, feel free to call it manually or, if you still want it automated, look into OnRegister, which will happen in the RegisterComponentWithWorld call that you have to do anyway.

    Furthermore, note that all attaching the component and setting transforms is only necessary if you're dealing with a scene component. If your component doesn't need a spatial representation, save yourself the trouble and overhead and inherit from actor component directly.
    Last edited by cmartel; 11-24-2014 at 07:58 PM.

  5. #5
    0
    Hi cmartel, thank you for your answer. It led me to look into the AActor source code and I think that aside InitializeComponent the only other missing step is calling OnComponentCreated.

    So my code ended looking something like this :

    Code:
    UMyActorComponent* ActorComponent = ConstructObject<UMyActorComponent>(UMyActorComponent::StaticClass(), this);
    ActorComponent->OnComponentCreated();
    ActorComponent->RegisterComponent();
    if (ActorComponent->bWantsInitializeComponent) ActorComponent->InitializeComponent();
    And in case the component inherits from USceneComponent then it should be attached too.


    Edit: Hey, it's me from the future! Now OnComponentCreated() and InitializeComponent() are called from RegisterComponent() so don't call them manually anymore.
    Last edited by TS100101; 01-10-2016 at 04:35 PM.

  6. #6
    0
    You don't need to call OnComponentCreated, though, unless you actually do something inside it yourself. It does nothing beyond setting a flag that allows OnComponentDestroyed to be called. If you're not planning to do anything in either of these functions, save yourself the overhead.

  7. #7
    0
    The Rainbow Warrior



    Join Date
    Mar 2014
    Posts
    2,627
    I have fully tested just this workflow as working

    PrimitiveComponent was my chosen base class, you could use Scene component for components that dont have collision.

    Code:
     UPrimitiveComponent* NewComp = ConstructObject<UPrimitiveComponent>( CompClass, TheOwner, YourObjectName);
    if(NewComp)
    {
      NewComp->RegisterComponent();
      //attach or set location, etc
    }
    100+ UE4 C++ Tutorials on the UE4 Code Wiki, including UE4 Multi-Threading!

    UE4 Marketplace: Melee Weapon Plugin & Compressed Binary Save System Plugin | Rama's C++ AI Jumping Videos | Vertex Snap Editor Plugin

    Visit www.ue4code.com to see lots of videos about my C++ Creations! ♥ Rama

  8. #8
    0
    Quote Originally Posted by Rama View Post
    Creating and Registering Components During Runtime

    Code:
    //in some AActor class
    
    void AYourActor::CreateComponent(UClass* CompClass,const FVector& Location, const FRotator& Rotation, const FName& AttachSocket=NAME_None)
    {
      FName YourObjectName("Hiiii");
    
      //CompClass can be a BP
      UPrimitiveComponent* NewComp = ConstructObject<UPrimitiveComponent>( CompClass, this, YourObjectName);
      if(!NewComp) 
     {
        return NULL;
     }
     //~~~~~~~~~~~~~
    
      NewComp->RegisterComponent();        //You must ConstructObject with a valid Outer that has world, see above	 
      NewComp->SetWorldLocation(Location); 
      NewComp->SetWorldRotation(Rotation); 
      NewComp->AttachTo(GetRootComponent(),SocketName,EAttachLocation::KeepWorldPosition); 
       //could use different than Root Comp
    }


    The most notable line is this

    Code:
    UPrimitiveComponent* NewComp = ConstructObject<UPrimitiveComponent>( CompClass, this, YourObjectName);
    in this case, "this" is the owning Actor that is creating its own component, and I am passing in "this" to ConstructObject

    NewComp->RegisterComponent() will not work unless "this" is valid and has a valid world associated with itself, as most AActors will

    ~~~

    Attach Location

    Keep in mind you could use SnapToTarget or KeepRelativePosition

    I am choosing here to specify world space starting location and THEN attach.

    You could always use Root Comp or add parameter to specify which component to attach to.

    You'll probably want to use "Mesh" for any Character

    It's up to you!

    Enjoy!

    Rama
    Rama, thank you so much for this! This post here is golden.

    It was the straw that broke the camel's back that got my physics system working.

    Thank you a million, again.

  9. #9
    0
    Infiltrator
    Join Date
    Oct 2015
    Posts
    14
    And what is the correct way to remove/destroy components at runtime ?

  10. #10
    0
    The docs tell you to to call UActorComponent::UnregisterComponent(). However UActorComponent::DestroyComponent() seems like the way to go, actually.

    Also, don't forget to null any pointer holding a reference to the component.

  11. #11
    0
    Somehow I think the following lines are more correct for constructing components:

    USphereComponent* SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("RootComponent"));
    RootComponent = SphereComponent;

    or

    UStaticMeshComponent* SphereVisual = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("VisualRepresentation"));
    SphereVisual->AttachTo(RootComponent);


    They're according to this official tutorial.
    https://docs.unrealengine.com/latest/INT/Programming/Tutorials/Components/1/index.html

  12. #12
    0
    Quote Originally Posted by marsonmao View Post
    Somehow I think the following lines are more correct for constructing components:
    That code is only valid within a constructor. The question was specifically asking how to do it dynamically, outside of a constructor.

  13. #13
    0
    Quote Originally Posted by kamrann View Post
    That code is only valid within a constructor. The question was specifically asking how to do it dynamically, outside of a constructor.
    Whoa that's big news!

    So do you know how to add Blueprint component in C++ code?
    I mean designing a Add Component function which could accepts both C++ and BP Component class.
    I'm reading this function AActor::AddComponent(), but this one is BlueprintInternalUseOnly, so I think I shouldn't use it in my C++ code.

  14. #14
    0
    Thanks for your reply earlier on the Q&A post over at Answerhub, kamrann.

    I'm fairly new to the engine (coming from Unity), but I've poked into something related to this as I'm used to manipulating components like this for some objects. For all I know, I might just be doing it wrong.

    As an FYI though, if you use this method on a component that you want a designer to go crazy with, you may want to consider that components created at runtime only seem to expose their properties to the editor via their parent but not if you examine the component itself.
    I'm not sure if this is true in blueprint, but if it crops up, have a read of kamrann's answer in the following:
    https://answers.unrealengine.com/questions/372595/uproperties-and-dynamically-created-components.html

    Perhaps someone else could also chime in on this, just to see if this really isn't an inherent limitation as he mentions.

  15. #15
    0
    @Hatsune-Miku
    I don't see how that issue relates to exposing a component for a designer. Since you're talking about dynamic creation, I'd assumed your AH question was only relevant to modifying component properties during a Simulate In Editor session - something designers won't be doing and is only really useful in some specific testing/debugging scenarios. When a designer is working in the blueprint or level editor, dynamic components don't exist. Am I missing something?

    @marsonmao
    Not sure exactly what you're asking. The C++ equivalent to AddComponent is what is discussed in this thread. It's a bit outdated now though, see Hatsune's answer hub link for an example of the code to do it now.

  16. #16
    0
    Quote Originally Posted by kamrann View Post
    @marsonmao
    Not sure exactly what you're asking. The C++ equivalent to AddComponent is what is discussed in this thread. It's a bit outdated now though, see Hatsune's answer hub link for an example of the code to do it now.
    I've read the link of Hatsune now; To take that link for example, I was asking that how to put Blueprint component class in this line: Audio = NewObject<UAudioComponent>(this);
    So I've checked the source code of NewObject, looks like I could give the UClass parameter, so I might be able to do it like NewObject<SomeBaseClass>(this, The BP Component Class)?

    But there's a concern, that's why I mentioned the function Actor::AddComponent, which is called by Blueprint's Add Component node. Comparing Hatsune's link to Actor::AddComponent, you can see that Actor::AddComponent is a lot more complicated than it, so I'm not sure if Hastune's link is able to completely add a BP Component.

  17. #17
    0
    I have a question, hope someone knows the answer, I create new (NewObject()) UStaticMeshComponents at runtime and place them in an TArray. They are registered and i can succesfully set a mesh and manipulate their placement right after creation. However, if i try to access the same TArray, which was declared in the header file, at another time, the array is empty.. the meshes are still visible in the editor, but for some reason the TArray is empty? any clue??? tahnks a billion!

  18. #18
    0
    Supporter
    Join Date
    Jun 2016
    Posts
    1
    Hey, I am not sure if you guys found it out or not, in the newer versions, when you need to use SetupAttachment(), it has to be called before RegisterComponent(), other wise, the attachment will not work.

  19. #19
    0
    Quote Originally Posted by TommieBommie View Post
    I have a question, hope someone knows the answer, I create new (NewObject()) UStaticMeshComponents at runtime and place them in an TArray. They are registered and i can succesfully set a mesh and manipulate their placement right after creation. However, if i try to access the same TArray, which was declared in the header file, at another time, the array is empty.. the meshes are still visible in the editor, but for some reason the TArray is empty? any clue??? tahnks a billion!
    If you are using array with pointer, please note by adding/removing elements to array, it's content can get invalidated. That holds especially true for pointers.. Eg if you plan to use and add dynamically to it, consider pre-allocate some space in array first. When array is resizing pointers might get lost..

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •