02 Getting Started

11 min read

Get from an empty project to a character moving and jumping on both keyboard and gamepad, using the wizard to lay the groundwork and the editor to shape it.

By the end of this page you will have Scylla Input running in a scene, an action asset picked for your genre, a context that stops the pause menu and the player fighting over the same button, and a character that moves and jumps on keyboard and gamepad without you writing a device check. Budget about twenty minutes, most of it in the wizard.

The path runs: install, add the module, run the wizard, open the editor to shape what the wizard produced, then write the controller that reads it.

Installation

Scylla Input needs Scylla Core in the project first, and Unity’s Input System package, which it builds on rather than replaces. It requires Scylla Core 1.2.0 or newer; the Getting Started window lists Core with that minimum version.

  1. Import Scylla Core, then Scylla Input.
  2. If Unity’s Input System is not already installed, add com.unity.inputsystem through the Package Manager. Unity will ask to restart the editor when it switches the active input handling; accept.
  3. Optionally import the Input demos, which include a playable ConfigScreen showing a full rebinding UI.

Setup and Configuration

Add the module to your scene

The module is a component under the bootstrap object, like every other Scylla module.

  1. If the scene has no Scylla bootstrap yet, create one with Tools > Scylla > Create > Scylla Core. That menu item adds the bootstrap object, and it greys out once the scene has one, since only one is allowed per scene.
  2. Choose Tools > Scylla > Create > Scylla Input. This adds a Scylla Input GameObject as a child of the bootstrap with the ScyllaInput component on it.
  3. Press Play. The Unity console reports the module initializing. Nothing is bound yet; the wizard fixes that next.

The component has two Inspector slots, both optional: an Input Configuration and an Input Context Configuration. Leave them empty for now. When they are unassigned the module looks for them under Resources/Config and otherwise runs on built-in defaults with the shipped default actions and contexts. The wizard will create and assign real ones in a moment.

Run the Input Wizard

The wizard is the fastest way to a working setup, because it picks sensible values for a genre rather than making you discover them. Open it with Tools > Scylla > Input > Input Wizard…. It opens centered on the Unity main window and always starts from the introduction.

It walks nine steps:

StepWhat it decides
Scylla Input WizardThe introduction. Nothing to choose.
Game ProfileThe genre. This is the important one, and everything after it is pre-filled from your choice.
Input ActionsWhich action asset to create, seeded from the profile.
Input ContextsThe context set: which situations exist and which of them block the ones beneath.
Platform SupportWhich device families the project targets.
Binding and RebindingWhether players can remap, and how rebinding behaves.
Input BufferingWhether an input pressed slightly early still counts, and for how long. Shown only when the chosen profile turns buffering on.
OutputWhere the generated assets are written.
Review and CreateA summary before anything is written to disk.

Twelve genre profiles ship, one for each factory action asset, plus a Custom profile. Each genre profile copies its factory asset and pre-configures buffering and device-detection thresholds rather than only naming an asset:

ProfileFitsNotes
3D ActionFirst or third person, on footA short input buffer for lenient jump and attack timing, and even-handed device detection for a game played as readily on a pad as on mouse and keyboard. The safe default if your game is broadly action-shaped.
Party Tactics / RPGA camera over a party, orders by pointerMouse-led detection, so the pointer keeps the active scheme and a resting gamepad does not steal it. Buffering off, because orders are deliberate rather than timed.
4X / Grand StrategyWorld map play with turn or speed controlsMouse-led detection and an unhurried scheme switch. Buffering off.
2D PlatformerRunning and jumping in two dimensionsBuffering on, for forgiving jump timing.
2D Top-DownTwin-stick movement and aimPad-led detection, so a knocked mouse does not interrupt a run. A short buffer.
PuzzleA board or grid driven by a pointerNo buffering, because nothing is timed. Mouse-led detection.
Fighting / Beat-em-upTwo players, six attack buttons eachThe longest buffer window and the deepest queue of any profile. Device detection is off, because on a shared keyboard one player’s input would otherwise switch the other player’s scheme.
RacingSteering on an axis, pedals on the triggersHigh detection thresholds, because a wheel and pedals rest away from center.
Flight / Space SimPitch, roll, yaw and a throttle axisHigh detection thresholds, for a stick and throttle that sit off-center all game.
Shoot ’em UpMove, fire, bomb, focusA short buffer, so a bomb pressed a frame late still counts.
Point & Click / AdventurePointer-driven scenes and dialogueMouse-led detection and relaxed switching. No locomotion map.
Survival / SandboxFirst person play plus a hotbar, building and craftingA short buffer for the on-foot actions.
CustomAnything elseStarts from the Input Configuration’s own defaults. No factory asset is copied.

Pick the profile closest to your game, walk the remaining steps, and let the final step write the assets. You are not locked in: everything the wizard produces is an ordinary asset, and the next section shows you how to edit it.

What the wizard leaves you with

The wizard adds the ScyllaInput module under the bootstrap if the scene does not have one yet. When the scene has no bootstrap either, the wizard creates that first, so it also works in an empty scene. Then it writes these assets:

  • An .inputactions asset, copied from the profile’s factory asset. This is Unity’s own format, holding maps, actions, bindings and control schemes.
  • A .scyllainput sidecar next to it, holding the Scylla-specific concerns Unity’s format has no room for: annotations, rebindability, config-screen layout and conflict tags.
  • An Input Configuration asset carrying the buffering and device-detection settings the profile chose. Its Input Action Assets list references the new actions asset.
  • An Input Context Configuration asset, when you keep the default contexts on the Input Contexts step.

Both configuration assets are assigned on the ScyllaInput component. By default they are written to Assets/Scylla/Resources/Config, which is also where the module looks when a slot is empty. Full settings reference is on Configuration.

Shaping it in the Input Actions Editor

The wizard gets you a working setup. The editor is where you make it yours. Open it with Tools > Scylla > Input > Input Actions Editor…, or with Ctrl+Shift+I (Cmd+Shift+I on macOS).

Load your asset

The editor opens on the asset it used last. To load a different one, use the asset field in the toolbar. Double-clicking an .inputactions asset in the Project window opens it here once you turn on the matching setting under Edit > Preferences > Scylla > Input; it is off by default, so a double-click opens Unity’s own editor until then.

Twelve factory assets ship, one per genre, and loading one is the quickest way to see how a genre’s input is usually laid out before you build your own. Each one also has a matching wizard profile, so you can compare genres here and then run the wizard on the one you settle on.

Add an action

The left pane holds the tree, with maps at the top level, actions nested under them, and bindings nested under those.

  1. Select the map you want the action in, for example Gameplay - On Foot.
  2. Use the add control in the toolbar to create an action under it.
  3. Name it, and set its type. A button for a discrete press, a value for something continuous like movement.
  4. With the action selected, add a binding and pick a control.

The control picker is searchable and filtered by device, so finding <Gamepad>/buttonSouth does not mean scrolling a list of every control Unity knows about.

The tree also supports the keyboard: Alt with an arrow key reorders and steps over a whole composite rather than into it, the platform’s action modifier with C, V or D copies, pastes or duplicates, and Delete or Backspace removes, which matters on a Mac laptop with no dedicated Delete key. The ? button in the toolbar lists them in full.

Set up contexts

A context is the answer to “which controls are live right now”. Without one, opening the pause menu leaves the player still able to jump, and the same button does two things at once.

The editor has a context editor where you declare them. Each context carries a priority and a flag for whether it blocks everything beneath it. A pause menu blocks; a HUD overlay usually does not.

At runtime you push and pop them as a stack:

/* Push when the menu opens. Menu is one of the default contexts, and it blocks the
   gameplay context beneath it, so the player cannot jump while the menu is up. */
ScyllaInput.Instance.PushContext("Menu");

