12 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
- 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.
Nueva física del jugador✅ HECHO — Player reescrito con pipeline de 6 fases, colisiones tile-based, ~20 métodos eliminados.Motor de colisiones por tiles✅ HECHO —TileCollidercon 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).Transición de pantalla animada✅ HECHO — Scroll con easingcubicInOut(0.5s), ambas rooms visibles, enemigos activos, jugador puede moverse durante la transición.- 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
PaletteManagery a todos los assets de color.
Estado del renombrado
Se han renombrado las referencias de JailDoctor's Dilemma → Projecte 2026 y jaildoctors_dilemma → projecte_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:endata/locale/*.yamly su uso ensource/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.rcyjdd.res(solo bundlean el icono).
Pendiente
- PaletteColor enum en
utils.hppsigue con los 16 índices antiguos (ZX Spectrum). Los índices 0-4 coinciden con CPC, pero 5+ mapean a colores diferentes (ej.PaletteColor::BRIGHT_RED=5ahora renderiza MAGENTA en CPC).stringToColor()ySPECTRUM_REFERENCEenpalette_manager.cpptampoco 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 Tools (Linters)
This project uses two complementary static analysis tools for code quality:
clang-tidy (Modernization & Best Practices)
Purpose: Detects style issues, modernization opportunities, and potential bugs. Best for refactoring and applying C++20 best practices.
IMPORTANT: Always run on specific files, NOT on the entire project, to avoid long execution times and errors in unrelated files.
# Analyze a specific file (RECOMMENDED)
tools/linter/run_clang-tidy.sh source/game/entities/player.cpp
# Analyze multiple specific files
tools/linter/run_clang-tidy.sh source/game/entities/player.cpp source/game/entities/enemy.cpp
# Apply fixes automatically to a specific file
tools/linter/run_clang-tidy.sh --fix source/game/entities/player.cpp
# Analyze entire project (SLOW, may have errors in defaults.hpp)
tools/linter/run_clang-tidy.sh
Known False Positives:
defaults.hpp: May report errors in constant definitionsreadability-magic-numbers/cppcoreguidelines-avoid-magic-numbers: Acceptable for game constants (block sizes, speeds, etc.)
cppcheck (Bug Detection & Memory Safety)
Purpose: Detects bugs, memory leaks, undefined behavior, and style issues. Complementary to clang-tidy.
# Warning, style, and performance analysis (RECOMMENDED for daily use)
tools/linter/run_cppcheck.sh -w --path source/game/entities/player.cpp
# Exhaustive analysis (slower, more thorough)
tools/linter/run_cppcheck.sh -a --path source/game/entities/
# Detect unused functions (whole project analysis)
tools/linter/run_cppcheck.sh -u
# Analyze entire project with warning level
tools/linter/run_cppcheck.sh -w
Output: Results are saved in tools/linter/cppcheck-result-*.txt
Known False Positives:
unusedFunction: May report false positives for callback functions or public API methodspassedByValue: Acceptable for small types like SDL_FRect in game codeconstParameter: Not always applicable for API consistency
When to Use Each Tool
| Scenario | Tool | Reason |
|---|---|---|
| Daily refactoring | clang-tidy | Fast, auto-fixable issues |
| Before committing | Both | Comprehensive quality check |
| After major changes | cppcheck -a | Deep bug analysis |
| Hunting memory leaks | cppcheck | Specialized detection |
| Code modernization | clang-tidy --fix | Automatic C++20 upgrades |
Integration with Development Workflow
When refactoring code (especially with /refactor-class command):
- Make structural changes
- Compile to verify syntax
- Run clang-tidy (without --fix) to identify issues
- Run cppcheck -w to catch bugs
- Review and fix legitimate issues
- Apply automatic fixes if appropriate
- Recompile and test
Note: The /refactor-class command automatically runs both linters after compilation and provides intelligent analysis of results.
Important Code Consistency Rules
-
Forward Declarations: Always use
classfor forward declarations of classes defined withclass(notstruct). TheSurfaceclass is defined asclass Surfaceinsurface.hpp:57, so all forward declarations must useclass Surface; -
Singleton Pattern: When creating new singletons, follow the existing pattern:
- Private static instance pointer
- Private constructor/destructor
- Public
init(),destroy(), andget()methods
-
Delta Time: Always use
DeltaTimerfor frame-rate independent physics calculations -
Memory Management: Prefer
std::shared_ptrfor shared resources (Surfaces, Sprites) andstd::unique_ptrfor sole ownership -
Room file format — single source of truth: Cualquier cambio al formato
data/room/*.yaml(añadir/quitar/renombrar campos) se hace exclusivamente ensource/game/gameplay/room_format.cpp. Esa clase es la única autoridad: combina parser (loadYAML), serializer (saveYAML, debug-only) ycreateDefaultpara rooms nuevas. Cuando añadas un campo nuevo:- Añade el field a
Room::Dataensource/game/gameplay/room.hpp. - Actualiza
parseRoomConfig/buildContent/createDefaultenroom_format.cpp(los tres en el mismo módulo). - Nunca escribas yaml a pelo con
std::ofstreamdesde otro sitio (especialmente desdeMapEditor::createNewRoom, que ya delega enRoomFormat::createDefault+RoomFormat::saveYAML). El editor solo manipulaRoom::Data; el formato yaml es invisible para él. Saltarse esta regla causa bugs como el del crash de06.yaml(formato hardcoded encreateNewRoomque se desincroniza del parser real).
- Añade el field a
-
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 enMapEditor::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 enMapEditor::handleMouseDowncon el nuevoEntityType. - Drag & drop para mover la entidad por el grid (con autosave al soltar). Extender
moveEntityVisualycommitEntityDrag. - Entry en la statusbar del editor cuando la entidad está seleccionada (mostrar id, animación, etc). Switch en
updateStatusBarInfo. - Comandos de consola:
cmd<Tipo>paraadd/delete/duplicatey routing encmdSetparasetXxxProperty. VercmdEnemy/cmdItem/cmdPlatform/cmdKey/cmdDoorenconsole_commands.cpp. Registrar endata/console/commands.yamltambién. - Helpers genéricos:
entityCount,entityRect,entityPosition,entityDataCount,entityLabeldeben cubrir el nuevo tipo (switch sobreEntityType). - Manager debug API: el manager de la entidad necesita
getCount()ygetXxx(int)bajo#ifdef _DEBUGpara que el editor pueda iterar. - Setter de posición: la entidad necesita
setPosition(float, float)bajo#ifdef _DEBUGpara el drag visual. EntityType enumenmap_editor.hppextendido con el nuevo tipo.- Si la entidad afecta a colisiones (como
Doorque escribeWALLen elCollisionMap), el manager debe exponermove<Tipo>(idx, x, y)yremove<Tipo>(idx)que encapsulen el bookkeeping. El editor no debe tocar nunca elCollisionMapdirectamente.
Cualquier entidad nueva debe nacer con soporte completo, no diferirlo "para después".
- Renderizado dentro del editor: añadir la llamada al
Last Updated: April 2026 Original Author: JailDesigner Repository: Gitea (internal)