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"

Pass parameter to constructor somehow?

I have a problem with the Constructor Helpers. I MUST create the UTexture and UMaterialInterface inside the constructor. But the UTexture must be set through a variable. So how can I set this variable prior to construction? I tried BeginDeferredActorSpawnFromClass() but that didn't help at all. SpawnActorDeferred() also did not work. It seems that those only work for Blueprint constructors but not for the C++ ones.

Please tell me there is a way to do this without me having to initialize ALL possible textures in the actor. I also tried a static TArray as a workaround but the moment I used it I get a LNK1120.

Spawning it:

 JobMarker = Cast<AJobMarker>(UGameplayStatics::BeginDeferredActorSpawnFromClass(this, AJobMarker::StaticClass(), GetTransform()));
         if (JobMarker != nullptr)
         {
             JobMarker->Init(MarkerTexturePath);
             UGameplayStatics::FinishSpawningActor(JobMarker, GetTransform());
         }
         else
         {
             LOG_ERROR("Failed to spawn JobMarker.")
         }

The actor that I'm trying to spawn:

 AJobMarker::AJobMarker()
 {
     PrimaryActorTick.bCanEverTick = true;
     <snip>
     Material = ULib::CreateObject<UMaterialInterface>("/Game/Materials/MI_MarkResource");
     Texture = ULib::CreateObject<UTexture>(TexturePath); // <<< This line is the problem
 }
 
 void AJobMarker::Init(FString texturePath) // This Init is too late!
 {
     TexturePath = texturePath;
 }
 
 // Called when the game starts or when spawned
 void AJobMarker::BeginPlay()
 {
     Super::BeginPlay();
     SetMarkerMaterial();
 }
 
 void AJobMarker::SetMarkerMaterial()
 {
     FMaterialSpriteElement element;
     element.bSizeIsInScreenSpace = false;
     element.BaseSizeX = 128.0f;
     element.BaseSizeY = 128.0f;
     MBB_Comp->Elements.Add(element);
     
     if (Material != nullptr)
     {
         UMaterialInstanceDynamic* newMaterialInstance = MBB_Comp->CreateDynamicMaterialInstance(0, Material);
         if (newMaterialInstance != nullptr)
         {
             newMaterialInstance->SetTextureParameterValue(FName("Texture"), Texture); // This line requires the GEngine so do NOT call this from a constructor.
             MBB_Comp->SetMaterial(0, newMaterialInstance);
         }
         else
         {
             LOG_ERROR("MaterialInstance is NULL.")
         }
     }
     else
     {
         LOG_ERROR("Material is NULL.")
     }
 }








Product Version: UE 4.18
Tags:
more ▼

asked Dec 07 '17 at 01:43 PM in C++ Programming

avatar image

Napoleonite
430 64 62 105

avatar image SnivelLots 6 days ago

It does not seem to be possible to pass parameters into a constructor, and the general consensus is to have an initialization function that you call immediately after spawning that takes the necessary parameters.

Is there any particular reason that you MUST create these in the constructor?

avatar image Napoleonite 6 days ago

Yes the UTexture MUST be initialized there (limitation from UE4) and this is a variable (FString). So the general consensus (to which I mostly agree) does sadly not apply here.

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

1 answer: sort voted first

I solved it the static way. It seemed the best solution given the limitations while also being forced to do it inside the constructor.

Header:

 static TArray<UTexture*> JobMarkerTextures;

Cpp:

 // below the #includes (this can't be assigned in the header file!)
 TArray<UTexture*> AJobMarker::JobMarkerTextures = TArray<UTexture*>();
 
 // In constructor method
 if (AJobMarker::JobMarkerTextures.Num() == 0) // or use a static boolean here.
 {
     AJobMarker::JobMarkerTextures.Add(ULib::CreateObject<UTexture>(P_MARKER_WOOD_TEX));
     AJobMarker::JobMarkerTextures.Add(ULib::CreateObject<UTexture>(P_MARKER_STONE_TEX));
 }

Now they all share the same materials while still having different material instances and without having to dump a variable to the constructor.

Note that the UTexture and UMaterial MUST be created in the constructor but the UMaterialInstanceDynamic MUST be created after BeginPlay() was called while also not being able to use parameters in the constructor in c++.

more ▼

answered Dec 08 '17 at 07:30 AM

avatar image

Napoleonite
430 64 62 105

(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