Shmup Design · June 30, 2026
Controller Rumble and Haptic Feedback in Shmups: Designing Feel Through Vibration
Most indie shmups skip controller rumble entirely. It is a mistake. Rumble is the only feedback channel that bypasses the visual system completely and reaches the player through touch. In a genre where visual attention is at maximum load during intense play, a well-designed rumble signal can communicate hit confirmation, power level, and boss phase transitions without demanding any additional visual processing. The players who notice rumble most are the players who play without it after getting used to it — the game suddenly feels distant and disconnected.
Published June 30, 2026
Two motors, two functions
Standard game controllers contain two vibration motors: a large low-frequency motor (the left motor in Xbox-style controllers) that produces a heavy, rumbling sensation, and a small high-frequency motor (right motor) that produces a buzzing, tingling sensation. These are designed for different categories of event.
| Motor | Character | Ideal shmup uses |
|---|---|---|
| Large / low-frequency | Heavy rumble, impact | Player hit, large explosion, boss contact, death |
| Small / high-frequency | Buzz, tingle | Rapid-fire shot, engine vibration, graze proximity |
Using only one motor for all events flattens the expressive range. Using both motors for every event simultaneously is fatiguing and makes distinct events indistinguishable by feel. The design goal is to use each motor for events in its natural frequency range and reserve combined motor use for the most significant moments.
Mapping game events to rumble
A practical starting point for a standard shmup:
- Player shooting (rapid fire): Very low intensity high-frequency motor, 0.03–0.05 magnitude. Runs continuously while the fire button is held. This simulates engine vibration and weapon recoil without being distracting. If it is noticeable while looking at the screen, it is too strong.
- Player hit (taking damage): Large motor at 0.7 magnitude for 150ms. Sharp and brief — long enough to register, short enough not to interfere with the dodge response that needs to follow immediately.
- Player death: Both motors at 0.9–1.0 magnitude, ramping down over 400ms. This is the most significant event in the run; the rumble should feel conclusive.
- Boss entrance: Large motor ramp from 0.0 to 0.5 over 600ms, then cut. Sets mood and signals the transition without being harsh.
- Bomb detonation: Both motors at high intensity for 200ms, then large motor alone sustaining at medium intensity for the bomb duration. Communicates the detonation impact and the ongoing field effect.
- Graze (if implemented): Small motor at 0.15 for 60ms per graze tick. Barely perceptible, adds presence to the graze zone without overwhelming other signals.
Rumble budget management
Multiple simultaneous rumble events stack, and unconstrained stacking produces undifferentiated constant vibration that loses all expressiveness within seconds. A simple priority queue solves this: each rumble event has a priority level, and only the highest-priority active event drives each motor. Lower-priority events queue but do not activate until the current event expires.
Set player hit and death as the highest priority events so they can never be masked by ongoing shoot rumble. Bomb effects take second priority. Ambient shoot vibration is lowest priority and is suppressed whenever any other event is active.
Platform considerations
Rumble API availability varies by platform and engine. In Godot, Input.start_joy_vibration(device, weak_magnitude, strong_magnitude, duration) controls both motors. In Unity, Gamepad.current.SetMotorSpeeds(low, high) provides direct control. SDL-based implementations use SDL_GameControllerRumble.
Notably, not all controllers implement rumble, and some controllers only implement one motor. Design rumble as enhancement, not dependency: the game must be fully playable with rumble disabled or absent without any mechanical disadvantage. This is also an accessibility requirement — some players with motor control differences find rumble disorienting and need a clean disable option in settings.
Testing methodology
Rumble design cannot be tested by reading code or looking at parameter values. It must be felt. The correct testing protocol:
- Set up a build on a device with a real controller, not a keyboard.
- Play through a full stage with rumble enabled, focusing attention entirely on what you feel rather than what you see.
- Identify events where rumble was unexpectedly absent (adding feedback opportunity) or unexpectedly present (causing confusion).
- Disable rumble entirely and play the same section. Note what feels missing — those absences identify the most valuable feedback slots.
- Have a second player do the same test blind, without being told what rumble events are designed. Their reactions identify whether the feedback is communicating what it is supposed to.
Tuning rumble magnitudes from a number in code produces guesses. Tuning them from what you feel while playing produces the correct values. Budget an afternoon for this process — it takes longer than expected but the improvement to game feel is disproportionate to the engineering effort.