Skip to main content

Runtime Performance

When building your playable experience in Unity, and C#, it is important to keep in mind that the end result will be running in HTML5 on a web browser. As such, optimising the performance as much as possible will result in higher-performing user experiences, with better device support and ultimately, ad performance.

We've assembled a number of examples and tips which will help you identify and optimise your C# code for better runtime performance on the Luna engine.

Accessing Data

tip

Use Arrays instead of lists.

When translating lists in C# to JavaScript, there are a number of additional check (such as methods to check whether the data is out of range) which add unnecessary overhead. Therefore, we recommend that you use arrays instead of lists where possible.

An example is using LINQ in your game to loop through lists, as this can result in performance issues if this process is repetitive. Generally avoid using LINQ loops during the gameplay to iterate through lists.

Although this operation is usually fine on start, it can be expensive during the gameplay.

Functions like List<>.FindAll() methods are really expensive, we have seen these used and can cause performance lags, especially when comparing enums as this adds additional overhead.

Where ever possible try to cache references, reducing these calls eliminates the need to:

• Search the list.

• Compare the elements multiple times.

Thus improving performance.

On top of caching using a regular for loop to iterate an array is much more efficient method than using LINQ to loop through lists. So if you have to iterate through, use arrays and use regular for loops where possible.

Don't do:

public List<int> Values;

Do:

public int[] Values;

Caching

tip

Store and reuse structures as much as possible.

When your C# is transpiled to JavaScript, every call (especially for a structure) will lead to duplication in memory. Therefore you should try to store and reuse as much as possible.

Storing structures

Don't do:

for (int index = 0; index < Triangles.Count; index++)
{
var tri = Triangles[index];
// grab local variables for easier access
var vA = new Vertex(tri.idA, tri.posA, tri.uvA, tri.normalA /*, tri.tangentA, tri.colorA*/);

/* Do something with vA, having it as a temp value */
}

Do:

var count = Triangles.Length;
Triangle tri = new Triangle();
var vA = new Vertex();
for (int index = 0; index < count; index++)
{
tri.Set( Triangles[index]);
// grab local variables for easier access
vA.Set(tri.idA, tri.posA, tri.uvA, tri.normalA /*, tri.tangentA, tri.colorA*/);

/* Note here Triangle and Vertex are Structures and Set method reuses them */
}

Storing vectors

Using vector.x is very common, yet add minor overhead in JavaScript since .x is a property which must be accessed.

Don't do:

var n = plane.normal;

Do:

var normalX = plane.normal.x;
var normalY = plane.normal.y;
var normalZ = plane.normal.z;

Allocation reduction

tip

Pass structures into methods as a reference to avoid cloning.

One of the most common use cases for allocations is passing structs in/out of methods.

To improve this in JavaScript, you can make use of the specific Bridge attribute, [Ref].

For example, a heavy Triangle structure being passed into a method: Don't Do:

public void Set( Triangle triangle){**}
/* This will lead to it being cloned at the moment it is called. */

Do:

public void Set( [Ref] Triangle triangle){**}
/* This way the structure is passed as a reference and no cloning will happen.{**}
Note: To get rid of missing attribute, wrap usage and method in defines: */

#if UNITY_LUNA
using Bridge;
#endif

#if UNITY_LUNA
public void Set( [Ref] Triangle triangle);

#else
public void Set( Triangle triangle);
#endif