07 — Puzzle Selection and Drag & Drop

Run Tools → Input System Starter Kit → Create Puzzle Demo (Drag and Drop) in an empty scene. Drag the three colored pieces into the translucent slots — they snap when close, return home when dropped in the void, and Esc aborts a drag mid-air. Tab/E/Q (or shoulder buttons) cycle a highlighted selection without touching the mouse.

Pointer input done right — DragAndDropController.cs

The Puzzle map's Point action is bound to <Mouse>/position, <Pen>/position, and <Touchscreen>/primaryTouch/position. The script reads the action, so it has no idea (and doesn't care) whether the player uses a mouse, stylus, or finger:

Vector2 screen = pointAction.ReadValue<Vector2>();
Vector3 world  = worldCamera.ScreenToWorldPoint(screen);

ScreenToWorldPoint is the bridge from screen pixels to world units — with an orthographic camera it's exact; just zero the z.

The drag lifecycle maps onto Click's events:

Draggable and SnapSlot are tiny marker components (a home position, an occupancy flag). The controller owns all logic — one place to read, one place to debug.

Selection without a pointer — SelectionCycler.cs

Puzzle games need "change which thing is active": Tab through pieces, shoulder-bump through tools. NextSelection/PreviousSelection handlers move an index and apply purely visual feedback (scale up, full opacity). Note both puzzle scripts call map.Enable() on the same map — that's safe and normal; maps reference-count internally.

This is also your accessibility story: everything the mouse can select, the keyboard can reach.

What about UI drag-and-drop?

This lesson drags world objects. For dragging UI elements (inventory icons in UI Toolkit), the concept transfers but the plumbing differs — UI Toolkit has its own pointer events (PointerDownEvent, PointerMoveEvent, capture). Cross-reference the UI Toolkit Starter Kit; samyam's drag and drop video covers the uGUI flavor.

Exercises

  1. Merge the two scripts' powers: make Click while a piece is selected via keyboard place the selected piece at the pointer.
  2. Add a RotatePiece action (R / buttonNorth) that rotates the held piece 90° — the start of every tile puzzle.
  3. Require each piece to match a specific slot (give both a pieceId int); wrong slots reject the drop. Congratulations: shape sorter → actual puzzle game.
  4. Build check: when all three slots are filled, log "Solved!" — where does that check belong? (Answer: the controller's snap-in moment, not Update.)

Next: 08 - Going Further