Microtube Docs
EN中文
Developers / Godot / Haptics setup

Godot haptics setup

Make objects felt with ready-made nodes, then from GDScript.

How haptics work

Each tracked hand carries six HapticFingerTrigger areas on physics layer 20: five fingertips and the palm. HEXR’s nodes are Area3Ds that watch that layer: when a finger trigger enters, they know the hand and the finger, and send through that hand’s PressureTrackerMain to its glove. Six channels, Thumb to Palm, each pressing (about 15–50 kPa), vibrating (0.1–40 Hz) or pulsing.

Without code

NodeUse it forSettings
HexRGrabbableChild of a RigidBody3D: pick it up with a pinch or the palm; each touching finger pressestype_of_grab pinch / palm, haptic_strength 10–60
HexRPhysicalButtonA button pressed by a fingertip; the finger feels it while it is downwhich fingers press it (thumb … palm), press_pressure, cap and travel; signals pressed and released
SpecialHapticsA zone with an effect for whatever is inside ittype_of_haptics: custom vibrations, custom haptics, fountain, rain drop, heart beat, hand squeeze
HexRInteractableHapticsChild of a Godot XR Tools pickable: pressure while it is held, following how tightly the hand closesstrength, follow_grip, the fingers
HexRUsableSignals when the chosen fingers curl and uncurl around itwhich fingers (thumb … little_finger), use_threshold
ProximityCheckOpens the hand-near check (below) while a hand is insideclear_delay; Auto Set Up in the Inspector adds its shape

The node and property names are the Unity package’s, in Godot’s snake_case. Size each node’s collision shape to the space a finger should feel. Zones skip the hand-near check: being inside is the evidence.

From code

One finger

gdscript
var hand := HexR.controller(HaptGloveHandler.HandType.RIGHT)   # the hand's PressureTrackerMain

# Pressure: finger, on/off, intensity 0.1-1, ramp speed 0.1-1, skip the hand-near check
hand.custom_single_haptics(Haptics.Finger.INDEX, true, 0.5, 1.0, false)

# Vibration: finger, on/off, intensity 0.1-1, frequency 0.1-40 Hz, skip the hand-near check
hand.custom_single_vibrations(Haptics.Finger.PALM, true, 0.7, 12.0, false)

# The components' 10-60 strength scale, as the 0.1-1 intensity above
var intensity := PressureTrackerMain.strength_to_intensity(30.0)

Several fingers

gdscript
# One entry per channel: Thumb, Index, Middle, Ring, Pinky, Palm
var grip := [true, true, true, false, false, false]

hand.trigger_custom_haptics_increase(grip, 0.6, 1.0)   # pressure 0.1-1, speed 0.1-1
hand.trigger_custom_vibrations(grip, 0.7, 12.0)        # intensity 0.1-1, frequency 0.1-40 Hz
hand.trigger_all_haptics_increase(0.5)                 # every channel
hand.trigger_pinch_pressure(0.6)                       # thumb and index together

The raw commands

gdscript
# Build the bytes yourself and send them: byte-for-byte what the Unity package sends.
var glove := HexR.right_hand   # the HaptGloveHandler; Unity: HexRManager.Instance.rightHand
glove.bt_send(glove.haptics.hexr_pressure(Haptics.Finger.INDEX, true, 0.8, 1.0))
glove.bt_send(glove.haptics.hexr_vibration(Haptics.Finger.PALM, true, 18.0, 0.7))
glove.bt_send(glove.haptics.hexr_pulse(Haptics.Finger.THUMB, true, 3.0, 0.6, 5))

Press the finger that touches

gdscript
extends Area3D
## Presses exactly the finger or palm that touches this area, and lets go when it leaves.
## Its collision mask must include layer 20 (hexr_touch).

@export_range(0.1, 1.0) var intensity := 0.5

func _ready() -> void:
    area_entered.connect(_on_area_entered)
    area_exited.connect(_on_area_exited)

func _on_area_entered(area: Area3D) -> void:
    if area is HapticFingerTrigger:
        area.trigger_fix_pressure(intensity)   # 0.1-1, skips the hand-near check

func _on_area_exited(area: Area3D) -> void:
    if area is HapticFingerTrigger:
        area.remove_haptics()

Letting go

gdscript
hand.remove_index_haptics()      # one finger: remove_thumb_haptics() ... remove_palm_haptics()
hand.remove_all_haptics()        # every channel's pressure on this hand
hand.remove_all_vibrations()     # every channel's vibration on this hand
HexR.right_hand.release_all_channels()   # everything on the glove, both paths, in one write
The hand-near check

The PressureTrackerMain’s gated calls (the single_*, trigger_* and pinch calls) only fire while the hand is near something: grabbing, poke-hovering, or inside a ProximityCheck. That stops a stray call pressing an empty hand. Pass bypass_hand_check = true to the custom calls to skip it; the remove_* calls are never gated.

A glove holds its last pressure

Nothing on the glove lets go by itself. The addon releases on disconnect, pause and quit, but if the app crashes or the link drops the glove keeps pressing: switch the arm module off.