A Wear OS arcade game built around the rotating crown. You defend a reactor core at the centre of the watch face; the crown spins a shield arc around it.
Roughly 25 KB, no dependencies, no Gradle. Build artifacts are git-ignored — build
it with build.ps1 (below) or grab a prebuilt APK from
Releases.
| Input | Action |
|---|---|
| Rotate the crown | Spin the shield around the core (the whole game) |
| Tap | Start / retry |
| Hold ~0.6 s on the title or game-over screen | Flip crown direction (saved) |
| Drag on screen | Fallback aiming, for testing off-watch |
Rules:
- Red bolts — block them. One that reaches the core costs a hit point.
- Green charges — let them through. They refuel the core (+1 HP, or bonus points at full health). Blocking one breaks your chain.
- Purple splitters — blocking one breaks it into two fragments that re-enter just outside the shield, so you have to swing back across to catch both.
Blocking without mistakes builds a chain multiplier (up to ×9). Speed, spawn rate and a slow angular drift on incoming bolts all ramp with your score. Five hit points; best score and best chain persist.
AXIS_SCROLL from SOURCE_ROTARY_ENCODER is converted to a scroll distance in
pixels using the device's own getScaledVerticalScrollFactor() — the same
normalisation Wear's scrollable views use — and then to degrees. That keeps the
feel consistent across watches with different encoder resolutions, instead of
hard-coding a degrees-per-detent constant.
Calibration as shipped: one screen-height of equivalent scrolling = one full 360°
revolution of the shield. Tune with ROTARY_SENSITIVITY in GameView.java.
Events are handled in GameView.onGenericMotionEvent, and GameActivity forwards
any that no view consumed, since some Wear builds deliver rotary scroll to the
activity rather than to the focused view.
No Gradle and no network needed — the app uses nothing beyond the framework
android.jar, so it compiles straight through the SDK build tools.
powershell -ExecutionPolicy Bypass -File .\build.ps1Pipeline: aapt2 compile → aapt2 link → javac → d8 → zip in classes.dex →
zipalign → apksigner. Output lands in dist/OrbitGuard.apk.
The script picks up the SDK from ANDROID_HOME (falling back to C:\Android\sdk)
and uses build-tools 36.0.0 with platforms/android-36.
On first run the script generates a throwaway dev signing key at
keystore/orbitguard.jks. That directory is git-ignored and is not in this
repository — you get your own key the first time you build. It is fine for
sideloading and useless for Play Store publishing.
To sign with your own key instead, set any of:
| Variable | Default |
|---|---|
ORBITGUARD_KEYSTORE |
keystore/orbitguard.jks |
ORBITGUARD_KEYSTORE_PASS |
orbitguard |
ORBITGUARD_KEY_ALIAS |
orbitguard |
adb install -r dist/OrbitGuard.apkTo sideload to a real watch, enable Developer options → ADB debugging → Debug over
Wi-Fi on the watch, then adb connect <watch-ip>:5555 first.
- Package
com.neo207.orbitguard, launcher activity.GameActivity minSdk 26,targetSdk 35, declaresandroid.hardware.type.watchandcom.google.android.wearable.standalone(runs without a paired phone)- Zero dependencies — plain
Activity+ a customViewdrawing on aCanvas, driven byChoreographerfor vsync-timed frames - Entities are pooled and paints pre-allocated, so the frame loop does not allocate
- Layout is derived from
min(width, height), so it fits round and square watches at any size
Verified on a wearos_large_round emulator (454×454, API 34): installs, launches,
plays, scores, ends, and persists a high score, with the crown driving the shield.
All in GameView.java:
| Constant | Effect |
|---|---|
ROTARY_SENSITIVITY |
Crown travel per rotation |
SHIELD_HALF_SPAN_DEG |
Shield width — the main difficulty dial |
MAX_HP |
Starting hit points |
level() / spawn() |
Difficulty ramp and projectile mix |
The manifest carries a package= attribute because aapt2 requires one for the
manual build. AGP 8+ rejects that attribute, so if you convert this to a Gradle
project, remove package="com.neo207.orbitguard" from AndroidManifest.xml and
put namespace = "com.neo207.orbitguard" in the module's build.gradle instead.
MIT — see LICENSE.