@threlte/extras
useGamepad
A hook that will provide a reference to an object that maps Gamepad values using the Standard Gamepad layout when connected.
<script lang="ts">
import { useGamepad } from '@threlte/extras'
const gamepad = useGamepad()
</script>
More than one gamepad can be connected at any given time, so an optional index
can be specified.
<script lang="ts">
import { useGamepad } from '@threlte/extras'
const gamepad1 = useGamepad({ index: 0 })
const gamepad2 = useGamepad({ index: 1 })
</script>
The raw unmapped Gamepad can be accessed via the raw
prop.
This prop will be null
unless a gamepad is connected.
<script lang="ts">
import { useFrame } from '@threlte/core'
import { useGamepad } from '@threlte/extras'
const gamepad = useGamepad()
useFrame(() => {
if (gamepad.raw) {
// A gamepad is connected!
}
})
</script>
Gamepad data is fetched as an immutable snapshot on every frame, so any variable that caches
gamepad.raw
will become stale on the next frame.
Connection status
The connected
property provides a currentWritable
that will update when a gamepad connects.
<script lang="ts">
import { useGamepad } from '@threlte/extras'
const gamepad = useGamepad()
const { connected } = gamepad
$: console.log(`A gamepad ${$connected ? 'connected' : 'disconnected'}!`)
</script>
Standard gamepad layout
If the button and axis layout of the gamepad corresponds with the Standard Gamepad layout, the gamepad object may be used to read and subscribe to input values.
Properties are given to more easily access button or joystick values.
<script lang="ts">
import { useFrame } from '@threlte/core'
import { useGamepad } from '@threlte/extras'
const gamepad = useGamepad()
useFrame(() => {
console.log(gamepad.leftStick.x, gamepad.leftStick.y)
console.log(gamepad.leftBumper.value)
console.log(gamepad.rightTrigger.value)
})
</script>
Event listeners can also be attached to buttons or joysticks, or the gamepad itself.
<script lang="ts">
import { useFrame } from '@threlte/core'
import { useGamepad } from '@threlte/extras'
const gamepad = useGamepad()
const off = gamepad.leftTrigger.on('down', (event) => {
console.log('The left trigger has just been pressed!')
// Unsubscribe from the event after it has fired once.
off()
})
gamepad.leftStick.on('change', (event) => {
console.log(`Left stick moved: ${event.value.x}, ${event.value.y}`)
})
gamepad.on('press', (event) => {
console.log(`A ${event.type} event on ${event.target} occurred: ${event.value}`)
})
const onPress = () => {
console.log('A button was pressed!')
}
gamepad.on('press', onPress)
// Some time later...
gamepad.off('press', onPress)
</script>
XR-Standard gamepad layout
To create a mapped object for a gamepad representing WebXR controller with the xr-standard
gamepad layout,
set the xr
flag to true
when calling the hook:
const leftGamepad = useGamepad({ xr: true, hand: 'left' })
const rightGamepad = useGamepad({ xr: true, hand: 'right' })
leftGamepad.trigger.on('change', (event) => console.log(event))
rightGamepad.trigger.on('change', (event) => console.log(event))
This will create a similar mapped object once XR controllers are connected.
Button mapping and events
The gamepad
object maps the 17 standard gamepad buttons and 4 axes to:
- The four right cluster buttons:
clusterBottom
,clusterRight
,clusterLeft
,clusterTop
. - The four top buttons:
leftBumper
,rightBumper
,leftTrigger
,rightTrigger
. - The center buttons:
select
,start
,center
. - The joystick axes and buttons:
leftStickButton
,leftStick
,rightStickButton
,rightStick
. - The directional pad:
directionalTop
,directionalBottom
,directionalLeft
,directionalRight
.
In a WebXR context, the following buttons and axes are mapped:
- Two cluster buttons per hand:
clusterBottom
,clusterTop
. - The
trigger
andsqueeze
buttons. - The
touchpad
andthumbstick
axes.
The available events for mapped buttons are the following:
change
will fire whenever thevalue
of the stick or button changes. This is helpful for buttons or joysticks that can have continuous values.press
will fire if a button is pressed.down
will fire when a button press begins.up
will fire when a button press ends.touch
is supported by some gamepads, and will fire if a small amount of pressure on a button is detected.touchstart
will fire when a touch begins,- and
touchend
will fire when a touch ends.