Showcase のゾーン詳細
This content is not available in your language yet.
Showcase サンプル の各ゾーンについて、操作・配線(どの GameObject にどのコンポーネントが付いているか)・試してみる(Inspector を変えて違いを確かめる改造)をまとめています。Unity で Showcase.unity を開き、Inspector と見比べながら読むことを想定しています。
改造したサンプルを元に戻すには、Package Manager から Showcase を再 Import します。再 Import でサンプルフォルダは上書きされるので、残したい改造は別のフォルダにコピーしてから行ってください。
Z1 Bowling Lane
Section titled “Z1 Bowling Lane”操作: 左クリックでボールを発射、Space でピンを元に戻す。ピンに当たると、衝突の速さに応じた強さで再生される。
配線
Prefabs/BowlingPin.prefabにHapbeatCollisionTrigger(6 本のピンはこの prefab のインスタンス)- Event Map:
ShowcaseEventMap、Event:Z1_pin_hit - Trigger Event:
CollisionEnter - Gain Mode:
VelocityScaled(衝突の速さが Max Velocity に近いほど強い)
- Event Map:
BallLauncher(Z1_Bowling)は発射とリセットだけを行い、Hapbeat のコンポーネントには触れない
試してみる
HapbeatCollisionTriggerの Max Velocity を下げる → 弱い衝突でも最大の強さで再生される- Gain Mode を
Fixedにする → 速さに関係なく同じ強さになる - EventMap の
Z1_pin_hitの Targeting を*/pos_neckにする → 首の位置のデバイスだけで再生される
Z2 Swing Door
Section titled “Z2 Swing Door”操作: F で開閉、G で叩きつけ、L で施錠 / 解錠。
配線
Z2_Door/DoorにAnimator+DoorController。キーで Animator の Trigger を送る(F →DoorAction、G →Slam、L →LockToggle)DoorAnimator.controllerの各 state にHapbeatStateBehaviour。state に入ったとき(On State Enter)にエントリを再生する
| state | Event | Required Previous State |
|---|---|---|
Open | Z2_door_open | Closed |
Closed | Z2_door_close | Open |
Slam | Z2_door_slam | Open |
LockEngage | Z2_door_lock | — |
LockRelease | Z2_door_unlock | — |
LockedRattle | Z2_door_rattle | — |
DoorController は Animator を動かすだけで、触覚のコードは持たない。
試してみる
Z2_door_open/Z2_door_closeの Clip を別の wav に替える → 音と触覚を別々に作れることを確かめる- EventMap で
Z2_door_closeの Gain を下げる → 静かに閉まるドアの触覚になる - state の
HapbeatStateBehaviourの Required Previous State を空にする → どの state から来ても再生される
Z3 Fishing Rod
Section titled “Z3 Fishing Rod”操作: 左クリックを押している間、物体を釣り糸で吊る(離すと落ちる)。視点を動かして竿を振ると物体が揺れる。吊っている間はループ再生され、物体が速く動くほど強くなる。
配線
Z3_FishingにHapbeatSequenceTrigger- On Start:
Z3_hook_start(吊った瞬間の一発) - Loop (hold):
Z3_hook_loop(CLIP、Loop) - On Stop:
Z3_hook_release(離した瞬間の一発)
- On Start:
Z3_Fishing/FishingObjectにHapbeatParameterBinding(Z3_hook_loopエントリの Bindings で設定)- Source Property:
VelocityMagnitude、Output:StreamGain
- Source Property:
スクリプト: FishingController.cs は、左クリックの押下で _sequence.Fire()、解放で _sequence.Stop() を呼ぶ。触覚に関わるコードはこの 2 行で、強さの変化は Parameter Binding が受け持つ。
試してみる
Z3_hook_loopの Bindings で Source Property をLocalPositionYにする → 物体を高く上げるほど強くなる- 入力 / 出力の範囲や Curve を変える → 振り始めの立ち上がり方が変わる
Z3_hook_loopの Clip を別のループ素材に替える(短い素材だとループの継ぎ目に注意)
Z4 Stream Console
Section titled “Z4 Stream Console”操作: Space でループ再生の開始 / 停止。Gain / Pan スライダーで再生中の強さと左右を変える(スライダーを動かすと刻みの触覚も再生される)。Z4 に切り替えるとカーソルのロックが外れ、スライダーをマウスで操作できる。
配線
Z4_Stream/StreamCanvas/StreamPanelHudにHapbeatUnityEventTrigger(Event:Z4_stream_loop、CLIP、Loop)とStreamDemoControllerGainSlider/PanSliderにそれぞれHapbeatParameterBinding(Source Property:SliderValue、Output:StreamGain/StreamPan)HapbeatTickEmitter(Tick Trigger、Event:Z4_slider_tick)
Z4_Stream/AddressOverridePanelで、player / group の実行時の上書きを試せる(→ ターゲティング)
スクリプト: StreamDemoController.cs は、Space で Trigger の ActivePlayback を見て、再生中なら Stop()、停止中なら Fire() を呼ぶ。スライダーの値を Binding の代わりにスクリプトで ActivePlayback.Gain / Pan に書く方法も、コメントで残してある(どちらでも同じ動作)。
試してみる
HapbeatTickEmitterの Tick Threshold を上げる → 刻みの数が減り、粗い手応えになるZ4_stream_loopの Loop を外す → 1 回だけの再生になるZ4_stream_loopの Targeting を*/pos_r_armにする → 右腕の位置のデバイスだけで再生される- スライダーの
HapbeatParameterBindingを外し、StreamDemoController.csのコメント部分を有効にする → 同じ動作をスクリプトで書いた形になる
Z5 Charge & Shoot
Section titled “Z5 Charge & Shoot”操作: 左クリックを押してチャージし、離して発射する。チャージ中はループ再生が強くなっていき、しきい値を超えると 1 回再生される。発射時はチャージ量に応じて弱 / 強の 2 種類を再生し分ける。的に当たると別の触覚が再生される。
配線
Z5_ChargeShotにChargeShooter(Trigger コンポーネントを使わないスクリプト)- Inspector で
ShowcaseEventMapと 4 つのエントリ(Z5_charge_loop/Z5_charge_thd/Z5_shot_light/Z5_shot_heavy)を選ぶ
- Inspector で
Z5_ChargeShot/TargetBoardにTargetReceiver、その子のEvent_Hit_Light/Event_Hit_HeavyにHapbeatUnityEventTrigger(Z5_tar_hit_light/Z5_tar_hit_heavy)TargetReceiverの UnityEventOnHitLight/OnHitHeavyから、それぞれの Trigger のFire()を呼ぶ(Inspector で配線)
スクリプト: ChargeShooter.cs は、HapbeatManager を直接呼ぶ上級例。
- チャージ開始:
HapbeatManager.StreamAudioClip(...)でZ5_charge_loopを再生し、毎フレーム返り値のハンドルにApplyGainModulation(_gainCurve.Evaluate(chargeT))を呼んで強さを変える - 発射: ループを
Stop()し、チャージ量でZ5_shot_light/Z5_shot_heavyを再生する - 強さ・送信先・クリップは EventMap のエントリから読む(
entry.GetEffectiveGain()/entry.target/entry.streamClip)ので、EventMap ウィンドウでの調整がそのまま効く
試してみる
ChargeShooterの Gain Curve を上に膨らんだ曲線にする → チャージの序盤から強くなる- Shot Follows Charge T を ON にする → 発射の強さもチャージ量に合わせて変わる
Z5_tar_hit_light/Z5_tar_hit_heavyの Mode をFIRE (Command)にして Kit を deploy する → 命中の応答が速くなる(下記)
共通のキー操作の配線
Section titled “共通のキー操作の配線”Q / P は、コードを書かずに UnityEvent で配線している。
[Hapbeat Event Router]に次をまとめているHapbeatManagerHapbeatKeyDispatcher— キーと UnityEvent の対応を Inspector で設定するHapbeatActionHelper—Ping()などを UnityEvent から呼べるようにするHapbeatUnityEventTrigger(Event:Z5_tar_hit_light)
- Q →
HapbeatUnityEventTrigger.Fire()、P →HapbeatActionHelper.Ping()とGlobalHotkeys.NotifyPingSent() GlobalHotkeysは Ping の応答を受けて画面の表示を更新するだけ
EventMap 全体で試す
Section titled “EventMap 全体で試す”Hapbeat → Open Event Mapで各エントリの Gain を変える → ゾーン全体の強さが変わる- Targeting を
*/pos_neckにする → 首の位置のデバイスだけで受ける - Mode を
CLIP (Stream Clip)からFIRE (Command)にする(次節)
FIRE (Command) で再生する
Section titled “FIRE (Command) で再生する”Showcase のエントリは、Kit を deploy しなくても動くよう、すべて CLIP(Stream)にしてあります。Kit をデバイスに deploy すると、FIRE(Command)でも再生できます。
FIRE にすると:
- 送るのは Event ID だけなので、応答が速い
- デバイスに保存した clip を再生するので、アプリに WAV を持たせなくてよい
- Studio で Kit を更新して deploy し直せば、Unity 側をビルドし直さずに触覚を差し替えられる
手順:
- Showcase に同梱の
Kit/showcase-kit/(manifest と、FIRE 用のinstall-clips/・CLIP 用のstream-clips/)を、Hapbeat Studio の Kit タブで開き、デバイスへ Deploy する(手順は Getting Started の「Studio で Kit をデプロイ」と同じ) - EventMap で試したいエントリの Mode を
FIRE (Command)にする(例:Z1_pin_hit→ Event IDshowcase-kit.z1_pin_hit)。Clip の欄はそのままでよい(FIRE では使わない) - Play で確かめる
すべてを FIRE にする必要はありません。衝撃のように速い応答が効くもの(Z1_pin_hit、Z2_door_slam、Z5_tar_hit_*、Z5_shot_* など)を FIRE、ループ(Z3_hook_loop、Z4_stream_loop、Z5_charge_loop)は再生中に強さを変えられる CLIP のまま、という使い分けが実用的です。
WASD と UI ナビゲーションの衝突
Section titled “WASD と UI ナビゲーションの衝突”Unity の InputSystemUIInputModule の既定の UI/Navigate には WASD が割り当てられています。スライダーが選択された状態で WASD を押すと、移動と同時にスライダーの値も変わります。
Showcase では次の 2 つで回避しています。
SimpleFPSControllerはカーソルをロックしている間だけ移動する(Z4 ではカーソルのロックが外れるので WASD で移動しない)- 各スライダーに
UiDeselectOnPointerUpを付け、ドラッグを離した時点で選択を解除する
自分のプロジェクトでは、UI 側から WASD を外すのが確実です。
Packages/Input System/.../DefaultInputActions.inputactionsをAssets/配下にコピーする- コピーを Input Actions Editor で開き、UI / Navigate / 2D Vector Composite から
<Keyboard>/w<Keyboard>/a<Keyboard>/s<Keyboard>/dを削除する(矢印キーは残す) - シーンの EventSystem → Input System UI Input Module → Actions Asset をコピーに差し替える
トラブルシューティング
Section titled “トラブルシューティング”| 症状 | 原因 / 対処 |
|---|---|
| 何も再生されない | Hapbeat デバイスがオフライン。Studio / Helper で接続を確認する |
| 接続済みなのに再生されない | [Hapbeat Event Router] に HapbeatManager が無い、または Trigger の Event Map が未選択 |
entry id '...' not found の警告 | Trigger が参照しているエントリが EventMap から削除された。Inspector の Event ドロップダウンで選び直す |
| Z3 のループが再生されない | Z3_hook_loop の Clip が未割当、または Loop が OFF |
| 刻み(tick)が多すぎる | HapbeatTickEmitter の Tick Threshold が小さすぎる。値を上げる |
| スライダーを触った後、WASD で値が動く | 上記 を参照 |