Download

Actors vs. components

I have struggling a while now to get grip on the concept of actors and components, how they differ and how the are connected. Unfortunately I haven’t found any good place where this whole concept is described.
This is what i have found so far:
On the unreal achitecture page in the manual, the relation between actors and components are described: “Take a car as an example. The car as a whole is an Actor, whereas the parts of the car, like the wheels and doors, would all be Components of that Actor.”
Ok, this sounds reasonable, but then the components have the the undocumented function: SetChildActorClass. This indicates that Components can have Actors as children, although the above mental model was indicating the opposite.
Further confusing is that classes seams to exist in both an actor and a component variant like, UStaticMesh and UStaticMeshComponent.

The documentation I found about components didn’t tell much about the component class or how to create a component. (It mainly tells that the components has to be registered, without telling where or when this has to be done.)

What I am trying to do is this:
Implement a city-object that can be dragged into a level. This city-object shall create a city by creating a bunch of block-objects at suitable positions. The block-object should then be responsible for drawing the actual building(s) on that block.
(During the initial experiments I am satisfied if the block-object just can draw a cube with the size of the block, simulating a house.)
So far i have tried to make both the the city-object and the block-object as actors. But when I look at the code required, this doesn’t feel like the right way.
And spawning actors is not an option in this case, since spawning does not occur until the game starts. I would like see the result from the city-object directly in the level editor so that I add further actors at suitable places.

Would it be better to make the block-object as a component instead of an actor?
If so, will it be possible for the block-object to have child objects like house-objects, and should this house-objects then be components or actors?

I could use a little help here or some good resources where actors and components are explained a bit more in detail?
Are there any examples including creation of a user-defined component?

Any help that can cast some light on the issue would be very much appreciated…

It may help to know that everything that moves in the world, moves via components. When actors are moved via SetActorLocation, AddActorWorldOffset, etc what is actually moved is their root component. Since components can be attached to each other, actors can be attached to components too which refers to attaching an actor’s root component to another component (owned by another actor).

The function SetChildActorClass is function for a specific type of component: a ChildActorComponent. What this component does is it spawns an actor of that class at game start and attaches it to itself. So actors can be attached to components but this is not the general use. The ChildActorComponent, when created in the blueprint editor and after setting the ChildActorClass, displays a preview of that actor. So that may help you in case you want to edit blueprints in which you have actors as children. I’m not sure how this works with multiple levels though (having a child actor that has child actors).

For your procedural generation task, I would use components for your blocks, but it also depends on the complexity of the behavior of the blocks. If you want your blocks to be heavily customizable in blueprint, then making them an actor might be a better option. But for now I’m just assuming you have blocks that just need to be rendered and have collision. In that case, use static meshes components or instanced static meshes components. Instanced static mesh components allow you to choose a mesh (a block in your case), a material and then very efficiently place multiple copies of those in your world. Instanced static mesh components are the way to go if your blocks have the same shape and material (or a small number of options). You can call AddInstance to specify a position where another one of the meshes should be shown.

For previewing generated stuff inside the editor, override the OnConstruction function (but don’t forget to call Super::OnConstruction):



	virtual void OnConstruction(const FTransform & Transform) override;


OnConstruction runs in the editor when your actor is placed, dragged, or detects a change in setting. If you place level generation logic in there (for example adding instances to your instanced static mesh component) they will show in your editor viewport.

Thanks for your time and answer!

The plan is that the blocks and buildings should be procedurally generated too, so they will probably be better as actors then, even if they for the moment will be simple static meshes or the instanced variant (even if i have run into performance issues with instanced meshes before).

The OnConstruction override seams to be the way to go, thanks again!

This was not so easy as i thought, or maybe I am doing something wrong here?
How do I pass arguments to the building-object (or block as it was called in the previous text) ?

In the constructor of the City-object I have this code:


Building = CreateDefaultSubobject<UChildActorComponent>(TEXT("MyBuilding"));
Building->SetChildActorClass(ABuildingActor::StaticClass());

I would then like to do this:


Cast< ABuildingActor >(Building->ChildActor)->SetBuildingSize(...);

