Skip to content

Arrays

An array holds a fixed number of values of the same type, decided in advance. The length can’t change afterward.

List and Dictionary aren’t available, so arrays hold multiple values together.

SyntaxDescription
new int[4]Generation with a fixed length
new int[count]Generation with the length from a variable
new int[] { 1, 2, 3 }Generation with listed initial values
int[] a = { 1, 2, 3 }Initialization at declaration
new[] { 1, 2, 3 }Inferring the element type
var a = new int[4]Inferring the variable’s type
new int[4][]Generating a jagged array
new int[][] { ... }Initializing a jagged array
new int[2][][]3 levels of nesting
new int[2][][][]4 levels of nesting
new int[4, 4]Generating a 2D array
new string[4]Element is a reference type
new Vector3[4]Element is a struct
new GameObject[4]Element is a runtime type
a[0] = 10Writing to an element
int x = a[0]Reading an element
a[0] += 10Compound assignment
a[0]++Increment and decrement
a[i] = 10Specifying the index with a variable
a[^1]Index from the end
a[1..]Slicing a range
points[0].x = 5fWriting to a field of a struct element
Vector3 v = points[0]Retrieving a struct element
a.LengthGetting the element count
a.RankGetting the rank
a.GetLength(0)Getting the length of a given dimension
a.GetValue(0)Reading regardless of type
a.SetValue(9, 0)Writing regardless of type
a.Clone()Cloning
System.Array.Copy(a, b, 3)Copying to another array
System.Array.Clear(a, 0, 3)Clearing a range
foreach (int v in a)Iterating all elements
foreach (var v in a)Iteration with the type inferred
for (int i = 0; i < a.Length; i++)Iteration by index
private int[] bufferHolding as a field
public GameObject[] targetsAssigning via a public field
[UdonSynced] private int[] valuesSync
Fill(scores)Passing as an argument
params int[] valuesReceiving as a variable number of arguments
int[] Make()Returning as a return value
int[] alias = originalAssigning to another variable
a == nullComparing with null
object boxed = scoresStoring in object
object[] boxes = namesAssigning to an array with a wider element type
boxes[0] = scoresStoring in an element of an object array
other.SetProgramVariable("values", a)Writing by specifying a name
(int[])other.GetProgramVariable("values")Reading by specifying a name
SendCustomNetworkEvent(..., a)Specifying as an argument to a network event
SyntaxDescriptionErrorReason
int[,,] a = new int[2, 2, 2];Multidimensional arrays with 3 or more dimensionsTUKI0001not yet
new int[2, 2] { { 1, 2 }, { 3, 4 } }Listed initial values for a 2D arrayTUKI0001undecided
foreach (int v in grid)Iterating a 2D arrayTUKI0001by design
Swap(ref a)Passing to your own method with refTUKI0001runtime
Make(out int[] b)Receiving from your own method with outTUKI0001runtime
Bump(ref a[0])Passing an element with refTUKI0001runtime
boxed is Vector3[]Type test for whether something is an array typeTUKI0001not yet
System.Array.IndexOf(a, 1)Finding an elementTUKI0001not yet
System.Array.Reverse(a)Reversing the orderTUKI0001not yet
System.Array.Sort(a)SortingTUKI0001not yet
System.Array.Resize(ref a, 5)Changing the lengthTUKI0001undecided
new List<int>()List (variable-length sequence)TUKI0102, TUKI0101runtime
new Dictionary<int, int>()DictionaryTUKI0102, TUKI0101runtime
using System.Linq;LINQ query expressionsCS0234 (the namespace itself doesn’t exist)runtime
foreach (int v in list)Iterating something other than an arrayTUKI0001, TUKI0101, TUKI0102runtime
s[^1]Index from the end of a stringTUKI0001not yet
points[1..]Slicing an array of structsTUKI0001not yet
System.Index i = 0;A type that represents a positionTUKI0102, TUKI0101, TUKI0099runtime
System.Range r = 0..1;A type that represents a rangeTUKI0102, TUKI0099runtime
Form you want to useAlternative
ListAn array sized larger than needed, plus a variable for how many are in use
DictionaryIf the key is a small integer or an enum, an array indexed by the key. Otherwise, hold a key array and a value array as a pair and search through them in order.
Arrays with 3 or more dimensionsA jagged array (int[2][][]), or a single array using z * w * h + y * w + x
Iterating a 2D arrayA nested for using GetLength(0) and GetLength(1)
Rewriting with ref/outPass the array and rewrite its contents, or return it as a return value
using UnityEngine;
using Tsukimi;
public class ArraysDeclareFixedLength : TsukimiBehaviour
{
private int[] scores;
void Start()
{
scores = new int[4];
}
}

