Announcement

Collapse
No announcement yet.

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

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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
    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, 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

    Comment


    • #3
      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.

      Comment


      • #4
        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, 07:58 PM.

        Comment


        • #5
          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, 04:35 PM.

          Comment


          • #6
            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.

            Comment


            • #7
              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

              Comment


              • #8
                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.

                Comment


                • #9
                  And what is the correct way to remove/destroy components at runtime ?

                  Comment


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

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

                    Comment


                    • #11
                      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...s/1/index.html

                      Comment


                      • #12
                        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.

                        Comment


                        • #13
                          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.

                          Comment


                          • #14
                            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/que...omponents.html

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

                            Comment


                            • #15
                              @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.

                              Comment

                              Working...
                              X