Some Utility Code

Every now and then, I’d like to share some of my small utility classes that I’ve made a long time ago but are still being used until now. The following are what I call some of my mini utilities. They can be used in your own Unity projects.

(Note that I’ve removed method description comments so that the code part looks more compact.)

Comment Component

A lot of times have come up where I have an object or prefab that contains a lot of components. Sometimes, I want to be able to note about the values I’ve entered for some component or state why the component is there. Sadly, Unity doesn’t have a feature where you can comment on components (let me know if you know one). However, it’s quite easy enough to roll your own “comment” component.

public class Comment : MonoBehaviour {

    [SerializeField]
    private string text;

    void Awake() {
        DestroyImmediate(this); // auto destroy to save memory
    }

    public string Text {
        get {
	    return text;
	}

        set {
	    this.text = value;
        }
    }

}

// This is the editor script. Place it under an Editor folder.
[CustomEditor(typeof(Comment))]
public class CommentEditor : Editor {

    private Comment targetComponent;

    void OnEnable() {
        this.targetComponent = (Comment)this.target;
    }

    public override void OnInspectorGUI() {
        if(targetComponent.Text == null) {
            // use an empty string so that it won't throw null pointer exception
            targetComponent.Text = "";
        }

        targetComponent.Text = GUILayout.TextArea(targetComponent.Text, GUILayout.Height(100), GUILayout.MinWidth(200));
    }

}

To use, just add the Comment component and type your comment text in the textbox.

CommentComponent

UI Image Sprite Animation

I tried to use the animation timeline for animating sprites in a UI Image. But it didn’t work or maybe I was using it wrong. I got impatient, so I turned to code.

public class ImageAnimation : MonoBehaviour {

    [SerializeField]
    private Image image;

    [SerializeField]
    private float framesPerSecond = 15;

    [SerializeField]
    private Sprite[] sprites; // The sequence of sprites comprising the animation

    private float polledTime;

    private int currentFrameIndex;

    private void Awake() {
        Assertion.AssertNotNull(this.image);
        Assertion.Assert(this.framesPerSecond > 0);

        this.polledTime = 0;

        // Reset
        this.currentFrameIndex = 0;
        SetSprite(this.currentFrameIndex);
    }

    private void Update() {
        this.polledTime += UnityEngine.Time.deltaTime;

        // We didn't cache this so we can see the effect of framesPerSecond on the fly like tweaking it in editor
        float timePerFrame = 1.0f / this.framesPerSecond;

        while(this.polledTime > timePerFrame) {
            this.polledTime -= timePerFrame;

            // Show next frame
            this.currentFrameIndex = (this.currentFrameIndex + 1) % this.sprites.Length;
            SetSprite(this.currentFrameIndex);
        }
    }

    private void SetSprite(int index) {
        this.image.sprite = this.sprites[index];
    }

}

This is very straightforward to use. Just specify an Image target, a frame rate, and the sequence of sprites to show. That’s it. It will play on loop. Nothing fancy. I’ve use this on the game over screen of Academia.

GameOver

SelectionSequence

Political Animals had a common UI where you select an item from a finite set of items using next and previous buttons. I’ve noticed that I’m repeating the same code spread across different UI screens. So I made a generic class for this.

public class SelectionSequence<T> {

    private readonly List<T> items = new List<T>();

    private int currentIndex = 0;

    public SelectionSequence(T[] array) {
        this.items.AddRange(array);
        Reset();
    }

    public void Reset() {
        this.currentIndex = 0;
    }

    public void MoveToNext() {
        this.currentIndex = (currentIndex + 1) % this.items.Count;
    }

    public void MoveToPrevious() {
        int decremented = this.currentIndex - 1;
        this.currentIndex = decremented < 0 ? this.items.Count - 1 : decremented;
    }

    public T Current {
        get {
            return this.items[this.currentIndex];
        }
    }

    public void Select(int index) {
        this.currentIndex = index;
    }

    public void Select(T item) {
        for(int i = 0; i < this.items.Count; ++i) {
            if(this.items[i].Equals(item)) {
                Select(i);
                return;
            }
        }

        throw new Exception("Can't find the item to select: " + item.ToString());
    }

