Download

How to add component to existing actor in level with Python/Blueprint?

In the level editor in the Details panel there is a button “Add Component”. And you can add any component to an existing actor.

But how can you add a component (StaticMeshComponent) to actor with a Python or Blueprint Script or maybe c++?

Cant find anything in references. It looks like it should be implemented.

Unfortunately a lot of the logic needed to correctly add an instanced component to an actor (both in a level and in a BP) for the editor is currently tied to the UI flow itself.

We have an open issue (UE-64131) to untangle that logic so it can be shared by the UI and scripting, however I can’t say at this point when that will happen.

If you’re curious about investigating more yourself, then SSCSEditor is the class that handles the UI. In this case a subset of the code dealing with the EComponentEditorMode::ActorInstance path of SSCSEditor::AddNewComponent will likely be required.

I’m trying to wrap my head around all of this. So in order to get that functionality we would need to write some c++ code to implement that feature? Currently the SSCSEditor is currently not available to BP or python?

I’m also trying to understand the best way to get this done. Can adding a component to existing actor or creating a fresh actor with components in level be done with c++ if not with python? And would I follow this order to do it :

  1. World->SpawnActor<AActor>(Class, Transform, SpawnParameters)
  2. Actor->PostSpawnInitialize(Transform, Actor, Pawn, bRemoteOwned, bNoFail, bDeferConstruction)
  3. Actor->PostActorCreated() or PostLoad()
  4. ActorComponent->OnComponentCreated()
  5. Actor->PreInitializeComponents()
  6. ActorComponent->InitializeComponent()
  7. Actor->PostInitializeComponents()
  8. **OnActorSpawned() ??? **( Not sure what this is or if it is important )
  9. BeginPlay() ???

If so could I just UFunction these in a custom cpp and h files, compile them to make them accessible in python?

I made this function and it works fine:



//You pass to it class of component, otherwise it creates StaticMeshComponent
UActorComponent* UBlackMesaLifeBlueprintLibrary::AddComponent(AActor* a,USceneComponent *future_parent, FName name, UStaticMesh* mesh, UClass* NewComponentClass)
{

    UActorComponent* retComponent = 0;
    if (!NewComponentClass)
    {
        //DuplicateObject<UStaticMeshComponent>(dup_source,a,name)
        UStaticMeshComponent* NewComponent = NewObject<UStaticMeshComponent>(a, name);// , EObjectFlags::RF_DefaultSubObject);
        //UStaticMeshComponent* NewComponent = DuplicateObject<UStaticMeshComponent>(dup_source, a, name/*ActorCmp, NewActor, NewName*/);
        //a->AddOwnedComponent(NewComponent);
        FTransform CmpTransform;// = dup_source->GetComponentToWorld();
        NewComponent->SetStaticMesh(mesh);
        NewComponent->AttachToComponent(future_parent, FAttachmentTransformRules::KeepWorldTransform);
        NewComponent->SetComponentToWorld(CmpTransform);
        a->AddInstanceComponent(NewComponent);
        NewComponent->OnComponentCreated();
        NewComponent->RegisterComponent();

        a->RerunConstructionScripts();
        retComponent = NewComponent;

    }
    else {
        UActorComponent* NewComponent = NewObject<UActorComponent>(a, NewComponentClass, name);
        FTransform CmpTransform;// = dup_source->GetComponentToWorld();
        //NewComponent->AttachToComponent(sc, FAttachmentTransformRules::KeepWorldTransform);
        // Do Scene Attachment if this new Comnponent is a USceneComponent
        if (USceneComponent* NewSceneComponent = Cast<USceneComponent>(NewComponent))
        {
            if(future_parent !=0)
                NewSceneComponent->AttachToComponent(future_parent, FAttachmentTransformRules::KeepWorldTransform);
            else
                NewSceneComponent->AttachToComponent(a->GetRootComponent(), FAttachmentTransformRules::KeepWorldTransform);

            NewSceneComponent->SetComponentToWorld(CmpTransform);
        }
        a->AddInstanceComponent(NewComponent);
        NewComponent->OnComponentCreated();
        NewComponent->RegisterComponent();

        a->RerunConstructionScripts();
        retComponent = NewComponent;
    }

    return retComponent;
}


What milestones has this code? Is it incorrect? I had no problems so far with it.

Hey YanDaik,

Thanks for sharing that snippet of code.

I have an editor utility widget that gets the current selection and does stuff to it, but it only works in the world outliner, not in a blueprint actor outliner. Is that the same issue as the one above?

Thanks for posting this YanDaik, just what I needed to get started with adding a component to an actor. I changed a few bits to suit my own needs but the overall idea works perfectly. I’m sure you probably know this, but if not, a small tip that maybe useful: instead of using UClass* as a parameter, use TSubclassOf<UActorComponent> . This will enforce that the class chosen will be derived from UActorComponent and will limit the choices available in Blueprint. Thanks again