Skip to content

vladguba/pulse-runner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Pulse Runner

Pulse Runner is a 3-lane endless runner built in Lens Studio 5.22 for Snapchat, starring the user's Bitmoji. You move between lanes to dodge the tall obstacles and jump the short ones, picking up coins and power-ups along the way, while a friend's Bitmoji chases you and the world keeps speeding up. Three hits end the run; you can restart or return to the menu without leaving the Lens. Three switchable visual themes re-skin the whole game.

This is a prototype. The goal is a readable, modular codebase with a sensible Lens Studio setup, not a finished product.


Controls

Input Action
Swipe left / right Move one lane
Tap Jump (clears short obstacles)
On-screen icons Start · Restart · Menu · Mute · Theme

In Lens Studio's Preview the mouse stands in for touch: click is a tap, click-drag is a swipe.

How to run

This repo keeps its binary assets (models, textures, audio, packages) in Git LFS. Run git lfs install once before cloning, so you pull the real files instead of small pointer stubs.

  1. Open Lens Studio 5.22+ and open PulseRunner.esproj.
  2. The Preview panel plays the Lens automatically. If the webcam source fails, switch the Preview input to a sample image or video.
  3. The Bitmoji shows a generic placeholder avatar in the editor. The real user's Bitmoji (and the friend chaser) only resolve on device, which is expected.

Testing on a phone

The editor preview can't show everything. Real Bitmoji, multi-touch, real audio and the chaser/leaderboard only behave correctly on a device.

  1. Log in to Lens Studio with the same Snapchat account you use on the phone.
  2. Click Preview Lens in the top toolbar; a Snapcode appears. In Snapchat, point the camera at it and press-and-hold to scan, which pairs the phone. Pairing is a one-time step.
  3. Once paired, the Lens previews live on the phone and updates as you edit. To share it beyond preview, use Publish.
  4. There are no print() logs on device; use Snapchat's developer logging or a temporary on-screen Text for debugging. The first Bitmoji load can briefly show the placeholder while it streams.

Features

  • Runner core: 3 lanes, a jump arc, world-scrolling obstacles and coins, object pooling.
  • Two obstacle types: dodge the tall ones by switching lane, jump the short ones (color-coded by theme).
  • Lives + Game Over: 3 hits ends the run; red hit-flash and a camera shake.
  • Score: coins add points, shown on the HUD; the high score persists between sessions.
  • Difficulty ramp: world speed and obstacle density rise over time, including two-lane walls.
  • Power-ups: a shield (absorbs a hit) and a magnet (pulls coins); plus a boost that briefly speeds you up with speed-lines.
  • Chaser: a My Friend Bitmoji trails you a fixed distance behind, stays in view, and closes in on each hit, then catches up on game over. It needs at least one friend on the account to load (the editor shows a placeholder). Tune the resting distance with ChaserController.restGap.
  • 3 themes: NEON / CANDY / COSMIC. A start-menu button re-skins the road, obstacles, coins and UI live, and the choice persists.
  • Pause: an in-game pause/resume button freezes the run (world and animation) and surfaces restart / menu without ending it.
  • Leaderboard: submits the score and shows friends' top scores on game over (device-only; guarded to no-op in the editor).
  • Audio: coin / hit / jump / power-up / shield-block / start / game-over SFX, a background music loop and a mute toggle. The mute choice persists.
  • Icon UI: start menu, on-screen restart / menu / mute / pause / theme buttons, heart lives, a dimmed menu backdrop.

Architecture

Small single-responsibility script components coordinate through a central GameManager and a few shared modules. Most cross-talk is event-driven (systems subscribe to the hub); a handful of direct calls remain where a hard dependency is clearer than an event, such as a spawner applying a buff or a controller playing a SFX.