    public int Count {
        get {
            return this.items.Count;
        }
    }

    public T GetAt(int index) {
        return this.items[index];
    }

}

// Usage
// Say you have an array of LanguageOption
LanguageOption[] languages = ...;
SelectionSequence<LanguageOption> langSequence = new SelectionSequence<LanguageOption>(languages);

// When next button is clicked
langSequence.MoveToNext();

// When previous button is clicked
langSequence.MoveToPrevious();

// Do something with current selection
ChangeLanguage(langSequence.Current);

This kind of selection have come up in Academia, too.

SelectionExample

These are just some of my cute little classes. They’re small but they have been very useful. Here’s some programming tip, think of making classes like making a new invention or a device. That way, you will think in terms of narrowing functionality as much as possible and expose only appropriate public methods. This will also make your classes more modular. Over time, you will develop a library of robust and reusable code.

Render Two Sprites in One Shader

Most of the character faces in Academia are generated in a procedural way. Each character has its own combination of face and head. Heads can either be hair or construction hat if they are workers. Both faces and heads are contained in a single texture so Unity may apply batching.

FaceHair
Part of the faces and heads texture

To generate a character, you simply render a face and render its head on top of it.

Characters

This can be done with two sprites. However, there are disadvantages. First, more draw calls. Second, it looks weird when the characters are overlapping because of z fighting. I needed a way to render both the face and head in only one sprite. This reduces draw calls and prevents weird z fighting. Fortunately, this is easy enough to do using a custom shader.

While working on our custom quad mesh where the characters would be displayed on, I realized that vertices can have more than one UV. This means that I can use the first UV for the face and use a second UV to draw the head. These two renders can be done within a single shader.

Shader "Common/TwoUvsLayeredTexture"
{
	Properties
	{
		_Texture("Main Texture", 2D) = "white" {}
	}

	SubShader
	{
		Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }
		ZWrite Off Lighting Off Cull Off Fog{ Mode Off } Blend SrcAlpha OneMinusSrcAlpha
		LOD 110

		Pass
		{
			CGPROGRAM
			#pragma vertex vert_vct
			#pragma fragment frag_mult 
			#pragma fragmentoption ARB_precision_hint_fastest
			#include "UnityCG.cginc"

			sampler2D _Texture;

			struct vin_vct
			{
				float4 vertex : POSITION;
				float4 color : COLOR;
				float2 texcoord0 : TEXCOORD0;
				float2 texcoord1 : TEXCOORD1;
			};

			struct v2f_vct
			{
				float4 vertex : SV_POSITION;
				fixed4 color : COLOR;
				float2 texcoord0 : TEXCOORD0;
				float2 texcoord1 : TEXCOORD1;
			};

			v2f_vct vert_vct(vin_vct v)
			{
				v2f_vct o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.color = v.color;
				o.texcoord0 = v.texcoord0;
				o.texcoord1 = v.texcoord1;
				return o;
			}

			fixed4 frag_mult(v2f_vct i) : SV_Target
			{
				fixed4 col1 = tex2D(_Texture, i.texcoord0) * i.color;
				fixed4 col2 = tex2D(_Texture, i.texcoord1) * i.color;

				fixed4 output;
				output.rgb = (col1.rgb * (1.0f - col2.a)) + (col2.rgb * col2.a);
				output.a = min(col1.a + col2.a, 1.0f);
				return output;
			}

			ENDCG
		}
	}
}

The magic is in frag_mult(v2f_vct i). Actually, I’m not too sure if that’s the proper way to blend two images. I’m not very good with shaders. I arrived with that using trial and error. Let me know if there’s a better way.

[Edit] Some people pointed out that it’s generally not ok to have conditionals in shader code. Thus, I’ve updated the code with a better one. This is why I blog.

A Generic Duration Timer Class

In game development, there are a lot of instances where you would like to do the following:

  • Wait for X seconds
  • Fly for X seconds
  • Fire for X seconds
  • Move forward for X seconds

The common element in these actions is the concept of a time duration. The most common solution that I see in tutorial pages looks like the following:

public class SomeComponent : MonoBehaviour {
    [SerializeField]
    private float durationTime; // the time to wait or go through

    private float polledTime;

    void Awake() {
        this.polledTime = 0;
    }

    void Update() {
        this.polledTime += Time.deltaTime;

        if(this.polledTime >= this.durationTime) {
            // time's up
            // maybe reset or do something since duration is up
            return;
        }

        float ratio = this.polledTime / this.durationTime;
        // do something with ratio like interpolation (lerp)
    }
}

This is good enough, but we can do something better. Imagine if you are maintaining more than one duration time. You’d probably do something like this:

public class SomeComponent : MonoBehaviour {
    [SerializeField]
    private float waitDurationTime;

    private float waitPolledTime;

    [SerializeField]
    private float fireDurationTime;

    private float firePolledTime;

    void Update() {
        UpdateWait();
        UpdateFire();
    }
    
    private void UpdateWait() {
    	this.waitPolledTime += Time.deltaTime;

        if(this.waitPolledTime >= this.waitDurationTime) {
            // time's up
            // maybe reset or do something since duration is up
            return;
        }

        float ratio = this.waitPolledTime / this.waitDurationTime;
        // do something with ratio
    }
    
    private void UpdateFire() {
    	this.firePolledTime += Time.deltaTime;

        if(this.firePolledTime >= this.fireDurationTime) {
            // time's up
            // maybe reset or do something since duration is up
            return;
        }

        float ratio = this.firePolledTime / this.fireDurationTime;
        // do something with ratio
    }
}

We can see here that the floating point arithmetic is repeated for each timed duration domain. A simple solution to manage this is to refactor and create a reusable DurationTimer class.

using UnityEngine;

/**
 * Generic class for implementing timers (specified in seconds)
 */
public class DurationTimer {
    private float polledTime;
    private float durationTime;

    /**
     * Constructor with a specified duration time
     */
    public DurationTimer(float durationTime) {
        Reset(durationTime);
    }

    /**
     * Updates the timer
     */
    public void Update() {
        this.polledTime += Time.deltaTime;
    }

    /**
     * Resets the timer
     */
    public void Reset() {
        this.polledTime = 0;
    }

    /**
     * Resets the timer and assigns a new duration time
     */
    public void Reset(float durationTime) {
        Reset();
        this.durationTime = durationTime;
    }

    /**
     * Returns whether or not the timed duration has elapsed
     */
    public bool HasElapsed() {
        return Comparison.TolerantGreaterThanOrEquals(this.polledTime, this.durationTime);
    }

    /**
     * Returns the ratio of polled time to duration time. Returned value is 0 to 1 only
     */
    public float GetRatio() {
        if(Comparison.TolerantLesserThanOrEquals(this.durationTime, 0)) {
            // bad duration time value
            // if countdownTime is zero, ratio will be infinity (divide by zero)
            // we just return 1.0 here for safety
            return 1.0f;
        }

        float ratio = this.polledTime / this.durationTime;
        return Mathf.Clamp(ratio, 0, 1);
    }

    /**
     * Returns the polled time since it started
     */
    public float GetPolledTime() {
        return this.polledTime;
    }

    /**
     * Forces the timer to end
     */
    public void EndTimer() {
        this.polledTime = this.durationTime;
    }

    /**
     * Returns the durationTime
     */
    public float GetDurationTime() {
        return this.durationTime;
    }

}

What we did here is we simply contained the duration timer variables and routines in a separate class. Take note of the usage of Comparison functions in HasElapsed() and GetRatio(). Read here for the reason why.

Let’s look at the basic usage using of this class:

public class SomeComponent : MonoBehaviour {
    [SerializeField]
    private float duration; // the time to wait or go through

    private DurationTimer timer;

    void Awake() {
        this.timer = new DurationTimer(this.duration);
    }

