Arquitectura - JRuizGil/MeltTheDeep GitHub Wiki

Arquitectura

TDD · Documento técnico

Plataforma y objetivo

Aspecto Objetivo
Plataforma PC con Windows 10/11 de 64 bits
API gráfica DirectX 11/12
Resolución 1920×1080
Rendimiento 60 FPS estables (16,6 ms por fotograma) en el PC de clase

El PC de clase es el punto de referencia para todo: si una medida sale bien en mi ordenador y mal en el del aula, vale la del aula.

Versión web (propuesta, pendiente de confirmar con los profesores)

Si los profesores dan el visto bueno, saco también una build para navegador con la plataforma Web de Unity 6 (WebGL 2, y WebGPU si está lo bastante estable), publicada en itch.io o en GitHub Pages. Tiene limitaciones que afectan justo a los sistemas más pesados del juego:

Tema Qué cambia en la web Qué haría
Hilos El código C# no se reparte entre varios hilos como en PC, así que los jobs de las cuevas y del remallado van más despacio Medir la generación de cuevas en la build web desde el principio, porque es mi objetivo de optimización, y bajar la resolución o generar por partes si no llega
Memoria El navegador da menos memoria que un PC Cargar un módulo cada vez y vigilar el tamaño del campo de densidad
Física Cientos de bolitas cuestan más Bajar el tope de bolitas activas solo en la versión web
Sonido FMOD tiene soporte para web, pero el navegador no deja sonar nada hasta que el jugador hace clic Pantalla de inicio con un botón de jugar
Descarga La build tiene que bajarse entera antes de jugar Texturas comprimidas y bancos de FMOD ligeros
Guardado No hay disco: se guarda en el almacenamiento del navegador Mismo formato de guardado, con un tope de tamaño

La versión de PC no se toca por esto: la web sale del mismo proyecto con ajustes de calidad propios.

Herramientas

Herramienta Para qué la uso
Unity 6 LTS (6000.3.23f1) Motor del juego
URP y Shader Graph Render y shaders del hielo, el agua, las grietas y las siluetas
Input System Controles de la pistola, el movimiento y el taller
Job System, Burst, Collections y Mathematics Campo de densidad, mallado y generación de cuevas
Splines Carril por el que se mueve el tanque
TextMeshPro y UGUI Interfaz
Unity Test Framework Pruebas EditMode y PlayMode
FMOD Studio y su integración para Unity Todo el sonido
Autodesk 3ds Max Modelado, exportado en FBX
Visual Studio Código C#
Git y Git LFS en GitHub Control de versiones
Hoja de cálculo Balance de costes, tanques y minerales
Esta wiki Documentación

Código propio

Todo el código lo escribo yo desde cero. Las referencias que he mirado se citan en la página del sistema al que pertenecen y sirven como idea, nunca como código. El único dato que copio tal cual es la tabla de triangulación de marching cubes de Paul Bourke, que también está citada en Sistema de hielo.

Estructura del proyecto

Assets/
  _Project/
    Scripts/
      Core/  Ice/  Caves/  Water/  Gun/  World/
      Economy/  Loot/  Fossil/  Audio/  UI/  Save/
    Shaders/
    ScriptableObjects/
    Prefabs/
    Materials/
    Art/
    Scenes/
    Tests/
      EditMode/
      PlayMode/
FMOD/            proyecto de FMOD Studio, en la raíz del repositorio

Cada carpeta de Scripts tiene su propia Assembly Definition y su espacio de nombres: MeltTheDeep.Ice, MeltTheDeep.Caves, MeltTheDeep.Gun y así con el resto. Las dependencias entre ensamblados son explícitas, de modo que si Ice intentara usar algo de Economy el compilador se queja, y los tiempos de compilación bajan porque Unity solo recompila el ensamblado que ha cambiado.

Escenas

Escena Para qué sirve
Boot Arranque, carga de guardado y paso a Game
Game El juego completo
Sandbox_Ice Probar el campo de densidad, el fundido y el mallado sin nada más
Sandbox_Caves Generar cuevas con cualquier semilla, ver cortes horizontales y estadísticas
Sandbox_Water Probar bolitas, fusión y rendimiento con cientos de ellas
Sandbox_Fossil Probar coger, girar, voltear y encajar huesos

Cada sistema difícil tiene su escena de pruebas. Así puedo trabajar en uno sin arrastrar el resto y medir su coste por separado.

Principios

  1. Componentes pequeños con una sola responsabilidad. Una clase que funde no mezcla el sonido ni la interfaz.
  2. Los datos viven en ScriptableObjects: minerales, huesos, módulos, perfil de dureza, tabla de mejoras.
  3. Los sistemas se avisan con canales de eventos hechos con ScriptableObjects (GameEvent, FloatEvent). La interfaz, el audio y el guardado escuchan sin que quien lanza el evento sepa que existen.
  4. PlayerStats se calcula a partir de los niveles comprados. Nadie lee las mejoras directamente: el chorro pregunta por su potencia a PlayerStats y no sabe qué mejora la subió.
  5. La lógica pura, como el generador de cuevas o la validación del encaje, no depende de la escena para poder probarse con tests.

Mapa de sistemas

