Creating a Custom Input Manager

In this short tutorial we'll go over the basics of how to create a custom input manager for your project.

The Ultimate Radial Menu Input Manager contains all the basic input types and functions. However, sometimes in your project you may have a very specific way that you want the Ultimate Radial Menu to receive input. You can get the radial menu to work with your custom input very easily! Let's see how.

Creating Your Input Manager

To create your custom input manager, create a new script inside your project and name it. For this example, we will create a script with the name: CustomInputManager. After the script is created, change it's inherited type to UltimateRadialMenuInputManager.

using UnityEngine;

public class CustomInputManager : UltimateRadialMenuInputManager
{
    
}

After creating your script, now you will want to choose which of the input types you want to override. For this example we will create an override for the Controller Input of the input manager, but you can override any of the methods listed here.

First, let's override the ControllerInput function.

using UnityEngine;

public class CustomInputManager : UltimateRadialMenuInputManager
{
    // Override the controller input.
    public override void ControllerInput ( ref bool enableMenu, ref bool disableMenu, ref Vector2 input, ref float distance, ref bool inputDown, ref bool inputUp, int radialMenuIndex )
    {
        
    }
}

At first glance, the function and parameters might seem confusing! Don't worry though! The code is very simple and straight forward. Let's go over the parameters and see what each of them is for.

ParameterPurpose

enableMenu

This parameter allows you tell the input manager if you want the radial menu to be enabled on this frame or not. For instance, if you want the menu to be enabled when the user presses the left trigger of the controller, then you can check when it has been pressed and set enableMenu to true to enable the radial menu.

disableMenu

The exact opposite of the enableMenu parameter. Determines if you want the radial menu disabled this frame or not.

input

The input value that should be processed. In this example we will use the controller input, but you will set this to what ever input you are needing to interact with the radial menu.

distance

The distance of the input from the radial menu.

inputDown

The state of the interact input button being pressed down this frame.

inputUp

The state of the interact input button being released this frame.

radialMenuIndex

The index of the radial menu in the UltimateRadialMenuInformations list on the input manager. Useful for checking specifics of the radial menu being interacted with.

All changes to these parameters (excluding the radialMenuIndex value) will be stored and sent back to the Update function for processing and sending to the radial menus in the scene.

Processing Custom Input Logic

Now that we have our script created and our override void ready for some custom logic, let's add some code to get the radial menu processing the input that we are looking for.

For this example, we will adjust the controller input so that it will not reset back to center when the controller joystick has been released. In this way the radial menu will continue to process the last known input direction of the joystick even when the joystick has been released. So the first thing to do would be to create a variable that can store the last known input value so that it can be sent to the input manager.

using UnityEngine;

public class CustomInputManager : UltimateRadialMenuInputManager
{
	// This variable will store the controller input value.
	Vector2 controllerInputValue = Vector2.zero;


	// Override the controller input.
	public override void ControllerInput ( ref bool enableMenu, ref bool disableMenu, ref Vector2 input, ref float distance, ref bool inputDown, ref bool inputUp, int radialMenuIndex )
	{
		// Store a boolean to check if the input from the mouse & keyboard has been caught.
		bool inputModifiedThisFrame = false;

		// If any of the bool variables have been modified, then the mouse and keyboard is still the active input, so set the bool to true.
		if( enableMenu || disableMenu || inputDown || inputUp )
			inputModifiedThisFrame = true;

		if( !UltimateRadialMenuInformations[ radialMenuIndex ].radialMenu.IsEnabled && controllerInputValue != Vector2.zero )
			controllerInputValue = Vector2.zero;

#if ENABLE_INPUT_SYSTEM
		// Store the gamepad from the input system.
		Gamepad gamepad = InputSystem.GetDevice<Gamepad>();

		// If the gamepad is null, then just return.
		if( gamepad == null )
			return;

		// Store the input data of the stick determined by the user.
		Vector2 currentControllerInputValue = joystick == Joysticks.Left ? gamepad.leftStick.ReadValue() : gamepad.rightStick.ReadValue();
		if( Vector2.Distance( Vector2.zero, currentControllerInputValue ) >= UltimateRadialMenuInformations[ radialMenuIndex ].radialMenu.minRange )
			controllerInputValue = currentControllerInputValue;

		// Check the controller buttons for interacting.
		CheckControllerButtons( gamepad, interactButtons, ref inputDown, ref inputUp );

		// Check the controller buttons for enabling/disabling the menu if the user wants that.
		if( enableMenuSetting != EnableMenuSetting.Manual )
			CheckControllerButtons( gamepad, enableButtons, ref enableMenu, ref disableMenu );
#else
		Vector2 currentControllerInputValue = new Vector2( Input.GetAxis( horizontalAxisController ), Input.GetAxis( verticalAxisController ) );

		if( Vector2.Distance( Vector2.zero, currentControllerInputValue ) >= UltimateRadialMenuInformations[ radialMenuIndex ].radialMenu.minRange )
			controllerInputValue = currentControllerInputValue;

		// If the activation action is set to being the press of a button on the controller...
		if( Input.GetButtonDown( interactButtonController ) )
			inputDown = true;
		else if( Input.GetButtonUp( interactButtonController ) )
			inputUp = true;

		// If the user has a enable key assigned...
		if( enableMenuSetting != EnableMenuSetting.Manual && enableButtonController != string.Empty )
		{
			// Check for the Enable and Disable button keys and set the enable or disable booleans accordingly.
			if( Input.GetButtonDown( enableButtonController ) )
				enableMenu = true;
			else if( Input.GetButtonUp( enableButtonController ) )
				disableMenu = true;
		}
#endif
		// If the input had not been modified from the Mouse & Keyboard function before this one, then check any of the bool variables. If they have changed, set the current input device to controller for reference.
		if( !inputModifiedThisFrame && ( enableMenu || disableMenu || inputDown || inputUp ) )
			CurrentInputDevice = InputDevice.Controller;

		// If the controller input is not zero...
		if( controllerInputValue != Vector2.zero )
		{
			// Set the current input device for reference.
			CurrentInputDevice = InputDevice.Controller;

			// If the user wants to invert the horizontal axis, then multiply by -1.
			if( invertHorizontal )
				controllerInputValue.x *= -1;

			// If the user wants to invert the vertical axis, then do that here.
			if( invertVertical )
				controllerInputValue.y *= -1;

			// Set the input to what was calculated.
			input = controllerInputValue;

			// Since this is a controller, we want to make sure that our input distance feels right, so here we will temporarily store the distance before modification.
			float tempDist = Vector2.Distance( Vector2.zero, controllerInputValue );

			// If the temporary distance is greater than the minimum range, then the distance doesn't matter. All we want to send to the radial menu is that it is perfectly in range, so make the distance exactly in the middle of the min and max.
			if( tempDist >= UltimateRadialMenuInformations[ radialMenuIndex ].radialMenu.minRange )
				distance = Mathf.Lerp( UltimateRadialMenuInformations[ radialMenuIndex ].radialMenu.CalculatedMinRange, UltimateRadialMenuInformations[ radialMenuIndex ].radialMenu.CalculatedMaxRange, 0.5f );
		}
	}
}

After saving the above script, simply replace the current Ultimate Radial Menu Input Manager that is located on the EventSystem object in your scene with this one. Then enable the Controller Input option and you should see the new input logic being used.

Last updated