    void Update() {
        this.timer.Update();

        if(this.timer.HasElapsed()) {
            // time's up
            // maybe reset or do something since duration is up
            return;
        }

        float ratio = this.timer.GetRatio();
        // do something with ratio like interpolation (lerp)
    }
}

By using this class, we reduce the clutter of floating point arithmetic (increment, check, compute ratio). We use the functions of the class instead, making it more readable. See how it looks like when it’s used for more than one timed duration:

public class SomeComponent : MonoBehaviour {
    [SerializeField]
    private float waitDuration; // the time to wait or go through

    private DurationTimer waitTimer;
    
    [SerializeField]
    private float fireDuration;
    
    private DurationTimer fireTimer;

    void Awake() {
        this.waitTimer = new DurationTimer(this.waitDuration);
        this.fireTimer = new DurationTimer(this.fireDuration);
    }

    void Update() {
        UpdateWait();
        UpdateFire();
    }
    
    private void UpdateWait() {
    	this.waitTimer.Update();

        if(this.waitTimer.HasElapsed()) {
            // time's up
            // maybe reset or do something since duration is up
            return;
        }

        float ratio = this.waitTimer.GetRatio();
        // do something with ratio like interpolation (lerp)
    }
    
    private void UpdateFire() {
    	this.fireTimer.Update();

        if(this.fireTimer.HasElapsed()) {
            // time's up
            // maybe reset or do something since duration is up
            return;
        }

        float ratio = this.fireTimer.GetRatio();
        // do something with ratio like interpolation (lerp)
    }
}

We can also reuse this class if we’re making other frameworks that uses time.

public class WaitAction : FsmAction {
    private DurationTimer timer; // pretty cool huh?
	
    ...
}

Getting Started with Strange IoC

I haven’t been posting for a while because I’ve been busy implementing the persistence feature using SimpleSQL and Strange. It’s not finished yet, thus this non development post of helping you getting a head start on using Strange.

I decided to use Strange because I want to explore this framework. Strange is an Inversion of Control (IoC) framework for Unity. IoC is another way of decoupling classes, and for me, any decoupling technique is worth studying. What is IoC? Read here. IoC frameworks have been a staple in enterprise and other non game software. It has matured in those areas tremendously. I’m betting on its promise that it makes games more testable and improves collaboration. I’m curious on how it can really help game development.

Using Strange is very “strange” indeed. I found it hard to set-up something like a Hello World for it. It has a how-to page but doesn’t really have a step by step guide on how to do it. This post is a step by step guide to a Strange Hello World.

Some notes:

  • Read the Strange how-to page first before heading back here for the guide on how to put them all together.
  • This guide uses Signals instead of Events (because I like Signals more than Events)
  • I won’t give a Unity project for this so that you’ll have to set it up on your own. You’ll probably learn more.
  • The Hello World sample merely gives a simple usage of injection binding, command binding, and mediation binding.

Start Signal

Start with an empty project. Download and extract the Strange framework in the Assets folder. The folder structure should look like this:

Assets
    StrangeIoC
        examples
        scripts
        StrangeIoCTemplate

Create a “Game” folder under Assets. This will the folder for our Hello World sample.

Assets
    Game
        Scenes
        Scripts

Create a script named HelloWorldSignals.cs under Scripts. This class will contain all signals used in the sample. Open up Mono. We begin coding.

using System;

using strange.extensions.signal.impl;

namespace Game {

    public class StartSignal : Signal {}

}

Signals are more like events in an observer pattern. They are implemented as named classes that extends from Signal. We’ll see later on how they are used.

Strange employs the concept of “contexts” to identify different problem domains or sub modules. In a real game project, you can have multiple contexts like game logic, asset sources, persistence, analytics, social features, etc. We only have one context in this guide for simplicity.

A pre-made context that is available in Strange is class called MVCSContext. However, MVCSContext uses events by default. We create another base context class that uses signals. This class can be reused in other contexts.

Create a script named SignalContext.cs under Scripts.

using System;

using UnityEngine;

using strange.extensions.context.impl;
using strange.extensions.command.api;
using strange.extensions.command.impl;
using strange.extensions.signal.impl;

namespace Game {
    public class SignalContext : MVCSContext {