Assets/Script/
├── Core/
│   ├── GameManager.ts    # State machine (Ready/Playing/GameOver) + pause, lives,
│   │                     #   score, shared world speed + difficulty, event hub, high score
│   ├── Lanes.ts          # Single source of truth for lane layout (count, spacing, lane-to-X)
│   ├── ThemePalette.ts   # 3 themes + current-theme state + listener bus (getTheme/cycleTheme)
│   └── LeaderboardController.ts # Submits score + shows friends' top scores (device-only)
├── Player/
│   ├── InputController.ts    # Raw touch to gestures (tap / swipe L/R); a UI tap can consume it
│   ├── PlayerController.ts   # Lane position + jump arc; tap = jump / start
│   ├── CharacterAnimator.ts  # Plays Bitmoji run/idle/jump/defeated clips from game state
│   ├── PlayerBuffs.ts        # Shield / magnet / boost state + timers (single owner)
│   └── PlayerBuffsVFX.ts     # Floating shield/magnet indicator above the player
├── World/
│   ├── ObstacleSpawner.ts  # Pooled obstacles (tall=dodge / short=jump), movement, ramp, walls
│   ├── PickupSpawner.ts     # Pooled coins, radius magnet pull, collection adds score
│   ├── PowerUpSpawner.ts    # Pooled power-ups (shield/magnet/boost models), applies PlayerBuffs
│   ├── CollisionSystem.ts   # World-space hit test reported to GameManager (shield absorbs)
│   └── ChaserController.ts  # Pursuer transform: trails, closes in on hit, catches up, mirrors jump
├── UI/
│   ├── UIController.ts   # HUD (score) + banner text + button wiring + menu backdrop
│   ├── ScreenButton.ts   # Base for tap buttons: hit-test + claim the tap from input
│   ├── UIButton.ts       # Generic icon button with onClick (start / restart / menu)
│   ├── MuteButton.ts     # Mute toggle icon (speaker on/off)
│   ├── PauseButton.ts    # In-game pause / resume toggle
│   ├── ThemeButton.ts    # Cycles themes, persists choice
│   └── LivesDisplay.ts   # Heart icons reflecting lives
├── Visual/
│   ├── ThemedVisual.ts   # Tints a prop (road/lane line) from the current theme, re-tints live
│   ├── HitFlash.ts       # Full-screen red damage flash
│   ├── ScorePopup.ts     # "+N" popup on coin pickup
│   ├── SpeedLines.ts     # Radial speed-lines overlay during boost
│   └── CameraShake.ts    # Camera-shake juice on hit
└── Audio/
    └── AudioController.ts # Single SFX + music hub; subscribes to GameManager events; mute flag

Key design decisions

  • GameManager as the hub. It owns the state machine, lives, score and the shared world speed, and broadcasts onLivesChanged / onScoreChanged / onStateChanged. Systems depend on the hub, not on each other, so they reset and react independently.
  • The world moves, not the player. The player only changes lane (X) and jumps (Y); obstacles and coins scroll toward the camera and recycle. Collisions become a cheap world-space distance check.
  • Single sources of truth. Lane geometry lives in Lanes and world speed in GameManager; the look lives in ThemePalette. Change one constant to retune.
  • Object pooling. Obstacles use runtime prefab.instantiate; coins and power-ups use pre-placed child pools. Two patterns are shown on purpose, with no per-spawn allocation.
  • Runtime theme switching. Consumers read getTheme() and subscribe to onThemeChanged(); one button re-skins everything at once.
  • Decoupled audio and juice. AudioController, HitFlash, CameraShake and SpeedLines only listen to game events; gameplay code doesn't know they exist.
  • Restart without leaving the Lens. The spawners reset themselves on the state-change event, and so do the player and the chaser; no central "reset everything" routine couples them.

Device-only / known notes

  • The friend chaser and leaderboard behave fully only on device; the editor shows a placeholder avatar.

About

A 3-lane endless runner Lens for Snapchat where your Bitmoji outruns a chasing friend. Built in Lens Studio 5.22.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors