Skip to content
EN

EventMap ウィンドウ

This content is not available in your language yet.

unity-eventmap

EventMap は Event ID と触覚エントリの対応関係を一括管理する ScriptableObject + 専用 Editor ウィンドウです。Trigger / StateBehaviour / スクリプトはすべて EventMap entry を参照し、エントリ側で mode・gain・target・bindings 等を一元定義します。

本ページは AI / 上級ユーザー向けの 網羅的 reference。読みやすさより漏れの無さを優先。タスク指向の使い方は プロジェクトに組み込むParameter Binding を参照。


HapbeatEventMap (ScriptableObject; .asset)
├─ entries : List<HapbeatEventEntry>
└─ revertPlayModeChanges : bool
HapbeatEventEntry
├─ _id (stable GUID, lazy-assigned)
├─ mode (Command / StreamClip)
├─ displayName / category / eventName (→ eventId = "category.eventName")
├─ streamClip / loop (StreamClip mode)
├─ bindings : List<HapbeatBindingPreset> (StreamClip mode)
├─ gain
├─ target
├─ delayOffsetSeconds
├─ notes
├─ manifestOverride
└─ _cachedManifestIntensity (HideInInspector)
HapbeatBindingPreset (entry.bindings の要素)
├─ _id (stable GUID)
├─ ownerObjectName
├─ sourceTransformPath
├─ sourceProperty, inputMin/Max
├─ curveType, customCurve
├─ outputParameter, outputMin/Max
└─ debugLog, debugLogInterval, debugLogChangeThreshold

エントリ間の参照は stable GUID (_id) で行うため、reorder / insert / delete / duplicate しても trigger 側の wiring は維持される。_id は初回 .id getter アクセス時に lazy-assign される。Editor は window 起動時 (EnsureEntryIdsAssigned) と entry 追加時に proactively 割り当てる。


フィールド説明
entriesList<HapbeatEventEntry>エントリの並び。順序は表示順のみで wiring には影響しない
revertPlayModeChangesbooltrue の場合、Play 中に行った EventMap 変更を Play 終了時に自動 revert(非破壊チューニング用)
メニュー動作
Assets → Create → Hapbeat → Event Map右クリックフォルダ直下に asset 生成
Hapbeat → Create Event MapAssets/HapbeatSDK/EventMaps/<scene-name>-EventMap.asset に生成
Hapbeat → Initial Scene SetupRouter GameObject + asset + window オープンを一括実行

Asset 作成後の .asset の場所はどこでも良いが、HapbeatSDK/EventMaps/ 配下が推奨。Initial Scene Setup は active scene 名を asset ファイル名に組み込む (<scene>-EventMap.asset)。

メソッド戻り値用途
GetEntry(int index)HapbeatEventEntry?list index ベース(legacy、index 不安定なので非推奨)
FindById(string id)HapbeatEventEntry?stable GUID 検索(推奨)。Trigger 側はこれを使う
IndexOfId(string id)intGUID → list index(-1 if not found)
FindByName(string displayName)HapbeatEventEntry?displayName 完全一致
FindByEventId(string eventId)HapbeatEventEntry?category.eventName 完全一致
GetDisplayNames()string[]エディタ dropdown 用。各行に [index] icon displayName 形式

フィールド既定値説明
_idstring (HideInInspector)"" → lazy GUIDstable identifier。reorder / insert に強い。Trigger は _entryId でこれを保持
HasId (getter)bool.id getter が副作用なく評価できるか
RegenerateId()強制再生成。Duplicate 時に使う
フィールド既定値説明
modeHapticMode enumCommandCommand(device 内蔵 Kit clip を ID で再生)/ StreamClip(PCM を UDP 送信)

UI 表示ラベルは s_ModeLabels:

  • FIRE (Command)
  • CLIP (Stream Clip)

LIVE (stream_source) モードは廃止済み。enum 名は API 互換のため Command / StreamClip のまま。

ModeIcon (1 文字)備考
Command>FIRE
StreamClip (U+266A)CLIP
(fallback) (U+25CF)未知 enum value 用
フィールド用途
displayNamestringエディタ表示用ラベル(例: “Landing Impact”)
categorystringevent-id の前半。^[a-z][a-z0-9_-]{0,63}$ のセグメント形式
eventNamestringevent-id の後半。同上のセグメント形式
eventId (computed)string"{category}.{eventName}"category 空時は eventName のみ、eventName 空時は ""

IsValidSegment(segment): ^[a-z][a-z0-9_-]{0,63}$ の正規表現で検証。 IsValid(): category + eventName 両方が valid segment。

フィールド既定値説明
streamClipAudioClipnullUDP で送信する PCM16 source。HapbeatSDK/Kits/<kit>/stream-clips/ 配下推奨
loopboolfalsetrue で Stop() まで再生継続。SequenceTrigger の hold phase / 連続 modulation 用
bindingsList<HapbeatBindingPreset>emptyParameter Binding preset の登録リスト

streamClip 変更時、所属 Kit の *-manifest.jsonmanifestOverrideauto-attach する(同じ entry の _cachedManifestIntensity も refresh)。

フィールド範囲説明
gainfloat[0, 2] (Range attribute)master gain。GetEffectiveGain() = gain × _cachedManifestIntensity
フィールド
targetstring"" (broadcast) / player_1 / */pos_neck / player_1/pos_chest / team_red/player_1/pos_chest/group_3

HasTarget (getter): !string.IsNullOrEmpty(target)

contracts の device-addressing spec に準拠した body position 12 種:

pos_neck, pos_chest, pos_abd,
pos_l_arm, pos_r_arm, pos_l_wrist, pos_r_wrist,
pos_hip, pos_l_thigh, pos_r_thigh, pos_l_ankle, pos_r_ankle

対応する PositionLabels:

Neck, Chest, Abdomen,
Left Arm, Right Arm, Left Wrist, Right Wrist,
Hip, Left Thigh, Right Thigh, Left Ankle, Right Ankle

BuildTarget(int player = -1, string position = null)

Section titled “BuildTarget(int player = -1, string position = null)”

target 文字列を組み立てる static ヘルパー:

playerposition戻り値
> 0non-emptyplayer_<N>/<position>
> 0null/emptyplayer_<N>
-1non-empty*/<position>
-1null/empty"" (broadcast)

window UI ではさらに Prefix (例: team_red) と Group (group_<N> suffix) を加えて 4 セグメント (prefix/player_N/position/group_N) を構築できる。

フィールド範囲説明
delayOffsetSecondsfloat[-0.2, 0.2] (Range)per-entry オフセット。global (HapbeatConfig.hapticDelaySeconds) と加算され、max(0, global + offset) が実 delay

UI に effective delay を ms 単位で readout 表示。

フィールド説明
notesstring (TextArea 1-3 行)デザイナーメモ。device には送られない
manifestOverrideTextAsset特定 <kit-name>-manifest.json を強制参照。未設定なら auto-resolve (clip path → eventId match)
_cachedManifestIntensityfloat (HideInInspector)manifest から resolve した intensity 値。-1f は “未解決”、0..1 は authored 値

CachedManifestIntensity (getter): 読み取り専用 accessor。 SetCachedManifestIntensity(float): Editor-only setter (duplicate 時の cache 伝搬等)。

メソッド戻り値説明
GetEffectiveGain()float_cachedManifestIntensity < 0 ? gain : gain × _cachedManifestIntensity。intensity=0 は honored (silence)
GetSummary()stringList 表示用要約。StreamClip → streamClip.name、Command → eventId
GetModeIcon()string> / /

4. HapbeatBindingPreset 全フィールド

Section titled “4. HapbeatBindingPreset 全フィールド”

HapbeatEventEntry.bindings の要素。StreamClip 再生中に gain / pan を modulate するための preset。

