Files
projecte_2026/CLAUDE.md
2026-04-11 16:25:56 +02:00

11 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.


Projecte 2026 - Nuevo juego (derivado de JailDoctor's Dilemma)

IMPORTANTE: Este repositorio parte del código de JailDoctor's Dilemma como base, pero es un juego nuevo. projecte_2026 es un nombre placeholder hasta tener el diseño final. Gran parte de la arquitectura documentada más abajo describe el código heredado; varios subsistemas se van a reescribir.

Cambios de diseño previstos respecto al juego original

  1. Habitaciones más grandes — aprovechar el espacio del marcador (scoreboard) para ampliar el área jugable. Esto implica revisar la resolución de canvas, el layout de la HUD y el tamaño de los tilemaps.
  2. Nueva física del jugador HECHO — Player reescrito con pipeline de 6 fases, colisiones tile-based, ~20 métodos eliminados.
  3. Motor de colisiones por tiles HECHOTileCollider con queries directas al grid. Collision tilemap editado desde el editor (tecla 8). Sistema antiguo de superficies preservado pero no usado. Pendiente: tiles kill (5) y conveyor (6).
  4. Transición de pantalla animada HECHO — Scroll con easing cubicInOut (0.5s), ambas rooms visibles, enemigos activos, jugador puede moverse durante la transición.
  5. Paleta Amstrad CPC — subir de la paleta actual (8-bit indexada limitada) a la paleta del Amstrad CPC (27 colores / más colores que la actual). Afecta a PaletteManager y a todos los assets de color.

Estado del renombrado

Se han renombrado las referencias de JailDoctor's DilemmaProjecte 2026 y jaildoctors_dilemmaprojecte_2026 en código, configs, Makefile, CMake, LICENSE, Info.plist, scripts, locales, etc. Copyright actualizado a 2026. Se han mantenido como placeholders:

  • La clave de locale jaildoctor: en data/locale/*.yaml y su uso en source/game/scenes/ending2.cpp (es contenido de juego, pendiente de rediseño).
  • El publisher jailgames (carpeta de config de sistema: ~/.config/jailgames/projecte_2026).
  • Los archivos release/windows/jdd.rc y jdd.res (solo bundlean el icono).

Pendiente

  • PaletteColor enum en utils.hpp sigue con los 16 índices antiguos (ZX Spectrum). Los índices 0-4 coinciden con CPC, pero 5+ mapean a colores diferentes (ej. PaletteColor::BRIGHT_RED=5 ahora renderiza MAGENTA en CPC). stringToColor() y SPECTRUM_REFERENCE en palette_manager.cpp tampoco están actualizados. Falta decidir cómo migrar cuando se vea el resultado visual.
  • Tile 6 (conveyor) no soportado aún en el nuevo motor de Player.
  • next()/previous() en PaletteManager desactivados de facto (solo 1 paleta). Posible futura reutilización para ciclar modos de ordenación.

Overview

Projecte 2026 is a retro-style 2D puzzle platformer game built in C++20 using SDL3 for graphics and audio. The game features 60+ rooms, collectible items, enemies, and an achievement system. It targets multiple platforms (Windows, macOS, Linux) with a focus on retro aesthetics and precise collision detection.

Language: C++20 Graphics: SDL3, OpenGL Audio: SDL3 + custom jail_audio library Build: CMake 3.10+ Game Canvas: 256x192 pixels (retro resolution)


Build Commands

Initial Setup & Build

# From project root
mkdir -p build
cd build
cmake ..
cmake --build .

Rebuild After Changes

# From build directory
cmake --build .

# Or from project root
cmake --build build

Clean Build

# From build directory
cmake --build . --clean-first

# Or from project root
cmake --build build --clean-first

Run the Game

# Executable is placed in project root
./projecte_2026

Important: The build directory is build/ relative to the project root and the output executable is placed in the project root directory.

Testing in Headless Environment (SSH/Remote Server)

IMPORTANT: When working on a remote server via SSH without a physical display, the game MUST be run using Xvfb (X Virtual Framebuffer) to avoid SDL3 display initialization errors.

Required Setup (One-time)

# Install Xvfb
sudo apt-get install xvfb

Running the Game in Headless Mode

Option 1: Using xvfb-run directly (RECOMMENDED)

xvfb-run -a ./projecte_2026

Option 2: Custom display configuration

xvfb-run -a -s "-screen 0 1280x720x24" ./projecte_2026

Why This Is Critical

  • SDL3 requires a display: The game uses SDL3 which requires X11/Wayland display
  • No code changes needed: Xvfb simulates a virtual display without modifying the codebase
  • Full logging: Console output and logs work normally, essential for debugging resource loading
  • Testing resource loading: When modifying asset loading code, running with xvfb-run allows seeing all initialization logs

ALWAYS use xvfb-run when testing on the remote server, especially when:

  • Modifying resource loading code
  • Testing asset initialization
  • Debugging startup issues
  • Verifying configuration changes

Static Analysis & Formatting (CMake targets)

Los linters y el formateador están integrados como targets de CMake. Todos excluyen source/external/ y los headers SPIR-V generados (*_spv.h).

# Desde el directorio build/
cmake --build . --target tidy         # clang-tidy sobre todo el código (sin fixes)
cmake --build . --target tidy-fix     # clang-tidy aplicando fixes automáticos
cmake --build . --target cppcheck     # cppcheck (warning/style/performance/portability, --std=c++20)
cmake --build . --target format       # clang-format -i sobre todo el código
cmake --build . --target format-check # clang-format en modo dry-run (CI)

Los targets se definen en CMakeLists.txt (sección STATIC ANALYSIS TARGETS) y se generan únicamente si las herramientas correspondientes (clang-tidy, clang-format, cppcheck) están instaladas en el sistema.

Falsos positivos conocidos de clang-tidy:

  • defaults.hpp: puede reportar errores en definiciones de constantes.
  • readability-magic-numbers / cppcoreguidelines-avoid-magic-numbers: aceptables para constantes de juego (tamaños de bloque, velocidades, etc).

Notas sobre cppcheck:

  • Avisos unusedStructMember son habituales en estructuras de datos accedidas vía serialización/yaml o por código #ifdef _DEBUG; revisar antes de borrar nada.
  • El target usa la lista explícita de fuentes (excluyendo source/external/ y *_spv.h), no --project=compile_commands.json. Si añades flags nuevos, actualiza el target en CMakeLists.txt.
  • Por defecto cppcheck solo evalúa 12 combinaciones de #ifdef. Para analizar todas, añadir --force (mucho más lento).

Para análisis puntual de un solo fichero, llamar la herramienta directamente:

clang-tidy -p build source/game/entities/player.cpp
cppcheck --enable=warning,style --std=c++20 -I source source/game/entities/player.cpp

Important Code Consistency Rules

  1. Forward Declarations: Always use class for forward declarations of classes defined with class (not struct). The Surface class is defined as class Surface in surface.hpp:57, so all forward declarations must use class Surface;

  2. Singleton Pattern: When creating new singletons, follow the existing pattern:

    • Private static instance pointer
    • Private constructor/destructor
    • Public init(), destroy(), and get() methods
  3. Delta Time: Always use DeltaTimer for frame-rate independent physics calculations

  4. Memory Management: Prefer std::shared_ptr for shared resources (Surfaces, Sprites) and std::unique_ptr for sole ownership

  5. Room file format — single source of truth: Cualquier cambio al formato data/room/*.yaml (añadir/quitar/renombrar campos) se hace exclusivamente en source/game/gameplay/room_format.cpp. Esa clase es la única autoridad: combina parser (loadYAML), serializer (saveYAML, debug-only) y createDefault para rooms nuevas. Cuando añadas un campo nuevo:

    • Añade el field a Room::Data en source/game/gameplay/room.hpp.
    • Actualiza parseRoomConfig/buildContent/createDefault en room_format.cpp (los tres en el mismo módulo).
    • Nunca escribas yaml a pelo con std::ofstream desde otro sitio (especialmente desde MapEditor::createNewRoom, que ya delega en RoomFormat::createDefault + RoomFormat::saveYAML). El editor solo manipula Room::Data; el formato yaml es invisible para él. Saltarse esta regla causa bugs como el del crash de 06.yaml (formato hardcoded en createNewRoom que se desincroniza del parser real).
  6. Nuevas entidades de room — soporte completo en editor y consola: Cuando añadas un tipo nuevo de entidad a las rooms (al estilo de enemies, items, platforms, keys, doors), no basta con el parser/serializer y el manager runtime. Debes implementar también su contrapartida en el editor y en la consola, en paridad con los tipos existentes:

    • Renderizado dentro del editor: añadir la llamada al room_->renderXxx() correspondiente en MapEditor::render(). Sin esto la entidad no se ve cuando el editor está activo (aunque sí se vea en juego), porque el editor renderiza entidades por separado del flujo normal del juego.
    • Selección visual en MapEditor (click sobre la entidad → selection_ con su tipo y índice). Extender el loop de hit test en MapEditor::handleMouseDown con el nuevo EntityType.
    • Drag & drop para mover la entidad por el grid (con autosave al soltar). Extender moveEntityVisual y commitEntityDrag.
    • Entry en la statusbar del editor cuando la entidad está seleccionada (mostrar id, animación, etc). Switch en updateStatusBarInfo.
    • Comandos de consola: cmd<Tipo> para add/delete/duplicate y routing en cmdSet para setXxxProperty. Ver cmdEnemy/cmdItem/cmdPlatform/cmdKey/cmdDoor en console_commands.cpp. Registrar en data/console/commands.yaml también.
    • Helpers genéricos: entityCount, entityRect, entityPosition, entityDataCount, entityLabel deben cubrir el nuevo tipo (switch sobre EntityType).
    • Manager debug API: el manager de la entidad necesita getCount() y getXxx(int) bajo #ifdef _DEBUG para que el editor pueda iterar.
    • Setter de posición: la entidad necesita setPosition(float, float) bajo #ifdef _DEBUG para el drag visual.
    • EntityType enum en map_editor.hpp extendido con el nuevo tipo.
    • Si la entidad afecta a colisiones (como Door que escribe WALL en el CollisionMap), el manager debe exponer move<Tipo>(idx, x, y) y remove<Tipo>(idx) que encapsulen el bookkeeping. El editor no debe tocar nunca el CollisionMap directamente.

    Cualquier entidad nueva debe nacer con soporte completo, no diferirlo "para después".


Last Updated: April 2026 Original Author: JailDesigner Repository: Gitea (internal)