x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

How to "expose on spawn" a constructor param in C++?

In BP you can "expose on spawn" a variable and you will have an option to feed some value in it on "SpawnActorFromClass" node.

In vanilla C++ you just define a constructor with params.

How do yo make it in UE4's UCLASS C++?

Product Version: UE 4.18
Tags:
more ▼

asked Mar 12 '18 at 05:36 PM in C++ Programming

avatar image

Arty-McLabin
703 13 23 41

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

3 answers: sort voted first

You have to use SpawnActorDeferred. This answer should be still valid.

more ▼

answered Mar 12 '18 at 09:02 PM

avatar image

Ninjin
3.7k 84 30 135

avatar image Arty-McLabin Mar 12 '18 at 11:55 PM

It seems like a messy workaround, isn't there a better and straighter way for achieving that?

avatar image Ninjin Mar 13 '18 at 01:47 PM

Messy? It's 3 lines of code. Spawn, Init, FinishSpawn. You need a 2nd function to call when creating the actor anyway, since the CDO is already created and you can't just re-run the constructor. You can put the code for FinishSpawn in your Init function, but I would stick to the 3 line combo.

avatar image Arty-McLabin Mar 13 '18 at 08:51 PM

it's messy because it breaks the function-programming paradigm of 1task=1function and therefore will cause forgotten 2 lines big time.
BP has an option to expose on spawn, it seems very strange to me that it's not available in C++ spawns. why would i need a 2nd/3rd function to call when crating the actor?
Logically it is completely possible to add inputs, for example adding an override for SpawnActorFromClass(), that has the input params you need, which just calls the other "classic" overrides and then runs the init+finishSpawn.

It seems too strange to not be implemented by Epic in the first place, that's what caused me asking if there's some more straight-forward way i am not aware of

avatar image Balgy Mar 13 '18 at 09:57 PM

Logically it is completely possible to add inputs, for example adding an override for SpawnActorFromClass()

Well, you answered your own question. It is impossible to add overrides for every object you wish to have the expose on spawn functionallity. To do something like the BP implementation on C++, it would need to dynamically alter the SpawnActorFromClass() function depending on the class you are spawning. Since this is not possible without the reflection code that makes Blueprints so helpful in these sorts of scenarios, you can use SpawnActorDeferred.

SpawnActorDeferred is a very helpful and really not messy way to do things. It gives you greater control over everything as you actually get a pointer to the object without running the constructor.

avatar image Arty-McLabin Mar 14 '18 at 08:01 PM

you don't need to specify args for each existing type. C++ templates come in handy for that. I know UE4 doesn't support templates anywhere, but there are exceptions and Epic's workarounds which we might not be aware of.

for example there is a type for wildcard inputs.

avatar image Ninjin Mar 13 '18 at 11:14 PM

Did you see that I mention the word CDO (which stands for Class Default Object, here my own 5 sec google search)? Because if you did and searched what it means and why it's being used, it should be understandable why you can't re-run the constructor. There is other functions that get called right after the constructor to initialize some stuff that is needed for the editor and the whole reflection system. One of these hidden functions also creates Blueprints. So, in that sense, if you call a "Blueprint Constructor", you call one of these post functions and not the C++ Constructor. Therefore, to get the same behavior in C++, you should implement a function that is exactly doing this. You might be able to find the function that is called in Blueprints, but last time I checked you shouldn't use it, because it comes with boilerplate code for Blueprints and if you make a Blueprint and change your Construction Script (which if you notice is not even called Constructor on purpose) things get even worse.

avatar image Arty-McLabin Mar 14 '18 at 08:04 PM

I know what's CDO and how classes in UE4 are being instanced for quite a while now.
The point is that i didn't ever say i want to run the constructor, rather i want to spawn an object with input similar to BP "expose on spawn" or C++ constructors params.

I am not sure why you mention that, perhaps we have confused each other :P

avatar image Arty-McLabin Mar 14 '18 at 10:35 PM

Anyway, your answer have helped me and it's not your fault for something being subjectively "messy" for me, so i am marking your answer, thanks :]

avatar image Ninjin Mar 15 '18 at 12:36 AM