フィールド既定値説明
_idstring (HideInInspector)"" → lazy GUIDstable identifier。runtime の HapbeatParameterBinding._linkedBindingId から参照される
ownerObjectNamestring""binding の scope。空 = shared (全 wired GO に適用) / 非空 = 指定 GameObject 名にのみ適用
sourceTransformPathstring""trigger root からの相対 path。空 or . = trigger 自身
sourcePropertyBindingSourceProperty enumLocalPositionY入力ソース種別
inputMinfloat0入力レンジ下端 → outputMin にマップ
inputMaxfloat1入力レンジ上端 → outputMax にマップ
curveTypeBindingCurveType enumLinearnormalize 後の curve
customCurveAnimationCurveLinear(0,0)-(1,1)curveType=Custom のとき
outputParameterBindingOutputParameter enumStreamGainmodulate 対象
outputMinfloat0出力下端
outputMaxfloat1出力上端
debugLogboolfalseper-frame debug log の on/off
debugLogIntervalfloat0.1log throttle (秒)
debugLogChangeThresholdfloat0.02正規化値がこれ以上動かないと log を出さない
入力必要 ref
LocalPositionX / Y / Z_sourceTransform.localPosition.{x,y,z}_sourceTransform
LocalScaleX / Y / Z_sourceTransform.localScale.{x,y,z}_sourceTransform
VelocityMagnitudeRigidbody.linearVelocity.magnitude (Unity 6+) or .velocity.magnitude_sourceTransform 上の Rigidbody
AngularVelocityMagnitudeRigidbody.angularVelocity.magnitude同上
PositionDeltaMagnitude(pos - prevPos).magnitude / Time.deltaTime。Kinematic / XRGrab 用_sourceTransform
SliderValueSlider.value_sourceSlider
Externalbinding.SetValue(v) で外部 pushなし
数式
Lineart
EaseIn
EaseOut1 - (1-t)²
Exponential(e^(3t) - 1) / (e^3 - 1)
CustomcustomCurve.Evaluate(t)
範囲効果
StreamGain0..2 (clamped)playback.ApplyGainModulation(output)entry.gain × manifest.intensity × bindingOutput の最終段
StreamPan-1..+1playback.Pan = output。equal-power pan law。mono clip では無視

  • メニュー: Hapbeat → Open Event Map (SDK menu 旧名: Hapbeat → Event Map
  • 内部実装: HapbeatEventMapWindow : EditorWindow
  • 最小サイズ: 500 × 300
  • Tab タイトル: Hapbeat Event Map(未保存時は末尾に *
Key内容
HapbeatEventMap_SelectedGUID直近選択された EventMap asset の GUID
HapbeatEventMap_SplitRatioList view の左右ペイン分割比 (0.2 .. 0.8、デフォルト 0.42)
HapbeatEventMap_ViewMode0 = List / 1 = Table
  • 編集ごとに EditorUtility.SetDirty + AssetDatabase.SaveAssetIfDirty を実行
  • OnLostFocus / OnDisable でも保存(domain reload / Unity 終了で edit が失われないように)
  • toolbar に ● Save (orange) / ✓ Saved の indicator

横一列、左から:

要素機能
Event Map: Object Field編集対象 EventMap を切替(GUID で persist)
● Save / ✓ Saveddirty 状態と手動保存ボタン
(FlexibleSpace)
Batch SetupHapbeatBatchSetupWindow を開く
Scan Scenescene 内 Trigger / State / Script wiring を再スキャン
manifest intensity cache を全 entry 分 refresh
List / Table (segmented)view mode 切替
+新規 entry 追加(直前 entry の mode を継承)
選択中 entry を削除
キー動作
/ 選択 entry 移動
Esc進行中の drag-reorder をキャンセル

  • 左ペイン: entry 一覧(行ごとに mode icon + displayName + summary)
  • スプリッタ (4px 幅) — ドラッグでペイン比変更
  • 右ペイン: 選択 entry の詳細編集
操作動作
左クリック選択
ドラッグハンドル () を 10px 超ドラッグ順序変更。GUID 参照なので wiring は保持される
右クリックcontext menu (下記)
  • Copy Entry Values / Paste Entry Values(clipboard 経由、binding preset id は再生成)
  • Add Entry Above / Below
  • Duplicate Entry(GUID 再生成)
  • Delete Entry

順に描画される UI:

  1. Test Play Bar(次節 §6.5)
  2. NamedisplayName の TextField
  3. ModeFIRE (Command) / CLIP (Stream Clip) popup
  4. Mode 別フィールド:
    • Command: Category / EventName(segment validation)+ Kit eventId dropdown(HapbeatSDK/Kits/<category>/<category>-manifest.json から候補列挙)
    • StreamClip: Clip (AudioClip) + Kit folder hint (stream-clips/) + Loop toggle
  5. Gain — 0..2 slider
  6. Delay Offset (s) — −0.2..+0.2 slider + effective delay readout (ms)
  7. Targeting セクション:
    • Prefix TextField (optional team_red 等)
    • Player IntField (1..99 / -1)
    • Position Popup (12 標準 + “(none)”)
    • Group IntField (1..99 / -1)
    • target 自動構築 + read-only preview
  8. Wiring セクション(§7.1)
  9. State Wiring セクション(§7.2)
  10. Script Wiring セクション(§7.3)
  11. Parameter Bindings セクション(StreamClip のみ; §8)
  12. Notes — TextArea
  • ボタン: ▶ Test Play (green) ⇔ ■ Stop (red) の toggle
    • Play 中: HapbeatManager.Instance 経由
    • Edit 中: HapbeatEditorTransport を lazy open
  • 右側: Manifest 行(Hapbeat → Open Settings で設定する HapbeatConfig の port/group を使う)
    • Label Manifest
    • Picker (*-manifest.json 限定 TextAsset field) — manifestOverride を設定
    • Refresh ボタン — clip の所属フォルダを walk up して *-manifest.json を auto-attach
  • inline hint: 接続未確立 / missing intensity warning / streaming indicator
  • パネル幅 < 260px で compact mode(label 省略)

Trigger / State / Script の 3 種について、scene および AnimatorController asset を walk して どの entry が誰から発火されているか を逆引き表示する。Scan Scene ボタンで明示再スキャン。EditorApplication.delayCall で再スキャンが要求されるケース(destroyed object 検出など)あり。

scene 内の全 HapbeatTriggerBase を walk:

フィールド内容
triggercomponent instance
gameObjectNamedisplay
typeNameColl / Seq / Tick / Event
wiredEventsUnityEvent reflection で接続元を列挙(例: XRGrabInteractable.selectEntered

Wiring セクションは GameObject 単位で grouping。各 GO 行に inline:

  • GameObject link button (click で ping)
  • type tag (Coll / Seq / Tick / Event)
  • gain inline editor (live scene component の _gainMultiplier を直接 RW)
  • TickEmitter のみ: Δ (tick threshold) + axis (X/Y/Mag) inline editor

HapbeatStateBehaviour を AnimatorController asset 上で列挙。scene 上で対応する Animator GO がいれば、その GO に紐づける(複数 GO で同 controller を共有可)。

フィールド内容
behaviourStateMachineBehaviour instance
controllerAnimatorController asset
layerName / stateName / phase”Enter” / “Exit”
animatorObjectscene Animator GO(null = asset only)

UI: GO 単位 grouping + State tag + gain editor。asset only entries は最後に “(Controllers without a scene Animator)” 見出しで列挙。

非 Hapbeat MonoBehaviour の [SerializeField] string を walk し、値が displayName または eventId と完全一致するものを surfacing。

フィールド内容
scriptMonoBehaviour instance
componentNamee.g. ChargeShooter
fieldNamee.g. _eventName
matchedValue文字列値
matchType"displayName" or "eventId"

heuristic なので false positive あり得る。


8. Parameter Bindings セクション (StreamClip mode のみ)

Section titled “8. Parameter Bindings セクション (StreamClip mode のみ)”

エントリ右ペインの最下部、Notes の直前に表示。

HapbeatBindingPreset.ownerObjectName で 3 種類に分類:

  1. wired GO 単位の foldoutownerObjectName == wiredGO.name。その GO の inline wiring と並べて表示
  2. Shared (all wired)ownerObjectName == ""。全 wired GO に attach される
  3. Orphan groupsownerObjectName が set されているが該当 GO が wiring 一覧に存在しない(rename / delete された GO の残骸)

8.2 各 preset 行で編集可能なフィールド

Section titled “8.2 各 preset 行で編集可能なフィールド”

§4 の全フィールド + compact 表示用の expand/collapse。_id は HideInInspector だが内部で auto-assign される。

SyncLinkedBindingsForEntry(entryIdx) を呼び、各 preset を対応する scene 上の trigger 子孫に HapbeatParameterBinding component として attach + link する(既存 link は維持)。(owner, sourceTransformPath, sourceProperty) のタプルが変わったら 自動で deferred sync も走る。

  • preset 削除 → window が link 中の全 scene HapbeatParameterBindingUndo.DestroyObjectImmediate(標準は EventMap = single source of truth)
  • scene 上の binding component 削除HapbeatParameterBinding.OnDestroy + EditorApplication.delayCallCleanupOrphanPreset を実行し、他に link 中の component がいなければ preset も map から除去
  • どちらの方向も Undo.RecordObject 経由なので Ctrl+Z で一括 revert 可

スプレッドシート形式の bulk 編集 view。

カラム内容
drag handle20px
#list index28px
Modepopup (FIRE / CLIP / LIVE*)70px
NamedisplayName TextFieldflex
Event ID / ClipCommand: category.eventName 結合表示 / StreamClip: AudioClip picker180px
GainFloatField48px
Targetread-only summary110px
×delete20px

*Table view の Mode popup には LIVE が残置されているが、enum 上の StreamClip 1 値しかないため LIVE 選択は no-op になる。

操作動作
クリック単一選択
Ctrl/Cmd + クリックtoggle multi-select
Shift + クリック範囲 multi-select
マルチセル状態でセル編集同一カラムを全選択行に伝播(spreadsheet 風)
  • Set Mode/FIRE (Command)
  • Set Mode/CLIP (Stream Clip)
  • Set Gain…/0.5 / 1.0 / 2.0
  • Duplicate All
  • Delete All

エントリ 0 件のとき (empty — click + to add) を表示。


HapbeatEventEntry._cachedManifestIntensity は Studio で deploy された Kit manifest の parameters.intensity 値をキャッシュする。Editor 時にのみ解決し、runtime は cache を読むのみ(device は manifest を見ず、SDK 側で gain × intensity を wire の gain として送る)。

  1. manifestOverride (TextAsset) が set されていればそれを使う
  2. StreamClip mode かつ streamClip あり → clip asset path から walk up して *-manifest.json を探す
  3. Command mode → HapbeatSDK/Kits/<category>/<category>-manifest.json を試行
  4. project 内全 *-manifest.json を scan して、events 内の clip パス or event_id が一致するものを探す
イベント動作
streamClip 変更該当 entry の manifestOverride を auto-attach + cache 更新
category / eventName 変更cache 更新
toolbar ボタンHapbeatManifestIntensity.Invalidate() + 全 entry の cache 更新
EventMap window 起動 / entries 変更RefreshIntensityCache()

未解決のとき _cachedManifestIntensity = -1fGetEffectiveGain() は -1 のとき gain のみ返す(intensity 乗算なし)。Test Play bar に “manifest intensity not found” warning を表示。


HapbeatEventMapPlaySnapshot static class ([InitializeOnLoad]) が EditorApplication.playModeStateChanged を購読:

状態遷移動作
ExitingEditModerevertPlayModeChanges = true の全 EventMap を JSON snapshot
EnteredEditModesnapshot を保持している EventMap を restore

snapshot は Dictionary<int instanceID, Snapshot{json, takenAt}> に保持。Play 1 サイクル分のみ有効。Play 中に toggle を false にすれば restore はスキップされる(編集が保持される)。


12. EventMap asset Inspector (HapbeatEventMapEditor)

Section titled “12. EventMap asset Inspector (HapbeatEventMapEditor)”

.asset を Project window で選択したときの Inspector:

セクション内容
Revert Play-mode changes on exitrevertPlayModeChanges toggle
手動 Snapshot / Restore ボタンtoggle off でも明示 snapshot を取れる
Export as Unity PackageEventMap + 参照 AudioClip を .unitypackage に bundle(portability)
entries collapsed by defaultパフォーマンス対策。Hapbeat.EventMap.ShowEntriesInInspector EditorPrefs で persist

labelWidth は narrow inspector でも長いラベルが切れないよう max(170, currentViewWidth × 0.55) で override。


13. Markdown export (HapbeatEventMapMarkdownExport)

Section titled “13. Markdown export (HapbeatEventMapMarkdownExport)”
メニュー動作
Hapbeat → Export Event Map (Selected)Project ビューで選択中の 1 EventMap を <MapName>.md として asset 隣に出力
Hapbeat → Export Event Map (All in Project)t:HapbeatEventMap で project 全 asset を一括 export

出力フォーマット: 各 entry に ## <name> 見出し + メタ情報。AI への context 提供 / design doc 貼付け用途。


  • ハンドル ( カラム) からのみ drag 開始(編集セルを誤って動かさないため)
  • 10px の threshold 超で confirmed drag に promote
  • blue ライン (Color(0.3, 0.7, 1, 1), 2px) で drop position を可視化
  • Esc キーで drag キャンセル
  • 同位置 drop (toSlot == from or from + 1) は no-op
  • Trigger は GUID 参照なので reorder で wiring は壊れない

prefab asset 内にのみ存在し、scene にインスタンス化されていない trigger は scan 対象外。「rename / restructure 後に prefab を開いて再 wire」が必要なケースで warning を log。


15. Stable GUID と wiring の不変条件

Section titled “15. Stable GUID と wiring の不変条件”
  • Entry は _id : string[SerializeField, HideInInspector] で保持し、最初の .id getter 呼び出しで Guid.NewGuid().ToString("N") を生成
  • Trigger は _entryId : string で参照(旧 _entryIndex は v2.0 で削除済み、id 一本化)
  • HapbeatBindingPreset._id も同様の GUID。HapbeatParameterBinding._linkedBindingId と照合
  • Duplicate / clipboard paste 時は RegenerateId() で新 GUID を割当(runtime の binding が複製元を指したまま残らないように)
  • 既存 scene の YAML に残った旧 _entryIndex 値は load 時に未知 field として無視

16. Editor 関連メニュー一覧(EventMap 関連だけ抜粋)

Section titled “16. Editor 関連メニュー一覧(EventMap 関連だけ抜粋)”
メニューパスpriority効果
Hapbeat/Open Event Map10window を開く
Hapbeat/Initial Scene Setup50folder + Router + EventMap asset + window を一括
Hapbeat/Create Event Router30scene に [Hapbeat Event Router] GO のみ
Hapbeat/Create Event Map31asset のみ
Hapbeat/Export Event Map (Selected)70Markdown 1 件
Hapbeat/Export Event Map (All in Project)71Markdown 全件
GameObject/Hapbeat/Event Router10hierarchy 右クリックメニューにも同コマンドを露出
Assets/Create/Hapbeat/Event Map(CreateAssetMenu)右クリックフォルダ直下に asset 生成