Files
UE5-Modular-Game-Framework/docs/game/haptics-example.md
Lefteris Notas 14441c000c Add haptics example documentation for Project Void controller feedback
- Introduced comprehensive guide for setting up controller haptics and force feedback.
- Detailed directory structure for haptic profiles and creation steps for DA_HapticProfile instances.
- Included platform-specific configurations for Xbox and PS5 DualSense adaptive triggers.
- Outlined wiring of BPC_HapticsController to various gameplay systems and events.
- Provided accessibility integration options and testing checklist for haptic functionality.
2026-05-22 17:16:34 +03:00

17 KiB
Raw Blame History

Haptics Example — Project Void Controller Feedback

Version: 1.0 | Target UE: 5.55.7 | Framework System: BPC_HapticsController (148) + DA_HapticProfile (121)


Purpose

This document walks through setting up controller haptics/force feedback in the Project Void horror game prototype. It covers creating DA_HapticProfile Data Asset instances for every gameplay event, wiring BPC_HapticsController to all relevant systems, and platform-specific tuning for Xbox rumble and PS5 DualSense adaptive triggers.

Rule: All game haptic content lives in Content/Game/DataAssets/Haptics/. Never modify Content/Framework/Settings/BPC_HapticsController.


Game Haptics Directory Structure

Content/Game/DataAssets/
├── Haptics/                              ← ALL game haptic profiles
│   ├── DA_Haptic_Damage_Light.uasset
│   ├── DA_Haptic_Damage_Heavy.uasset
│   ├── DA_Haptic_Heartbeat_Normal.uasset
│   ├── DA_Haptic_Heartbeat_Fast.uasset
│   ├── DA_Haptic_Weapon_Pistol.uasset
│   ├── DA_Haptic_Weapon_Shotgun.uasset
│   ├── DA_Haptic_Weapon_Crowbar.uasset
│   ├── DA_Haptic_Reload.uasset
│   ├── DA_Haptic_Footstep_Tile.uasset
│   ├── DA_Haptic_Footstep_Wood.uasset
│   ├── DA_Haptic_Footstep_Concrete.uasset
│   ├── DA_Haptic_Explosion.uasset
│   ├── DA_Haptic_Pickup_Item.uasset
│   ├── DA_Haptic_Pickup_Weapon.uasset
│   ├── DA_Haptic_Grab_Object.uasset
│   ├── DA_Haptic_Release_Throw.uasset
│   ├── DA_Haptic_Scare_JumpScare.uasset
│   ├── DA_Haptic_Scare_TensionRise.uasset
│   ├── DA_Haptic_Ambient_Void.uasset
│   ├── DA_Haptic_LowHealth.uasset
│   ├── DA_Haptic_StaminaExhaust.uasset
│   ├── DA_Haptic_Death.uasset
│   ├── DA_Haptic_UI_Confirm.uasset
│   └── DA_Haptic_UI_Navigate.uasset

Step 1: Create DA_HapticProfile Data Asset Instances

For each event below, create a Data Asset instance in the Content Browser.

How to Create a Haptic Profile

  1. Navigate to Content/Game/DataAssets/Haptics/
  2. Right-click → Miscellaneous → Data Asset
  3. Select class: DA_HapticProfile
  4. Name: DA_Haptic_{Event} (see table below)
  5. Open the asset → fill in the fields:
    • ProfileTag: The GameplayTag for this effect (e.g., Haptic.Damage.Light)
    • EventType: Select from EHapticEvent enum
    • ForceFeedbackEffect: Assign the UForceFeedbackEffect waveform curve asset
    • IntensityCurve: Optional UCurveFloat for intensity over time
    • Duration: Total effect seconds
    • MotorMask: Left, Right, or Both
    • Priority: 0 (lowest, like footsteps) to 100 (highest, like death)
    • bCanInterrupt: Whether lower-priority effects can interrupt this
    • PlatformMinIntensity: Minimum intensity before effect is felt

Complete Haptic Profile Data Table

Asset Name GameplayTag EventType Duration Motor Priority Trigger Condition
DA_Haptic_Damage_Light Haptic.Damage.Light Damage 0.15s Both 60 Player takes ≤10 damage
DA_Haptic_Damage_Heavy Haptic.Damage.Heavy HeavyDamage 0.4s Both 80 Player takes >30 damage
DA_Haptic_Damage_Critical Haptic.Damage.Critical HeavyDamage 0.6s Both 90 Player HP <10% and hit
DA_Haptic_Heartbeat_Normal Haptic.Heartbeat.Normal Heartbeat 0.1s Left 30 BPM 6090 (calm/tense)
DA_Haptic_Heartbeat_Fast Haptic.Heartbeat.Fast Heartbeat 0.08s Left 40 BPM 90140 (scared)
DA_Haptic_Heartbeat_Panic Haptic.Heartbeat.Panic Heartbeat 0.05s Both 50 BPM 140180 (panic)
DA_Haptic_Weapon_Pistol Haptic.WeaponFire.Pistol WeaponFire 0.08s Right 50 Pistol fired
DA_Haptic_Weapon_Shotgun Haptic.WeaponFire.Shotgun WeaponFire 0.25s Both 70 Shotgun fired
DA_Haptic_Weapon_Crowbar Haptic.MeleeImpact.Crowbar MeleeImpact 0.15s Both 55 Crowbar hits enemy
DA_Haptic_Reload Haptic.WeaponReload WeaponReload 0.1s Right 40 Reload magazine click
DA_Haptic_Footstep_Tile Haptic.Footstep.Tile Footstep 0.02s Left 10 Walking on tile floor
DA_Haptic_Footstep_Wood Haptic.Footstep.Wood Footstep 0.03s Left 10 Walking on wood floor
DA_Haptic_Footstep_Concrete Haptic.Footstep.Concrete Footstep 0.04s Both 10 Walking on concrete
DA_Haptic_Explosion Haptic.Explosion Explosion 0.6s Both 85 Nearby explosion
DA_Haptic_Pickup_Item Haptic.Pickup.Item PickupItem 0.05s Right 20 Item picked up
DA_Haptic_Pickup_Weapon Haptic.Pickup.Weapon PickupItem 0.1s Both 25 Weapon equipped
DA_Haptic_Grab_Object Haptic.Grab GrabObject 0.08s Both 35 Physics object grabbed
DA_Haptic_Release_Throw Haptic.Release.Throw ReleaseObject 0.12s Both 35 Physics object thrown
DA_Haptic_Scare_JumpScare Haptic.Scare.JumpScare ScareEvent 0.5s Both 95 Jump scare triggers
DA_Haptic_Scare_TensionRise Haptic.Scare.TensionRise ScareEvent 2.0s Left 65 Ambient tension building
DA_Haptic_Ambient_Void Haptic.Ambient.Void AmbientPulse 3.0s Left 15 Void Space ambient rumble
DA_Haptic_LowHealth Haptic.LowHealth LowHealth 0.2s Both 75 HP drops below 25%
DA_Haptic_StaminaExhaust Haptic.StaminaExhausted StaminaExhausted 0.3s Both 45 Stamina reaches zero
DA_Haptic_Death Haptic.Death Death 0.8s Both 100 Player dies
DA_Haptic_UI_Confirm Haptic.UI.Confirm UI_Confirm 0.03s Right 5 Menu option selected
DA_Haptic_UI_Navigate Haptic.UI.Navigate UI_Navigate 0.02s Right 5 Menu cursor moved

Creating ForceFeedbackEffect Assets (Waveform Curves)

For each haptic profile that uses a UForceFeedbackEffect:

  1. Navigate to Content/Game/DataAssets/Haptics/Curves/
  2. Right-click → Miscellaneous → Force Feedback Effect
  3. Name: FFE_{Event} (e.g., FFE_Damage_Light)
  4. Open the asset:
    • Add a channel: Left Large (low frequency rumble motor)
    • Add a channel: Right Small (high frequency precision motor)
    • For the Damage Light curve: short spike at 0.5 intensity, 0.15s duration
    • For the Shotgun curve: heavy dual-motor spike, 0.25s duration
    • For the Heartbeat curve: single low-frequency pulse at 0.1s
  5. Assign the FFE asset to the corresponding DA_HapticProfile