/* Pop when it closes. The stack restores whatever was live before, so you do not
   have to remember what that was. */
ScyllaInput.Instance.PopContext();

/* Ask, rather than tracking it yourself. */
if (ScyllaInput.Instance.IsContextActive("Gameplay"))
{
    /* ... */
}

The full model, including priorities, blocking rules and how contexts interact with control schemes, is on Contexts.

Usage

Read an action every frame

Movement, aiming, and anything feeding a per-frame calculation wants a cached action reference read in Update.

using Scylla.Core;
using Scylla.Input;
using UnityEngine;

public sealed class PlayerController : MonoBehaviour
{
    /* Cache the references once. GetAction is a dictionary lookup, cheap but not
       free, and the reference stays valid for the lifetime of the registered asset. */
    private ScyllaInputAction _moveAction;
    private ScyllaInputAction _jumpAction;

    private void Start()
    {
        /* The action asset is registered during module initialization, which happens
           after Awake. RunWhenReady hands control back the moment that is done, so
           this is the safe place to resolve actions. */
        ScyllaCore.Instance.RunWhenReady(() =>
        {
            /* Named by the map that declares it and its own name, exactly as they
               read in the editor. Returns null when the pair does not resolve. */
            _moveAction = ScyllaInput.Instance.ActionManager.GetAction("Gameplay - On Foot", "Move");
            _jumpAction = ScyllaInput.Instance.ActionManager.GetAction("Gameplay - On Foot", "Jump");
        });
    }

    private void Update()
    {
        if (_moveAction == null)
        {
            return;
        }

        /* ReadVector2 returns the composite value: WASD, a stick, or whatever else
           is bound. You never branch on which device produced it. Allocates nothing. */
        var move = _moveAction.ReadVector2();

        /* WasPerformedThisFrame is a property, true on exactly one frame. Prefer it
           over IsPressed for jump, attack and interact, or a held button retriggers
           every frame. */
        if (_jumpAction != null && _jumpAction.WasPerformedThisFrame)
        {
            Jump();
        }

        ApplyMovement(move);
    }

    private void Jump() { /* ... */ }
    private void ApplyMovement(Vector2 move) { /* ... */ }
}

When you only need a yes or no and do not want to cache anything, the facade answers directly:

/* IsActionPressed is true every frame the binding is held; WasActionPerformedThisFrame
   is true on the one frame it fired. Both return false when the names do not resolve,
   so a typo fails quietly rather than throwing. */
if (ScyllaInput.Instance.IsActionPressed("Gameplay - On Foot", "Sprint"))
{
    ApplySprint();
}

if (ScyllaInput.Instance.WasActionPerformedThisFrame("Gameplay - On Foot", "Interact / Pickup"))
{
    Interact();
}

/* GetActionValue for a single float. Use it on a Value action, where the number is
   the point; on a Button action it only ever reads 0 or 1. */
var zoom = ScyllaInput.Instance.GetActionValue("Gameplay - Common", "Camera Zoom");

React once per press instead of polling

When a system only needs to know that something happened, subscribing beats polling. The module publishes on the SEX (Scylla Event eXchange) bus.

private ScyllaEventSubscription _jumpSubscription;

private void OnEnable()
{
    /* Fires for every action that reaches its performed phase, so check which one
       before acting. */
    _jumpSubscription = ScyllaEvents.Listen<InputActionPerformedEvent>(this, OnActionPerformed);
}

private void OnDisable()
{
    /* The bus does not auto-unsubscribe. Dispose it or the handler outlives the object. */
    _jumpSubscription?.Dispose();
}

private void OnActionPerformed(InputActionPerformedEvent evt)
{
    if (evt.ActionID == "Jump")
    {
        PlayJumpSound();
    }
}

InputActionStartedEvent and InputActionCanceledEvent cover the other two phases. Device connect and disconnect have their own events, covered on Devices and Bridges.

Where to go next

Troubleshooting