flowchart LR
    Input
    subgraph arma["Pistola"]
        WaterGun["WaterGun (FSM)"]
        JetMode
        VacuumMode
    end
    subgraph hielo["Hielo y cuevas"]
        CaveGenerator
        MineralPlacer
        MineralVein
        MeltSystem
        IceVolume
        ChunkMesher
    end
    subgraph agua["Agua"]
        WaterBallPool
        WaterBall
        AccumulationGrid
    end
    subgraph botin["Botín"]
        LootItem
        SpeciesCatalog
        FossilInventory
    end
    subgraph taller["Fósil"]
        FossilAssembly
        GrabController
    end
    subgraph economia["Economía"]
        Tanks
        WaterMarket
        UpgradeShop
        PlayerStats
    end
    Eventos["Canales de eventos"]
    AudioService

    Input --> WaterGun
    WaterGun --> JetMode
    WaterGun --> VacuumMode
    JetMode --> MeltSystem
    MeltSystem --> IceVolume
    CaveGenerator --> IceVolume
    CaveGenerator --> MineralPlacer
    MineralPlacer --> MineralVein
    JetMode --> MineralVein
    IceVolume --> ChunkMesher
    IceVolume --> WaterBallPool
    WaterBallPool --> WaterBall
    WaterBall --> AccumulationGrid
    AccumulationGrid --> MeltSystem
    VacuumMode --> WaterBall
    VacuumMode --> LootItem
    VacuumMode --> Tanks
    LootItem --> SpeciesCatalog
    LootItem --> FossilInventory
    FossilInventory --> FossilAssembly
    GrabController --> FossilAssembly
    Tanks --> WaterMarket
    WaterMarket --> UpgradeShop
    UpgradeShop --> PlayerStats
    PlayerStats --> WaterGun
    Eventos -.-> AudioService

El bucle del agua y el del dinero se cierran solos: el hielo fundido da bolitas, las bolitas frenan el fundido de la zona donde se acumulan, el tanque se vende, la venta paga mejoras y las mejoras cambian lo que hace la pistola. Los canales de eventos no aparecen conectados uno a uno para que el diagrama se pueda leer, pero casi todos los sistemas lanzan algún evento y AudioService escucha los suyos.

Componentes

Componente Tipo Responsabilidad
WaterGun MonoBehaviour Máquina de estados de la pistola: Inactivo, Chorro, Aspirar
JetMode Clase de estado Chorro: temperatura, consumo, raycast y calor sobre vetas
VacuumMode Clase de estado Aspiradora: selección de objetivos, fuerza y entrada al tanque
MeltSystem MonoBehaviour Aplica el fundido al campo de densidad y convierte lo fundido en litros
IceVolume Clase C# Dueña del NativeArray de densidad, de los ids de región y del porcentaje restante
ChunkMesher MonoBehaviour y Job Marching cubes por chunk y colliders
HardnessProfile ScriptableObject Curva de dureza por profundidad
CaveGenerator Clase estática Genera las cuevas de un módulo a partir de una semilla
MineralPlacer Clase estática Reparte las vetas sobre las paredes de las cuevas
MineralVein MonoBehaviour Cristales, integridad y grietas de una veta
MineralDefinition ScriptableObject Tipo, resistencia, tamaño y volumen de un mineral
WaterBallPool MonoBehaviour Pool de bolitas y límite de activas
WaterBall MonoBehaviour Nivel, litros y fusión
AccumulationGrid Clase C# Litros por celda de 1 m para frenar el fundido
LootItem MonoBehaviour Pez, mineral o hueso recogible
Tanks Clase C# Tanque de agua caliente y tanque de la aspiradora
WaterMarket Clase C# Venta del agua y multiplicadores
UpgradeShop Clase C# Costes, niveles y compra de mejoras
PlayerStats Clase C# Valores finales calculados desde las mejoras y el fósil
SpeciesCatalog ScriptableObject y datos de partida Especies existentes y cuáles se han registrado
BoneDefinition, SkeletonDefinition ScriptableObject Datos de cada hueso y del esqueleto completo
FossilInventory Clase C# Huesos recogidos y huesos montados
FossilAssembly MonoBehaviour Armazón, sockets y montaje
GrabController MonoBehaviour Coger, mover, girar y voltear huesos
SnapValidator Clase estática Decide si un hueso está bien colocado
ModuleDefinition, ModuleTracker ScriptableObject, MonoBehaviour Datos de cada módulo y avance de su fundido
Elevator MonoBehaviour Subir y bajar entre superficie y módulos
HoseCart MonoBehaviour Tanque sobre el carril, manguera y límite de movimiento
AudioService MonoBehaviour Escucha eventos y lanza los sonidos de FMOD
SaveSystem Clase C# Guardar y cargar la partida

Presupuesto de fotograma

Sistema Presupuesto
Render 6,0 ms
Física 4,0 ms
Hielo (fundido y remallado) 3,0 ms
Gameplay, UI y audio 1,5 ms
Margen 2,1 ms
Total 16,6 ms

La generación de cuevas queda fuera de este presupuesto porque se ejecuta tras la pantalla de carga, no durante el juego. Su tiempo es el principal objetivo de optimización del proyecto, y lo mido con la misma semilla en cada iteración. Estos números son valores iniciales y los reviso con cada captura del Profiler; las medidas van a Planificación.