Managing inputs in Unity can quickly become unwieldy, especially when dealing with multiple devices and input schemes. This guide explores a modular approach using ScriptableObjects to manage device-specific icons, decouple input events, and enable dependency injection for flexibility.
Goals
- Ease of Management: Simplify handling device-specific input icons.
- Decoupling: Avoid relying on a centralized input manager.
- Flexibility: Use ScriptableObjects for modular and reusable input definitions.
Drawbacks
InputActionDefinition
OnInput
returns aCallbackContext
that can have any information- Subscribers have to assume the
CallbackContext
has the info they need (ex. aVector2
)
Steps
Follow these steps to implement this architecture:
- Setup Input Actions: Open a Unity
InputAction
asset and configure the necessary inputs. - Create InputActionDefinitions: For each input, create an
InputActionDefinition
ScriptableObject. - Add a PlayerInput Component: Attach a
PlayerInput
component to a GameObject in the scene. - Set to Invoke Unity Events: Configure the
PlayerInput
component’s behavior to Invoke Unity Events. - Bind Input Definitions: Assign an
InputActionDefinition
to trigger theFire()
method for each input action. - Inject Inputs Where Needed: In future components, reference the appropriate
InputActionDefinition
assets to handle inputs.
Architecture Diagram
Below is a high-level architecture diagram of this setup:
classDiagram
class ScriptableObject
class InputActionDefinition {
+name : string
+keyboardIcon : Sprite
+gamepadIcon : Sprite
+touchIcon : Sprite
+OnInput : Action~InputAction.CallbackContext~
+Fire() void
+GetIcon() Sprite
}
ScriptableObject <|-- InputActionDefinition
InputActionDefinition -- Move.asset : Create SO
InputActionDefinition -- Jump.asset : Create SO
Move.asset <.. PlayerController : References
Jump.asset <.. PlayerController : References
class PlayerController {
+InputActionDefinition OnMove
+InputActionDefinition OnJump
+Move() void
+Jump() void
}
class PlayerInput {
}
note for PlayerController "Pass in the desired definition assets.
Use their OnInput event." note for PlayerInput "Set behavior to invoke Unity Event.
Match the InputActions with
the related InputActionDefinition"
Use their OnInput event." note for PlayerInput "Set behavior to invoke Unity Event.
Match the InputActions with
the related InputActionDefinition"
Example PlayerInput Component
Example Implementation
Here’s a simple example of how input handling might look in your script:
//PlayerController.cs
[SerializeField] InputActionDefinition OnMove;
[SerializeField] InputActionDefinition OnJump;
private void Start()
{
OnMove.OnInput += HandleMove;
OnJump.OnInput += HandleJump;
}
private void HandleMove(InputAction.CallbackContext ctx) {
Vector2 movement = ctx.ReadValue<Vector2>();
// Movement Logic
}
private void HandleJump(InputAction.CallbackContext ctx) {
if (ctx.started) {
// Jump Logic
}
}