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"

Workarounds for referencing TArray of pointers to UStruct

I have a situation where I have a "graph" of different nodes contained in a UPolygonGraph class. Specifically, I have FCenter (accessing the center of a polygon), FVertex (accessing the vertex of a polygon) and FEdge (connecting neighboring centers or neighboring vertices) classes.

All 3 of these are stored in 3 different TArray variables in my UPolygonGraph class. Each struct also contains information about its neighbors -- the FCenter struct contains information about all neighboring FCenter structures, as well as information about the FVertex structures that make up the vertices in the polygon and all the FEdge structures connecting vertex to vertex and center to center. The FVertex struct has information about neighboring vertices, what centers use this vertex as a polygon, all edges connected to the vertex, and so on.

The logical way to access the first vertex of a FCenter structure would be to do something like:

 FVertex FirstVertex = FCenter.Vertices[0];
 FirstVertex.Location = FVector::ZeroVector;

However, in reality, I can't do that -- while I can make as many copies of these structs as I want, because the TArray` is a UPROPERTY, it won't work properly (since, IIRC, pointers to UStructs in general aren't permitted, let alone pointers to TArrays of UStructs). I can't modify that vertex and have my changes "automatically" propagate to the larger UPolygonGraph class and all neighboring structures.

As it is right now, neighboring structures are actually being referred to by integers (which correspond to the index of that structure in its respective array). Here's that above example, where I try to fetch the first vertex of a FCenter object:

 int VertexIndex = FCenter.Vertices[0];
 FVertex FirstVertex = UPolygonGraph.GetVertexByIndex(VertexIndex);
 FirstVertex.Location = FVector::ZeroVector;
 UPolygonGraph.SetVertexByIndex(VertexIndex, FirstVertex);

As you can see, about 0% of that was intuitive. It doesn't make sense that accessing the first element in the vertices array would return an integer. It doesn't make sense that getting a vertex by index would return a copy and not a reference. It doesn't make sense that you'd need to "manually" update the graph after you make changes to something.

I'm not sure exactly what a good workaround would be. I'd like to leave as much exposed to Blueprints as possible. I've been trying to use TArray and UPROPERTY instead of just using a native C++ array with pointers to everything. As mentioned, I can't make a pointer to a UStruct accessible to Blueprints, so I can't use pointers to the neighboring structures. I can't call any functions declared within the UStruct within Blueprints, so I haven't really written any functions for them. Changing them all to be UClass instead of UStruct is out of the question; I tried it once and took a major performance hit.

Any ideas? Or will this continue to just be super-confusing?

Product Version: UE 4.16
Tags:
more ▼

asked Jun 02 '17 at 01:59 AM in C++ Programming

avatar image

Jay2645
188 4 14 25

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

1 answer: sort voted first

This is a bit cludgy, and I'm not sure that it will actually streamline anything for you; but this might help.

You say, "It doesn't make sense that getting a vertex by index would return a copy and not a reference." and I'm not sure why you're choosing not to return by reference. I may have missed something in your explanation, but as far as I know that can be done in the situation you're describing.

You also say, "I can't call any functions declared within the UStruct within Blueprints, so I haven't really written any functions for them."

And this is correct, to a point. However, you can expose methods within structs to being called within a Blueprint by creating an intermediary library of static methods.

For use in C++, you can build your structs as you would without regard to BP, and use pointers to neighbors etc. You can build methods within your structs to perform the graph updates automatically; and you can build accessor methods that traverse the internal pointer chain to get the desired data.

Once you have that complete, you can build a BP Static Library of methods that call the methods within your structs for you.

A simple example might make this more clear. Let's say you have a struct:

 USTRUCT(BlueprintType)
 struct FExampleStruct
 {
 
     GENERATED_USTRUCT_BODY()
 
     /** Some BP exposed data */
     UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Example")
     FVector Location;
 
     /** Some non-BP exposed data */
     FVector HiddenLocation;
 
     //default constructor
     FExampleStruct(
         FVector NewLocation = FVector(0.0f),
         FVector NewHiddenLocation = FVector(0.0f)
     )
         :
         Location(NewLocation),
         HiddenLocation(NewHiddenLocation)
     {}
 
     //internal methods
     void AdjustLocation(FVector& Movement)
     {
         Location += Movement;
     }
 
     void AdjustHiddenLocation(FVector& Movement)
     {
         HiddenLocation += Movement;
     }
 
     float& ReferenceHiddenX()
     {
         return HiddenLocation.X;
     }
 
 };

Normally, the internal methods and the HiddenLocation variable would be inaccessible from BP. But if we create a UBlueprintFunctionLibrary of static methods, we can access and modify the values:

 HEADER:::
 
 #pragma once
 
 #include "Kismet/BlueprintFunctionLibrary.h"
 
 UCLASS(Blueprintable, BlueprintType)
 class EXAMPLE_API UExampleStructLibrary : public UBlueprintFunctionLibrary
 {
     GENERATED_BODY()
 public:
 
     /** Retrieves HiddenLocation value from referenced struct */
     UFUNCTION(BlueprintCallable, Category = "Example Struct")
     static FVector GetHiddenLocation(FExampleStruct& TargetStruct);
     
     /** Retrieves reference to HiddenLocation value from referenced struct */
     UFUNCTION(BlueprintCallable, Category = "Example Struct")
     static FVector& ReferenceHiddenLocation(FExampleStruct& TargetStruct);
     
     /** Retrieves reference to HiddenLocation.X value from referenced struct */
     UFUNCTION(BlueprintCallable, Category = "Example Struct")
     static float& ReferenceHiddenX(FExampleStruct& TargetStruct);

     /** Assigns referenced FVector value HiddenLocation within referenced struct */
     UFUNCTION(BlueprintCallable, Category = "Example Struct")
     static FVector SetHiddenLocation(FExampleStruct& TargetStruct, FVector& NewHiddenLocation);
 
     /** Adjusts Location within referenced struct by referenced FVector */
     UFUNCTION(BlueprintCallable, Category = "Example Struct")
     static void AdjustLocation(FExampleStruct& TargetStruct, FVector& Movement);
 
     /** Adjusts HiddenLocation within referenced struct by referenced FVector */
     UFUNCTION(BlueprintCallable, Category = "Example Struct")
     static void AdjustHiddenLocation(FExampleStruct& TargetStruct, FVector& Movement);
 
 };
 
 
 SOURCE:::
 
 #include "ExampleGame.h"
 
 #include "ExampleStructLibrary.h"
 
 FVector UExampleStructLibrary::GetHiddenLocation(FExampleStruct& TargetStruct)
 {
     return TargetStruct.HiddenLocation;
 }

 FVector& UExampleStructLibrary::ReferenceHiddenLocation(FExampleStruct& TargetStruct)
 {
     return TargetStruct.HiddenLocation;
 }

 //note this implementation doesn't call the internal reference method
 float& UExampleStructLibrary::ReferenceHiddenX(FExampleStruct& TargetStruct)
 {
     return TargetStruct.HiddenLocation.X;
 }
 
 FVector UExampleStructLibrary::SetHiddenLocation(FExampleStruct& TargetStruct, FVector& NewHiddenLocation)
 {
     TargetStruct.HiddenLocation = NewHiddenLocation;
 }
 
 void UExampleStructLibrary::AdjustLocation(FExampleStruct& TargetStruct, FVector& Movement)
 {
     TargetStruct.AdjustLocation(Movement);
 }
 
 void UExampleStructLibrary::AdjustHiddenLocation(FExampleStruct& TargetStruct, FVector& Movement)
 {
     TargetStruct.AdjustHiddenLocation(Movement);
 }
more ▼

answered Jun 02 '17 at 03:36 AM

avatar image

GigasightMedia
1.7k 43 13 61

(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