Skip to content

Input and controls ​

Open Settings → Project Input (or use Input in the bottom shelf) to connect keys, mouse buttons and gamepads to named actions in scripts and Flow. Built-in controllers also expose their own movement and jump bindings in the Inspector.

Create an action for a script ​

  1. Open Input → Gameplay. This context is active by default.
  2. Click Jump · Space, Move left / right · A D, or Move 2D · WASD for a ready-to-use action. Add Action creates a custom one.
  3. Choose Button for jump/fire, Axis for left/right, or Vector2 for four-direction movement. Click + to add the appropriate binding. For movement, Left stick adds a gamepad stick; its selector can switch to the right stick.
  4. Copy the input expression displayed under the action. A string matches its stable ID or a unique, case-sensitive name. Renaming the action requires updating string references; typed Actions.Jump bindings keep their saved identity.
  5. Press Play, focus the game, and test. The row's meter shows resolved action activity. The device map separately shows which physical inputs are arriving.
ActionScript readResult
Button named JumpInput.Pressed("Jump")True once on the press frame
Button named JumpInput.Held("Jump")True while held
Button named JumpInput.Released("Jump")True once on release
Axis named MoveHorizontalInput.Axis("MoveHorizontal")-1 left, 0 idle, +1 right
Vector2 named MoveInput.Vector("Move")X/Y direction; diagonals are normalized

Input.Pressed("Space") only works if an action is named Space. It does not read a raw key. Missing actions and inactive contexts read false or zero. Additional contexts require the Push input context Flow action; choosing their tab in the panel only edits them.

For a complete input-to-physics example, see Jump with Space. The full Input API is also available in Scripts → Manual → Reference → Input.

Pointer interactions ​

A pointer is a mouse cursor or a touch point. Both produce the same interactions.

You wantAdd thisReacts to
An object the player can tapInteractable component (or an on-tap graph)Tap, double-tap, long-press
An object the player can dragDraggable componentPress, drag, release
A place a dragged object can be droppedDrop Zone componentAn accepted drop

In Visual scripting, objects can also listen for pointer events directly — tap, double tap, long press, pointer enter / pointer leave, and the drag lifecycle (drag start, drag, drag end) plus drop results (drop, dropped on). Use these when a plain component reaction is not enough.

A tap only reaches an object that opts in. Decorations and background art are ignored, so taps fall through to the interactive object beneath them.

Do — tappable coin

  • Interactable enabled, Block taps behind `on` (default — consumes the tap)
  • Sprite 48×48 px with 8 px padding in Asset Studio
  • On Tap → Add Counter score +1 → Destroy on the coin itself

Don't — wall that eats taps

  • Big invisible panel with Interactable + Block taps behind `on` sitting above the coin
  • Transparent hitbox twice the sprite size, not trimmed
  • On Tap on a parent that never receives the tap

Multi-touch ​

Opal games are multi-touch. Every finger on the screen is tracked as its own independent pointer, so more than one thing can happen at once:

  • Two objects, two fingers. A player can drag two draggable objects at the same time — each object follows only its own finger.
  • Drag while tapping. One finger can hold and drag an object while another finger taps or interacts with a different object.
  • Independent gestures. Each touch has its own tap, drag, and long-press timing — one finger's gesture never cancels another's.

There is nothing to turn on. Any Interactable or Draggable object automatically works under multiple simultaneous touches, and this holds both in editor Play mode and in published and exported games.

Two-finger interaction is easiest to feel on a real phone or tablet. Desktop browsers have one mouse pointer, so you will see one interaction at a time there.

Keyboard controls ​

The keyboard is the main way to drive character movement.

When a movement component (Top-Down, Platformer, or Side-Scroller Controller) is set to Controlled By: Player, it reads the keys configured on that component:

FieldDefaultMoves
Left KeyArrowLeftLeft
Right KeyArrowRightRight
Up KeyArrowUpUp
Down KeyArrowDownDown
Jump KeySpaceJump (Platformer)

WASD Also Moves is on by default, so W A S D work alongside the arrow keys. In a Platformer, the Up key and W also jump, so a character can jump without any extra setup. Set Controlled By to Flow, AI, or Network when movement should come from somewhere other than the keyboard.

