Set Array Elem / Resize / Clear / Append Array¶
At a glance
Lives in: Kismet Array Library; Blueprint API / Utilities / Array -
Mutates: the connected Target Array - Returns: no data value and no
success Boolean - Shape changes: Set Array Elem only when Size to Fit
grows; Resize sets an exact Length; Clear sets Length to zero; Append adds
the Source Array's elements at the end - Invalid input: normally leaves
the array unchanged, continues execution, and writes an array warning in
editor/development output - Official docs: Set Array Elem,
Resize,
Append Array,
and Kismet Array Library
The one-minute version¶
- Set Array Elem replaces the value at one zero-based index. It does not insert or shift later items.
- With Size to Fit = false, the index must already be valid (
0throughLength - 1). An invalid/negative index produces no success pin; the array stays unchanged and a development/editor array warning is the visible clue. - With Size to Fit = true, a non-negative index beyond the end grows the
array to
Index + 1. Every skipped slot receives the element type's default value before the requested slot is assigned. - Resize preserves the prefix that still fits, default-fills a grown tail,
or removes a shrunken tail. Clear guarantees
Length == 0. - Append Array copies the source elements, in order, onto the target's end. Values/structs are copied; object-reference elements still point to the same runtime objects. It allows duplicates and returns no count or success value.
- None of these nodes replicate, save, destroy referenced Actors/UObjects, or tell a ListView/inventory UI that the model changed. Those are separate owner-system jobs.
Start with the shape, not the node name¶
Given:
Items = [Potion, Key]
index 0 1
Length = 2
the nodes make different promises:
| Operation | Result |
|---|---|
Set Array Elem(Index 1, Map) |
[Potion, Map]; Length stays 2. |
Set Array Elem(Index 2, Map, Size to Fit false) |
Warning; unchanged because index 2 does not yet exist. |
Set Array Elem(Index 2, Map, Size to Fit true) |
[Potion, Key, Map]; Length becomes 3. |
Set Array Elem(Index 4, Map, Size to Fit true) |
[Potion, Key, default, default, Map]; Length becomes 5. |
Resize(4) |
[Potion, Key, default, default]. |
Resize(1) |
[Potion]; the old Key slot is removed. |
Clear |
[]; Length becomes 0. |
Append Array([Map, Key]) |
[Potion, Key, Map, Key]; duplicates are kept. |
No operation above sorts, de-duplicates, or shifts an existing item to make room at a chosen index. Choose the shape change deliberately.
What Set Array Elem actually does¶
Set Array Elem is assignment into a slot:
pseudocode of the Blueprint behavior - not engine source
function SetArrayElem(Array, Index, Item, SizeToFit):
if Index < 0:
emit array warning
return
if Index >= Length(Array):
if not SizeToFit:
emit array warning
return
Resize(Array, Index + 1) // new slots receive defaults
Array[Index] = copy of Item
The node has an execution output but no result output. Execution continuing only means the node call finished; it does not prove the write happened.
Replacing does not insert¶
Starting from [A, B, C]:
Set Array Elem(Index 1, X) -> [A, X, C]
Insert(Index 1, X) -> [A, X, B, C]
Use Set when the slot identity should stay put. Use Insert when every existing item at/after the position should shift right.
What Size to Fit means¶
Size to Fit does not find an empty slot. It does not add only one item. It
makes the requested index legal by growing Length to exactly Index + 1.
Current Length = 2
Set index 100 with Size to Fit = true
-> Length becomes 101
-> slots 2..99 are default values
-> slot 100 receives Item
That can be intentional for a dense array keyed by a small, bounded slot number. It is usually a data-model bug when the index is a sparse database ID, network ID, or unchecked user value. A Map expresses sparse key-to-value data without allocating every missing integer position.
Negative indices can never be made valid. Size to Fit does not turn -1
into the last slot.
Which defaults fill a grown gap?¶
Growth initializes each new slot to the element type's default:
| Array element type | Typical new-slot value |
|---|---|
| Integer / Real | 0 / 0.0 |
| Boolean | false |
| String / Text / Name | empty/default value |
| Object or Actor reference | None |
| Class reference | None unless the type/property supplies another default |
| Vector / Rotator / Transform-like value | its type default (commonly zero/identity as defined by that type) |
| Struct | a default-initialized struct, including member defaults supplied by the type |
Do not treat a default-filled slot as proof that real data exists there. An
Object Array grown to index 8 now has valid indices 0..8, but the gap
slots can contain None. Is Valid Index
and Is Valid answer different questions.
Struct copy write-back: the Set pattern beginners need¶
The normal Array Get for a struct gives you a value copy. Changing that copy does not mutate the struct still stored in the array:
wrong:
Entry = Get Inventory[Index]
Entry.Count = Entry.Count + 1
// Inventory still contains the old struct
right:
Entry = Get Inventory[Index]
Entry.Count = Entry.Count + 1
Set Array Elem
Target Array = Inventory
Index = Index
Item = Entry
Size to Fit = false
Validate the index before Get and again if any called event/function could
mutate the array before Set. The local Entry is a snapshot; another mutation
can make its saved index point at a different intent or no slot at all.
For an object-reference element, Array Get copies the reference value. Both copies point at the same object, so changing that object's properties changes the live object. Replacing the array slot changes which reference the array stores; it does not clone or destroy either object.
Resize: set the exact Length¶
Resize takes the final desired element count, not an amount to add or remove:
Items = [A, B, C]
Resize(5) -> [A, B, C, default, default]
Resize(2) -> [A, B]
Resize(0) -> []
The prefix 0..min(old Length, new Length)-1 keeps its values and order.
Growing creates defaults at the tail. Shrinking removes the tail; it does not
choose items by equality and does not move the removed values elsewhere.
A negative Size is invalid. The node has no failure output; the useful array stays unchanged and the engine reports an array warning in development/editor output. Clamp or reject an externally calculated size before calling Resize.
What becomes stale after Resize?¶
- Saved indices: indices below the new Length still identify the same positions because Resize does not reorder the retained prefix. Every removed index is invalid.
- Struct/value copies already read: they remain old snapshots. They do not follow later writes to the array.
- Object references already read: they still identify the same object if that object remains valid; they are no longer proof that the array contains it.
- Element references/native addresses: growth can reallocate the dynamic array, and shape mutations can invalidate references into its storage. Do not retain an element-by-reference path across Resize, Clear, or Append.
Removing an object-reference slot only removes this array's reference. It does not call Destroy Actor. A UObject with no remaining strong references may later become eligible for garbage collection; an Actor follows its own world lifetime and destruction rules.
Clear: Length becomes zero¶
Clear removes every logical element:
Clear(Items)
-> Length = 0
-> Last Index = -1
-> no element can be read
That is the guarantee Blueprint code should use. Blueprint exposes no Array capacity contract, so do not treat Clear as a promise that backing allocation was retained for pooling or immediately returned to the operating system. Capacity is an implementation/performance detail; logical contents are not.
Clear also does not destroy referenced objects. It releases this collection's references, after which ordinary Actor/UObject lifetime rules decide what happens.
Use Clear when the same Array variable should become empty. Assigning a new empty Array can express the same logical result, but Clear makes the in-place mutation visible in the graph and works naturally with an Array passed by reference.
Append Array: concatenate a source onto a target¶
Append copies the Source Array's current elements, in order, onto the Target Array's tail:
Target = [A, B]
Source = [C, D]
Append Array(Target, Source)
-> Target = [A, B, C, D]
-> Source = [C, D]
The source's Length is added to the target's Length. An empty source is a successful no-op: target remains unchanged and there is no special branch.
Append does not test equality. If Target already has C, appending [C]
creates another C. Use Add Unique/Set/Map only when uniqueness is the actual
collection contract.
Copying values versus sharing objects¶
For Integer, Vector, and struct arrays, the appended elements are value copies. Changing a struct in Source later does not rewrite the struct copy in Target.
For object-reference arrays, the reference values are copied:
Source[0] -> Enemy_12
Target appended slot -> Enemy_12
Both arrays now point at the same Enemy_12 object. Changing the object is
visible through either reference; replacing/removing one array slot does not
rewrite the other array.
Do not alias Target and Source¶
Epic's Blueprint page documents appending a source array to a target, but does
not promise a result when both pins alias the same Array storage. The native
TArray self-append contract is unsupported. Do not rely on an observed engine
version doubling the array, warning, or doing nothing.
Make the snapshot explicit when duplication is intended:
Copy = Items // Array value copy
Append Array
Target Array = Items
Source Array = Copy
Now the source is stable even if growing Target reallocates its storage. This is the structurally safe pattern across engine versions.
When an operation does nothing or warns¶
These nodes do not throw exceptions and do not run a hidden failure branch.
| Situation | Visible result | Array result |
|---|---|---|
| Set receives a negative Index | Array warning in editor/development output; execution continues | unchanged |
Set receives Index >= Length, Size to Fit false |
Array warning; execution continues | unchanged |
| Set receives a non-negative out-of-range Index, Size to Fit true | no bounds failure if the requested size is supported | grows to Index + 1, then writes |
| Resize receives a negative Size | Array warning; execution continues | unchanged |
| Clear receives an already-empty Array | no special result | remains empty |
| Append receives an empty Source | no special result | unchanged |
| Growth would exceed the engine's supported container size | development warning/no success pin | no reliable requested mutation; validate bounds yourself |
If gameplay must know that a write occurred, validate before the call and/or read the resulting Length/value afterward. The execution wire itself is not a success signal.
The patterns everyone actually uses¶
Initialize a fixed slot array once¶
BeginPlay:
Resize(HotbarSlots, 8)
AssignHotbarSlot(Index, Item):
Branch Is Valid Index(HotbarSlots, Index)
true:
Set Array Elem(Index, Item, Size to Fit = false)
One owned initialization step establishes the invariant. Later writes do not silently grow the hotbar because of a bad input index.
Grow only to a bounded requested slot¶
SetUnlockedReward(RewardIndex, Reward):
require RewardIndex >= 0 AND RewardIndex < MaxRewardSlots
Set Array Elem
Index = RewardIndex
Item = Reward
Size to Fit = true
The explicit upper bound prevents a corrupted ID from allocating a giant default-filled gap.
Rebuild a derived list, then notify once¶
RebuildVisibleItems:
Clear(VisibleItems)
Append Array(VisibleItems, EquippedItems)
Append Array(VisibleItems, BackpackItems)
Broadcast OnVisibleItemsChanged
The Array nodes only create the model shape. The final event tells presentation that one coherent rebuild is complete.
Mutate an inventory struct and write it back¶
if Inventory Is Valid Index(Index):
Entry = Inventory[Index]
Entry.Count = Entry.Count + AddedCount
Set Array Elem(Inventory, Index, Entry, Size to Fit = false)
Broadcast OnInventoryChanged
The inventory's replication, SaveGame copy, weight totals, and UI refresh stay with the system that owns Inventory rather than being implied by Set Array Elem.
Replication, SaveGame, and UI are separate¶
These Array operations mutate one in-memory variable on the machine running the graph.
- Replication: mutate authoritative gameplay arrays on the server. A replicated property can send its later state through the replication system, but the Array node itself is not an RPC and a client mutation does not upload authority.
- SaveGame: changing a runtime Array does not write a slot. Copy/serialize the intended data into a SaveGame object and call the save workflow.
- User interface: a Widget binding, ListView, or cached entry widget may not know the model changed. Broadcast one owner event and refresh/reconcile the view through its documented path.
Keep mutation plus notification in one owner function. Scattering direct Set/ Clear calls across actors makes it impossible to guarantee that derived totals, replication rules, and UI updates stay paired.
What these nodes do not do¶
They do not:
- validate gameplay meaning just because an index is numerically valid;
- use
-1as the last element; - insert or shift items when Set replaces a slot;
- de-duplicate, sort, or compact default gaps;
- update struct copies that were read earlier;
- clone objects when object references are appended;
- destroy an Actor/UObject when its reference is removed;
- guarantee a Blueprint-observable memory-capacity policy;
- replicate or save the mutation; or
- broadcast an inventory/ListView/model-changed event.
Lookalikes - which one do I want?¶
| Node | Use when | Shape/return difference |
|---|---|---|
| Set Array Elem | Replace one known slot; optionally grow to that index. | No shift and no success output. |
| Resize | Establish an exact Length. | Preserves a fitting prefix; default-fills or removes the tail. |
| Clear | The same Array should become empty. | Length becomes zero; referenced objects are not destroyed. |
| Append Array | Copy a whole source sequence onto the end. | Duplicates allowed; source unchanged; no count output. |
| Add | Append one item. | Returns the new index. |
| Add Unique | Append one item only when no equal value exists. | Equality scan; Blueprint returns -1 if already present. |
| Insert | Put one item before an index and shift the tail. | Length grows by one; later indices move. |
| Remove Index / Item | Delete one position or all equal values. | Later indices can shift left. |
| Set Array variable | Replace the entire Array value from another Array. | Expresses whole-value assignment rather than in-place concatenation. |
| Map | Sparse/stable keys retrieve values. | No giant default-filled integer gap; keys are not array positions. |
Rule of thumb: Set replaces a slot, Resize owns Length, Clear owns empty, Append copies a sequence, and Map owns sparse keys.
C++ twins¶
Original example code:
if (Items.IsValidIndex(Index))
{
Items[Index] = UpdatedItem;
}
Items.SetNum(DesiredLength); // grow with defaults or remove the tail
Items.Reset(); // logical empty; capacity policy is explicit in C++
Items.Append(MoreItems); // MoreItems must not alias Items
C++ has direct access to capacity/reserve choices and can use return values or assertions around project invariants. Blueprint's four nodes intentionally present the simpler reflected-container contract.
Going deeper¶
- Array Get / Length / Last Index / Is Valid Index - safe reads, empty arrays, copy/reference behavior, and index guards.
- Array Add / Add Unique / Insert / Remove / Find / Contains - one-item mutation, equality, return values, and shifting indices.
- Arrays, Sets, Maps, and ForEach - choose the collection shape before choosing a node.
- Add, Remove, Stack, and Broadcast Inventory Changes - the model-owner contract around primitive Array writes.
- Blueprint variables and references - value copies versus references to live UObjects.
- Is Valid - object lifetime after an index has already been proven valid.
- Replication basics - why a local container mutation and authoritative replicated state are different.
- Official docs: Resize,
Append Array,
Array Containers,
and
TArray. - Engine source (requires engine access - we do not reproduce it here):
UKismetArrayLibrary::GenericArray_Set,UKismetArrayLibrary::GenericArray_Resize,UKismetArrayLibrary::GenericArray_Clear, andUKismetArrayLibrary::GenericArray_AppendinEngine/Source/Runtime/Engine/Private/KismetArrayLibrary.cpp; Blueprint declarations and maximum-container warnings inEngine/Source/Runtime/Engine/Classes/Kismet/KismetArrayLibrary.h; generic reflected element initialization/copying inFScriptArrayHelperunderEngine/Source/Runtime/CoreUObject/Public/UObject/UnrealType.h; and nativeTArray::SetNum,TArray::Reset, andTArray::AppendinEngine/Source/Runtime/Core/Public/Containers/Array.h.