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。 以下为已保存的摘录。
El juego sigue funcionando exactamente igual que antes. Lo único nuevo es una pestaña GLOBAL junto a la de LOCAL, y una pregunta al terminar una partida de invasión. Si no despliegas nada de esto, el juego funciona igual: la pestaña GLOBAL simplemente avisará de que no pudo conectar. index.html va en la raíz. La carpeta api/ es lo que Vercel convierte automáticamente en endpoints: api/scores.js se publica como /api/scores. 1. Crear la base de datos en Neon查看完整 README ↗
El juego sigue funcionando exactamente igual que antes. Lo único nuevo es una pestaña GLOBAL junto a la de LOCAL, y una pregunta al terminar una partida de invasión. Si no despliegas nada de esto, el juego funciona igual: la pestaña GLOBAL simplemente avisará de que no pudo conectar.
tu-repo/
├── index.html (el juego)
├── package.json
├── schema.sql (ranking global)
├── schema_salas.sql (salas del multijugador en línea)
└── api/
├── scores.js (función de servidor: ranking)
└── salas.js (función de servidor: salas)
index.html va en la raíz. La carpeta api/ es lo que Vercel convierte
automáticamente en endpoints: api/scores.js se publica como /api/scores.
schema.sql y pulsa Run.schema_salas.sql y pulsa Run (sin esto, el
multijugador en línea no funciona).postgresql://. Marca la opción Pooled connection si aparece.Guarda esa cadena: es la que usarás como DATABASE_URL.
Vuelve a pegar y ejecutar los dos archivos, schema.sql y
schema_salas.sql, en el SQL Editor de Neon. Están hechos para ejecutarse
sobre una base existente: no borran ni cambian ningún puntaje, solo añaden lo
que falte:
alien,
viltrum, dragon, maquina, mago y boros), tanto en el ranking como
en las salas;ranking_alien,
ranking_viltrum, ranking_dragon, ranking_maquina, ranking_mago y
ranking_boros.
Sirven para ver cada tabla de puntajes desde Neon
(SELECT * FROM ranking_mago;); el juego no las necesita.Después haz Redeploy en Vercel para que api/scores.js y api/salas.js
acepten a los personajes nuevos. Hasta entonces el servidor antiguo guardaba
lo suyo como si fuera la cría.
Cada personaje tiene su propio ranking: los cinco comparten la tabla scores
y se separan por la columna hero. En el navegador, los puntajes locales
también van por separado (invasion_scores, invasion_scores_vil,
invasion_scores_dra, invasion_scores_maq e invasion_scores_mag).
Cada mapa tiene además su propia tabla, global y local. Para activarlo en una
base que ya existía, vuelve a pegar y ejecutar schema.sql en el SQL Editor
de Neon y después haz Redeploy en Vercel. El script:
mapa (ciudad, alien o infierno); todos los puntajes
que ya tenías quedan como de la ciudad, sin perder ninguno;ranking_mapa_alien y ranking_mapa_infierno.Ejecuta schema.sql antes del Redeploy: el api/scores.js nuevo ya
consulta la columna mapa y, sin ella, el ranking global no cargaría.
En el navegador, los puntajes locales de los mapas nuevos añaden el nombre
del mapa a la clave (por ejemplo invasion_scores_alien o
invasion_scores_vil_infierno); los de la ciudad no cambian.
git init
git add index.html package.json schema.sql api/scores.js
git commit -m "Invasión Tentacular con ranking global"
git branch -M main
git remote add origin https://github.com/TU-USUARIO/TU-REPO.git
git push -u origin main
Entra en https://vercel.com y accede con tu cuenta de GitHub.
Add New → Project e importa el repositorio.
En Framework Preset deja Other. No hace falta build command.
Antes de desplegar, abre Environment Variables y añade:
| Name | Value | Environments |
|---|---|---|
DATABASE_URL | la cadena postgresql://… de Neon | Production, Preview, Development |
Pulsa Deploy.
Si añades la variable después del primer despliegue, entra en Settings → Environment Variables, guárdala y luego Deployments → ⋯ → Redeploy, porque las variables se leen al construir.
En tu proyecto de Vercel, Storage → Connect Database → Neon. Al vincularlo,
Vercel crea DATABASE_URL por ti y no tienes que copiar nada a mano.
https://tu-proyecto.vercel.app/api/scores?hero=dragon debe responder
{"ok":true,"hero":"dragon","scores":[…]} (vacío al principio).https://tu-proyecto.vercel.app/api/scores debe responder
{"ok":true,"scores":[]}.Si algo falla, Vercel → Deployments → Functions muestra los registros de
/api/scores.
| Variable | Obligatoria | Para qué |
|---|---|---|
DATABASE_URL | sí | Conexión a Neon. Solo la lee el servidor. |
La cadena nunca aparece en el HTML ni en el JavaScript del navegador: el
juego solo conoce la ruta /api/scores.
GET /api/scores?limit=25&hero=alienHay una tabla por personaje, igual que en el ranking local. hero acepta
alien, viltrum, dragon, maquina, mago o boros; si se omite, devuelve el
ranking conjunto.
{ "ok": true, "scores": [
{ "id": 1, "player_name": "ZORA", "score": 99000,
"hero": "alien", "device": "pc", "created_at": "2026-09-11T12:00:00.000Z" }
]}
limit admite de 1 a 100; por defecto 25. El campo hero de la respuesta
indica de qué tabla se trata, o null si vienen mezclados.
GET /api/scores?hero=alien&name=ZORAConsulta la posición de un jugador concreto, para poder decirle en qué puesto está cuando no entra en los 25 visibles.
{ "ok": true, "encontrado": true, "hero": "alien",
"score": 9000, "rank": 4, "total": 128 }
Si ese jugador nunca subió nada con ese personaje: { "ok": true, "encontrado": false }.
POST /api/scores{ "player_name": "ZORA", "score": 99000, "hero": "alien", "device": "pc" }
Cada jugador tiene un solo registro por personaje: el de su mejor partida.
{ "ok": true, "mejorado": true, "score": 99000, "rank": 3, "total": 128, "hero": "alien" }
201 y mejorado: true → era mejor que la marca anterior y se guardó.200 y mejorado: false → ya tenía una marca igual o mejor; la tabla no se
toca y score devuelve la que conserva.Quién decide es la base de datos, con ON CONFLICT ... WHERE scores.score < EXCLUDED.score, así que dos partidas terminadas a la vez no pueden pisarse.
El servidor no se fía del navegador y rechaza con 400:
Además recorta el nombre a 14 caracteres, le quita etiquetas y caracteres de
control, y normaliza hero y device a los valores conocidos.
SaveIO, localStorage, saveScore(), loadScores(),
renderScoreList(), commitName() y pendingScore siguen tal cual.