Delegates, Action Delegates, Func Delegates, and Lambda Expressions

Delegates

A delegate is a type that safely encapsulates a method, similar to a function pointer in C and C++. Unlike C function pointers, delegates are object-oriented, type safe, and secure. The type of a delegate is defined by the name of the delegate. A Delegate can be thought of as a reference pointer to an object/method. When it gets called, it notifies all methods that reference the delegate.

Delegate Multicast Example (+=):

using UnityEngine;
using System.Collections;

public class MulticastScript : MonoBehaviour 
{
    delegate void MultiDelegate();
    MultiDelegate myMultiDelegate;
    

    void Start () 
    {
        myMultiDelegate += PowerUp;
        myMultiDelegate += TurnRed;
        
        if(myMultiDelegate != null)
        {
            myMultiDelegate();
        }
    }
    
    void PowerUp()
    {
        print ("Orb is powering up!");
    }
    
    void TurnRed()
    {
        renderer.material.color = Color.red;
    }
}

Action Delegates

You can use the Action(Of T) delegate to pass a method as a parameter without explicitly declaring a custom delegate. The benefit here is you don’t have to declare a delegate. The compiler is smart enough to figure out the proper types.

However there is a limitation, the corresponding method action must not return a value. (In C#, the method must return void.)

Action Delegate Example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ModernLanguageConstructs
{
    class Program
    {
        static void Main(string[] args)
        {
            // Part 1 - First action that takes an int and converts it to hex
            Action<int> displayHex = delegate(int intValue)
            {
                Console.WriteLine(intValue.ToString("X"));
            };

            // Part 2 - Second action that takes a hex string and 
            // converts it to an int
            Action<string> displayInteger = delegate(string hexValue)
            {
                Console.WriteLine(int.Parse(hexValue,
                    System.Globalization.NumberStyles.HexNumber));
            };
            
            // Part 3 - exercise Action methods
            displayHex(16);
            displayInteger("10");
        }
    }
}

Func Delegates
This differs from Action<> in the sense that it supports parameters AND return values.
You can use this delegate to represent a method that can be passed as a parameter without explicitly declaring a custom delegate. The encapsulated method must correspond to the method signature that is defined by this delegate.
This means that the encapsulated method must have one parameter that is passed to it by value, and that it must return a value.
Func Delegate Example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ModernLanguageConstructs
{
    class Program
    {
        static void Main(string[] args)
        {
            // Part 1 - First Func&lt;&gt; that takes an int and returns a string
            Func&lt;int, string&gt; displayHex = delegate(int intValue)
            {
                return (intValue.ToString("X"));
            };

            // Part 2 - Second Func&lt;&gt; that takes a hex string and 
            // returns an int
            Func&lt;string, int&gt; displayInteger = delegate(string hexValue)
            {
                return (int.Parse(hexValue,
                    System.Globalization.NumberStyles.HexNumber));
            };

            // Part 3 - exercise Func&lt;&gt; delegates
            Console.WriteLine(displayHex(16));
            Console.WriteLine(displayInteger("10"));
        }
    }
}
 Lambda Expressions
A lambda expression is an anonymous function that can contain expressions and statements, and can be used to create delegates or expression tree types.
All lambda expressions use the lambda operator =>, which is read as “goes to”. The left side of the lambda operator specifies the input parameters (if any) and the right side holds the expression or statement block.
The lambda expression x => x * x is read “x goes to x times x.”
Lambda Expression Example:
private IEnumerator waitThenCallback(float time, Action callback)
{
   yield return new WaitForSeconds(time);
   callback();
}

void Start()
{
  splashScreen.show();

  StartCoroutine(waitThenCallback(5, () =&gt; 
         { Debug.Log("Five seconds have passed!"); }));
  StartCoroutine(waitThenCallback(10, () =&gt; 
         { Debug.Log("Ten seconds have passed!"); }));
  StartCoroutine(waitThenCallback(20, () =&gt; 
  {
    Debug.Log("Twenty seconds have passed!"); 
    splashScreen.hide();
  }));
}
Another Lambda Expression Example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ModernLanguageConstructs
{
    class Program
    {
        static void Main(string[] args)
        {
            // Part 1 - An action and a lambda
            Action&lt;int&gt; displayHex = intValue =&gt;
            {
                Console.WriteLine(intValue.ToString("X"));
            };

            Action&lt;string&gt; displayInteger = hexValue =&gt;
            {
                Console.WriteLine(int.Parse(hexValue,
                    System.Globalization.NumberStyles.HexNumber));
            };

            // Part 2 - Use the lambda expressions
            displayHex(16);
            displayInteger("10");

        }
    }
}

Communicate with Comments

/// Comments

After declaring the public method or field,  enter “///” in the line above it, that will auto fill a comment block. This will also enable hover help text.

Summary Comment Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// &lt;summary&gt;
/// Initializes a new instance of the &lt;see cref="EnemyLoader"/&gt; class.
/// &lt;/summary&gt;
/// &lt;param name='enemyName'&gt;
/// Enemy name. e.g evilfrog bustyfox
/// &lt;/param&gt;
/// &lt;param name='successCallback'&gt;
/// Success callback.
/// &lt;/param&gt;
/// &lt;param name='failureCallback'&gt;
/// Failure callback.
/// &lt;/param&gt;
public EnemyLoader( string enemyName, LoadSuccess successCallback, LoadFailure failureCallback)

Code Comment Example:

Bad Good
// increment enemies // we know there is now another enemy
enemies++; enemies++;

Enums and Bitwise operators

Enums and Unity Editor

How to make life easier by making enum flags into mask fields in the Unity inspector.

EnumFlagAttribute.cs [Must be placed in a folder that is not Editor]

using UnityEngine;

public class EnumFlagAttribute : PropertyAttribute
{
 public string enumName;

 public EnumFlagAttribute() {}

 public EnumFlagAttribute(string name)
 {
    enumName = name;
 }
}

EnumFlagsAttributeDrawer.cs [Must be placed in the Editor folder]

using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(EnumFlagAttribute))]
public class EnumFlagDrawer : PropertyDrawer {
 public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
 {
    EnumFlagAttribute flagSettings = (EnumFlagAttribute)attribute;
    Enum targetEnum = GetBaseProperty&lt;Enum&gt;(property);

    string propName = flagSettings.enumName;
    if (string.IsNullOrEmpty(propName))
    propName = property.name;

    EditorGUI.BeginProperty(position, label, property);
    Enum enumNew = EditorGUI.EnumMaskField(position, propName,   
    targetEnum);
    property.intValue = (int) Convert.ChangeType(enumNew,  
    targetEnum.GetType());

    EditorGUI.EndProperty();
 }