Generation with the length from a variable

Section titled “Generation with the length from a variable”
using UnityEngine;
using Tsukimi;
public class ArraysDeclareVariableLength : TsukimiBehaviour
{
public int count = 4;
private int[] scores;
void Start()
{
scores = new int[count];
scores[0] = 10;
}
}
using UnityEngine;
using Tsukimi;
public class ArraysDeclareInitializer : TsukimiBehaviour
{
private int[] scores;
void Start()
{
scores = new int[] { 1, 2, 3 };
}
}

You can omit new int[] when writing it at the same time as the declaration.

using UnityEngine;
using Tsukimi;
public class ArraysDeclareShortInitializer : TsukimiBehaviour
{
private int[] scores = { 1, 2, 3 };
void Start()
{
scores[0] = 10;
}
}
using UnityEngine;
using Tsukimi;
public class ArraysDeclareInferredInitializer : TsukimiBehaviour
{
private int[] scores;
void Start()
{
scores = new[] { 1, 2, 3 };
}
}
using UnityEngine;
using Tsukimi;
public class ArraysDeclareVar : TsukimiBehaviour
{
private int[] scores;
void Start()
{
var made = new int[4];
made[0] = 10;
scores = made;
}
}
using UnityEngine;
using Tsukimi;
public class ArraysDeclareJagged : TsukimiBehaviour
{
private int[][] grid;
void Start()
{
grid = new int[4][];
Debug.Log(grid[0] == null); // => true
grid[0] = new int[4];
grid[0][0] = 1;
Debug.Log(grid[0][0]); // => 1
}
}
using UnityEngine;
using Tsukimi;
public class ArraysDeclareJaggedInitializer : TsukimiBehaviour
{
private int[][] grid;
void Start()
{
grid = new int[][] { new int[] { 1, 2 }, new int[] { 3 } };
grid[0][0] = 10;
}
}
using UnityEngine;
using Tsukimi;
public class ArraysDeclareJaggedThreeLevels : TsukimiBehaviour
{
private int[][][] deep;
void Start()
{
deep = new int[2][][];
deep[0] = new int[2][];
deep[0][0] = new int[2];
deep[0][0][0] = 1;
}
}

There’s no limit to the number of levels.

using UnityEngine;
using Tsukimi;
public class ArraysDeclareJaggedFourLevels : TsukimiBehaviour
{
private int[][][][] deep;
void Start()
{
deep = new int[2][][][];
deep[0] = new int[2][][];
deep[0][0] = new int[2][];
deep[0][0][0] = new int[2];
deep[0][0][0][0] = 1;
Debug.Log(deep[0][0][0][0]); // => 1
}
}

There are at most 2 dimensions. Elements go into and out of a box one at a time, so it takes more instructions than a same-sized 1D array or jagged array.

using UnityEngine;
using Tsukimi;
public class ArraysMultidimensional : TsukimiBehaviour
{
void Start()
{
int[,] grid = new int[4, 4];
grid[0, 0] = 1;
Debug.Log(grid[0, 0]); // => 1
Debug.Log(grid.GetLength(1)); // => 4
}
}
using UnityEngine;
using Tsukimi;
public class ArraysElementReferenceType : TsukimiBehaviour
{
private string[] names;
void Start()
{
names = new string[4];
Debug.Log(names[0] == null); // => true
names[0] = "hello";
Debug.Log(names[0]); // => "hello"
}
}
using UnityEngine;
using Tsukimi;
public class ArraysElementStructType : TsukimiBehaviour
{
void Start()
{
Vector3[] points = new Vector3[4];
points[0] = new Vector3(1f, 2f, 3f);
}
}

Types the runtime exposes can also be elements.

using UnityEngine;
using Tsukimi;
public class ArraysElementObjectType : TsukimiBehaviour
{
void Start()
{
GameObject[] targets = new GameObject[4];
targets[0] = gameObject;
}
}
using UnityEngine;
using Tsukimi;
public class ArraysWriteElement : TsukimiBehaviour
{
private int[] scores;
void Start()
{
scores = new int[4];
scores[0] = 10;
}
}
using UnityEngine;
using Tsukimi;
public class ArraysReadElement : TsukimiBehaviour
{
void Start()
{
int[] scores = new int[] { 1, 2, 3 };
int first = scores[0];
Debug.Log(first); // => 1
}
}
using UnityEngine;
using Tsukimi;
public class ArraysCompoundAssign : TsukimiBehaviour
{
private int[] scores;
void Start()
{
scores = new int[4];
scores[0] += 10;
}
}
using UnityEngine;
using Tsukimi;
public class ArraysIncrementElement : TsukimiBehaviour
{
private int[] scores;
void Start()
{
scores = new int[4];
scores[0]++;
}
}
using UnityEngine;
using Tsukimi;
public class ArraysIndexByVariable : TsukimiBehaviour
{
private int[] scores;
void Start()
{
scores = new int[] { 1, 2, 3 };
int i = 1;
scores[i] = 10;
}
}

