Inspiration

VR archery usually comes down to pulling a trigger. We wanted the bow to feel like a real bow, where how hard you pull is how hard you shoot. MyoWare EMG sensor on your forearm reads how hard you squeeze, and that squeeze draws the string. We put that idea in the most dramatic setting we could think of: a prehistoric valley full of dinosaurs, a meteor strike, and a final boss. When a dinosaur gets its teeth into you, a vest on your torso buzzes on the side it came from, so you feel where the next threat is before you turn your head.

What it does

The bow lives in your left hand. To shoot, you grab the string with your right hand and squeeze your fist: the MyoWare 2.0 sensor on your forearm turns that squeeze into draw strength, and the arrow flies when you let go. A short calibration at the start (relax, then squeeze as hard as you can) maps your own range onto the bow, so a strong player and a weak player both get a full draw.

A vest with three vibration motors (left, right, back) tells you where a hit came from. The game works out the attacker's direction relative to your head: a bite from the left buzzes the left motor, from the right the right one, and a bite straight to the face fires all three at once. Harder hits buzz longer.

  • Calibrate: the game learns your resting and full-strength muscle signal.
  • Act 1, Survive: dinosaurs spawn outside your view and close in from every side.
    • Maip is fast and attacks up close.
    • Gorgosaurus is slower and tougher, and spits acid from range.
    • Aim matters: a head shot kills instantly, a body shot takes 3 hits, and hitting the legs slows them down.
  • Act 2, Meteors and the Boss: survive the timer and the sky goes dark. Meteors wipe out the dinosaurs, a box crashes down, and a boss breaks out. His face comes from a photo uploaded from a phone. Defeat him before time runs out, or he snaps his fingers and you lose.
  • The haptic vest buzzes on the side you get hit, so you feel where the danger came from.

There's a fast mode (30 s survive) for demos and a regular mode (180 s) for the full experience.

How we built it

•One ESP32 on the player's body runs both the armband and the vest, and talks to the game over Wi-Fi. Everything else is Unity.

• Wearable hardware. An ESP32 (LilyGO T-Display) powered from a USB power bank. The MyoWare 2.0's envelope output goes to pin 32; a three-channel relay board on pins 25, 26 and 27 switches the left, right and back vibration motors from their own battery. • Firmware (Arduino C++). Samples the EMG 8 times per reading, smooths it and streams it to the game 50 times a second over UDP. It listens for hit messages like L,200 and turns strength into buzz length (120 to 400 ms), with non-blocking timers so overlapping hits extend a buzz instead of stacking. Motors are forced off if Wi-Fi drops. • Networking. Plain UDP in both directions (port 5005 muscle data, 5006 hits). The game sends a silent heartbeat every second so the ESP32 learns the laptop's address immediately, instead of relying on broadcasts that phone hotspots often drop. • EMG in the game. The armband sends its raw level; the game does the calibration. During "relax" it averages your resting level, during "squeeze" it records your peak, and it maps that range to a 0 to 1 draw (topping out at 85% of your peak, so a full draw doesn't need a full-strength squeeze). • VR and the bow. Unity 6 with URP and the XR Interaction Toolkit on a Meta Quest Pro over Link. The bow is two-handed: draw strength sets arrow speed, and arrows are simulated with gravity and raycasts so fast shots never pass through a dinosaur. • Dinosaurs. Two CC BY models from Sketchfab, reduced from about 151k to 29k triangles. On top of the model animations we wrote procedural leg, neck and tail motion that follows the NavMesh agent's real velocity (walking backwards plays the legs in reverse), sidestep and strafe behaviour, several death variations, hit zones (head, body, legs), and per-dinosaur size and colour variation. • Game flow. A single state machine runs the whole act: tutorial, calibration, practice targets, facing check, countdown, survival timer, cutscene and restart. Every tuning number (round length, health, spawn arc, music volumes) lives in one config asset, so we tuned the game without touching code. • The world. We rendered the full terrain map plus 25 close-up sheets, walked the best candidates in the headset, and picked a clearing that looks out over a valley. We baked a NavMesh for just the arena. • Face-scan boss. MediaPipe Face Mesh (ONNX) runs locally through Unity's Inference Engine, finds 468 landmarks in three passes, and builds a 3D face mesh fitted to a generic head. Hair style and colour are read from the photo. Consent comes first, and the photo lives in memory only. • Audio and video. The battle music was generated by our team with Suno; the meteor cutscene plays through Unity's VideoPlayer on a world-anchored screen while the rest of the world fades to black. • Teamwork. Four people on four Git branches with Git LFS, a shared contracts file (events, hit zones, haptics and EMG interfaces) so nobody had to touch anyone else's scripts, and test scenes for every part.

Challenges we ran into

_An alpha that could not die. Our big opening dinosaur shared hitboxes with a lighter model whose bones had different names, so arrows passed straight through it. Instead of patching hitboxes one by one, we gave it a whole-body fallback hitbox and turned the bug into a mechanic: it ignores arrows until it has bitten you twice, then one arrow kills it.

  • Turning a noisy muscle signal into a bowstring. EMG data is jittery and different for every person, so per-player calibration and smoothing were essential.
  • Missing animations. The dinosaur models only had idle or run cycles, so we built procedural animation ourselves instead of swapping to simpler models.
  • VR performance. Smoke, fire, foliage and several dinosaurs on screen all compete for frame time, and low frame rates in VR make people sick.
  • Merge conflicts. Two of us edited the same dinosaur script at once and had to coordinate which branch merged first.

Accomplishments that we're proud of

  • A bow that responds to how hard you actually pull.
  • A full two-act game loop, from the first dinosaur to the boss fight, built in one hackathon.
  • Dinosaurs that feel alive despite having almost no original animations.

What we learned

  • How EMG signals work and how much calibration matters for body-based input.
  • NavMesh AI, hitbox design and procedural bone animation in Unity.
  • How to keep a VR scene beautiful and fast.
  • How to split one Unity project across four people without breaking each other's work.

What's next for EMG Bow

  • Richer haptics. Proportional motors with PWM instead of relays, more points on the vest, and patterns that tell a bite from a spit.
  • Fatigue as a mechanic. EMG shows when a muscle is tiring, so long fights could demand pacing, not just aim.
  • Standalone Quest build. Bluetooth from the ESP32 straight to the headset, with no laptop or hotspot in between.
  • Rehab and fitness. The same loop of squeeze, reward and feedback could make grip-strength exercises feel like a game.

Built With

  • arduino
  • c#
  • c++
  • emg
  • esp32
  • ffmpeg
  • git-lfs
  • mediapipe
  • meta-quest-pro
  • myoware
  • onnx
  • openxr
  • suno
  • udp
  • unity
  • unity-inference-engine
  • universal-render-pipeline
  • xr-interaction-toolkit
Share this project:

Updates

Submission history