What exactly occurs when arrays are manipulated? Trouble setting elements of arrays within arrays.

In UE4 blueprints, arrays are handled in an interesting way. If we have an int variable and we wish to add a value to it, we must

(Get int) —> (Add value) —> (Save sum back to variable)

But for an array, we have the “Add” node which (seemingly) takes care of the last part for us.

(Get array) —> (Add element)

So my question is - what is actually happening here? For this scenario, it is obvious. But for others it is not.

I was recently trying to help other user in another post and I came across a complex problem. How can I modify the elements in an array if the array is not a variable? For example, here is the screenshot I had posted.

Just offscreen to the left is the execution node and a reference to “MapIndex”. So for a little bit of an overview…

MapIndex is an array of TileRows
TileRow is a struct containing an array of TileStructs
TileStruct is a struct containing an int (“Type”) and an actor reference (“ActorRef”)

oikT9yT.png

The idea was to create a 2D array where each element in the array has an int to define the type and a reference to the actual actor ingame. I’m not sure if there was a better way to set this up, but that’s not really the point of this post.

What I am doing is looping through each element in the 2D array. If the “Type” is 1, spawn a “Wall” actor. Then, I need to feed a reference to that actor back into that element in the “ActorRef”. The whole bottom half is me trying to accomplish that.

So in the screenshot, the logic is as follows

  1. Get the main MapIndex array
  2. Get the index into MapIndex we’re looking at (Outer “ForEach” loop)
  3. Break the “row” to get the elements within it
  4. Get the index into TileStructs we’re looking at (Inner “ForEach” loop)
  5. Break the “tile” to get the elements within it
  6. Make a new “tile” with the “type” from the old tile and a reference to the newly spawned actor
  7. Use the broken row from #3, setting the element at the inner loop index to be the newly created tile.
  8. Make a new row from the broken row.
  9. Replace the old row with the new row in Map Index

Overall, I HATE the steps I took here. It’s messy and convoluted. I shouldn’t need to replace an entire row of elements every time I want to change a single one. But I don’t know any other way to accomplish it. To make matters worse, this doesn’t even work.

Here’s where my confusion starts.

In step 7, I link “TileStructs” from step 3 into the “Set Array Element”. When this executes, what exactly has changed? In step 8, I make a TileRow from the TileStructs in step 3… but does doing this actually give me the modified array or am I simply getting the original array? From my testing, it looks like the ladder.

  • Why does this not work?
  • What would be the correct way to make this setup work?
  • Is there a better way to accomplish this?

Thanks,
Chumble

I would do something like this: (Assuming SetArrayElement works as intended)

Structs are kind of awkward right now in blueprints. I think most people find they are doing too much with a single struct and eventually move the functionality into a UObject or AActor based class. In your case, I think a struct is fine, though I believe there are issues with accessing struct members by pointer in 4.11.

This is essentially what I have, although much cleaner than mine. Also, you modify the elements in “MyStructArray” but do not use a “Set Array Element” to save it back to “2D Array”. I don’t know if that’s needed or not, but it’s what I did.

I don’t understand how this works internally. In the “ForEachLoop”, does the “Array Element” output contain a copy of the element in that array or a reference to that element? If we simply run an “Add” to that output then check the contents of “2DArray” will it be modified?

And likewise, when we “Break MyStructArray” to get the contained struct, does that output contain a copy or a reference? If it’s a copy, this wont work. If it’s a reference (and the above is also a reference), it should work fine.

I guess some more isolated tests are needed to confirm this functionality. I’ll be playing with this shortly when I get home.

Arrays are pointers under the majority of situations (i could be wrong on this, I have not done explicit testing)
Stucts are by value.
Struct members are I think currently by value as well (there was a 4.12 roadmap about struct member references/pointers)
UObject based classes are by pointer under most situations
AActor based classes are basically UObject functionality with Replication (and I believe they cannot be static?)

You can open the Loop functions to see their internal workings (they are macros). The ArrayElement will be a pointer or value depending on the data type afaik.
BreakStruct should give pointer/value return based on data type as well, but see above.

Set Array Element is the black sheep for blueprint arrays. Array Nodes | Unreal Engine Documentation

When you *get *a struct from an array, you do not get it by reference, you get it by value - a copy. This is not an ideal behaviour and will eventually get fixed, so I hope. The issue is as old as the UE4 structs themselves.

Essentially, in step 8, you fetch another copy of an unmodified MapIndex entry.

One (and only?) way around it is to rebuild the entire nested subarray first and save it to a temporary var. Once that loop is done, move to the outer one.

And I’d agree with Nodrak here regarding everything but his TestActor - this shouldn’t yield the expected results. Not with structs.

Yea my bad, I recently converted from Stuct based data to class based data, so I kinda of glossed over the 2D array being struct based ><. There is a Set Members In <Struct> pin, that should be what you need to handle struct reference additions, but passing them around and keeping data parity is still another issue.

Something like this:

If I remember my previous setup, struct pins (direct lines in blueprints) are references, the issue comes when you enter and exit scope or set variables.