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.