InputMaster Primer

From Unify Community Wiki
(Difference between revisions)
Jump to: navigation, search
(Control Functionality, or, The PlayerController)
Line 170: Line 170:
  
  
Press play, and then test the control with the assigned KeyCode:
+
== OneWayControl ==
  
[[File:BSGTools_InputMaster_ColorChangeTest.gif]]
+
Go back to the InputManager script, add a new OneWayControl, and finally, make sure to include the control as a parameter for CreateMaster():
 +
<syntaxhighlight lang="csharp">
 +
using UnityEngine;
 +
using System.Collections;
 +
using BSGTools.IO;
 +
 
 +
public class InputManager : MonoBehaviour {
 +
public readonly DigitalControl changeColor = new DigitalControl(KeyCode.Space, "Change Color");
 +
 
 +
public readonly OneWayControl scaleUp = new OneWayControl(KeyCode.R, "Scale Up");
 +
 
 +
public InputMaster Master { get; private set; }
 +
 
 +
void Start() {
 +
Master = InputMaster.CreateMaster(changeColor, scaleUp);
 +
DontDestroyOnLoad(this);
 +
}
 +
}
 +
</syntaxhighlight>

Revision as of 19:58, 23 May 2014

Contents

InputMaster Primer

Initial Notes

  • This tutorial is NOT a Unity tutorial nor a primer to C# or programming in general. This tutorial assumes that you already have a good grasp of how Unity works and that you have intimate knowledge of programming concepts and the C# language.
  • BSGTools is C# ONLY. Unityscript and Boo are NOT supported.
  • InputMaster was designed for programmers, by a programmer. It has no configurable options in the Inspector, and should not be manually added to a GameObject for any reason. All configuration is done in code. However, if you'd like to make some variables editable in the Inspector, there are methods of doing this that will be discussed below.


Setting Up The Scene

Our basic scene will be comprised of a few very basic objects:

  1. An orthographic camera
  2. A quad primitive (our basic "player")
  3. An empty GameObject (Referred to as the Immortal GameObject, this object will be made indestructible)
  4. A directional light (to make things actually visible)


Creating The InputManager

Once the basic scene is set up, create a new C# script, name it InputManager, and attach it to the Immortal GameObject.

The initial goal is to create a single control and an InputMaster object. Creating the Master object sets several things in motion:

  • It tells the system to create a new instance of InputMaster
  • To call DontDestroyOnLoad on InputMaster.
  • To provide the new master instance with the default controls for the game.


Note that you will never actually see your instance of InputMaster. It will be attached to a hidden GameObject.

First things first, creating a Master object. Creating a new master is as easy as calling CreateMaster:

/// <summary>
/// Creates a new, empty, hidden GameObject, adds a new instance of InputMaster to it,
/// and adds the provided controls to the master's control list.
/// </summary>
/// <param name="controls">A full listing of all of the games controls with the default bindings.</param>
/// <returns>The new InputMaster instance.</returns>
public static InputMaster CreateMaster(params Control[] controls)


Please take note of the method summary above. ALL controls with their default bindings used in the game should be added here. You cannot add new controls later. Of course, however, you may change the bindings of those controls at any point. This will be discussed later.

We want to make sure that this object is also not destroyed on a new scene load, so add DontDestroyOnLoad(this); to your Start method.

All in all, your starting point should look like this:

using UnityEngine;
using System.Collections;
using BSGTools.IO;
 
public class InputManager : MonoBehaviour {
	public InputMaster Master { get; private set; }
 
	void Start () {
		Master = InputMaster.CreateMaster(); //FIXME: This needs controls!
		DontDestroyOnLoad(this);
	}
}


Creating The Controls

There are three types of controls, two of which are analog based:

  • DigitalControl:
    • Has one key map.
    • Perfect for most controls, such as an Interact/Use function.
    • Maintains three states:
      • Down - Was the control pressed this frame?
      • Up - Was the control released this frame?
      • Held - True as long as the control is pressed.
  • AxisControl (Analog):
    • Has two key maps, Positive and Negative.
    • Contains the same information as DigitalControl, except it also maintains a floating point value (clamped to -1...0...1) representing the current value.
    • A near perfect replica of Unity's default Input Axis system. It has the same configurable parameters (Sensitivity, Gravity, Dead, and Snap), all of which can be changed at runtime.
    • Perfect for movement.
  • OneWayControl (Analog):
    • Has one key map.
    • Exact same system as AxisControl, except the floating point is clamped to 0...1.
    • Think of this as a lever, with one side marked as 0 and the other marked as 1.
    • Perfect for a Sprint control for smooth transitions between walking and running.


The easiest of all the controls is the DigitalControl, so let's start there. We're going to have our player (read: quad) change color every time its pressed. There is only one required parameter, the KeyCode binding. However, if you'd like to give it a friendly name (:D) you can provide as well. This is a good idea, as doing a ToString() on a Control object returns this name. If the name is not defined, a name of this pattern is created for you: UNNAMED_[Random 12 Char String]. Defining this name now and not later makes debugging MUCH easier, as this name is used in exceptions and stack traces.


Your InputManager should look something like this at this point:

using UnityEngine;
using System.Collections;
using BSGTools.IO;
 
public class InputManager : MonoBehaviour {
	public readonly DigitalControl changeColor = new DigitalControl(KeyCode.Space, "Change Color");
 
	public InputMaster Master { get; private set; }
 
	void Start() {
		Master = InputMaster.CreateMaster(changeColor);
		DontDestroyOnLoad(this);
	}
}


This doesn't add functionality to the control yet, but when the game is run the system will be updating the control's state.


The ManagerAccessor

We need a clean, safe way of getting the InputManager instance. My favourite way of doing this is through a Manager Accessor, a MonoBehaviour that creates instances of all of the game's managers and keeps them in one place.

Create a new C# script, name it ManagerAccessor and add it to the Immortal GameObject.

The ManagerAccessor is simple, and works like this:

  1. Managers are set up as public static properties with a private set, undefined.
  2. Start() is used to assign the manager's values through GetComponent().
  3. A null check is performed to make sure that all Manager instances have been assigned a value.


For advanced users, you can avoid having to check each Manager instance manually through reflection. However, for the sake of this primer tutorial, this is the most basic implementation:

using UnityEngine;
using System.Collections;
 
public class ManagerAccessor : MonoBehaviour {
	public static InputManager InputManager { get; private set; }
 
	void Start() {
		//redundant, because InputManager also does this and they are
		//both on the same GameObject, but be safe, not sorry!
		DontDestroyOnLoad(this);
 
		InputManager = GetComponent<InputManager>();
		if(InputManager == null)
			throw new System.NullReferenceException("Could not find InputManager, InputManager is null!");
	}
}


Control Functionality, or, The PlayerController

The InputManager is configured with a instance of InputMaster, the initial control is configured, and it can all be accessed through ManagerAccessor.

The last major step is to set up the PlayerController to turn the control's state into actual functionality.

Create a new C# script, name it PlayerController, and add it to the Quad primitive.

This script is really simple (for now). In our Update method, we're going to get an instance of the InputManager through ManagerAccessor and poll the state of the changeColor DigitalControl. If the Down state is true, we assign a random color to the renderer's material.

using UnityEngine;
using System.Collections;
 
public class PlayerController : MonoBehaviour {
	void Update() {
		InputManager io = ManagerAccessor.InputManager;
 
		if(io.changeColor.Down)
			renderer.material.color = new Color(Random.value, Random.value, Random.value);
	}
}


OneWayControl

Go back to the InputManager script, add a new OneWayControl, and finally, make sure to include the control as a parameter for CreateMaster():

using UnityEngine;
using System.Collections;
using BSGTools.IO;
 
public class InputManager : MonoBehaviour {
	public readonly DigitalControl changeColor = new DigitalControl(KeyCode.Space, "Change Color");
 
	public readonly OneWayControl scaleUp = new OneWayControl(KeyCode.R, "Scale Up");
 
	public InputMaster Master { get; private set; }
 
	void Start() {
		Master = InputMaster.CreateMaster(changeColor, scaleUp);
		DontDestroyOnLoad(this);
	}
}
Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox