コンテンツにスキップ
JA

Fire と Clip — 使い分けと実装

EventMap entry の Mode フィールドの値(Fire / Clip)は、Unity への組み込み方針・触覚素材の置き場・反復作業のフローに大きく影響します。本ページは Unity 開発者の視点で「どちらを選ぶか」と「どう書くか」を整理します。

protocol / schema レベル(manifest bucket・wire 形式・gain 適用タイミング等)の詳細は Fire と Clip の違い を参照してください。

Fire (FIRE / command)Clip (CLIP / stream_clip)
一言でデバイス内蔵 clip を ID で再生Unity の AudioClip を PCM 送信
推奨用途本番運用、短い one-shot試作、長尺、動的変調
事前 deploy必要 (Studio から Kit を書込)不要
遅延小・安定大きめ・環境依存
動的変調gain は発火ごとに固定再生中に gain / pan を per-chunk 変調可

Fire を選んだ場合Clip を選んだ場合
触覚素材の置き場Hapbeat Studio の Kit (install-clips/)Unity の AudioClip
反復作業のフローWAV 編集 → Studio → device deploy → Unity PlayAudioClip を Inspector で差し替え → 即 Play
Trigger 側コードmode 非依存 (Trigger / StateBehaviour は mode を意識しない)同左
動的 modulation不可 (固定 gain のみ)可 (Trigger.GainMultiplier / HapbeatParameterBinding)

Trigger / StateBehaviour 側のコードは mode を意識しないため、後から切り替えが可能です。EventMap entry の Mode フィールドを変えるだけで wire 形式が変わります。これは Unity SDK が EventMap を経由した抽象を提供しているためで、Fire / Clip 比較における Unity 側の最大の特徴です。

Showcase Zone選んだ Mode理由
Z1 Pin hitClip開発中に色々な打撃感を試したいため。本番化なら Fire への移行が自然
Z2 Door open/closeClipAnimator state 連動で短い one-shot。試作段階のため Clip 維持
Z3 grab loopClip (loop)長尺ループ + 物体速度に応じた動的 modulation が必要
Z5 charge releaseClipチャージ量を AnimationCurve で gain modulation するため Clip 必須
  • 試作段階 → Clip(差し替えの速さ)
  • 触覚が確定 + 出荷予定 → Fire に切り替え(低遅延・安定)
  • 長尺 / ループ / 動的 modulation 必須 → Clip 維持
  • Wi-Fi 混雑 or 多人数同時 → Fire(帯域消費が小さい)
  • 同じ entry を 2 モード両対応したい → manifest の BOTH 表現(Fire と Clip の違い で詳述)

EventMap entry の Mode フィールドで FIRE (Command) / CLIP (Stream Clip) を選びます。コンポーネント / Behaviour 側は mode を意識せず、内部で適切な API (HapbeatManager.Play / StreamAudioClip) に分岐します。

Mode 設定時必須フィールドwire 形式
FIRE (Command)Category + Event NamePLAY / STOP packet (Event ID + パラメータ)
CLIP (Stream Clip)Stream Clip (AudioClip)STREAM_BEGIN / STREAM_DATA × N / STREAM_END

詳細: EventMap ウィンドウ


プロジェクトに組み込む と同じ分類で示します。A / B は mode 非依存で使えるため Unity 側コードは共通、C のみ mode 別 API を使います。

GameObject に Hapbeat 系コンポーネント(Collision / Sequence / UnityEvent / TickEmitter)を attach、または HapbeatStateBehaviour を AnimatorController state に attach し、Inspector で対象 EventMap entry を選びます。コードは不要。

Fire / Clip の違いは EventMap entry 側の Mode と関連フィールドで吸収されるため、コンポーネント / Behaviour の Inspector 操作は同じです:

GameObject の Inspector
└─ HapbeatUnityEventTrigger
Event Map : MyEventMap
Event : [▶ sword_hit] ← entry.mode = FIRE
: [♪ ambient_drone] ← entry.mode = CLIP

EventMap entry 側の Mode を切り替えるだけで、コンポーネント / Behaviour を一切触らずに wire 形式が変わります。

B. スクリプトから Trigger を呼ぶ (mode 非依存)

Section titled “B. スクリプトから Trigger を呼ぶ (mode 非依存)”

[SerializeField] で Trigger 参照を持ち、ゲームロジックから Fire() を呼びます。entry.mode が FIRE / CLIP どちらでも同じ呼び方です。

public class GunController : MonoBehaviour
{
[SerializeField] private HapbeatUnityEventTrigger _shootTrigger;
void OnShoot() {
_shootTrigger.Fire();
}
}

Clip のとき、GainMultiplier を毎フレーム書けば再生中の動的変調も可能です(Fire のときは setter 自体は動作しますが、再生中の波形には反映されず、次の Fire() から効きます):

void Update() {
if (_isCharging)
_shootTrigger.GainMultiplier = _gainCurve.Evaluate(_chargeT);
}

実装例: Showcase Z5 ChargeShooter (Samples~/Showcase/Scripts/ChargeShooter.cs)。

C. Manager.Play() / StreamAudioClip() を直接呼ぶ (mode 別 API、特殊ケース)

Section titled “C. Manager.Play() / StreamAudioClip() を直接呼ぶ (mode 別 API、特殊ケース)”

EventMap を介さない場合は mode 別に API を選びます。

Fire:

HapbeatManager.Instance?.Play(
eventId: "my-game.sword_hit",
gain: 0.8f,
target: "player_1/pos_r_arm"
);

Clip:

[SerializeField] private AudioClip _footstepClip;
void OnFootstep() {
var playback = HapbeatManager.Instance?.StreamAudioClip(
clip: _footstepClip,
gain: 0.7f
);
// 必要なら playback.SetGain(0.5f) / playback.Stop()
}

EventMap 経由の自動補正(manifest intensity / latency offset / wiring 一覧 / Inspector チューニング)は失われます。この経路を選ぶ条件は プロジェクトに組み込む を参照。


Fire モードを使う前に、Kit(WAV + manifest.json)を device に書き込む必要があります。手順は Studio 側のドキュメントを参照:


Fire / Clip ともに runtime の SDK は直接 device に UDP を送る ため、Helper は不要です。Helper が要るのは:

  • Studio から Kit を deploy するとき(mDNS discovery + WS 中継)
  • Studio 上の再生テスト・waveform preview