Sorry I could not find a suggestion-section to post in + this is kinda hard to explain.
In UE4 as we all know we can not spawn actors at designtime. And spawning stuff at designtime outside of the actor’s constructor can be a real pain, but is possible. But on top of that we can not mark those as UPROPERTY.
Example:
I have an actor with an array of shapecomponents so that I can use the same door with different triggerboxes without having to create a new c++/blueprint class for each door.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyDynamicTriggers")
TArray<UShapeComponent*> Triggers;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyDynamicTriggers")
TArray<FMyTriggerSetup> TriggersSetup; // Contains an enum telling the actor what type of shapecomponent to spawn
// outside of the constructor in the PostEditChangeProperty():
void FooClass::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
if (PropertyChangedEvent.MemberProperty->GetName() != "Triggers")
{
...
case ECollisionShapeEnum::Capsule:
Triggers[i].ShapeComp = NewObject<UCapsuleComponent>(this); // Note: NO FName param or UE4 will go nuts (duplicate names) :P.
break;
...
}
}
The above seems to work at first. But when you try to edit the Capsule component size, location, etc. you can’t… It’s readonly and you get the message:
Okay… And there is no way to do this dynamically in c++. But it is possible in blueprints (blueprints do this regardless of whether you want it or not).
Because I really do not want to use blueprints just for this one variable, I came up with an ugly hack (but still the best one out there I think). It basically puts the ShapeComponent (which we can not mark as UPROPERTY in c++) inside a struct and then we mark the variable of that struct as a UPROPERTY:
USTRUCT(BlueprintType)
struct FShapeCompHack
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ShapeCompHack")
UShapeComponent* ShapeComp;
FShapeCompHack()
{
ShapeComp = nullptr;
}
};
And then in the header:
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "BaseCrusher")
TArray<FShapeCompHack> Triggers; //TArray<UShapeComponent*> Triggers; // Apply dirty hack because... you know...
I can, to some degree, understand that actorspawning at designtime is problematic. But not being able to mark dynamically-spawned components in c++ as a UPROPERTY seems like a really bad limitation and I see not reason why this was done. I already have to go to lengths to spawn stuff dynamically at designtime. This just makes it so much more worse.
Also there may be a bug with this particular hack where spawning stuff dynamically and then running the PostEditChangeProperty() function will cause the “Multiple values selected” to appear on ALL fields every time. It seems that the editor selected all components in the array (even though the editor says it selected only one). But I also have a workaround for that in place… The (possible) bug is kinda hard to explain but then again, I’m applying a workaround (multiple values) on top of a hack (no dynamic uproperty) on top of a workaround (no actor spawning at designtime) to get around the engine limitations. And then there is that intended behavior where only the triggerbox that is the root-component can overlap/hit non-pawns. So if you try to apply all this for a dynamic array of trigger-shapes that must collide with something other than pawns, then not even this will work for you…
See also: