Input Integration¶
Massive Swarm System ships an optional input layer that feeds movement directions into the swarm simulation from any player-controlled character. This page covers the IMoveInputSource contract, the Unity Input System adapter, and the mobile joystick canvas.
Optional package required
The Input System adapter components — InputSystemMoveInputSource and MobileTouchJoystickCanvas — live in the MassiveSwarmSystem.InputSystem assembly. That assembly only compiles when com.unity.inputsystem is installed in your project. The core runtime (MassiveSwarmSystem.Runtime) has no dependency on Input System and compiles cleanly without it.
If com.unity.inputsystem is not in your project, install it via Window → Package Manager → Unity Registry → Input System before using these components.
The switch is automatic. The assembly declares a version define that sets MASSIVE_SWARM_SYSTEM_INPUT_SYSTEM whenever com.unity.inputsystem is present, and constrains itself to that symbol, so installing the package compiles the assembly in and removing it compiles the assembly out. Nothing to configure, and no compile errors either way. You can guard your own code with the same symbol when it has to work in projects that may or may not have Input System installed.
DefaultTargetMoveController — Zero-Setup Option¶
DefaultTargetMoveController moves the bundled default target with WASD or a gamepad left stick. Add it to your target GameObject and press Play — no Input Actions asset, no package dependencies, no wiring required.
It lives in the core runtime (MassiveSwarmSystem.Runtime) and has no dependency on com.unity.inputsystem. When the Input System package is installed, it reads keyboard and gamepad input via reflection so it works without an Input Actions asset. It also reads the legacy Horizontal and Vertical axes whenever the old Input Manager is compiled in, which includes Active Input Handling = Both. Under Both it sums the two reads and clamps the result to magnitude 1, so holding W on the keyboard and pushing a stick does not double the speed. If those axes are missing from Project Settings, the legacy half falls back to zero and logs one warning rather than throwing every frame.
This component is not an IMoveInputSource. It moves the target transform directly in Update and is meant to be replaced by your real player controller once you are past the getting-started stage.
Add it via Component → Massive Swarm System → Input → Default Target Move Controller. Only one per GameObject.
Inspector fields¶
| Field | What it controls |
|---|---|
| Move Speed | World units per second the target moves. Default 6. |
| Dead Zone | Analog stick dead zone as a magnitude fraction (0–0.5). Input below this is ignored. Default 0.15. |
| Camera Relative Movement | When on, WASD and stick input move relative to the main camera's flat forward and right axes. When off, input maps directly to world X/Z. On by default. |
| Face Move Direction | Rotates the target toward the movement direction each frame. On by default. |
| Rotation Speed | Degrees per second used to rotate toward the movement direction when Face Move Direction is on. Default 720. |
Movement is flat, on the world XZ plane, with no grounding at all. That suits the flat getting-started ground and nothing else, which is another reason to replace it with your own controller before you build a real level.
When to use this vs InputSystemMoveInputSource
Use DefaultTargetMoveController to get the swarm moving in minutes with no setup. Switch to InputSystemMoveInputSource (or a custom IMoveInputSource) once you want input rebinding, action maps, or mobile touch support.
Overview¶
Any component that implements IMoveInputSource can feed movement to a controller that reads directional input — a player controller, an AI driver, or any custom system.
One ready-made implementation ships: InputSystemMoveInputSource, which wraps a Unity InputActionReference such as a Gameplay/Move action from your Input Actions asset.
MobileTouchJoystickCanvas builds a complete on-screen joystick at runtime, no prefab required, but it is not an IMoveInputSource and cannot be assigned where one is expected. It works a layer lower down: it simulates a virtual gamepad left-stick, so any Move action bound to <Gamepad>/leftStick picks it up automatically. The chain is joystick, then your Move action, then InputSystemMoveInputSource, then your controller.
The IMoveInputSource Contract¶
IMoveInputSource is the only thing any system in this package needs to know about player input.
ReadMove() returns the current movement vector. The XY axes map to horizontal and vertical movement in whatever coordinate space the consuming system expects (typically world-relative XZ). Return Vector2.zero when there is no input.
Implement this interface on any MonoBehaviour to provide input from a source not covered by the shipped adapters — keyboard polling, a custom gamepad mapper, a nav-mesh-driven AI controller, or a replay system.
using MassiveSwarmSystem.Runtime.Input;
using UnityEngine;
public sealed class KeyboardMoveInputSource : MonoBehaviour, IMoveInputSource
{
public Vector2 ReadMove()
{
#if ENABLE_LEGACY_INPUT_MANAGER
return new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
#else
// Input System only: read Keyboard.current / Gamepad.current here instead.
return Vector2.zero;
#endif
}
}
Do not call UnityEngine.Input unguarded
Input.GetAxis compiles under any setting, but it throws an InvalidOperationException at runtime once Active Input Handling is set to Input System Package (New), which is what the note at the top of this page asks you to install. The ENABLE_LEGACY_INPUT_MANAGER guard above is the same one DefaultTargetMoveController uses, and it wraps the call in a try/catch for the same reason.
Have your own player controller hold a reference to this component as an IMoveInputSource and call ReadMove() each frame. Nothing in the core package calls it for you — the FullDemo DemoPlayerController shows the pattern, reading its source once per Update.
InputSystemMoveInputSource¶
Add via Component → Massive Swarm System → Input → Input System Move Input Source.
Reads a Vector2 action from the Unity Input System and exposes it through IMoveInputSource.
Requires com.unity.inputsystem
This component only compiles when the Input System package is installed. See the warning at the top of this page.
Inspector fields¶
| Field | What it controls |
|---|---|
| Move Action | An InputActionReference pointing to a Vector2 Move action. Assign the Gameplay/Move action (or equivalent) from your Input Actions asset. |
| Dead Zone | Radial dead zone applied to the action's Vector2 (0–0.5, default 0.15). Input below this magnitude reads as zero; input above it is rescaled so the usable range still reaches full magnitude. |
How it works¶
On OnEnable, the component enables the assigned action if it is not already enabled, and disables it again on OnDisable — but only if this component was the one that enabled it. If the action was already running (managed by a PlayerInput component or an InputActionAsset enabled elsewhere), the component leaves it alone and does not disable it on teardown.
If no InputActionReference is assigned, ReadMove() returns Vector2.zero and a one-time warning is logged to the console.
Setup steps¶
- Create or open your Input Actions asset (Assets → Create → Input Actions).
- Add a Vector2 action named
Moveunder an action map (e.g.Gameplay). Bind it to the controls you need (keyboard WASD, gamepad left stick, etc.). - Add
InputSystemMoveInputSourceto the same GameObject as your player controller. - Drag the
Moveaction from the Input Actions asset into the Move Action field. - Assign the
InputSystemMoveInputSourcecomponent reference to your player controller's input source field.
MobileTouchJoystickCanvas — Mobile On-Screen Joystick¶
Add via Component → Massive Swarm System → Input → Mobile Touch Joystick Canvas.
Drop this component on any GameObject in your scene. When Play mode starts, it builds a self-contained Canvas with a draggable joystick. No prefab, no manual UI hierarchy needed — everything is created at runtime.
The joystick simulates a virtual gamepad left-stick by default (<Gamepad>/leftStick). Any Move action bound to that path receives the input without extra wiring.
Requires com.unity.inputsystem
This component only compiles when the Input System package is installed.
Quickstart¶
- Add an empty GameObject to your scene. Name it
Mobile Joystick. - Add Mobile Touch Joystick Canvas via the Component menu.
- Leave the defaults. Press Play. A joystick appears in the bottom-left corner (Editor counts as a touch platform under the default Activation Mode).
- If your
Moveaction already binds<Gamepad>/leftStick, input flows automatically. If not, add that binding or change Control Path to match your action.
Parameter Reference¶
Activation group¶
| Field | What it controls |
|---|---|
| Activation Mode | Auto Touch And Editor (default) always shows the joystick in the Editor and in iOS/Android builds, and on any other platform it shows it when Unity reports a touchscreen. Always shows it everywhere with no check. Touch Only shows it whenever a touchscreen device is present, which includes the Editor on a touch laptop or with the Device Simulator open. |
| Mode | Fixed — joystick sits in a screen corner permanently. Follow Finger — joystick is hidden until touched; it appears under the finger and follows it past the outer ring. |
Fixed Layout group¶
Applies only when Mode is Fixed.
| Field | What it controls |
|---|---|
| Anchor | Which screen corner the joystick base sits in: Bottom Left, Bottom Right, or Bottom Center. |
| Anchor Offset | Pixel offset from the chosen corner to the joystick center, at the configured reference resolution. |
Follow Finger Layout group¶
Applies only when Mode is Follow Finger.
| Field | What it controls |
|---|---|
| Press Zone | Which portion of the screen reacts to touches: Full Screen, Left Half, or Right Half. |
| Base Follows Finger | When on, the base drags with the finger once the finger crosses the outer ring. When off, the knob saturates at the rim. |
| Show Visuals | When on, the base and knob are visible while the finger is pressed. Turn off for an invisible stick. |
| Inner Dead Zone | Dead zone as a fraction of the outer radius. Movements smaller than this give zero output. |
| Outer Saturation Padding | Once the finger is within this fraction of the rim, output locks to full magnitude. Improves the "full-speed" feel near the edge. |
| Fade Duration | Seconds for the base and knob to fade out after the finger lifts. They snap to fully visible on press, so this governs the release only. 0 is instant. |
| Secondary Tap Control | Input System control path for a secondary button. A second finger landing while the joystick is held sends a press to this control — useful for a jump button on the same touch zone. Default <Gamepad>/buttonSouth. Leave empty to disable. |
The inspector draws the ring for you
Below these fields the custom inspector paints a small preview: an outer circle for the full stick, a filled inner disc for Inner Dead Zone, and a second ring where Outer Saturation Padding starts. Drag either slider and watch the rings move rather than guessing at the numbers.
Visuals group¶
| Field | What it controls |
|---|---|
| Base Diameter | Diameter of the joystick base in pixels at the reference resolution. |
| Handle Diameter | Diameter of the draggable knob in pixels. |
| Outer Radius (px) | How far the knob travels from center (in pixels at the reference resolution) before the output magnitude saturates at 1. |
| Opacity | Overall opacity of the base and knob. |
| Base Color | Fill color of the outer base ring. |
| Handle Color | Fill color of the inner knob. |
Input System group¶
| Field | What it controls |
|---|---|
| Control Path | Input System control path the joystick simulates. Default <Gamepad>/leftStick. |
| Use Isolated Input Actions | Fixed mode only. Prevents the stick snapping back when control schemes auto-switch. Leave on unless your input setup has a specific reason to disable it. |
| Stick Behaviour | Fixed mode only. Passed to Unity's OnScreenStick.Behaviour. |
Canvas group¶
| Field | What it controls |
|---|---|
| Canvas Sort Order | Sort order of the runtime canvas. Raise this if your own UI renders on top of the joystick. |
| Reference Resolution | Reference resolution for the CanvasScaler (Scale With Screen Size mode). Match this to your game's design resolution. |
How the canvas is built¶
MobileTouchJoystickCanvas creates the entire UI hierarchy in code when the component first enables. It adds a Screen Space Overlay Canvas with a CanvasScaler and GraphicRaycaster, plus the joystick base, hit area, and knob Image components sized from your visual settings. If no EventSystem exists in the scene, it creates one with an InputSystemUIInputModule. If one exists without an InputSystemUIInputModule, the component replaces the existing input module so drag events reach the stick correctly.
The Canvas and its children are parented under the same GameObject as MobileTouchJoystickCanvas. Disabling the component hides the canvas; enabling it shows it again (or builds it for the first time).
Follow Finger mode for mobile games
For most mobile games, Follow Finger mode with Press Zone = Left Half is the best starting point. The joystick only occupies screen space while the player is touching it, and the base always appears where the finger lands — no learning curve.
FloatingOnScreenStick — Advanced Use¶
FloatingOnScreenStick is the lower-level component that MobileTouchJoystickCanvas uses internally in Follow Finger mode. You can add it directly to a UI Image when you want to build your own joystick visual hierarchy but still need the floating stick behavior.
Add via Component → Massive Swarm System → Input → Floating On Screen Stick. The component requires a RectTransform.
Inspector fields¶
| Field | What it controls |
|---|---|
| Control Path | Input System control path the stick drives. Default <Gamepad>/leftStick. |
| Base Rect | Optional RectTransform for the visible joystick base. Repositioned to the touch point on press; hidden when not pressed. |
| Knob Rect | Optional RectTransform for the draggable knob. Follows the finger within the outer radius. |
| Outer Radius | Distance from the base center in canvas units at which output magnitude reaches 1. |
| Follow Finger | When on, the base repositions when the finger passes the outer radius so the knob stays within range. |
| Inner Dead Zone | Dead zone as a fraction of Outer Radius. |
| Outer Saturation Padding | Saturation zone as a fraction of Outer Radius. Output locks to 1 before the finger fully reaches the rim. |
| Fade Duration | Seconds for the base and knob to fade out on release. Press is always instant. 0 is instant both ways. |
| Secondary Tap Control Path | A second finger landing while the joystick is held sends a press to this control. Default <Gamepad>/buttonSouth. Leave empty to disable. |
When to use FloatingOnScreenStick directly¶
Use FloatingOnScreenStick when you have your own joystick visual hierarchy and just need the floating-stick input behavior, or when the joystick must sit inside an existing Canvas you control.
Use MobileTouchJoystickCanvas when you want everything built automatically with no manual UI setup.
Attach to a raycast-target Image
FloatingOnScreenStick receives input through Unity's UI event system. Attach it to a RectTransform that has an Image with Raycast Target enabled — the stick will not receive pointer events without one. MobileTouchJoystickCanvas handles this automatically; it is only a concern when placing FloatingOnScreenStick manually.
Quickstart — wire input in this order
- Install
com.unity.inputsystemif you haven't already (Window → Package Manager → Unity Registry → Input System). - For keyboard/gamepad input: add
InputSystemMoveInputSourceto your player GameObject, assign yourMoveaction reference. - For mobile touch input: add an empty GameObject to the scene, add
MobileTouchJoystickCanvas, leave Mode = Fixed and press Play to confirm the joystick appears. - Switch to Mode = Follow Finger and Press Zone = Left Half once the basic flow works.
- Assign
InputSystemMoveInputSourceto your player controller's input source field. The joystick is not assignable there: it feeds the gamepad stick that your Move action already reads. - For a custom input source, implement
IMoveInputSourcedirectly on a MonoBehaviour and assign that instead.