@dloizides/游戏输入
框架-不可知游戏输入原始. v1 船安全, 玩家可切换的意外 - 一个薄薄的包裹 在网络振动 API 上, 当禁用、 不支持或屏蔽时, 无法静默地操作, 所以呼叫站点可以 火花和他们的SFX/视觉反馈一起无条件.
零运行时间依赖关系. 异态性(不需要DOM lib)—— navigator 和储存是结构性的
注射式),因此它在浏览器游戏,React Industrial shells,以及测试中都起作用.
范围说明: 键盘/游戏板的正常化是有意的 没有 (原始内容存档于2018-03-25). in v1. 被审核的游戏 (Aurora, Morphe) 执行输入,其设计根本不同——没有共同的逻辑 提炼出来 当出现真正的第2种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同种同相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相.
没有捆绑的引导
createSteerInput 用于连续移动(飞行、驱动); createMenuNav 还行菜单. dist/index.mjs 没有导入, 因此一个普通页面可以在没有导入地图的情况下直接加载 :
<script type="module">
import { createSteerInput, STANDARD_BUTTON } from 'https://cdn.jsdelivr.net/npm/@dloizides/[email protected]/dist/index.mjs';
const steer = createSteerInput({ surface: canvas, enabled: () => playing });
function frame() {
const { x, y, back, pressed, touch } = steer.read();
move(x, y);
if (back) exitPlay();
if (pressed.includes(STANDARD_BUTTON.south)) act();
drawStick(touch);
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
</script>
打电话 read() 每帧一次: back 财务报告和审定财务报表 pressed 被读取所消耗。 给 surface 支助科 touch-action: none。从 enabled ,而菜单或对话框则拥有输入;然后按键保留在页面上. touch 带着客户端 px 加上方向盘中的媒体点,用于绘制一根棒.
安装
npm install @dloizides/game-input
使用量
import { createHaptics, HAPTIC_PATTERNS } from '@dloizides/game-input';
// One controller per game; the storage key namespaces the player's preference.
const haptics = createHaptics({ storageKey: 'aurora.haptics' });
// Fire unconditionally — disabled/unsupported just no-ops.
haptics.vibrate(HAPTIC_PATTERNS.tap); // menu navigation / selection
haptics.vibrate(HAPTIC_PATTERNS.success); // level cleared
haptics.vibrate([0, 14, 24, 14]); // or your own pattern
// Settings toggle — returns the new state, fires a confirming tick when enabling.
function onHapticsToggle(): boolean {
return haptics.toggle();
}
haptics.isEnabled();
语义图案词汇
HAPTIC_PATTERNS 是由意图键入的一组共享的调谐振动模式,所以每款游戏使用相同的
感觉而不是重新选择魔法持续时间:
| 意图 | 图案 | 使用 |
|---|---|---|
tap | 10 | 菜单导航 / 选择/ 撤销/ 重新启动 |
select | 12 | 拾取工具/图/项目 |
lock | 18 | 东西锁定位置 |
bump | 24 | 动作被屏蔽 |
navigate | 16 | 门户/翻页 |
success | [0,40,50,90] | 级别/分组已清除 |
error | [0,14,24,14] | 致命/破坏性事件 |
loss | [0,40,50,40] | 玩家丢失/ 掉落 |
reveal | [0,14,20,18,26,24] | 谜题解析/ 退出打开 |
API 密码
createHaptics(options?)→Haptics—— 说{ isEnabled, setEnabled, toggle, vibrate }无震动 用户手势前 :navigator.userActivation.hasBeenActive现在在哪里, 否则第一个pointerdown编号 :keydown编号 :touchstart打开options.activationTarget(默认)globalThis) (中文(简体) ).options.storageKey(默认)game.haptics) ——上下优惠的本地Storage键.options.enableConfirmation(违约a)15毫秒勾选;通过null——开启时被发射.options.navigator编号 :options.storage——注入测试/RN;默认为globalThis。 。 。 .
HAPTIC_PATTERNS, (中文(简体) ),DEFAULT_HAPTICS_STORAGE_KEY, (中文(简体) ),DEFAULT_ENABLE_CONFIRMATION。 。 。 .createGamepadPoller({ getPads, requestFrame, cancelFrame, onAction })→{ start, stop }- 民意调查 第一次连接 W3C 标准 Gamepad 每个帧和调用onAction(PadAction)。通过() => navigator.getGamepads(), (中文(简体) ),requestAnimationFrame, (中文(简体) ),cancelAnimationFrame在浏览器中.- 按位置排列的按钮: 南-
confirm东 东back西部地区view北边mood, (中文(简体) ), L/R 肩 →pagePrev编号 :pageNext(仅形成边缘). - D-pad或左接棒(0.5个死区)-
up编号 :down编号 :left编号 :right:起火一次,重复后为380ms后,再每110ms后.
- 按位置排列的按钮: 南-
stepPad(prev, next, repeat, now)- 传票人背后的纯每帧减少器;IDLE_REPEAT, (中文(简体) ),PAD_ACTIONS, (中文(简体) ),STANDARD_BUTTON。 。 。 .
许可证
麻省理工学院
帆布菜单:行走钩(NAV-1)
一个在画布上绘制菜单的游戏( 没有 DOM 按钮) 发布其菜单状态, 所以共享的行走者 in
@dloizides/game-e2e (单位:千美元)expectHookMenuWalkable)可以证明每件物品都可以被箭头和花板所达到:
import { installMenuWalkHook } from '@dloizides/game-input';
installMenuWalkHook({
screen: () => menu.screenId, // e.g. 'title', 'settings'
items: () => menu.items.map((i) => i.id),
focused: () => menu.focusedId ?? null,
});
标签调试器( T)createTabPager(中文(简体) )
const pager = createTabPager({ host: dialogEl, ignore: '.h-rail' });
const onPad = (a: PadAction): void => { if (!pager.pad(a)) menuNav.pad(a); };
host 必须保持挂载; 里面的一切可能都重新卸载。 标签需要 role="tab" 内置 a role="tablist", (中文(简体) ), aria-selected,并选择它们的点击处理器;面板是标签的 aria-controls 目标或第一个 role="tabpanel"。箭头和 D-pad 沿着标签行移动焦点,而不切换标签(手动激活); Enter/Space/ 点击,肩部按钮或刷出按钮.
控制器滚动( O)MenuNav.stick(中文(简体) )
const poller = createGamepadPoller({ getPads, requestFrame, cancelFrame, onAction: (a) => menuNav.pad(a), onScroll: (y, now) => menuNav.stick(y, now) });
// own poll loop: menuNav.stick(pad.axes[RIGHT_STICK_Y] ?? 0, now) every frame
右接棒滚动了焦点控件的滚动容器(也就是菜单中第一个可滚动的,包含一个标签面板),并带有一个死区和平方速度曲线;当将焦点控件滚动出视线时,焦点移动到视图中的第一个控件. 向上/向下(d-pad,左棒,箭头键)向上滚动半个视图,而不是在下个控件距离超过一步时,在滚动列表后移动焦点,或缺失(文本页),并仅在容器到尾后才进行包装. 焦点移动将新控件滚动到视图 block: nearest,顺利,除非 prefers-reduced-motion。 。 。 .
动作提示 (1.11.0)
import { createBindings, createInputDeviceTracker, glyphSvg, PadFamily, promptFor } from '@dloizides/game-input';
const binds = createBindings({ actions: ['jump'], keys: { jump: 'Space' }, pad: { jump: 0 }, storageKey: 'surge.binds' });
const tracker = createInputDeviceTracker({ target: window, getPads: () => navigator.getGamepads() });
const prompt = promptFor(binds, 'jump', tracker.current());
const icon = prompt.glyph === null ? '' : glyphSvg(prompt.glyph, tracker.current().family ?? PadFamily.Generic);
打电话 tracker.poll() 每帧一次。 样式格言 --gi-fg 财务报告和审定财务报表 --gi-bg。隐藏的快取(触碰或对该设备没有约束力)不会造成任何结果.
动作芯片( O)createActionPrompts页:1
import { createActionPrompts } from '@dloizides/game-input';
const prompts = createActionPrompts({ bindings: () => binds, onBindingsChanged: (repaint) => binds.onChange(repaint) });
prompts.tag(jumpButton, 'jump');
prompts.tagFixed(pauseButton, 'pause', { key: 'Esc', pad: 'Menu' });
prompts.untag(jumpButton);
每个被标记的控件都得到 data-gi-action (单位:千美元) .gi-chip (单位:千美元)data-kind="key"|"pad"保持一个格子跨度和 .gi-text[data-gi-prompt]. 芯片跟随最后使用的装置和当前绑定,隐藏在触摸上,如果控制器重新发回,则重新附加. 纸被调查 requestAnimationFrame; 通过 schedule: null 调查你自己,或者你自己 tracker属性和类名称为选项(默认为 ACTION_CHIP_DOM) (中文(简体) ).