Platform-Specific Force Feedback Assets

For PS5 DualSense-only effects, create separate FFE assets in Curves/PS5/:

  • FFE_Damage_Heavy_PS5 — higher fidelity trigger and haptic pattern
  • FFE_Shotgun_PS5 — trigger kick + body rumble simultaneously
  • FFE_Heartbeat_PS5 — pulse on both adaptive triggers

The BPC_HapticsController selects the right asset at runtime based on CurrentPlatform.


Step 2: Wiring BPC_HapticsController to Gameplay Systems

2.1 Player Damage → Haptic

In BP_HorrorPlayerCharacter (or wherever BPC_HealthSystem is attached):

[In BPC_HealthSystem: OnTakeDamage Event]
  → Get BPC_HapticsController from Owner (PlayerController)
  → Branch on damage amount:
    ≤10:    PlayHapticByTag(Haptic.Damage.Light, 1.0)
    1030:  PlayHapticByTag(Haptic.Damage.Heavy, 1.0)
    >30:    PlayHapticByTag(Haptic.Damage.Critical, 1.0)
  → Branch on current health / max health:
    <0.25:  PlayHapticByTag(Haptic.LowHealth, 1.0)

2.2 Weapon Fire → Haptic

In BP_Pistol_Held and BP_Shotgun_Held (or the BPC_FirearmSystem):

[In BPC_FirearmSystem: OnFire Event]
  → Get Owner PlayerController → Get BPC_HapticsController
  → Switch on equipped weapon:
    Pistol:  PlayHapticByTag(Haptic.WeaponFire.Pistol, 1.0)
    Shotgun: PlayHapticByTag(Haptic.WeaponFire.Shotgun, 1.0)

For DualSense adaptive triggers (PS5 only — no-op on other platforms):

[AimDownSights pressed]
  → if IsDualSenseConnected:
    → SetDualSenseTriggerEffect("Right", "WeaponFire", 2, 5)  ← R2 stiffens at position 2

[AimDownSights released]
  → if IsDualSenseConnected:
    → SetDualSenseTriggerEffect("Right", "Resistance", 0, 0)  ← Remove trigger resistance

2.3 Reload → Haptic

[In BPC_ReloadSystem: ReloadComplete Event]
  → Get BPC_HapticsController
  → PlayHapticByTag(Haptic.WeaponReload, 1.0)

2.4 Melee → Haptic

[In BPC_MeleeSystem: OnMeleeHit Event]
  → Get BPC_HapticsController
  → PlayHapticByTag(Haptic.MeleeImpact.Crowbar, 1.0)

2.5 Heartbeat → Continuous Haptic

In PC_HorrorController (child of PlayerController with BPC_HapticsController attached):

[Event BeginPlay]
  → Get Pawn → Get BPC_StateManager
  → Bind Event OnHeartRateChanged → [Custom Event]
  
[Custom Event: OnHeartRateChanged(BPM)]
  → Get BPC_HapticsController (self)
  → PlayHeartbeatHaptic(BPM)    ← This starts/stops the looping heartbeat pulse

The heartbeat haptic automatically switches profiles based on BPM range:

In PlayHapticByTag (heartbeat):
  → Clamp BPM to 40180
  → Select profile:
    BPM 4090:  Haptic.Heartbeat.Normal  (slow pulse on left motor)
    BPM 90140: Haptic.Heartbeat.Fast    (faster pulse, stronger)
    BPM 140180: Haptic.Heartbeat.Panic  (both motors, double-pulse)

2.6 Footsteps → Surface-Dependent Haptic

In GASP animation notifies or BPC_MovementStateSystem:

[Animation Notify: Footstep]
  → Physical Surface Trace → Get Surface Type (Tile, Wood, Concrete, Carpet, Metal)
  → Get BPC_HapticsController
  → Switch on Surface:
    Tile:     PlayHapticByTag(Haptic.Footstep.Tile, surfaceDependentIntensity)
    Wood:     PlayHapticByTag(Haptic.Footstep.Wood, surfaceDependentIntensity)
    Concrete: PlayHapticByTag(Haptic.Footstep.Concrete, surfaceDependentIntensity)
    Metal:    PlayHapticByTag(Haptic.Footstep.Metal, surfaceDependentIntensity)
    Carpet:   Skip (no haptic on soft surfaces)
  → Scale intensity by movement speed:
    Sneak (0.3x), Walk (1.0x), Sprint (1.5x)