^1 is the last element. It points to the same position as a[a.Length - 1].

using UnityEngine;
using Tsukimi;
public class ArraysIndexFromEnd : TsukimiBehaviour
{
void Start()
{
int[] a = { 1, 2, 3 };
Debug.Log(a[^1]); // => 3
}
}

A new array is created, and the elements in the given range are copied into it. The original array doesn’t change.

using UnityEngine;
using Tsukimi;
public class ArraysRangeSlice : TsukimiBehaviour
{
void Start()
{
int[] a = { 1, 2, 3 };
int[] b = a[1..];
Debug.Log(b.Length); // => 2
Debug.Log(b[0]); // => 2
}
}
using UnityEngine;
using Tsukimi;
public class ArraysStructElementFieldWrite : TsukimiBehaviour
{
void Start()
{
Vector3[] points = new Vector3[4];
points[0].x = 5f;
}
}

What goes into the variable is a copy, so changing that variable doesn’t change the array’s element.

using UnityEngine;
using Tsukimi;
public class ArraysCopyStructElement : TsukimiBehaviour
{
void Start()
{
Vector3[] points = new Vector3[4];
Vector3 copy = points[0];
copy.y = 9f;
Debug.Log(copy); // => runtime value
}
}
using UnityEngine;
using Tsukimi;
public class ArraysLength : TsukimiBehaviour
{
void Start()
{
int[] scores = new int[4];
int n = scores.Length;
Debug.Log(n); // => 4
}
}
using UnityEngine;
using Tsukimi;
public class ArraysRank : TsukimiBehaviour
{
void Start()
{
int[] scores = new int[4];
int r = scores.Rank;
Debug.Log(r); // => 1
}
}
using UnityEngine;
using Tsukimi;
public class ArraysGetLength : TsukimiBehaviour
{
void Start()
{
int[] scores = new int[4];
int n = scores.GetLength(0);
Debug.Log(n); // => 4
}
}

The return value is object, so you need to convert it before use.

using UnityEngine;
using Tsukimi;
public class ArraysGetValue : TsukimiBehaviour
{
void Start()
{
int[] scores = new int[] { 1, 2, 3 };
object first = scores.GetValue(0);
Debug.Log(first); // => 1
}
}
using UnityEngine;
using Tsukimi;
public class ArraysSetValue : TsukimiBehaviour
{
private int[] scores;
void Start()
{
scores = new int[3];
scores.SetValue(9, 0);
}
}

The return value is object, so you need to convert it before use.

using UnityEngine;
using Tsukimi;
public class ArraysClone : TsukimiBehaviour
{
void Start()
{
int[] scores = new int[] { 1, 2, 3 };
object copy = scores.Clone();
Debug.Log(copy); // => System.Object[]
}
}
using UnityEngine;
using Tsukimi;
public class ArraysArrayCopy : TsukimiBehaviour
{
private int[] destination;
void Start()
{
int[] source = new int[] { 1, 2, 3 };
destination = new int[3];
System.Array.Copy(source, destination, 3);
}
}
using UnityEngine;
using Tsukimi;
public class ArraysArrayClear : TsukimiBehaviour
{
void Start()
{
int[] scores = new int[] { 1, 2, 3 };
System.Array.Clear(scores, 0, 3);
}
}
using UnityEngine;
using Tsukimi;
public class ArraysForeach : TsukimiBehaviour
{
void Start()
{
int[] scores = new int[] { 1, 2, 3 };
int sum = 0;
foreach (int v in scores)
{
sum += v;
}
Debug.Log(sum); // => 6
}
}
using UnityEngine;
using Tsukimi;
public class ArraysForeachVar : TsukimiBehaviour
{
void Start()
{
int[] scores = new int[] { 1, 2, 3 };
int sum = 0;
foreach (var v in scores)
{
sum += v;
}
Debug.Log(sum); // => 6
}
}
using UnityEngine;
using Tsukimi;
public class ArraysForIndex : TsukimiBehaviour
{
void Start()
{
int[] scores = new int[] { 1, 2, 3 };
int sum = 0;
for (int i = 0; i < scores.Length; i++)
{
sum += scores[i];
}
Debug.Log(sum); // => 6
}
}
using UnityEngine;
using Tsukimi;
public class ArraysFieldPrivate : TsukimiBehaviour
{
private int[] buffer;
void Start()
{
buffer = new int[16];
buffer[0] = 10;
}
}

A public field appears in the inspector, and you can set its value there.

using UnityEngine;
using Tsukimi;
public class ArraysFieldPublic : TsukimiBehaviour
{
public GameObject[] targets;
void Start()
{
targets[0] = gameObject;
}
}

If you don’t specify a sync method, it uses the default method.

using UnityEngine;
using Tsukimi;
public class ArraysFieldSynced : TsukimiBehaviour
{
[UdonSynced] private int[] values = new int[4];
void Start()
{
values[0] = 10;
RequestSerialization();
}
}
using UnityEngine;
using Tsukimi;
public class ArraysPassAsArgument : TsukimiBehaviour
{
private int[] scores;
void Start()
{
scores = new int[] { 1, 2, 3 };
Fill(scores);
}
private void Fill(int[] target)
{
target[0] = 10;
}
}

Receiving as a variable number of arguments

Section titled “Receiving as a variable number of arguments”
using UnityEngine;
using Tsukimi;
public class ArraysParamsParameter : TsukimiBehaviour
{
void Start()
{
int total = Total(1, 2, 3);
Debug.Log(total); // => 6
}
private int Total(params int[] values)
{
int sum = 0;
for (int i = 0; i < values.Length; i++)
{
sum += values[i];
}
return sum;
}
}
using UnityEngine;
using Tsukimi;
public class ArraysReturnFromMethod : TsukimiBehaviour
{
private int[] scores;
void Start()
{
scores = Make();
scores[0] = 10;
}
private int[] Make()
{
return new int[4];
}
}
using UnityEngine;
using Tsukimi;
public class ArraysAliasSharesReference : TsukimiBehaviour
{
void Start()
{
int[] original = new int[4];
int[] alias = original;
alias[0] = 10;
Debug.Log(original[0]); // => 10
}
}
using UnityEngine;
using Tsukimi;
public class ArraysCompareToNull : TsukimiBehaviour
{
private int[] buffer;
void Start()
{
Debug.Log(buffer == null); // => true
if (buffer == null)
{
buffer = new int[4];
}
Debug.Log(buffer.Length); // => 4
}
}

An array is a reference, so it goes into an object variable as is.

using UnityEngine;
using Tsukimi;
public class ArraysStoreInObject : TsukimiBehaviour
{
void Start()
{
int[] scores = new int[4];
object boxed = scores;
Debug.Log(boxed); // => System.Object[]
}
}

Assigning to an array with a wider element type

Section titled “Assigning to an array with a wider element type”

string[] can be treated as object[]. This only works in the direction that widens the element type.

using UnityEngine;
using Tsukimi;
public class ArraysCovariantAssign : TsukimiBehaviour
{
void Start()
{
string[] names = new string[4];
object[] boxes = names;
Debug.Log(boxes.Length); // => 4
}
}
using UnityEngine;
using Tsukimi;
public class ArraysElementInObjectArray : TsukimiBehaviour
{
private object[] boxes;
void Start()
{
int[] scores = new int[4];
boxes = new object[2];
boxes[0] = scores;
}
}

Specify the other Behaviour’s variable name as a string to write the array.

using UnityEngine;
using Tsukimi;
public class ArraysSetProgramVariable : TsukimiBehaviour
{
public TsukimiBehaviour other;
void Start()
{
int[] scores = new int[] { 1, 2, 3 };
other.SetProgramVariable("values", scores);
}
}

The return value is object, so you need to convert it when you receive it.

using UnityEngine;
using Tsukimi;
public class ArraysGetProgramVariable : TsukimiBehaviour
{
public TsukimiBehaviour other;
void Start()
{
int[] got = (int[])other.GetProgramVariable("values");
Debug.Log(got.Length);
}
}

Specifying as an argument to a network event

Section titled “Specifying as an argument to a network event”

If you add [NetworkCallable] to the receiving method, you can pass an array as an argument.

using UnityEngine;
using Tsukimi;
using VRC.Udon.Common.Interfaces;
using VRC.SDK3.UdonNetworkCalling;
public class ArraysSendAsNetworkEvent : TsukimiBehaviour
{
private int[] scores;
void Start()
{
scores = new int[] { 1, 2, 3 };
SendCustomNetworkEvent(NetworkEventTarget.All, nameof(Receive), scores);
}
[NetworkCallable]
public void Receive(int[] values)
{
Debug.Log(values.Length);
}
}