        /**
         * Constructor
         */
        public SignalContext (MonoBehaviour contextView) : base(contextView) {
        }

        protected override void addCoreComponents() {
            base.addCoreComponents();

            // bind signal command binder
            injectionBinder.Unbind<ICommandBinder>();
            injectionBinder.Bind<ICommandBinder>().To<SignalCommandBinder>().ToSingleton();
        }

        public override void Launch() {
            base.Launch();
            Signal startSignal = injectionBinder.GetInstance<StartSignal>();
            startSignal.Dispatch();
        }

    }
}

Create a new folder named “Controller” under “Scripts”. It’s pretty clear that we are heading towards an MVC pattern. The author of Strange suggests that we implement controllers as Command classes. This folder will contain all Command classes. For now, we create a command that will be executed when StartSignal is dispatched. Create a class named HelloWorldStartCommand  under Controller.

using System;

using UnityEngine;

using strange.extensions.context.api;
using strange.extensions.command.impl;

namespace Game {
    public class HelloWorldStartCommand : Command {

        public override void Execute() {
            // perform all game start setup here
            Debug.Log("Hello World");
        }

    }
}

Now we create the custom context class for the Hello World sample. Create a class named HelloWorldContext under Scripts.

using System;

using UnityEngine;

using strange.extensions.context.impl;

namespace Game {
    public class HelloWorldContext : SignalContext {

        /**
         * Constructor
         */
        public HelloWorldContext(MonoBehaviour contextView) : base(contextView) {
        }

        protected override void mapBindings() {
            base.mapBindings();

            // we bind a command to StartSignal since it is invoked by SignalContext (the parent class) on Launch()
            commandBinder.Bind<StartSignal>().To<HelloWorldStartCommand>().Once();
        }

    }
}

In here, we bind StartSignal to HelloWorldStartCommand which means that HelloWorldStartCommand gets instantiated and executed whenever an instance of StartSignal is dispatched. Note that in our sample, StartSignal is dispatched in SignalContext.Launch().

The final step is to create the MonoBehaviour that will host the context. Create a class named HelloWorldBootstrap.cs under Scripts.

using System;

using UnityEngine;

using strange.extensions.context.impl;

namespace Game {
    public class HelloWorldBootstrap : ContextView {

        void Awake() {
            this.context = new HelloWorldContext(this);
        }

    }
}

Components that hosts a Strange context is usually called a “Bootstrap”. It’s just a suggestion but it can be anything. The only thing to note here is that it extends ContextView which is a MonoBehaviour. In Awake(), it assigns an instance of the custom context that we have implemented to a special inherited variable “context”.

Create a new empty scene named “HelloStrange” under Scenes folder. Create a new GameObject named “Bootstrap”. Add the HelloWorldBootstrap to it. Hit play. “Hello World” should be printed on the console.

Strange Hello World
Strange Hello World

Injection in Mediator

So much code, we only logged “Hello World”, what’s the fuzz with Strange then? Let me say that what we have done until now is pretty cool! We now have a working context. From here on, we can now add views and their corresponding mediators. We can also use the injection binder to map an instance to some interface which can be injected into controllers/commands and mediators without them knowing where the instance came from. Follow through the rest of the guide to see some magic.

When we make games, we usually use singleton managers like EnemyManager, AsteroidManager, CombatManager, etc. There are many ways to resolve an instance to any one manager. We may use GameObject.Find() or add a GetInstance() static method. Let’s create a hypothetical manager and see how instance resolution works in Strange. Create an interface named ISomeManager.cs under Scripts folder.

namespace Game {
    public interface ISomeManager {

        /**
         * Perform some management
         */
        void DoManagement();

    }
}

This will be the interface for our sample manager. The author of Strange suggests to always use an interface and map it to an actual implementation using the injectionBinder, although the mapping would still work without using one. Let’s create a concrete implementation. Create a class named ManagerAsNormalClass.cs under Scripts.

using System;

using UnityEngine;

namespace Game {
    public class ManagerAsNormalClass : ISomeManager {