For custom key handling anywhere in a game, Flow graphs can listen for key down and key up events and act on any key.

Playing on touch devices ​

Because Opal uses one shared input path for mouse and touch, tap and drag gameplay works on phones and tablets out of the box — including multi-touch. Games built around tapping objects, dragging pieces, and dropping them onto targets are ready for mobile with no extra work.

The touch joystick gap — three honest workarounds ​

Player character controllers read the keyboard by default, and the editor does not yet ship a placeable on-screen virtual joystick / button pack. At runtime the controller also reads a virtualInput store ({ moveX, moveY, jump }, additive with keys), but there is no Set virtualInput Flow node — you drive movement through controller actions (Move Direction, Move Toward, Jump) with Controlled By: Flow. For a touch-first game today, use one of these:

Pattern A · Tap-to-move (no virtual stick)Easiest

Set controller Controlled By: Flow. On your Scene Flow:

text
On Tap (on the ground object) → Move To → target = pointer.worldX/Y
On Tap (on the ground) → Play Motion "Walk"
On Timer 0.15s → Stop Motion when arrived

No virtualInput needed. Works on phone and desktop. Feels like an adventure game.

Pattern B · On-screen D pad from UI buttons4 buttons

Keep controller Controlled By: Player. Add 4 UI Button widgets (← → ↑ ↓) anchored bottom-left. Each button emits a custom event you listen for in Flow:

text
UI Button "Left"  → On Custom Event "leftDown"  → Move Direction x:-1 y:0  (on player, once; hold repeats via repeat)
UI Button "Left"  → On Custom Event "leftUp"    → Move Direction x:0  y:0  (or Stop)
# mirror for Right / Up / Down
UI Button "Jump"  → On Custom Event "jumpDown"  → Jump  (Platformer action)

Use Move Direction (x, y in -1..1) on a controller set to Controlled By: Flow or Move Toward (x, y, stopWithin). The runtime also keeps a virtualInput store ({ moveX, moveY, jump }) that is additive with keys, but there is no Set virtualInput node — drive movement through those Flow actions. Make buttons 44×44 px minimum with 8 px padding — that's a comfortable finger target.

Pattern C · Flow-driven intent (precise)Most control

Set controller Controlled By: Flow and drive it entirely from Flow graphs. On your player Object Flow:

text
On Custom Event "leftDown"  → Move Direction x:-1 y:0   (on player)
On Custom Event "leftUp"    → Move Direction x:0  y:0
On Custom Event "rightDown" → Move Direction x:1  y:0
On Custom Event "rightUp"   → Move Direction x:0  y:0
On Custom Event "jumpDown"  → Jump
# Hold a direction → player walks; release → Stop. Combine with keyboard — Flow intent is additive with keys.

For point-and-click movement, use Move Toward (x, y, stopWithin: 8) to a tapped world position instead of holding a direction. This is the "you own every frame" path — use it when you need coyote time, buffered jumps, or an analog-ish stick you draw yourself.

Touch-friendly checklist ​

  • [ ] Tap targets ≥ 44×44 px including padding (mouse targets can be 24 px — fingers can't)
  • [ ] HUD elements anchored to corners/edges so they stay readable at 375 px and 1280 px
  • [ ] Tested in fullscreen Play with browser chrome visible (iOS Safari hides the bottom bar and shrinks the viewport)
  • [ ] Nothing large with Interactable (Block taps behind on) sits above smaller tap targets
  • [ ] Dragged objects have a Drop Zone with a visible highlight when something hovers

Debugging input ​

SymptomCheck
Tap never firesInteractable disabled, wrong object, edit mode not Play, covered by another Interactable
Drag snaps backDraggable missing, or Drop Zone rejected the drop — watch Flow overlay for drop vs droppedOn
Keys move the wrong objectTwo controllers both set to Player — set the non-player one to Flow or AI
Virtual buttons driftMove Direction left non-zero on pointer up — always send x:0 y:0 / Stop on pointer up / pointer leave
Multi-touch fails on desktopExpected — desktop has one mouse. Test on a phone with Play → Fullscreen