 static T GetBaseProperty&lt;T&gt;(SerializedProperty prop)
 {
    // Separate the steps it takes to get to this property
    string[] separatedPaths = prop.propertyPath.Split('.');

    // Go down to the root of this serialized property
    System.Object reflectionTarget =   
    prop.serializedObject.targetObject as object;
    // Walk down the path to get the target object
    foreach (var path in separatedPaths)
    {
       FieldInfo fieldInfo =  
       reflectionTarget.GetType().GetField(path);
       reflectionTarget = fieldInfo.GetValue(reflectionTarget);
    }
    return (T) reflectionTarget;
 }
}

It is important to note that Enum definition should also use power-of-two values. Bitwise shifts achieve this, they basically shift the bits of a number right (>>) or left (<<). If you have a decimal number, let’s say “1” and you shift it of one position to the left, you’ll have “10”. Another shift and you’ll get “100”. If shifting one position in base ten is equivalent to multiply (or divide) by ten, shifting one position in base two is equivalent to multiply (or divide) by two. This is why bitwise shifts can be used to easily create powers of two.

Test.cs [Attach this to a gameObject to see the property drawer in action]

using UnityEngine;
using System.Collections;
using System;

public enum MyEnum
{                      //BINARY DEC
  None = 0 &lt;&lt; 0,     //000000 0
  First = 1 &lt;&lt; 1,    //000001 1
  Second = 1 &lt;&lt; 2,   //000010 2
  Third = 1 &lt;&lt; 3,    //000100 4
  Fourth = 1 &lt;&lt; 4,   //001000 8
  Fifth = 1 &lt;&lt; 5,
  Sixth = 1 &lt;&lt; 6,
  Seventh = 1 &lt;&lt; 7,
  Eighth = 1 &lt;&lt; 8,
}