You are asking to change C++ constructor params without running the constructor and the only way to do this, is running a function after your constructor, which you can define yourself. Luckily, Blueprints already have such a function and the ExposeOnSpawn was neatly integrated with this function = ConstructionScript. You got a valid question why Epic didn't refactor this function into 1 line of code where you specify the functionname in the parameter list of SpawnActorDeferred and if I had to guess, they don't bother and think people use these kinds of features in BPs anyway or they didn't want to implement a function in AActor called ConstructionRound2 that only calls FinishSpawn and needs to be overridden. Probably not that easy, something is probably missing. But then again, I don't want to know how exactly Actors are spawned, when they locate memory and what else is happening when Spawning. Maybe there is something magical I miss, but I doubt you will find such an answer here on Answerhub. It's okay to ask though, there is always this slight chance an engine programmer has a happy day :).

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

You create the variable as a UPROPERTY and also give it a special parameter. Here is an example:

 UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (ExposeOnSpawn = true), Category = "MyClass")
     int Foo;
more ▼

answered Mar 12 '18 at 08:11 PM

avatar image

Jin_VE
4.2k 31 75 34

avatar image Arty-McLabin Mar 12 '18 at 11:52 PM

Thanks, but this is a solution for exposing on BP, while i need to feed that in C++ spawn. sorry for confusing you :P

your answer might be useful for future viewers though.

avatar image Jin_VE Mar 13 '18 at 12:07 AM

Your question wasn't entirely clear on that. Last I checked there is no way to do the equivalent when spawning an actor in C++.

What you can do is use a static variable as temporary storage. Set it before you spawn an instance of the class, then in the constructor/whatever you can get the value and clear it. As long as you're only doing this in a single thread, it will be fine.

Other than that, I think Ninjin's answer is the best you're going to get.

avatar image Jin_VE Mar 14 '18 at 08:19 PM

OK guys this is getting ridiculous. At this point you're not trying to get to an answer anymore. I'm turning off notifications. But before I do I will once again suggest the very easy (but not elegant way) to do what you want. Here is a sample class that does it. It will work fine as long as you are using the main thread -- and since that's the only place you can spawn from, this will always work as long as that doesn't change.

H:

 UCLASS()
 class SHOOTER_API AMyActor : public AActor
 {
     GENERATED_BODY()
 
 public:
     AMyActor(const FObjectInitializer& ObjectInitializer);
 
     UPROPERTY(EditAnywhere, BlueprintReadWrite)
     int MyVar1;
 
     UPROPERTY(EditAnywhere, BlueprintReadWrite)
     bool MyVar2;
 
     static AMyActor* Spawn(UWorld* world, int myVar1, bool myVar2);
 
 private:
     static bool ParamsSet;
     static int Param_Var1;
     static bool Param_Var2;
 };

CPP:

 int AMyActor::Param_Var1 = -1;
 bool AMyActor::Param_Var2 = false;
 bool AMyActor::ParamsSet = false;
 
 AMyActor::AMyActor(const FObjectInitializer& ObjectInitializer)
     :    AActor(ObjectInitializer)
 {
     if(!ParamsSet)
     {
         UE_LOG(LogTemp, Error, TEXT("AMyActor spawned without using internal Spawn function!"));
     }
     else
     {
         MyVar1 = AMyActor::Param_Var1;
         MyVar2 = AMyActor::Param_Var2;
     }
 }
 
 AMyActor* AMyActor::Spawn(UWorld* world, int myVar1, bool myVar2)
 {
     AMyActor::Param_Var1 = myVar1;
     AMyActor::Param_Var2 = myVar2;
     AMyActor::ParamsSet = true;
 
     AMyActor* myActor = world->SpawnActor<AMyActor>();     // fill Spawn() with parameters as you need
 
     AMyActor::ParamsSet = false;
 
     return myActor;
 }
avatar image Jin_VE Mar 14 '18 at 08:21 PM

Obviously you don't need to make the members as UPROPERTY, I just wanted to be explicit about what was what.

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

You dont.

You spawn an actor, then set the values to what you want. Spawning from the Blueprint does this. Nothing written code does not do this. However you make a single line of code look it is still executing 1 instruction at a time, however many dozens, hundreds, thousands, or millions of instructions are invoked. They are still only executed 1 instruction at a time.

I'm not sure where you got this "1task=1function" idea, but you might as well unlearn that right now. Your entire application is running from a single function called main(). EVERYTASK = 1 function.

more ▼

answered Mar 14 '18 at 08:19 PM

avatar image

HollingsworthDan
126 2 2 6

avatar image Arty-McLabin Mar 14 '18 at 10:32 PM

It's a paradigm from functional programming. If you have 2 functions that you always or mostly execute one after another, it's a good habit to combine them into one function (possibly 3rd), without this paradigm, we would still write in assembly language.

Whole the point of functions is to encapsulate smaller steps into a shortcuts.
I am not going to unlearn that.

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question