Controls (Hunter Assassin scheme)¶
Source: PROJECT_CONTEXT.md §4;
config.jsmove,melee,combat;game.jsonTap/findPath/smoothPath/updatePlayerAttacks/autoBackstabPlayer/backstabReady/backstabTell/doMelee/tryMelee. Status: ✅ Implemented
What it is¶
The player's entire input layer, modeled on Hunter Assassin: tap to move, no dedicated attack button. Combat happens automatically from positioning — the skill is where you go, not aiming. Reproducing Hunter Assassin's movement feel is a stated priority (§4).
How it works¶
- Tap to move. Tap a point; the raider auto-paths there by the shortest route (
findPath= A*, thensmoothPath= LOS smoothing).onTapresolves a tap by priority: enemy → chest/loot/gate/extract → bare move. - Double-tap sprint. A second tap within
move.doubleTapMsrequests a sprint (if there's somewhere to run and enough stamina); costs stamina (move.sprintDrain/s),move.sprintMultspeed. - Swipe dodge-roll. A fast swipe (
move.swipeMinpx withinmove.swipeMs) triggers a roll: burst of speed with i-frames — you can't be spotted or hit during the invuln window (stealth.invulnWindow). Costsmove.dodgeCoststamina, onmove.dodgeCdcooldown. - No dedicated attack button — attacks are automatic:
- Auto-melee backstab. Standing directly behind a visible enemy → a silent crit fires unprompted (
autoBackstabPlayer→backstabReady). The passive trigger uses the stricter rear-only arccombat.autoBackstabArc(wider than the landed-crit arc, so a side-brush won't auto-kill). A pulsing 🗡️ kill-zone tell (backstabTell, shown within the widercombat.backstabTellRangeas you close in) signals when you're in the blind spot. It's a stealth opener, fired once: the first hit sets the enemy's target to you, which disarms the auto-trigger (backstabReadyreturns false onceen.target === player) so it won't chain a second crit while the enemy turns. Re-arm by breaking line of sight (it loses you) or commit a tapped strike to follow up. A silent backstab also briefly mutes auto-fire (combat.meleeToFireLock) so the stealth kill isn't blown by a loud shot. - Tap an enemy to hunt. Tap a perceived enemy to actively chase it for melee (
onTapsetsmeleeTarget; homes in with clear LOS, A-paths around cover otherwise) — for finishing fleeing/aware enemies or committing to a frontal swing. A committed strike still crits across the wider*combat.backstabArc(decided indoMelee), so deliberately flanking to a side and striking is still a backstab — only the hands-off auto-trigger is held to the tighter cone. - Auto-ranged on sight. Entering an enemy's vision (mutual: it sees you and you see it) → both sides auto open ranged fire (
updatePlayerAttacks→nearestEngaged). Symmetric — while hidden, nothing fires. - (Stance note:
combat.autoMeleearbitrates one stance at a time — melee when a threat is in your face with ranged suppressed, ranged otherwise, with hysteresis. See the combat doc.) - Tap an object → walk-and-interact. Tap a chest, gate, loot, or extract; the raider walks to it and auto-interacts on arrival (
onTapsetsinteractTarget). - Sustained interactions. Some objects need continued presence — cracking a chest takes ~
loot.chestTime(4.0s) and you must stay close the whole time or it resets.
Tunables¶
| Group | Key | Default |
|---|---|---|
move |
baseMove |
80 (ungeared pace, px/s) |
move |
sprintMult |
1.9 |
move |
sprintDrain / stamRegen |
32 / 24 (stamina/s) |
move |
stamMax |
100 |
move |
doubleTapMs |
300 (sprint double-tap window) |
move |
dodgeCost / dodgeTime / dodgeCd |
30 / 0.25 / 0.55 |
move |
dodgeSpeed / dodgeEase |
500 / 1.0 (peak roll speed; brake curve) |
move |
swipeMin / swipeMs |
46 / 320 (dodge-swipe gesture) |
melee |
dmgMult / simpleMult |
2.0 / 0.7 (mob lunge vs simple) |
melee |
windup / lockLead |
0.65 / 0.18 (lunge telegraph; dodge cue) |
combat |
backstabArc |
0.55 (× PI; landed-crit rear/side arc) |
combat |
autoBackstabArc |
0.72 (× PI; stricter passive auto-stab arc) |
combat |
critBase |
1.5 (backstab base crit ×) |
combat |
meleeToFireLock |
0.5 (auto-fire mute after silent backstab, s) |
combat |
meleeReach |
25 (extra strike reach, px) |
combat |
backstabTellRange |
72 (🗡️ approach radius, px) |
combat |
backstabHitstop |
0.13 (freeze-frame on backstab kill, s) |
stealth |
invulnWindow |
0.34 (dodge i-frames, s) |
Design intent¶
Directly serves Hide-and-kill (backstab = crit; head-on is risky) and Route over reflexes (§2): with no attack button, the only thing the player controls is movement and positioning, so all combat outcomes flow from where you stand. The stricter autoBackstabArc + fired-once lock keep the auto-stab a deliberate stealth opener rather than auto-DPS, preserving the "tactical stealth, positioning, deception, timing" pillar (§2.3).
Open questions / deltas¶
- Stamina + dodge i-frames (§9.5): not in the concept doc — a prototype addition fleshing out the tension/readability pillars; carry forward to Unity unless cut.
- 2.5D tap unprojection (§9.1): taps are unprojected through the isometric tilt (
onTapusesunproject); a flat top-down Unity build would simplify this — port decision pending.