public class Test : MonoBehaviour 
{
  [EnumFlagAttribute]
  public MyEnum m_enum;

  public MyEnum m_lastEnum;
  public void Update()
  {
    if (m_lastEnum != m_enum) 
    {
      Debug.Log (m_enum);
      m_lastEnum = m_enum;
      if ((m_enum &amp; MyEnum.Fourth) != 0) 
                        {
        Debug.Log ("HAS FOURTH");
      }

    }
  }
}

Agile

Agile isn’t what you do, it’s how you do it. Agile is not about having a strict list of tasks and rules. It is about finding methods that work best for your team/company, and using them. At its core it is about cutting inefficient practices and adopting more efficient ones.

The Core values of any true Agile Methodology

Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration over contract negotiation
Responding to change over following a plan

It is important to realise that while Scrum and Kanban are agile frameworks, they are not what agile is.  They can lead to benefits but it depends on how you are using them. Do not fit the team to the framework, adapt the framework to the team.

The Twelve principles of the Agile Manifesto

  1. Our highest priority is to satisfy the customer
    through early and continuous delivery
    of valuable software.
  2. Welcome changing requirements, even late in
    development. Agile processes harness change for
    the customer’s competitive advantage.
  3. Deliver working software frequently, from a
    couple of weeks to a couple of months, with a
    preference to the shorter timescale.
  4. Business people and developers must work
    together daily throughout the project.
  5. Build projects around motivated individuals.
    Give them the environment and support they need,
    and trust them to get the job done.
  6. The most efficient and effective method of
    conveying information to and within a development
    team is face-to-face conversation.
  7. Working software is the primary measure of progress.
  8. Agile processes promote sustainable development.
    The sponsors, developers, and users should be able
    to maintain a constant pace indefinitely.
  9. Continuous attention to technical excellence
    and good design enhances agility.
  10. Simplicity–the art of maximizing the amount
    of work not done–is essential.
  11. The best architectures, requirements, and designs
    emerge from self-organizing teams.
  12. At regular intervals, the team reflects on how
    to become more effective, then tunes and adjusts
    its behavior accordingly.

Automated Deployment in Unity

The automated deployment process of an application is critical to achieving the Continuous Delivery approach. CD is about helping teams or individuals build, test, and release faster and more reliably. Essential to automated deployment is the Build Automation server which plays a major part in a solid Continuous Delivery Deployment Pipeline. A deployment pipeline is basically an automated implementation of your application’s build, deploy, test and release process.

AutoDeployment

Unity has finally come out with a built in solution to build automation, Unity Cloud Build. You simply:

  • Setup a repo (.git BitBucket) and commit your Unity Project files
  • Create/Activate Unity Cloud Build from the services window
  • Copy the repo url into the Unity Cloud Build window (Window – Services – Cloud Build)
  • Setup Access Rights if the repo is private by adding an SSH key created by Unity Cloud Build to your BitBucket repo
  • Configure your Unity Cloud Build – Select platform, select branch of repo to build from
  • Build

From here Unity Cloud Build will watch your repo for new changes. Once a change has been detected the project will start building. Once complete, emails are sent out with links to install on your devices.

UnityCloudBuildPipeline

What is the difference between a Library and a Framework?

Library
A library contains many pieces of functionality that can be individually selected and used. The pieces do not depend upon one another and so you are not locked into functionality you do not want. Ultimately this means you are not bound to a workflow and the code base is more adaptable to change.

Framework
A framework unlike a library sets out strictly how you will be working. It provides a workflow that can add value however is hard to change. Frameworks can speed up development allowing rapid development however they can result in changes required being impossible to implement.

Anonymous Functions – Closure Callbacks

Here is an example of anonymous functions in unity, below is a very helpful technique around loading assets and then setting a delegate to grab that loaded asset. Below, take note of the ‘closure’ delegate, which is being passed into the asset bundle manager load function as the second parameter. Because the delegate was defined inside the loop it forms closure around the variable ‘i’ which would usually not exist. When each bundle is loaded the callback will trigger and the asset will be placed at the correct index in the array.