But this won’t work since the ChildActor pointer is not valid until the OnConstruction has been called on the building-actor.
Hence the building won’t know its size until it’s already created and drawn, not good:(

Is it possible to generate actors within actors in C++, send parameter to the child actors and see the result in the level editor?
Where did I go wrong here, or am I trying to do the impossible?

The more I dig into this problem, the more confused I get.
Can anyone show the C++ code that gives the same functionality as this blueprint:

Where Mesh and Height are variables in the blueprint that are visible for editing.

Sorry for replying late. I usually take just a moment per day to check the forums. To do that, here’s how it would look in C++, from the top of my head:



UStaticMeshComponent* SM = NewObject<UStaticMeshComponent>(this); // where this is an actor
SM->SetStaticMesh( ... )
SM->SetRelativeScale3D( ... )

**SM->AttachTo(GetRootComponent());**


Its important to attach the mesh to a component, otherwise it won’t be in the world. If it still doesn’t show up, try calling:



SM->Activate();
SM->RegisterComponent();


See their function comments to see what those do. Usually though components are set to auto activate and auto register via bAutoActivate and bAutoRegister.

I don’t blame you for not answering. I am very thankful for all help i can get.
I have a question though:
Where shall i put this code?
If I put it in the constructor I think the scale will not be updated if I change the value Height.

I got it working by putting the code in PostRegisterAllComponents and first deleting all actors before recreating them again:



void MyActor::PostRegisterAllComponents()
{
	Super::PostRegisterAllComponents();
	UE_LOG(LogTemp, Warning, TEXT("BuildingActor-RegisterAllComponents %f"), sizeX);
	TArray< UActorComponent * > components = GetComponents();
	for (UActorComponent * component : components)
	{
		component->DestroyComponent(true);
	}

	UStaticMeshComponent* SM = NewObject<UStaticMeshComponent>(this);
	SM->SetStaticMesh(MyMeshVariable);
	SM->SetRelativeScale3D(...);
	SM->AttachTo(GetRootComponent());
	SM->Activate();
	SM->RegisterComponent();
}


But I suppose you can do better than this? Call RegisterComponent from PostRegisterComponents does not seam quite right, does it?
And I also get this message in the Output Log:
LogSCSEditor:Warning: Calling UpdateTree() from Tick() more frequently than expected due to invalid tree node state. This might be a performance issue.

I also realize that this code will crash the editor when I reopen my project :frowning:
So, how could this simple BP be so complicated to implement in C++?

I wouldn’t recommend doing that in PostRegisterAllComponents. Putting it in OnConstruction should be fine. The OnConstruction function is ran everytime a value marked UPROPERTY() on the actor is changed. That includes the actor’s position, or your Height variable. Have you tried it?

Another option, if you don’t want to execute the code whenever ANY variable changes, but only when a specific variable changes, you can override AActor::PostEditChangeProperty(): https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/GameFramework/AActor/PostEditChangeProperty/index.html
This function is called whenever a variable changes, but actually gives you the name of the variable that has changed. Use it like this:



.h:
#if WITH_EDITORONLY_DATA
	virtual void PostEditChangeProperty(struct FPropertyChangedEvent& e) override;
#endif

.cpp:
#if WITH_EDITORONLY_DATA
void AMyActor::PostEditChangeProperty(struct FPropertyChangedEvent& e)
{
	Super::PostEditChangeProperty(e);
	if (e.Property->GetName() == FString("Height"))
	{
		// Do something
	}
}
#endif


Make sure to surround the code with #if WITH_EDITORONLY_DATA and #endif. The reason for that is because this function should only be compiled while you’re developing with editor, and it should be ignored when the editor compiles the game for release.

Also, I see that when you start spawning static meshes you destroy all actor components. Two notes about this: first of all you are potentially destroying components that weren’t spawned by you, so this is unwise! Its better to manually track the static meshes you spawned to clean those up. Secondly, I think the crash you experience may be caused by the fact that you are removing components while iterating through the list. In other words you are modifying the list while iterating through it. That is not allowed. See the implementation of GetComponents(), you are not getting a copy of the list, but the direct list itself:



	/**
	 * Get a direct reference to the Components array rather than a copy with the null pointers removed.
	 * WARNING: anything that could cause the component to change ownership or be destroyed will invalidate
	 * this array, so use caution when iterating this list!
	 */
	const TArray<UActorComponent*>& GetComponents() const
	{
		return OwnedComponents;
	}


So I believe that is causing the crash.

My mistake, during my wild experiments I moved the code to PostRegisterAllComponents.
Good point about cleaning only my own meshes.
So a lot solved so far. By applying all suggestions adding static meshes now works like a charm.
A little embarrassing that I didn’t sort this out by my self, but thanks a lot for the help.

Then I am still left with my original problem:
I want to add an actor by using AddChildActorComponent instead of a static mesh.
This child actor needs some parameters in it’s OnConstruction code and I can’t find a way to pass arguments to the child actor before it’s to late…

There is a way to spawn an actor and set some parameters before the construction script is ran. In C++ instead of calling UWorld::SpawnActor, you would call UWorld::SpawnActorDeferred, set your parameters and then call AActor::FinishSpawning on the created actor. The construction scripts will only run when FinishSpawning is called. Here is an example of deferred spawning:



		// Spawn and initialize the actor
		const FTransform SpawnTransform(SpawnRot, SpawnLoc);
		ACombatCharacter* CombatChar = GetWorld()->SpawnActorDeferred<ACombatCharacter>(CharClass, SpawnTransform);
		CombatChar->Identity = Spawn->Identity;
		CombatChar->FinishSpawning(SpawnTransform);


You could try making a subclass of ChildActorComponent, which does deferred spawning and sets those parameters in time.

That sounds like a great idea. I have already found the SpawnActorDeferred so that works now, but the actor cannot be a subcomponent.
But by creating a new ChildActorComponent class that will be possible. Unfortunately the class has to be a copy of the existing ChildActorComponent since the CreateActor function is not virtual.

However I found that a small bug has given me a bit of extra work here.
If you spawn objects in the OnConstruction function, sometimes they disappear when you enter play-mode. This can be solved by hiding and showing them in the editor.
But when I experimented with different places to put the code, this bug led me to believe that OnConstruction didn’t work in play mode, but i suppose it does? Or is the bug the other way around?

Maybe it was the other way around?
To improve the performance i changed mobility to static for the meshes in the spanwned actor to static, and now the actors always disappear when start play?!

There is onConstruct as well as other hooks for play mode. You can add the same call in both places.