Skip to content

A run of PIXEL INVASION in progress: a player ship at the bottom of a dark 3D arena firing up into a full descending formation of invaders, with Lives, Level, Score, and Time in the HUD across the top.

Boots straight into Play Solo — co-op needs a live session, so that one lives behind Open full app. Best with a keyboard or a gamepad; a WebGL build this size is more than most phone browsers will hold.

Level 07

PIXEL INVASION — Online Co-op Shooter

Bring a friend. The server calls every shot.

A 3D co-op arcade shooter built in Unity 6 — Space Invaders' shape, with real online multiplayer underneath it. Two players share one run against the same wave director: shooting is server-authoritative with client-side prediction, sessions are brokered through Unity Gaming Services Relay, and the whole thing ships as a WebGL build that runs on any static host with no special headers. The single-player arcade core came first and never touches the network at all — which is exactly why it's the mode that loads on this page.

The problem

Space Invaders is the most copied game in history, and almost every clone stops at one player — because the moment two people share a run you inherit every hard problem in networked games at once: who gets to decide a hit landed, what happens when that answer arrives three frames late, and how a browser tab and a desktop build end up in the same session at all. Pixel Invasion answers a narrower question: can a small arcade shooter be genuinely server-authoritative — trusting the client for nothing that costs a life — and still feel instant to the person holding the trigger?

Built with

UnityC#Netcode for GameObjectsWebGLServer-authoritative

What went into this

  • Server-authoritative shooting with client-side prediction — the tracer leaves your ship the frame you press fire, but the host is the only thing that decides whether anything actually died
  • A custom xorshift32 RNG replaced UnityEngine.Random everywhere, so an entire run — every wave, every spawn — replays exactly from one seed. That determinism is also what made 30 EditMode unit tests across 6 files possible in the first place
  • Explosions and hit flashes broadcast as ~16-byte RPCs instead of spawned NetworkObjects — cheaper on the wire, and the fix for a real bug where your own death explosion was the one nobody else could see
  • Owner-authoritative movement, on purpose: this is PvE co-op, so a movement cheater only ruins their own run — the server spends its authority on damage, where it actually costs someone something
  • A "mercy rule" difficulty slew that's deliberately asymmetric — it ramps up slowly when you're winning and backs off fast when you're not, because a co-op run that punishes the weaker player just ends early

How it fits together

Single-player came first and never learned about the network: Play Solo runs the same wave director, the same seeded RNG, and the same difficulty curve with the netcode layer simply not instantiated — so the mode most visitors will actually play can't be broken by a session bug. Online is that same core with Netcode for GameObjects on top and one deliberate split of authority: the host owns damage (a fire request arrives as a ServerRpc, gets validated against the weapon's real cadence, and hit resolution happens once, on the host) while each player owns their own movement, because in PvE co-op a movement cheater only cheats themselves. Everything cosmetic is deliberately not a networked object — explosions travel as ~16-byte RPCs, which is both cheaper than spawning a NetworkObject per particle burst and the fix for a bug where your own death explosion never reached anyone else. Unity Gaming Services Relay carries the traffic, forced to WSS so a WebGL tab and a desktop build can share one session instead of sitting on two incompatible transports.

Pixel Invasion server-authoritative shot lifecycle — architecture diagramCLIENTInputfire pressedCLIENTPredicted tracerspawns this framelocal only — a guessCLIENTReconcileserver result replacesthe guessCLIENTVFX in~16 B → spawn locallyRELAYUGS Relayforced WSSshared by WebGL + desktopHOSTValidatecadence, cooldownHOSTRaycast + damageresolved once, herenothing else is trustedHOSTVfx ClientRpceffect id + position① predicted tracer② ServerRpc via Relay③ host validates④ cadence⑤ NetworkVariable delta → reconcile⑥ vfx RPC~16 B, not a NetworkObject— Movement never appears above — it's owner-authoritative, so a movement cheater only ever cheats themselves.— Play Solo never instantiates the host column at all — same wave director, same seed, just no host, no relay, no session.
  1. You press fire. The client spawns a predicted tracer on the same frame — a local guess, never sent anywhere, so the shot leaves your ship with no perceived latency.
  2. The same input goes out as a ServerRpc through Unity Gaming Services Relay, forced to WSS so a WebGL tab and a desktop build can share one session instead of two incompatible transports.
  3. The host validates the request against the weapon's real fire cadence and cooldown. A client asking to shoot faster than the weapon allows is simply ignored.
  4. The host raycasts and applies damage. This happens exactly once, on the host — nothing a client claims about a hit is trusted.
  5. The result comes back as a NetworkVariable delta, and the client reconciles: the predicted tracer is replaced by the authoritative outcome rather than argued with.
  6. Cosmetics travel separately. Explosions and hit flashes broadcast as roughly 16-byte ClientRpcs carrying an effect id and a position, not as spawned NetworkObjects — cheaper on the wire, and the fix for a bug where a player's own death explosion never reached anyone else.
  7. Movement never enters this loop. Each player owns their own transform, deliberately: in PvE co-op a movement cheater only ruins their own run.
  8. Play Solo never instantiates the network layer at all — the same wave director and the same seeded RNG, with no host, no relay, and no session.

No repo link on this one, and that's a decision rather than an oversight: the build bundles three Unity Asset Store packs, licensed for use in the game but not for redistributing their source. Publishing the repo would mean publishing theirs. So the build is the proof instead — play it.

How it works