        public ManagerAsNormalClass() {
        }

        #region ISomeManager implementation
        public void DoManagement() {
            Debug.Log("Manager implemented as a normal class");
        }
        #endregion

    }
}

This is a non MonoBehaviour version of the manager. I’ll show you later how to bind a MonoBehaviour one.

Let’s create a simple UI where there’s a button that when clicked, it invokes ISomeManager.DoManagement() without using a reference to ISomeManager. In an MVC pattern, this is ideal. Views should only say, “Hey I’m clicked/used” and it should not know what happens next.

Create a folder named View under Scripts. This folder will contain the View and Mediator classes.

Game
    Controller
    View

Create a file named HelloWorldView.cs under View folder.

using System;

using UnityEngine;

using strange.extensions.mediation.impl;
using strange.extensions.signal.impl;

namespace Game {
    public class HelloWorldView : View {

        public Signal buttonClicked = new Signal();

        private Rect buttonRect = new Rect(0, 0, 200, 50);

        public void OnGUI() {
            if(GUI.Button(buttonRect, "Manage")) {
                buttonClicked.Dispatch();
            }
        }

    }
}

View is a MonoBehaviour class that is included in Strange. All views that should work within a Strange context should extend this class. HelloWorldView just renders a “Manage” button that dispatches a generic signal when clicked.

The author of Strange recommends that each view should have a corresponding mediator. A mediator is a thin layer that lets a view communicate with the rest of the application. The mediation binder is used to map a view to its corresponding mediator. Let’s create the mediator to HelloWorldView. Create a file named HelloWorldMediator.cs under View folder.

using System;

using UnityEngine;

using strange.extensions.mediation.impl;

namespace Game {
    public class HelloWorldMediator : Mediator {

        [Inject]
        public HelloWorldView view {get; set;}

        [Inject]
        public ISomeManager manager {get; set;}

        public override void OnRegister() {
            view.buttonClicked.AddListener(delegate() {
                manager.DoManagement();
            });
        }

    }
}

Now we see the magical Inject attribute here. This attribute only works with properties. When a property has this attribute, it means that Strange will automatically assign/inject an instance to it based on the mappings in the context. In the perspective of the class above, it knows that it can get an instance for its properties view and manager without knowing where it came from.

OnRegister() is a method that can be overridden to mark that the injection of instances has been done and they are ready for use. What is done here is mostly initialization or preparation routines. In the class above, we add a listener to the HellowWorldView.buttonClicked signal using a closure that invokes ISomeManager.DoManagement().

To put them all together, we will map the binding in the Strange context. Open HelloWorldContext and set the following lines inside mapBindings() method:

        protected override void mapBindings() {
            base.mapBindings();

            // we bind a command to StartSignal since it is invoked by SignalContext (the parent class) during on Launch()
            commandBinder.Bind<StartSignal>().To<HelloWorldStartCommand>().Once();

            // bind our view to its mediator
            mediationBinder.Bind<HelloWorldView>().To<HelloWorldMediator>();

            // bind our interface to a concrete implementation
            injectionBinder.Bind<ISomeManager>().To<ManagerAsNormalClass>().ToSingleton();
        }

In HelloStrange scene, create a new GameObject named “View” and add the HelloWorldView script to it. Play the scene. You should be able to see a Manage button that prints “Manager implemented as a normal class” when clicked.

ISomeManager in action
Strange in action

Note also that Strange automatically adds the mediator component when the scene is played. Remember that we didn’t add the HelloWorldMediator to the View scene object.

Where did the mediator came from?
Where did the mediator came from?

MonoBehaviour Manager

Almost always, we want our managers to be implemented as a MonoBehaviour so we can inherit its advantages like coroutines, and serialization. How do we bind a MonoBehaviour manager instance in Strange?

Let’s create our MonoBehaviour manager. Create a file named ManagerAsMonoBehaviour.cs under Scripts folder.

using System;

using UnityEngine;

namespace Game {
    public class ManagerAsMonoBehaviour : MonoBehaviour, ISomeManager {

