Underground 2 Revived
Play Need for Speed: Underground 2 (2004) in Chrome and Firefox with WebGPU graphics, Web Audio, up to 120 fps widescreen, controller support, free roam and Online races with friends. Fan project, not
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
Real-time multiplayer .io game about growing a mycelial network — plant colonies, wire them
together with hyphae, and drain nutrients out of wild falls, out of rivals, or straight out of an
opponent's network while they try to do the same to you.
Modelled on an older browser game. The mechanics and the reference screenshots are written up in
design-document.md.查看完整 README ↗Real-time multiplayer .io game about growing a mycelial network — plant colonies, wire them together with hyphae, and drain nutrients out of wild falls, out of rivals, or straight out of an opponent's network while they try to do the same to you.
Modelled on an older browser game. The mechanics and the reference screenshots are written up in design-document.md.
You start as one colony with a small pool of nutrients. Nutrients only enter your network by draining a nutrient fall or someone else's colony, and a colony that isn't being fed bleeds upkeep until it withers. Everything is one gesture: drag from a colony. Drag to empty ground and you throw a new colony there, carrying a share of the parent; drag onto another node and you grow a hypha, which flows from where the drag started to where it ended — so dragging out of a rival's colony is how you steal from it.
Terrain blocks hyphae as well as movement, so the cave walls decide who can reach whom, and walls you build yourself can cut an attacker's line. Hyphae never cross each other either, so every line is also a barrier. The round runs on a timer and the biggest gatherer wins.
npm install
npm run server # authoritative game server on http://localhost:8787
npm run dev # client dev server on http://localhost:5173
npm test # sim, server, camera and bot specs (vitest)
npm run build # typecheck + production build into dist/
The client opens on a menu: a name, a bot difficulty (Easy / Normal / Hard) and an optional server.
Leave the server empty to play solo against bots. On the dev server it's pre-filled with
localhost:8787, so Play joins your local server; if that server isn't running, the client plays
solo meanwhile and keeps retrying, switching to multiplayer the moment the server answers. When the
page is served by the game server itself, the field defaults to that server.
Spectate (next to Play on the menu) watches the whole arena, fog-free, without playing: a local all-bot match when the server field is empty, or a live server's game when it isn't. Spectators get no colony, can't issue commands, and don't count toward the arena size. Stats (or Tab) opens a live panel with everyone's graphs and totals.
Leaderboard: players still in, ranked by the nutrients they hold right now; anyone wiped out is greyed out at the bottom.
Match stats: when you're wiped out, win, or leave, a summary shows graphs of your nutrients in and out (gathered, drained from rivals, spent, lost to rivals), nutrients held and colonies over time, and a table of totals. Solo, it compares everyone; online, leaving mid-round shows only your own (a rival's live numbers would see through the fog), and the round-end summary shows everyone's.
Open http://localhost:5173 in two tabs to play against yourself — add ?name=Armillaria so the
tabs don't share a stored name. After npm run build the server also hosts the client itself on
port 8787.
The real game is the server. Like any .io game, players visit the game server's own web
address: after npm run build it serves the client and the game connection from the same place.
GitHub Pages is a demo. Every push to main runs the tests and publishes the client there
(.github/workflows/pages.yml), where it plays solo against bots. Pages is static, so it can't host
the Node server. A visitor can enter a server to join, but a page served over https can only reach
servers using wss, so a remote server joined from Pages must serve wss. Two ways:
TLS_CERT and TLS_KEY to the paths of a PEM certificate and key
(e.g. from Let's Encrypt for a domain pointing at the machine), and the server speaks https/wss
on the same port. A self-signed certificate won't be accepted by browsers.wss://example.trycloudflare.com.| Input | Action |
|---|---|
| Left-drag from a node → empty space | Throw a new colony, auto-connected by a hypha from its parent |
| Wheel while dragging | Share of the parent the new colony carries (15–90%, default 65%, 5% per notch) |
| Left-drag from a node → another node | Grow a hypha; nutrients flow from drag start → drag end (drag from a rival to drain them) |
| Left-click a hypha | Reverse which way it flows (only hyphae you grew) |
| Right-drag from your colony | Build a wall (⊢): both the stem and the crossbar block line of sight |
| Right-click your wall / your hypha | Demolish it / cut it (only hyphae you grew) |
| Right-drag from anywhere else, or WASD | Pan |
| Mouse wheel | Zoom |
| R | New round (solo and spectated local matches only) |
| Tab | Live stats panel (spectating) |
| F | Toggle the render profiler |
server/ runs the same src/sim/ code. Clients send Commands and
receive snapshots; nothing is simulated client-side, and a forged player id is re-stamped.src/
config.ts every tuning number, plus the size / reach / aura curves
sim/ pure game logic — no DOM, runs headless on the server and in tests
world.ts state, rule checks (canEject/canConnect/canReverse/...), the tick
arena.ts seeded cave generation + WallIndex for line-of-sight queries
spawn.ts where a joining or respawning player lands
vision.ts fog-of-war queries, used by the server to filter snapshots
stats.ts per-player match stats and history, and their wire format
bot/ computer players (bot-design.md); issue ordinary Commands, no special access
match.ts one authoritative tick (bots + world.step)
geometry.ts segment/circle maths, seeded RNG
types.ts entities + the Command union
render/ Canvas 2D renderer
territory.ts metaball "fluid" auras (WebGL2 shader, CPU fallback)
fog.ts vision, remembered ground, the grey overlay
terrain.ts cached terrain image for zoomed-out frames
growth.ts purely visual timing for new hyphae and colonies
camera.ts eased fly-to camera
net/ protocol (shared with the server) + client connection
input/ mouse/keyboard → Commands
ui/statsPanel.ts the stats panel: graphs and totals
main.ts menu, fixed-timestep loop, HUD, solo fallback
server/ rounds, join/respawn, per-player snapshots
tests/ vitest specs for the sim, bots, stats, the server room and the camera
tools/mapgen/ experimental map-generator previews; not used by the game (see below)
reference/ screenshots of the original game
Every player action is a Command queued into the World and applied at the start of the next
tick — the same path locally and over the network.
tools/mapgen/ holds standalone scripts that draw and test a proposed replacement for the arena
generator. Nothing in src/ uses them.
npx tsx tools/mapgen/preview.ts [seed ...] # writes tools/mapgen/out/index.html
npx tsx tools/mapgen/check.ts [seeds] # connectivity, speed and fairness checks
Bots play by the same rules as a person and issue ordinary Commands (src/sim/bot/, designed in
bot-design.md). Three layers run every time a bot looks: a strategy state
machine picks a posture (opening, expand, consolidate, war, defend) from its live stats; tasks
carry multi-step plans as state machines — expeditions that path round terrain, wall-then-sever,
Harvest loops, boost holds, sieges; reflexes keep the network healthy — taps, supply lines,
reversals, rings, relinking pieces, walls, drains, Flow. Every candidate is priced on one scale,
weighted by the posture, checked against the rules best-first, and the best legal one is taken.
Difficulty is hands, reaction and temperament: one action at a time with a gap after each
(Easy 5 s, Normal 2 s, Hard 1.4 s on average, each varied ±40%); a reaction delay before answering anything new that comes
into contact (5 s, 3 s, 1.5 s); and what it reaches for — easy walls rivals off on sight, hard
latches on and drains them. A bot stops throwing at 40 colonies. The difficulty picked sets a mix,
so no two bots are quite equal: Easy is all easy bots, Normal is normal, normal and easy, Hard is
hard, hard and normal; each bot's level shows in its name.
The design doc leaves these open; these are the prototype's answers, all in config.ts unless
noted.
220 + 20·√nutrients, capped at 600 (MAX_REACH), so a colony never reaches across
the map however rich it gets. It governs throwing, connecting and building walls alike.CAMERA_FLY_TAU_MS, CAMERA_FLY_ON_EJECT).FALLS_PAY_UPKEEP).