2.7 Scare Events → Haptic

[In BPC_ScareEventSystem: OnScareTriggered(ScareType)]
  → Get BPC_HapticsController
  → Switch on ScareType:
    JumpScare:  PlayHapticByTag(Haptic.Scare.JumpScare, 1.0)
    TensionRise: PlayHapticByTag(Haptic.Scare.TensionRise, 1.0)
                  → This plays a 2s ramp-up rumble on the left motor

2.8 Void Space Ambient → Continuous Tension Rumble

[In BP_AtmosphereController_WardA: EnterVoidSpace Event]
  → Get BPC_HapticsController
  → PlayHapticByTag(Haptic.Ambient.Void, 0.6)    ← Low-intensity ambient rumble

[ExitVoidSpace Event]
  → Get BPC_HapticsController
  → StopHaptic    ← Stop all ambient

2.9 Death → Final Rumble

[In BPC_DeathHandlingSystem: OnDeath Event]
  → Get BPC_HapticsController
  → PlayHapticByTag(Haptic.Death, 1.0)

2.10 Stamina Exhausted → Warning Pulse

[In BPC_StaminaSystem: Stamina = 0 Event]
  → Get BPC_HapticsController
  → PlayHapticByTag(Haptic.StaminaExhausted, 1.0)

2.11 UI Navigation → Subtle Clicks

[In WBP_MainMenu or WBP_PauseMenu: OnButtonHovered / OnSelectionChanged]
  → Get BPC_HapticsController (from owning PlayerController)
  → PlayHapticByTag(Haptic.UI.Navigate, 1.0)

[OnButtonPressed / Confirm]
  → PlayHapticByTag(Haptic.UI.Confirm, 1.0)

Step 3: Platform-Specific Configuration

3.1 Xbox Controller Settings

Xbox controllers use standard dual-motor rumble (Left = low frequency, Right = high frequency). No special setup required beyond creating UForceFeedbackEffect assets.

For Xbox-specific tuning:

  • Left motor (low frequency): Use for heavy impacts, explosions, death
  • Right motor (high frequency): Use for weapon fire, reload clicks, UI feedback
  • Both motors: Use for damage, jump scares, melee impacts

3.2 PS5 DualSense Adaptive Triggers

The DualSense supports two trigger effect types via the PS5 Controller Plugin:

Effect Type Description Use Case
Resistance Trigger stiffens at a certain press point Aiming down sights (R2)
Vibration Trigger motor vibrates Weapon fire kick on R2
WeaponFire Simulated trigger break Pulling trigger on pistol/shotgun
BowDraw Increasing resistance as trigger pulls (future: bow weapon)
AutomaticRifle Rapid trigger vibration (future: automatic rifles)

Trigger Effect Parameters:

  • StartPosition: Where on the trigger pull the effect begins (0 = fully released, 9 = fully pressed)
  • Strength: Effect intensity (0 = off, 8 = maximum)
  • EndPosition (Resistance only): Where the resistance wall ends

Example: Pistol trigger effect:

WeaponFire effect:
  StartPosition = 4    ← Effect starts midway through pull
  Strength = 6         ← Moderate break-point feel

Graceful fallback: On Xbox/PC, SetDualSenseTriggerEffect is a no-op. No crash, no error.

3.3 Controller Speaker Audio (PS5)

The DualSense has a small speaker. Use it sparingly for immersion:

Game Event Speaker Audio
Radio crackle When near a working radio or walkie-talkie
Heartbeat Quiet heartbeat thump when stress is high
Key jingle When picking up keys
Flashlight click Mechanical click when toggling flashlight

Implementation:

  1. Create USoundWave or UMetaSoundSource assets
  2. Route through SS_AudioManager with Bus = Dialogue (or a dedicated Speaker sub-bus)
  3. SS_AudioManager detects platform and routes to controller speaker on PS5, falls back to main output on other platforms

