useGamepad
为 Gamepad API 提供响应式绑定。
Demo
使用
由于 Gamepad API 的工作方式,你必须先使用游戏手柄与页面进行交互,然后它才会被检测到。
<script setup>
import { useGamepad } from '@vueuse/core'
import { computed } from 'vue'
const { isSupported, gamepads } = useGamepad()
const gamepad = computed(() => gamepads.value.find(g => g.mapping === 'standard'))
</script>
<template>
<span>
{{ gamepad.id }}
</span>
</template>
游戏手柄更新
目前 Gamepad API 不提供事件支持来更新游戏手柄的状态。为了更新游戏手柄状态,requestAnimationFrame 被用于轮询游戏手柄的变化。你可以通过 useGamepad 提供的 pause 和 resume 函数来控制此轮询。
import { useGamepad } from '@vueuse/core'
const { pause, resume, gamepads } = useGamepad()
pause()
// gamepads object will not update
resume()
// gamepads object will update on user input
游戏手柄连接与断开事件
onConnected 和 onDisconnected 事件将在游戏手柄连接或断开时触发。
const { gamepads, onConnected, onDisconnected } = useGamepad()
onConnected((index) => {
console.log(`${gamepads.value[index].id} connected`)
})
onDisconnected((index) => {
console.log(`${index} disconnected`)
})
震动
Gamepad Haptics API 功能稀疏,因此在使用前请查看 兼容性表格。
import { computed } from 'vue'
const supportsVibration = computed(() => gamepad.hapticActuators.length > 0)
function vibrate() {
if (supportsVibration.value) {
const actuator = gamepad.hapticActuators[0]
actuator.playEffect('dual-rumble', {
startDelay: 0,
duration: 1000,
weakMagnitude: 1,
strongMagnitude: 1,
})
}
}
映射
为了让 Gamepad API 更易于使用,我们提供了映射,将控制器映射到控制器的按钮布局。
Xbox360 控制器
<script setup>
import { mapGamepadToXbox360Controller } from '@vueuse/core'
const controller = mapGamepadToXbox360Controller(gamepad)
</script>
<template>
<span>{{ controller.buttons.a.pressed }}</span>
<span>{{ controller.buttons.b.pressed }}</span>
<span>{{ controller.buttons.x.pressed }}</span>
<span>{{ controller.buttons.y.pressed }}</span>
</template>
目前,只提供了 Xbox 360 控制器的映射。如果你有想添加映射的控制器,请随时提交 PR(Pull Request)来贡献更多的控制器映射!
SSR 兼容性
此组件 设计用于客户端。在某些情况下,SSR(服务端渲染)可能会导致 注水不匹配 问题。
如果你正在使用 Nuxt,你可以简单地将组件文件 重命名为 .client.vue 后缀(例如,GamepadComponent.client.vue),这会自动使其 仅在客户端渲染,从而避免注水不匹配。
在其他框架或纯 Vue 中,你可以将使用该组件的地方包裹在一个 <ClientOnly> 组件 中,以确保它仅在客户端渲染。
类型声明
export interface UseGamepadOptions
extends ConfigurableWindow,
ConfigurableNavigator {}
/**
* Maps a standard standard gamepad to an Xbox 360 Controller.
*/
export declare function mapGamepadToXbox360Controller(
gamepad: Ref<Gamepad | undefined>,
): ComputedRef<{
buttons: {
a: GamepadButton
b: GamepadButton
x: GamepadButton
y: GamepadButton
}
bumper: {
left: GamepadButton
right: GamepadButton
}
triggers: {
left: GamepadButton
right: GamepadButton
}
stick: {
left: {
horizontal: number
vertical: number
button: GamepadButton
}
right: {
horizontal: number
vertical: number
button: GamepadButton
}
}
dpad: {
up: GamepadButton
down: GamepadButton
left: GamepadButton
right: GamepadButton
}
back: GamepadButton
start: GamepadButton
} | null>
export declare function useGamepad(options?: UseGamepadOptions): {
isSupported: ComputedRef<boolean>
onConnected: EventHookOn<number>
onDisconnected: EventHookOn<number>
gamepads: Ref<
{
readonly axes: ReadonlyArray<number>
readonly buttons: readonly {
readonly pressed: boolean
readonly touched: boolean
readonly value: number
}[]
readonly connected: boolean
readonly id: string
readonly index: number
readonly mapping: GamepadMappingType
readonly timestamp: DOMHighResTimeStamp
readonly vibrationActuator: {
playEffect: (
type: GamepadHapticEffectType,
params?: GamepadEffectParameters,
) => Promise<GamepadHapticsResult>
reset: () => Promise<GamepadHapticsResult>
}
}[],
| Gamepad[]
| {
readonly axes: ReadonlyArray<number>
readonly buttons: readonly {
readonly pressed: boolean
readonly touched: boolean
readonly value: number
}[]
readonly connected: boolean
readonly id: string
readonly index: number
readonly mapping: GamepadMappingType
readonly timestamp: DOMHighResTimeStamp
readonly vibrationActuator: {
playEffect: (
type: GamepadHapticEffectType,
params?: GamepadEffectParameters,
) => Promise<GamepadHapticsResult>
reset: () => Promise<GamepadHapticsResult>
}
}[]
>
pause: Fn
resume: Fn
isActive: Readonly<ShallowRef<boolean>>
}
export type UseGamepadReturn = ReturnType<typeof useGamepad>