Guardado rendimiento y pruebas - JRuizGil/MeltTheDeep GitHub Wiki

Guardado, rendimiento y pruebas

TDD · Documento técnico

Guardado

La partida se guarda cada vez que subo a la superficie. Elegí ese momento porque no hay bolitas activas que guardar, y así no tengo que serializar cientos de cuerpos con física.

Lo que se guarda:

  • La semilla de la partida y los módulos generados.
  • Por cada chunk que el jugador ha modificado, su densidad comprimida con GZip.
  • El estado abierto o cerrado de cada región de cueva.
  • Las vetas que quedan y la integridad de cada una.
  • Las mejoras compradas, el dinero y los minerales.
  • Las especies registradas.
  • Los huesos recogidos y los montados.
  • Los módulos completados.

El formato es un JSON con los datos pequeños y un binario comprimido con los chunks, ambos en Application.persistentDataPath, y el JSON lleva un número de versión para poder migrar partidas si cambio la estructura. Al cargar no leo los módulos enteros: regenero cada uno desde la semilla (Generación de cuevas) y encima aplico los chunks guardados. Como la generación es determinista, las vetas y las regiones salen en el mismo orden, y el guardado las identifica por su índice.

Rendimiento

Mido antes de optimizar. Los sistemas que más cuestan llevan un ProfilerMarker:

Marcador Qué mide
CaveGenerator.Generate Generación de las cuevas de un módulo
MeltSystem.Apply Un golpe de fundido
ChunkMesher.Build Mallado de un chunk
WaterBallPool.Spawn Creación de bolitas
VacuumMode.Tick Búsqueda y fuerza de la aspiradora
SnapValidator.Check Validación de un encaje

Para poder comparar un cambio con el estado anterior uso escenarios fijos: la misma semilla y el mismo recorrido, de modo que la diferencia entre dos capturas viene del cambio y no del azar. Los bucles calientes no reservan memoria por fotograma: uso consultas NonAlloc, buffers reutilizados y nada de LINQ en Update. Los milisegundos de cada sistema los vuelco a un CSV para el informe, y cada captura queda anotada en el registro de medidas de Planificación.

Riesgos técnicos

Riesgo Señal Plan
El remallado pasa de 3 ms ChunkMesher.Build por encima de 3 ms en una captura de referencia Remallo un chunk por fotograma en vez de dos y reviso el tamaño de chunk
Abrir una cueva grande ensucia muchos chunks de golpe Pico de fotograma justo al abrir una cueva Remallo primero los más cercanos y reparto el resto en varios fotogramas
La generación tarda demasiado La carga del módulo se nota o CaveGenerator.Generate no mejora entre iteraciones en Sandbox_Caves Ruido más grueso y paralelizo por chunk
La curva de aprendizaje de Jobs y Burst Me atasco o aparecen errores que no sé interpretar Escribo primero una versión en C# normal, mido, y solo después paso a Burst
Picos al cocinar colliders Saltos en el Profiler tras remallar El cocinado va en un job y el collider anterior sigue mientras tanto
Demasiadas bolitas La física pasa de su presupuesto de 4 ms Bajo el límite de activas, pongo más litros por bolita y duermo las bolitas antes
Objetos que atraviesan hielo fino Un pez o un hueso aparece al otro lado de una pared Colisión continua para los objetos grandes y suelto los atrapados solo cuando el collider del chunk ya está actualizado
FMOD rompe el build La compilación falla o el juego arranca sin sonido Compilo pronto y a menudo para enterarme en el momento

Los umbrales de la columna Señal son valores iniciales y los ajusto con las primeras capturas.

Pruebas

Las pruebas EditMode comprueban lógica pura, sin escena:

  • El generador es determinista: el hash del campo es el mismo en 200 semillas.
  • Todas las anclas quedan conectadas.
  • Las zonas protegidas no tienen aire.
  • El volumen de cuevas cae dentro del rango de su módulo.
  • Las vetas solo aparecen en superficies de cuevas.
  • La fórmula de coste de las mejoras.
  • El freno por agua acumulada.
  • El recálculo de PlayerStats al comprar una mejora.
  • La validación del encaje, incluido el lado equivocado.

Las pruebas PlayMode comprueban comportamientos que dependen de la física y de la escena:

  • Una bolita nunca se fusiona dos veces.
  • Con el tanque lleno, la aspiradora deja de aspirar.
  • La apertura bloquea los objetos más grandes que ella.
  • Una cueva se abre cuando se funde su pared.
  • Un hueso se monta en su sitio y un hueso mal colocado resbala.

Control de versiones

El repositorio está en GitHub con estas ramas:

Rama Uso
main Siempre jugable
dev Integración del trabajo en curso
feature/<sistema> Una rama por sistema, por ejemplo feature/cuevas

Marco las entregas con las etiquetas ae2, ae3 y ae4. Los archivos pesados van con Git LFS: *.fbx, *.png, *.psd, *.wav y *.bank. Para que Git pueda leer las escenas y los prefabs uso Asset Serialization en Force Text y UnityYAMLMerge, y parto del .gitignore estándar de Unity.

Trabajo con commits pequeños. Al empezar cada sesión hago pull y al terminarla hago push, para que lo que hay en GitHub y lo que hay en el PC de clase nunca difieran mucho.

⚠️ **GitHub.com Fallback** ⚠️