for(int i=0; i < things.Length; i++)
{
    AssetBundleManager.Load(thingNames[i], delegate (AssetBundle bundle)
    {
        characters[i] = bundle.Load(thingNames[i] + "LOD0")
    });
}

Optimising Unity games for Mobile

Optimise for CPU and GPU

CPU

CPU is often limited by the number of batches that need to be rendered. “Batching” is where the engine attempts to combine the rendering of multiple objects into a chunk of memory in order to reduce CPU overhead due to resources switching.

To draw an object on the screen, the engine has to issue a draw call to the graphics API (e.g. OpenGL or Direct3D). Draw calls are often expensive, with the graphics API doing significant work for every draw call, causing performance overhead on the CPU side. This is mostly caused by the state changes done between the draw calls (e.g. switching to a different material), which causes expensive validation and translation steps in the graphics driver.

Basically draw calls are the commands that tells the GPU to render a certain set of vertices as triangles with a certain state (shaders, blend state and so on). It should be noted that draw calls aren’t necessarily expensive. In older versions of Direct3D, many calls required a context switch, which was expensive, but this isn’t true in newer versions. The main reason to make fewer draw calls is that graphics hardware can transform and render triangles much faster than you can submit them. If you submit few triangles with each call, you will be completely bound by the CPU and the GPU will be mostly idle. The CPU won’t be able to feed the GPU fast enough. Making a single draw call with two triangles is cheap, but if you submit too little data with each call, you won’t have enough CPU time to submit as much geometry to the GPU as you could have.

There are some real costs with making draw calls, it requires setting up a bunch of state (which set of vertices to use, what shader to use and so on), and state changes have a cost both on the hardware side (updating a bunch of registers) and on the driver side (validating and translating your calls that set state).

Unity uses static batching and dynamic batching to address this.

  • Static Batching: combine static (i.e. not moving) objects into big meshes, and render them in a faster way.

Internally, static batching works by transforming the static objects into world space and building a big vertex + index buffer for them. Then for visible objects in the same batch, a series of “cheap” draw calls are done, with almost no state changes in between. So technically it does not save “3D API draw calls”, but it saves on state changes done between them (which is the expensive part).

  • Dynamic Batching: for small enough meshes, transform their vertices on the CPU, group many similar ones together, and draw in one go.

Built-in batching has several benefits compared to manually merging objects together (most notably, the objects can still be culled individually). But it also has some downsides too (static batching incurs memory and storage overhead; and dynamic batching incurs some CPU overhead). Only objects sharing the same material can be batched together. Therefore, if you want to achieve good batching, you need to share as many materials among different objects as possible.

If you have two identical materials which differ only in textures, you can combine those textures into a single big texture – a process often called texture atlasing. Once textures are in the same atlas, you can use a single material instead.

Currently, only Mesh Renderers are batched. This means that skinned meshes, cloth, trail renderers and other types of rendering components are not batched.

Semitransparent shaders most often require objects to be rendered in back-to-front order for transparency to work. Unity first orders objects in this order, and then tries to batch them – but because the order must be strictly satisfied, this often means less batching can be achieved than with opaque objects.

Manually combining objects that are close to each other might be a very good alternative to draw call batching. For example, a static cupboard with lots of drawers often makes sense to just combine into a single mesh, either in a 3D modeling application or using Mesh.CombineMeshes.

 

GPU

GPU is often limited by fillrate or memory bandwidth. If running the game at a lower display resolution makes it faster then you’re most likely limited by fillrate on the GPU. Fill rate refers to the number of pixels that a video card can render or write to memory every second. It is measured in megapixels or gigapixels per second, which is obtained by multiplying the clock frequency of the graphics processing unit (GPU) by the number of raster operations (ROPs).

 

Textures – Texture Size, Compression, Atlases and MipMaps

Optimal Texture Type – PNG is the lesser of many evils. It does lossless image compression compared to lossy JPEG compression, it doesn’t do alpha as great as TGA does – but it does do compression and alpha mapping good enough to make it better than the other file types.

Texture Compression –  ETC texture compression, however doesn’t support alpha channels. If alpha then go with uncompressed.

