Announcement

Collapse
No announcement yet.

Howto procedurally create child actors (properly)?

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

    Howto procedurally create child actors (properly)?

    Cross posted with answers here, here, here, here

    How do I properly setup parent-child relationships between two AActors in C++? Or in other words: How do I setup an Actor A to be the child of an Actor B?

    An in-depth explanation of this relation is appreciated.

    Goals
    • I want to auto-configure/layout a large set of actors which are in principle independent but there positions. Manual placement here is too much work and also this is intended to be part of a procedural level setup.
    • This should work procedurally (at runtime via c++) and from within the UE4-Editor.
    • All child actors should be grouped below the parent actor within the world outliner, to denote that this is a logical group.
    • Each child actor must still be working as an independent actor (Tick() for example).
    • If a child actor gets changed (deleted for example) this event must be propagated to the parent actor, so it may react to this change.
    • All child actors should move accordingly if the parent actor is moved. But not vice versa.
    I tried two major approaches:

    Variant A

    I use "AActor::AttachToActor()" which works to some extent. The NewCustomActor is attached to the current (this) AActor, which is also visible in the UE4-Editor-Outliner. However:
    • If I delete the parent AActor (this) within the editor, all child ACustomActors remain present, without their parents
    • If I change an aspect in any of the child actors, this event is not propageted back to the parent actor and therefore AActor::OnConstruction() is not called, which I require. I do not want to implement a manual event propagation here, as CustomActor must also work independently of a parent-child relationship.

    Code:
    ACustomActor* NewACustomActor = GetWorld()->SpawnActor(ACustomActor::StaticClass(), SpawnParams);
    NewACustomActor->SetActorLocation(Position);
    NewACustomActor->SetActorLabel(Name);
    //NewACustomActor->SetOwner(this);
    NewACustomActor->AttachToActor(this, FAttachmentTransformRules::KeepWorldTransform);
    Variant B

    please also see attached example code files - myactor.[h|cpp] and mychildactor.[h|cpp]

    I use UChildActorComponent on the parent actor. This also works to some extent. However:
    • I could not find a solution to dynamically spawn UChildActorComponents while also beeing able to edit the spawned Actors/UChildActorComponents within the UE4-Editor. A spawned Actor/UChildActorComponent is always labeled as "Native components when declared as a UPROPERTY in c++". However, UPROPERTY() is normally set statically on class attributes, which do not exist at runtime.
    • Furthermore I even cannot select any child actor from the UE4-Editor-Viewport or World-Outliner.
    • Also, this approach seems to be a bit of a crutch as it introduces an layer of indirection which increases code complexity?
    The resulting question here is: How do I make a dynamically spawned actor/component editable in the UE4-Editor and/or how do I set UPROPERTY values at runtime?

    Variant B code snippet

    Code:
    UChildActorComponent* NewComp1 = NewObject<UChildActorComponent>(this);
    NewComp1->bEditableWhenInherited = true;
    NewComp1->RegisterComponent();
    NewComp1->SetChildActorClass(AMyChildActor::StaticClass());
    NewComp1->CreateChildActor();
    Variant B screenshot

    The screenshot below shows a MyActor which spawns a MyChildActor during runtime. However, selection of MyChildActor is not possible in the Outliner or in the Viewport. Properties are also not editable.

    Click image for larger version  Name:	Screen_1.PNG Views:	1 Size:	101.3 KB ID:	1508417
    Attached Files
    Last edited by chrarlait; 07-29-2018, 04:49 PM.

    #2
    For Variant A
    I think what you are really looking for is the notion of the "Outer Object". If I am not mistaken, it is the equivalent of ownership in a hierarchy of Objects. It is used by GC as well such that any objects below the hierarchy chain would be marked for destruction if their outer is being destroyed (confirmation needed). In any case, if you ever tried creating a UObject using the NewObject method, you would notice one of the arguments you need to pass is the Outer object that owns the one being instantiated.

    I do not see a method in UWorld that allows you to spawn the actor from one that is already constructed (and it shouldn't since the assumption is that Actors must be owned by UWorld). The only way I see to reset the Outer Object is using the answer from here:Again, I do not recommend stripping the world from ownership of the AActors, I can't tell what behaviors you'll get from the above - try it out and report back.

    For Variant B
    This is generally the way to go if you can pull it off. You CAN create components dynamically, and this is again via the NewObject method. You have to ensure you call RegisterComponents() afterwards however.
    Similar to the above, when creating the component dynamically, you would pass the owning actor as the argument for the Outer, then follow by "component->RegisterComponent() to finalize and create the physical state for the component.

    Code:
    UMyActorComponent* someComponent = NewObject<UMyActorComponent>(owningActor);
    someComponent->RegisterComponent();

    More on object instantiation here: https://docs.unrealengine.com/en-us/...jects/Creation

    EDIT: To address the second point, part B. So long as your properties are UPROPERTIES and instance editable using UPROPERTY(EditAnywhere) or UPROPERTY(EditInstanceOnly), you SHOULD be able to select individual components of an Actor placed in the level and manipulate them as you see fit. This includes transformations.
    Last edited by herob4u; 07-28-2018, 11:17 PM.

    Comment


      #3
      I changed some statements to be more precise and added more information in/to the original post (#1)

      Thank you herob4u!

      Variant A

      I tried your suggestion and used Rename() to change the outer. This seems to work as within the UE4-Editor an association between the two Actors is created (when trying to delete an actor, one gets a message informing about a reference). But the behavior is the same, as described above in my initial question. So this does not seem to work as desired.

      Code:
      FActorSpawnParameters SpawnParams;
      FName Name("Actor21");
      SpawnParams.Name = Name;
      AMyChildActor* NewActor1 = GetWorld()->SpawnActor<AMyChildActor>(AMyChildActor::StaticClass(), SpawnParams);
      NewActor1->SetActorLocation(GetActorLocation());
      NewActor1->Rename(TEXT("NEW NAME"), this, REN_None);
      NewActor1->AttachToActor(this, FAttachmentTransformRules::KeepWorldTransform);
      Variant B

      I also revisted Variant B with your comments in mind. The problem here is that the spawned actor is not editable (or even selectable) from within the UE4-Editor Viewport or World Outliner (see added screenshot in post #1). I could not find a solution to dynamically set EditAnywhere on a procedurally spawned Actor/Component. I do not have a class attribute where I can put the UPROPERTY() macro on top, which then gets pre-processed at compile time. So this needs to be done dynamically, during runtime - which I do not know how to do.

      This is the code I use to spawn the child actor via UChildActorComponent (full example files are now attached to this post - see original question post):

      Code:
      UChildActorComponent* NewComp1 = NewObject<UChildActorComponent>(this);
      NewComp1->bEditableWhenInherited = true;
      NewComp1->RegisterComponent();
      NewComp1->SetChildActorClass(AMyChildActor::StaticClass());
      NewComp1->CreateChildActor();
      Problems for Variant B:
      • How to make procedurally spawned actors/components editable?
      • How to dynamically add UPROPERTY values (through UProperty class?)?
      Last edited by chrarlait; 07-29-2018, 04:30 PM.

      Comment


        #4
        The idea of having random and dynamically allocated objects appear as properties is a bit counter-intuitive I think - reflecting a class's properties and making them appear in the editor is a fairly static process. This means they need to be determined during compile time. From the sounds of it, the effect you are seeking sounds impossible. Even worse, if you attempt to create a similar effect using blueprints, you won't even be able to see the component in the window at all, let alone edit it.

        Can you explain what you mean by being able to modify the property of the object when its dynamically instantiated? If it is dynamic, then it probably implies it is being created some time during play (i.e BeginPlay or some other occurrence), but manipulating an object through the editor at such times is almost meaningless- unless it's for debugging. Maybe its a different workflow you truly need?

        Here is a similar problem to which no solution was found: https://forums.unrealengine.com/deve...editable/page2



        EDIT: The only way I can see this working dynamically is if you implement Variant A. Can you try the suggestion with renaming to reset the Outer object and see if that goes a step forward?
        Last edited by herob4u; 07-29-2018, 06:15 PM.

        Comment


          #5
          First one thing I do not understand: The UE4 Editor exibits the same capabilities I want to achieve. For example: I drag an Actor into the level, select it, goto its Details Panel and dynamically add a UStaticMeshComponent to the actor which I then can configure. That is exactly the workflow I want, only from C++. And because the editor shows it works, it must be possible to do myself?

          Some more background
          What I am trying to achieve is to procedurally generate a level as an initial starting point to then work out the finer details from within the UE4-Editor. For this I did setup a parent actor which spawns associated child actors (which exhibit their own behavior). This parent actor is responsible for procedural generation of specialized aspects of the level and can be configured from within the UE4-Editor (like number of objects, diversity, density, random seeds, etc.). So, the number of child actors can vary depending on the configuration. I choose an actor as parent as I want to be able to move the whole actor group (parent and childs) as a whole and place them around in the base level. Also this actor then is meant to be used purely procedural from within the running game.

          So that is the background. Since I have trouble to find a way to implement this (this forum thread) I started on an alternative solution. Here I do not setup parent-child relationships at all but simply spawn all actors as to the configuration of a master actor, which is placeable within the editor or spawnable from c++ at runtime. All relative movements of actors I need to capture through editor events (only relevant in editor) and re-configure/move all other actors accordingly. I guess it will work and propably be a cleaner solution after all, but I am lacking experience to give verdict on that just yet.

          As to your Rename() question: If I understood you correctly in your first answer I did that already - please see my answer or the newly attached files in the frist post. If that is not what you meant, could you please clarify? I will play around with this some more and post back the results.

          Thank you for keeping on the topic!

          Comment

          Working...
          X