Command to Mediator

Introduction

This tutorial teaches how to use a signal in a command to make a mediator act accordingly.

In this tutorial we continue with the result of the previous tutorial. If this is the first time using IoC+, we suggest to read the introduction first.

A Prefab View

In the previous tutorial we’ve instantiated the PlayerInput view as a new empty gameobject. Let’s create a view that actually displays the player and make it jump based on the player’s input. Create a cube in your scene and add a rigidbody to it. Leave all options as default, so the cube will fall down on play.

Create a new script file called “PlayerView.cs” and add the following code.

using IoCPlus;
using UnityEngine;

public class PlayerView : View {

    Rigidbody myRigidbody;

    public void Jump() {
        myRigidbody.AddForce(Vector3.up * 100.0f);
    }

    private void Awake() {
        myRigidbody = GetComponent<Rigidbody>();
    }

}

A simple view that has only one functionality and that is to jump. Add the PlayerView script to the cube we’ve just created. Rename the cube to “Player”, turn it into a prefab and place the prefab in a folder called “Resources” so we can load it from code.

The Jump Signal

Before we implement its mediator, let’s first add a signal that will actually make the player jump. Create a new script file called “JumpSignal.cs” and add the following code.

using IoCPlus;

public class JumpSignal : Signal { }

Remember the JumpInputSignal? That signal was named after an event, because it was triggered by the player’s input. This time the signal is named after an action, the “jump” action. Naming a signal as “event” when using it to trigger a set of commands or naming it as “action” when using the signal in a command to make a mediator act accordingly is a great convention to keep a clear flow of signals.

Let’s first bind the JumpSignal and the PlayerView and PlayerMediator in the GameContext. Note that we haven’t made our PlayerMediator yet! Open up the GameContext and add the following code.

using IoCPlus;

public class GameContext : Context {

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

        Bind<string>("Welcome! Look at me, I'm injecting a value!");
        Bind<JumpInputSignal>();
        Bind<JumpSignal>();

        BindMediator<PlayerInputMediator, PlayerInputView>();
        BindMediator<PlayerMediator, PlayerView>();

        On<EnterContextSignal>().Do<WelcomeCommand>()
                                .Do<InstantiatePlayerInputCommand>();

        On<JumpInputSignal>().Do<JumpCommand>();
    }

}

Now that the JumpSignal is bound we can inject it into our commands and mediators.

Listening to Signals from Commands

Until now we’ve only seen mediators listen to signals from their view. This time we want the PlayerView’s mediator to listen to a signal that is potentially dispatched from a command. Create a new script file called “PlayerMediator.cs” and add the following code.

using IoCPlus;

public class PlayerMediator : Mediator<PlayerView> {

    [Inject] JumpSignal jumpSignal;

    public override void Initialize() {
        jumpSignal.AddListener(OnJumpSignal);
    }

    public override void Dispose() {
        jumpSignal.RemoveListener(OnJumpSignal);
    }

    private void OnJumpSignal() {
        view.Jump();
    }

}

We inject the JumpSignal and start listening to it in the Initialize method. As we know, mediators in IoC+ automatically have a reference to their view. When the signal is dispatched, we make the PlayerView jump. Clean and simple.

Instantiating the Prefab View

Let’s instantiate our player first. Create a new script file called “InstantiatePlayerCommand.cs” and add the following code.

using IoCPlus;
using UnityEngine;

public class InstantiatePlayerCommand : Command {

    [Inject] IContext context;

    protected override void Execute() {
        PlayerView prefab = Resources.Load<PlayerView>("Player");
        context.InstantiateView(prefab);
    }

}

We first load our PlayerView from the Resources folder. Then we make our context instantiate the view based on the prefab. Prefabs may contain multiple view components using this method. Let’s add this command as a response to the EnterContextSignal in the GameContext by adding the following code.

using IoCPlus;

public class GameContext : Context {

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

        Bind<string>("Welcome! Look at me, I'm injecting a value!");
        Bind<JumpInputSignal>();
        Bind<JumpSignal>();

        BindMediator<PlayerInputMediator, PlayerInputView>();
        BindMediator<PlayerMediator, PlayerView>();

        On<EnterContextSignal>().Do<WelcomeCommand>()
                                .Do<InstantiatePlayerInputCommand>()
                                .Do<InstantiatePlayerCommand>();

        On<JumpInputSignal>().Do<JumpCommand>();
    }

}

Go ahead and hit play. The player view should now be instantiated on startup, and fall right down because of its rigidbody.

Can’t see the player? Make sure to set the position of the prefab to (0, 0, 0), as the instance might be out of camera view.

Dispatching the Signal from a Command

Let’s open up our JumpCommand and update it with the following code.

using IoCPlus;

public class JumpCommand : Command {

    [Inject] JumpSignal jumpSignal;

    protected override void Execute() {
        jumpSignal.Dispatch();
    }

}

There! We inject the JumpSignal, the same signal as the PlayerMediator injects, and dispatch it on execution. The mediator should now respond to the signal from this command. Go ahead and hit play! Once we hit the up arrow key the player will start jump up, so we can try and keep the player in the air.

The IoC+ Monitor

Signals dispatched from commands will also light up in the IoC+ Monitor. Go ahead and open it up, you’ll see the JumpSignal light up on the JumpCommand’s execution.

That’s a lot of insight for one context! Be sure to use the Options button in the IoC+ Monitor to filter the monitor’s output as your contexts get bigger.

Conclusion

In this tutorial we’ve seen how to dispatch a signal from a command and listen to the same signal in a mediator. We’ve learned about naming a signal as either an event or an action to give insight of its usage. We’ve also seen that the InstantiateView<T>() method can also be used to instantiate a view from a prefab.