Step 4: Accessibility Integration

Settings Menu Integration

In WBP_SettingsMenu (or WBP_AccessibilityUI), add a Haptics section:

Haptics Settings:
├── [Toggle] Controller Vibration: ON/OFF
│   └─ Calls BPC_AccessibilitySettings.SetHapticsEnabled(bool)
│        └─ Dispatcher → BPC_HapticsController.SetHapticsEnabled()
├── [Slider] Vibration Intensity: 0%  100%
│   └─ Sets BPC_HapticsController.HapticIntensityScale
├── [Toggle] Adaptive Triggers (PS5 Only): ON/OFF
│   └─ Sets BPC_HapticsController.bEnableDualSenseTriggers
└── [Toggle] Controller Speaker (PS5 Only): ON/OFF
    └─ Sets BPC_HapticsController.bEnableSpeakerAudio

Accessibility Presets

Provide preset profiles:

  • Full Haptics (default): All effects on, full intensity
  • Reduced Haptics: Half intensity, no ambient rumble, no trigger effects
  • No Haptics: All vibration off (accessibility minimum)

Step 5: Testing Checklist

Basic Functionality

  • Pick up an item → controller vibrates briefly
  • Fire pistol → right motor kicks
  • Fire shotgun → both motors heavy kick
  • Take damage → vibration intensity scales with damage amount
  • Heartbeat BPM increases when enemy nearby → pulse speeds up
  • Walk on tile floor → light footstep ticks on left motor
  • Sprint on concrete → heavier footstep pulses on both motors
  • Jump scare triggers → intense 0.5s dual-motor rumble
  • Enter Void Space → low continuous ambient rumble starts
  • Leave Void Space → ambient rumble stops
  • Death → final heavy 0.8s rumble plays

Platform

  • Xbox controller: all effects work (standard rumble)
  • PS5 DualSense: adaptive triggers stiffen when aiming
  • PS5 DualSense: trigger kick on weapon fire
  • PS4 DualShock: falls back to standard rumble
  • PC keyboard/mouse: no vibration (expected — no controller connected)
  • Controller hot-swap: new platform detected, correct profiles load

Accessibility

  • Toggle vibration OFF in settings → no haptic effects play
  • Toggle vibration ON again → haptics resume
  • Reduce intensity to 50% → all effects half strength
  • Disable adaptive triggers → trigger effects stop on PS5

Edge Cases

  • Rapid weapon fire → respects MinTimeBetweenEffects, no rumble spam
  • Damage + weapon fire simultaneously → higher priority damage wins
  • Heartbeat continues during combat — doesn't overwhelm other effects
  • Controller disconnected mid-gameplay → no crash, haptics gracefully stop
  • Load save file → haptics settings restored from SS_SettingsSystem

Haptic GameplayTag Reference

All tags are in the Haptic. namespace, registered in DT_Tags_Player.csv:

Haptic.Damage.Light
Haptic.Damage.Heavy
Haptic.Damage.Critical
Haptic.Heartbeat.Normal
Haptic.Heartbeat.Fast
Haptic.Heartbeat.Panic
Haptic.WeaponFire.Pistol
Haptic.WeaponFire.Shotgun
Haptic.WeaponReload
Haptic.MeleeImpact.Crowbar
Haptic.MeleeImpact.Default
Haptic.Footstep.Tile
Haptic.Footstep.Wood
Haptic.Footstep.Concrete
Haptic.Footstep.Metal
Haptic.Footstep.Gravel
Haptic.Explosion
Haptic.Pickup.Item
Haptic.Pickup.Weapon
Haptic.Grab
Haptic.Release.Throw
Haptic.Scare.JumpScare
Haptic.Scare.TensionRise
Haptic.Ambient.Void
Haptic.Ambient.Default
Haptic.LowHealth
Haptic.StaminaExhausted
Haptic.Death
Haptic.UI.Confirm
Haptic.UI.Navigate

Haptics Example v1.0 — Part of the Project Void horror game prototype. Framework systems: BPC_HapticsController (148), DA_HapticProfile (121).