Quick answer: Iterate backwards with a manual For loop, or collect indices to remove during a forward pass then delete in a separate descending pass. Don’t delete mid-ForEachElement.

An inventory array holds items. Some events delete used-up items during a ForEachElement loop. Every other expired item survives the deletion sweep — consumables you should have removed sit in slots they should have left.

Why Mid-Iteration Deletes Skip

Construct’s ForEachElement walks indices 0, 1, 2, ... When you delete index N, the array shifts: what was N+1 becomes N. But the iteration counter advances to N+1 anyway — jumping over the promoted item.

If you delete items at positions 0, 2, 4 in a 6-element array, only positions 0 and 2 actually get hit because each deletion shifts the array but the index keeps marching forward.

Fix 1: Iterate Backwards

// Backwards For loop — safe for deletion
For "i" from Array.Width - 1 to 0:
    if Array.At(loopindex("i")) == 0:
        Array Delete index loopindex("i") on X axis

Deleting at index i shifts only indices > i. Since we iterate down, we never visit those shifted indices, so the iteration stays correct.

Fix 2: Collect-Then-Delete

// Pass 1: identify indices to remove
Local List ToRemove = ""
Array For each element:
    if Array.CurValue == 0:
        ToRemove Add item Array.CurX

// Pass 2: delete in descending order
For "j" from ToRemove.ItemCount - 1 to 0:
    Array Delete index ToRemove.AtIndex(loopindex("j")) on X axis

Pass 1 uses ForEachElement safely (no mutation). Pass 2 walks the removal list backwards to avoid shifting issues.

Why Sort by Index Descending

If your removal indices are [2, 4, 6] and you delete in that order:

  1. Delete index 2: array shifts; original indices 4 and 6 are now at positions 3 and 5.
  2. You delete index 4 next — but the intended item is at 3.

Reversed order [6, 4, 2]:

  1. Delete index 6: nothing at lower indices shifts.
  2. Delete index 4: still correct because index 2 hasn’t shifted.
  3. Delete index 2: correct.

This generalizes to any mutation that removes elements — always work from the highest index down.

Alternative: Filter into a New Array

// Build a new array of survivors
NewArray Clear
Array For each element:
    if Array.CurValue != 0:
        NewArray Push back Array.CurValue on X axis

// Swap
Array Set size NewArray.Width
Array Copy NewArray

Functional-style. Allocates a second array; clearer for complex filter logic.

Verifying

Build an array [1, 0, 2, 0, 3, 0] and remove zeros. Final array should be [1, 2, 3]. If you get [1, 2, 0] or [1, 0, 3], you have the skip bug — apply Fix 1 or Fix 2.

“Mutating during iteration always invites bugs. Backwards loop or two-pass is the universal fix.”

Make “backwards-for to delete” a reflex — saves you reaching for the debugger every time array filtering goes wrong.