You should always have mipmaps checked if you’re using 3D, because otherwise you get awful artifacts when the camera moves, plus it runs faster since it doesn’t have to calculate so many pixels for distant objects. Other than looking slightly blurry compared to not having mipmaps, there shouldn’t be any downsides, and the slight blurriness is more than compensated for by the lack of flickering texture artifacts. You can use trilinear filtering so that the transition between mipmap levels is smooth. If you have any serious degradation with mipmaps, that’s not normal

To create Texture Atlases use Texture Packer Tool with the standalone version

http://www.codeandweb.com/texturepacker/download

https://www.assetstore.unity3d.com/en/#!/content/8905

 

Models – Triangle Count and UV Map

  • Don’t use any more triangles than necessary
  • Try to keep the number of UV mapping seams and hard edges (doubled-up vertices) as low as possible

You should use only a single skinned mesh renderer for each character. Unity optimizes animation using visibility culling and bounding volume updates and these optimizations are only activated if you use one animation component and one skinned mesh renderer in conjunction. The rendering time for a model could roughly double as a result of using two skinned meshes in place of a single mesh and there is seldom any practical advantage in using multiple meshes.

When animating use as few bones as possible

A bone hierarchy in a typical desktop game uses somewhere between fifteen and sixty bones. The fewer bones you use, the better the performance will be. You can achieve very good quality on desktop platforms and fairly good quality on mobile platforms with about thirty bones. Ideally, keep the number below thirty for mobile devices and don’t go too far above thirty for desktop games.

Use as few materials as possible

You should also keep the number of materials on each mesh as low as possible. The only reason why you might want to have more than one material on a character is that you need to use different shaders for different parts (eg, a special shader for the eyes). However, two or three materials per character should be sufficient in almost all cases.

 

Culling and LOD (Level of Detail)

Occlusion Culling is a feature that disables rendering of objects when they are not currently seen by the camera because they are obscured (occluded) by other objects. This does not happen automatically in 3D computer graphics since most of the time objects farthest away from the camera are drawn first and closer objects are drawn over the top of them (this is called “overdraw”). Occlusion Culling is different from Frustum Culling. Frustum Culling only disables the renderers for objects that are outside the camera’s viewing area but does not disable anything hidden from view by overdraw. Note that when you use Occlusion Culling you will still benefit from Frustum Culling.

The occlusion culling process will go through the scene using a virtual camera to build a hierarchy of potentially visible sets of objects. This data is used at runtime by each camera to identify what is visible and what is not. Equipped with this information, Unity will ensure only visible objects get sent to be rendered. This reduces the number of draw calls and increases the performance of the game.

 

Fog and Lighting Effects

The solution we came up with is the use of simple mesh faces with a transparent texture (Fog planes) instead of global fog. Once a player comes too close to a fog plane, it fades out and moreover, vertices of the fog plane are pulled away (because even a fully transparent alpha surface still consumes lot of render time).

 

Debug Performance – Rendering Statistics, and Frame Debugger

Rendering Statistics

The Game View has a Stats button in the top right corner. When the button is pressed, an overlay window is displayed which shows realtime rendering statistics, which are useful for optimizing performance. The exact statistics displayed vary according to the build target.

Frame Debugger

The Frame Debugger lets you freeze playback for a running game on a particular frame and view the individual draw calls that are used to render that frame. As well as listing the drawcalls, the debugger also lets you step through them one-by-one so you can see in great detail how the scene is constructed from its graphical elements.

 

Extra Tips

  • Set Static property on a non-moving objects to allow internal optimizations like static batching.
  • Do not use dynamic lights when it is not necessary – choose to bake lighting instead.
  • Use compressed texture formats when possible, otherwise prefer 16bit textures over 32bit.
  • Use pixel shaders or texture combiners to mix several textures instead of a multi-pass approach.
  • CG: Use half precision variables when possible.
  • Do not use Pixel Lights when it is not necessary – choose to have only a single (preferably directional) pixel light affecting your geometry.
  • Alpha blending is ruthless on mobile.
  • Use occlusion culling.
  • Use texture atlases and pay attention to texture memory.
  • Limit particle emission count, use fast mobile shaders.
  • Use lightmapping, baked shadows, and blob shadows.