        #region ISomeManager implementation
        public void DoManagement() {
            Debug.Log("Manager implemented as MonoBehaviour");
        }
        #endregion

    }
}

In HelloStrange scene, create a new scene object named “Manager” then add the ManagerAsMonoBehaviour script to it.

Edit mapBindings() method of HelloWorldContext to the following:

        protected override void mapBindings() {
            base.mapBindings();

            // we bind a command to StartSignal since it is invoked by SignalContext (the parent class) during on Launch()
            commandBinder.Bind<StartSignal>().To<HelloWorldStartCommand>().Once();

            // bind our view to its mediator
            mediationBinder.Bind<HelloWorldView>().To<HelloWorldMediator>();

            // REMOVED!!!
            //injectionBinder.Bind<ISomeManager>().To<ManagerAsNormalClass>().ToSingleton();

            // bind the manager implemented as a MonoBehaviour
            ManagerAsMonoBehaviour manager = GameObject.Find("Manager").GetComponent<ManagerAsMonoBehaviour>();
            injectionBinder.Bind<ISomeManager>().ToValue(manager);
        }

Instead of mapping ISomeManager to a type, we map it with an instance value. Play the scene again and click Manage, you should see something like this:

Manager is now a MonoBehaviour
Manager is now a MonoBehaviour

Injection in Command

What we did so far is we injected an ISomeManager instance in HelloWorldMediator and use that directly. That is actually not ideal. A mediator should only be a thin layer between its view and controllers. As much as it can be, it should not know about which part of the code performs the complex processing like managers. It can, however, know about signals that is mapped to commands.

Edit HelloWorldSignals.cs and add a DoManagementSignal:

using System;

using strange.extensions.signal.impl;

namespace Game {

    public class StartSignal : Signal {}

    public class DoManagementSignal : Signal {} // A new signal!

}

Let’s create the command that is mapped to that signal. Add a file named DoManagementCommand.cs under Controller folder.

using System;

using UnityEngine;

using strange.extensions.context.api;
using strange.extensions.command.impl;

namespace Game {
    public class DoManagementCommand : Command {

        [Inject]
        public ISomeManager manager {get; set;}

        public override void Execute() {
            manager.DoManagement();
        }

    }
}

In here, we inject ISomeManager to the command class and invoke ISomeManager.DoManagement() in its Execute() method.

Edit HelloWorldMediator to the following:

using System;

using UnityEngine;

using strange.extensions.mediation.impl;

namespace Game {
    public class HelloWorldMediator : Mediator {

        [Inject]
        public HelloWorldView view {get; set;}

        [Inject]
        public DoManagementSignal doManagement {get; set;}

        public override void OnRegister() {
            view.buttonClicked.AddListener(doManagement.Dispatch);
        }

    }
}

We now removed any references to ISomeManager in the mediator. We get an instance of DoManagementSignal instead and dispatch it whenever the button is clicked. In a way, HelloWorldMediator now doesn’t know about any managers. It just knows signals.

Finally, we add a signal-command mapping in HelloWorldContext.mapBindings():

        protected override void mapBindings() {
            base.mapBindings();

            // we bind a command to StartSignal since it is invoked by SignalContext (the parent class) during on Launch()
            commandBinder.Bind<StartSignal>().To<HelloWorldStartCommand>().Once();
            commandBinder.Bind<DoManagementSignal>().To<DoManagementCommand>().Pooled(); // THIS IS THE NEW MAPPING!!!

            // bind our view to its mediator
            mediationBinder.Bind<HelloWorldView>().To<HelloWorldMediator>();

            // bind the manager implemented as a MonoBehaviour
            ManagerAsMonoBehaviour manager = GameObject.Find("Manager").GetComponent<ManagerAsMonoBehaviour>();
            injectionBinder.Bind<ISomeManager>().ToValue(manager);
        }

Play the scene. It should still work like the previous one.

Last Words

I always mention “the author of Strange recommends/suggests…”. That’s because his suggestions are optional. For example, you can inject instances directly in your views. You may not use a mediator at all. What I’m trying to say is, you can choose another pattern of using Strange depending on your needs. I just chose to follow his recommendations because it works for me.

If you made it this far, then you are probably strange, too. You might be asking “why should I add this complexity and extra layer of indirection to my project?” I’m currently looking for the answer to that question by applying it to my current game. All I can say right now is Strange forces me to keep things separate. Like for now, I have this separate scene that handles persistence using SimpleSQL within a Strange context. Database transactions are executed in commands. The existing game logic, which is non Strange, communicates with this module through signals.

We are also using it in another RPG project. I hope that it does help with respect to code collaboration as it promised. I can’t say how good it is yet as we are still starting the project but so far it is working for us. We are working on multiple contexts. Each context is owned by only one programmer. We communicate with other contexts using signals.

A Generic Floating Point Comparison Class

You should never compare floating point values for equality using the following operators:

  • ==
  • <=
  • >=
float a = 2.0f;
float b = a;

// any of these is best avoided

if(a == b) {
    // you expect it to work but sometimes it won't
}

if(a <= b) {     
    // you expect it to work but sometimes it won't 
} 

if(a >= b) {
    // you expect it to work but sometimes it won't
}

Why? The short answer is because the representation of floating numbers is not consistent such that two floats may have the same perceived value but differ in bit representation. The long answer is here.

So how do we compare floats for equality then? If you’re using Unity, Mathf.Approximately() is very handy. Here’s a full Comparison class using exactly that:

using UnityEngine;

/**
 * Class for comparing floating point values 
 */
public static class Comparison {

    /**
     * Returns whether or not a == b
     */
    public static bool TolerantEquals(float a, float b) {
        return Mathf.Approximately(a, b);
    }

    /**
     * Returns whether or not a >= b
     */
    public static bool TolerantGreaterThanOrEquals(float a, float b) {
        return a > b || TolerantEquals(a, b);
    }

    /**
     * Returns whether or not a <= b
     */
    public static bool TolerantLesserThanOrEquals(float a, float b) {
        return a < b || TolerantEquals(a, b);
    }

}

If you’re not using Unity, you should define a tolerance value such that any value less then this is considered meaningless. This may vary across different games and applications. To define equality, we just take the absolute value of the difference of the two floating values and compare if this is lesser than the tolerance value. If it is, we can say that the two floating values are equal. In other words, we are merely discarding floating values that are already too small to be significant for our use.

using System;

/**
 * Class for comparing floating point values 
 */
public static class Comparison {

    private const float TOLERANCE_VALUE = 0.0001f;

    /**
     * Returns whether or not a == b
     */
    public static bool TolerantEquals(float a, float b) {
        return Math.Abs(a - b) < TOLERANCE_VALUE;
    }

    /**
     * Returns whether or not a >= b
     */
    public static bool TolerantGreaterThanOrEquals(float a, float b) {
        return a > b || TolerantEquals(a, b);
    }

    /**
     * Returns whether or not a <= b
     */
    public static bool TolerantLesserThanOrEquals(float a, float b) {
        return a < b || TolerantEquals(a, b);
    }

}

Finally, the following are the sample usage:

float a = 2.0f;
float b = a;

// these are better

if(Comparison.TolerantEquals(a, b)) {
    // now this works as expected
}

if(Comparison.TolerantLesserThanOrEquals(a, b)) {     
    // now this works as expected
} 

if(Comparison.TolerantGreaterThanOrEquals(a, b)) {
    // now this works as expected
}

Now look at your code and see if you’re making this mistake. This may be the source of bugs that you couldn’t solve before.

Development Tip: Search for Files Efficiently in Mono

I often find programmers who open a lot of tabs in Mono. It becomes inefficient if you have too many tabs and you need to click on the Next or Previous buttons to get to the file that you want. You don’t have to do this.

Pressing Alt + Shift + 'O' will bring you here
Pressing Alt + Shift + ‘O’ will bring you here

You can use Search > Go to File… or press Alt + Shift + ‘O’ and the type the file that you want to open. I really like this feature and it’s the one that I mostly use. I usually close all tabs and open only those source files that are related to what I’m currently working with.