creat project.h
This commit is contained in:
92
.gitignore
vendored
92
.gitignore
vendored
@@ -1,4 +1,92 @@
|
|||||||
|
# IDEs and Editors
|
||||||
.vscode/*
|
.vscode/*
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Build directories
|
||||||
|
build/
|
||||||
|
bin/
|
||||||
|
out/
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
orni
|
||||||
|
asteroids
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.ko
|
||||||
|
*.elf
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles/
|
||||||
|
CMakeScripts/
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
CTestTestfile.cmake
|
||||||
|
_deps/
|
||||||
|
|
||||||
|
# Debug files
|
||||||
|
*.dSYM/
|
||||||
|
*.su
|
||||||
|
*.idb
|
||||||
|
*.pdb
|
||||||
|
*.ilk
|
||||||
|
|
||||||
|
# Core dumps
|
||||||
|
core
|
||||||
|
core.*
|
||||||
|
*.core
|
||||||
|
|
||||||
|
# macOS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
thumbs.db
|
.AppleDouble
|
||||||
bin/*
|
.LSOverride
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Windows
|
||||||
|
Thumbs.db
|
||||||
|
Thumbs.db:encryptable
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
*.stackdump
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Linux
|
||||||
|
*~
|
||||||
|
.directory
|
||||||
|
.fuse_hidden*
|
||||||
|
.Trash-*
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
*.log
|
||||||
|
*.bak
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|||||||
212
CLAUDE.md
212
CLAUDE.md
@@ -4,11 +4,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
This is an **Asteroids-style game** originally written in **Turbo Pascal 7 for DOS** (1999), now being **migrated to modern C++20 with SDL3**. The game features a spaceship that must avoid and destroy enemies (pentagonal "ORNIs"). This is a **phased migration** preserving the original game feel.
|
This is **Orni Attack**, an **Asteroids-style game** originally written in **Turbo Pascal 7 for DOS** (1999), now being **migrated to modern C++20 with SDL3**. The game features a spaceship that must avoid and destroy enemies (pentagonal "ORNIs"). This is a **phased migration** preserving the original game feel.
|
||||||
|
|
||||||
**Language**: All code, comments, and variable names are in **Catalan/Valencian** (preserved from original).
|
**Language**: All code, comments, and variable names are in **Catalan/Valencian** (preserved from original).
|
||||||
|
|
||||||
**Current Status**: **BETA 2.2** - Phases 0-9 completed (playable with ship, enemies, and bullets).
|
**Current Status**: **BETA 3.0** - Modernized architecture with dynamic windows, modular code organization, viewport scaling, and auto-generated project metadata.
|
||||||
|
|
||||||
## Build System
|
## Build System
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ Based on `/home/sergio/gitea/pollo` project structure.
|
|||||||
make clean && make
|
make clean && make
|
||||||
|
|
||||||
# Run
|
# Run
|
||||||
./asteroids
|
./orni
|
||||||
|
|
||||||
# Individual targets
|
# Individual targets
|
||||||
make linux # Linux build
|
make linux # Linux build
|
||||||
@@ -31,22 +31,68 @@ make windows # Windows build (MinGW)
|
|||||||
|
|
||||||
### Build Files
|
### Build Files
|
||||||
|
|
||||||
- **CMakeLists.txt** - CMake configuration (C++20, SDL3)
|
- **CMakeLists.txt** - CMake configuration (C++20, SDL3, project metadata)
|
||||||
- **Makefile** - Cross-platform wrapper, extracts project info from CMakeLists.txt
|
- **Makefile** - Cross-platform wrapper, extracts project info from CMakeLists.txt
|
||||||
|
- **source/project.h.in** - Template for auto-generated project.h
|
||||||
|
- **build/project.h** - Auto-generated (by CMake) with project constants
|
||||||
- **release/** - Platform-specific resources (icons, .rc, .plist)
|
- **release/** - Platform-specific resources (icons, .rc, .plist)
|
||||||
|
|
||||||
|
### Project Metadata System
|
||||||
|
|
||||||
|
**Auto-generation with CMake**:
|
||||||
|
|
||||||
|
CMake generates `build/project.h` from `source/project.h.in` template on every compilation:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// build/project.h (generated automatically)
|
||||||
|
namespace Project {
|
||||||
|
constexpr const char* NAME = "orni"; // From project(orni ...)
|
||||||
|
constexpr const char* LONG_NAME = "Orni Attack"; // From PROJECT_LONG_NAME
|
||||||
|
constexpr const char* VERSION = "0.1.0"; // From VERSION
|
||||||
|
constexpr const char* COPYRIGHT = "© 1999..."; // From PROJECT_COPYRIGHT
|
||||||
|
constexpr const char* GIT_HASH = "abc1234"; // From git rev-parse
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Window title format** (dynamic, in sdl_manager.cpp):
|
||||||
|
```cpp
|
||||||
|
std::format("{} v{} ({})",
|
||||||
|
Project::LONG_NAME, // "Orni Attack"
|
||||||
|
Project::VERSION, // "0.1.0"
|
||||||
|
Project::COPYRIGHT) // "© 1999 Visente i Sergi, 2025 Port"
|
||||||
|
```
|
||||||
|
|
||||||
|
Result: `Orni Attack v0.1.0 (© 1999 Visente i Sergi, 2025 Port)`
|
||||||
|
|
||||||
|
**Single source of truth**: All project info in CMakeLists.txt, no hardcoded strings.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
### File Structure
|
### File Structure (BETA 3.0)
|
||||||
|
|
||||||
```
|
```
|
||||||
source/
|
source/
|
||||||
├── main.cpp # Entry point, game loop, delta_time calculation
|
├── core/ - Reusable engine layer
|
||||||
├── sdl_manager.hpp/cpp # SDL3 initialization, window, renderer
|
│ ├── defaults.hpp - Configuration constants (SINGLE SOURCE OF TRUTH)
|
||||||
├── joc_asteroides.hpp # Game structures, constants
|
│ ├── types.hpp - Data structures (IPunt, Punt, Triangle, Poligon)
|
||||||
└── joc_asteroides.cpp # Game logic, physics, rendering
|
│ └── rendering/
|
||||||
|
│ ├── sdl_manager.hpp/cpp - SDL3 window management + viewport scaling
|
||||||
|
│ └── primitives.hpp/cpp - Pure geometric functions
|
||||||
|
├── game/ - Asteroids-specific game logic
|
||||||
|
│ ├── constants.hpp - Legacy constant aliases
|
||||||
|
│ └── joc_asteroides.hpp/cpp - Game loop, physics, rendering
|
||||||
|
├── utils/ - Shared utilities (empty for now)
|
||||||
|
├── main.cpp - Entry point, F1/F2/F3 window controls
|
||||||
|
└── legacy/
|
||||||
|
└── asteroids.cpp - Original Pascal code (reference only)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Key architectural decisions:**
|
||||||
|
- **core/** contains reusable, game-agnostic code
|
||||||
|
- **game/** contains Asteroids-specific logic
|
||||||
|
- All constants centralized in `core/defaults.hpp`
|
||||||
|
- Backward compatibility via `game/constants.hpp` aliases
|
||||||
|
|
||||||
### Core Data Structures
|
### Core Data Structures
|
||||||
|
|
||||||
The game uses **polar coordinates** for all geometric objects (preserved from Pascal original):
|
The game uses **polar coordinates** for all geometric objects (preserved from Pascal original):
|
||||||
@@ -571,6 +617,153 @@ if (time_accumulator >= 1.0f) {
|
|||||||
- Cross-platform testing
|
- Cross-platform testing
|
||||||
- Final physics tuning
|
- Final physics tuning
|
||||||
|
|
||||||
|
## IMPORTANT: Modernization Architecture (BETA 3.0)
|
||||||
|
|
||||||
|
Starting from BETA 3.0, the project has evolved into a professional modular architecture:
|
||||||
|
|
||||||
|
### Structural Changes
|
||||||
|
|
||||||
|
**Before (BETA 2.2):**
|
||||||
|
```
|
||||||
|
source/
|
||||||
|
├── main.cpp
|
||||||
|
├── sdl_manager.hpp/cpp
|
||||||
|
├── joc_asteroides.hpp/cpp
|
||||||
|
└── asteroids.cpp (Pascal)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Now (BETA 3.0):**
|
||||||
|
```
|
||||||
|
source/
|
||||||
|
├── core/ - Reusable engine
|
||||||
|
│ ├── defaults.hpp - SINGLE SOURCE OF TRUTH for constants
|
||||||
|
│ ├── types.hpp - Data structures
|
||||||
|
│ └── rendering/
|
||||||
|
│ ├── sdl_manager - Dynamic windows + viewport
|
||||||
|
│ └── primitives - Pure geometric functions
|
||||||
|
├── game/ - Asteroids-specific logic
|
||||||
|
│ ├── constants.hpp - Aliases for backward compatibility
|
||||||
|
│ └── joc_asteroides - Game loop
|
||||||
|
├── utils/ - Shared utilities
|
||||||
|
├── main.cpp - Entry point
|
||||||
|
└── legacy/
|
||||||
|
└── asteroids.cpp - Original Pascal code (reference)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dynamic Window System
|
||||||
|
|
||||||
|
**Controls:**
|
||||||
|
- **F1**: Decrease window (-100px width/height)
|
||||||
|
- **F2**: Increase window (+100px width/height)
|
||||||
|
- **F3**: Toggle fullscreen
|
||||||
|
- **ESC**: Exit (unchanged)
|
||||||
|
|
||||||
|
**Behavior:**
|
||||||
|
- Window starts at 640x480 centered on screen
|
||||||
|
- Each resize keeps window centered on itself
|
||||||
|
- Minimum size: 320x240
|
||||||
|
- Maximum size: Calculated from display resolution (limit -100px)
|
||||||
|
|
||||||
|
**Viewport Scaling (SDL3):**
|
||||||
|
- Game ALWAYS renders in logical coordinates 640x480
|
||||||
|
- SDL3 automatically scales to any physical window size
|
||||||
|
- Aspect ratio preserved (4:3 with letterboxing)
|
||||||
|
- Vectors look SHARPER in larger windows (higher resolution)
|
||||||
|
- Game physics UNCHANGED (still px/s relative to 640x480 logical)
|
||||||
|
|
||||||
|
**Implementation:**
|
||||||
|
```cpp
|
||||||
|
SDL_SetRenderLogicalPresentation(
|
||||||
|
renderer_,
|
||||||
|
640, 480, // Fixed logical size
|
||||||
|
SDL_LOGICAL_PRESENTATION_LETTERBOX // Maintain aspect ratio
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration System
|
||||||
|
|
||||||
|
**core/defaults.hpp** - Only place to change constants:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace Defaults {
|
||||||
|
namespace Window {
|
||||||
|
constexpr int WIDTH = 640;
|
||||||
|
constexpr int HEIGHT = 480;
|
||||||
|
constexpr int SIZE_INCREMENT = 100; // F1/F2
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Game {
|
||||||
|
constexpr int WIDTH = 640; // Logical
|
||||||
|
constexpr int HEIGHT = 480;
|
||||||
|
constexpr int MARGIN_LEFT = 20; // MARGE_ESQ
|
||||||
|
constexpr int MARGIN_RIGHT = 620; // MARGE_DRET
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Physics {
|
||||||
|
constexpr float ROTATION_SPEED = 2.5f;
|
||||||
|
constexpr float ACCELERATION = 100.0f;
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**game/constants.hpp** - Backward compatibility:
|
||||||
|
```cpp
|
||||||
|
using Defaults::Game::MARGIN_LEFT; // For legacy code using MARGE_ESQ
|
||||||
|
// ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Important Reminders
|
||||||
|
|
||||||
|
**1. Logical vs Physical Coordinates**
|
||||||
|
- ALL game code uses logical coordinates (640x480)
|
||||||
|
- NO need to adjust physics or collision calculations
|
||||||
|
- SDL3 handles conversion automatically
|
||||||
|
|
||||||
|
**2. Rendering**
|
||||||
|
- `linea()`, `rota_tri()`, `rota_pol()` still use direct coords
|
||||||
|
- NO manual transformation, SDL does it internally
|
||||||
|
|
||||||
|
**3. Configuration**
|
||||||
|
- NEVER use magic numbers in new code
|
||||||
|
- Always reference `Defaults::*`
|
||||||
|
- For game values, create aliases in `game/constants.hpp` if needed
|
||||||
|
|
||||||
|
**4. Future OpenGL**
|
||||||
|
- Current system allows migrating to OpenGL without changing game code
|
||||||
|
- Would only require changing SDLManager and rendering function implementations
|
||||||
|
- Postponed until needing >50 enemies or complex effects
|
||||||
|
|
||||||
|
### Compilation
|
||||||
|
|
||||||
|
**No changes:**
|
||||||
|
```bash
|
||||||
|
make clean && make
|
||||||
|
./asteroids
|
||||||
|
```
|
||||||
|
|
||||||
|
**Files modified by CMake:**
|
||||||
|
- Updated to include subdirectories core/, game/
|
||||||
|
- Include path: `${CMAKE_SOURCE_DIR}/source` (for relative includes)
|
||||||
|
|
||||||
|
### Migration for Future Sessions
|
||||||
|
|
||||||
|
If you find code using magic numbers:
|
||||||
|
1. Add constant in `core/defaults.hpp` in the appropriate namespace
|
||||||
|
2. If it's a frequently used game value, create alias in `game/constants.hpp`
|
||||||
|
3. Replace the number with the constant
|
||||||
|
4. Compile and verify
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```cpp
|
||||||
|
// Before (bad):
|
||||||
|
if (enemy.centre.x < 20 || enemy.centre.x > 620) { ... }
|
||||||
|
|
||||||
|
// After (good):
|
||||||
|
if (enemy.centre.x < MARGIN_LEFT || enemy.centre.x > MARGIN_RIGHT) { ... }
|
||||||
|
```
|
||||||
|
|
||||||
## Tips for Future Claude Code Sessions
|
## Tips for Future Claude Code Sessions
|
||||||
|
|
||||||
- **Always read this file first** before making changes
|
- **Always read this file first** before making changes
|
||||||
@@ -582,3 +775,4 @@ if (time_accumulator >= 1.0f) {
|
|||||||
- **Angle convention**: angle=0 points UP (not right), hence `angle - PI/2` in calculations
|
- **Angle convention**: angle=0 points UP (not right), hence `angle - PI/2` in calculations
|
||||||
- **One bullet at a time**: Original game limitation, preserve it
|
- **One bullet at a time**: Original game limitation, preserve it
|
||||||
- **Simple code style**: Avoid over-engineering, keep "small DOS program" feel
|
- **Simple code style**: Avoid over-engineering, keep "small DOS program" feel
|
||||||
|
- **Use defaults.hpp**: Never hardcode constants, always use Defaults namespace
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# CMakeLists.txt
|
# CMakeLists.txt
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(asteroids VERSION 0.1.0)
|
project(orni VERSION 0.1.0)
|
||||||
|
|
||||||
# Info del proyecto
|
# Info del proyecto
|
||||||
set(PROJECT_LONG_NAME "Asteroides")
|
set(PROJECT_LONG_NAME "Orni Attack")
|
||||||
set(PROJECT_COPYRIGHT "© 1999 Visente i Sergi, 2025 Port")
|
set(PROJECT_COPYRIGHT "© 1999 Visente i Sergi, 2025 Port")
|
||||||
|
|
||||||
# Establecer estándar de C++
|
# Establecer estándar de C++
|
||||||
@@ -28,16 +28,15 @@ else()
|
|||||||
set(GIT_HASH "unknown")
|
set(GIT_HASH "unknown")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Configurar archivo de versión (si existe project.h.in en el futuro)
|
# Configurar archivo de versión
|
||||||
if(EXISTS "${CMAKE_SOURCE_DIR}/source/project.h.in")
|
configure_file(${CMAKE_SOURCE_DIR}/source/project.h.in ${CMAKE_BINARY_DIR}/project.h @ONLY)
|
||||||
configure_file(${CMAKE_SOURCE_DIR}/source/project.h.in ${CMAKE_BINARY_DIR}/project.h @ONLY)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# --- LISTA DE FUENTES ---
|
# --- LISTA DE FUENTES ---
|
||||||
set(APP_SOURCES
|
set(APP_SOURCES
|
||||||
source/main.cpp
|
source/main.cpp
|
||||||
source/sdl_manager.cpp
|
source/core/rendering/sdl_manager.cpp
|
||||||
source/joc_asteroides.cpp
|
source/game/joc_asteroides.cpp
|
||||||
|
source/core/rendering/primitives.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Configuración de SDL3
|
# Configuración de SDL3
|
||||||
|
|||||||
9
Makefile
9
Makefile
@@ -34,8 +34,9 @@ endif
|
|||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
APP_SOURCES := \
|
APP_SOURCES := \
|
||||||
source/main.cpp \
|
source/main.cpp \
|
||||||
source/sdl_manager.cpp \
|
source/core/rendering/sdl_manager.cpp \
|
||||||
source/joc_asteroides.cpp
|
source/game/joc_asteroides.cpp \
|
||||||
|
source/core/rendering/primitives.cpp
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# INCLUDES
|
# INCLUDES
|
||||||
@@ -57,7 +58,7 @@ ifeq ($(OS),Windows_NT)
|
|||||||
CXXFLAGS_DEBUG := -std=$(CPP_STANDARD) -Wall -g -D_DEBUG -DWINDOWS_BUILD
|
CXXFLAGS_DEBUG := -std=$(CPP_STANDARD) -Wall -g -D_DEBUG -DWINDOWS_BUILD
|
||||||
LDFLAGS := -lmingw32 -lSDL3
|
LDFLAGS := -lmingw32 -lSDL3
|
||||||
WINDRES := windres
|
WINDRES := windres
|
||||||
RESOURCE_FILE := release/asteroids.res
|
RESOURCE_FILE := release/orni.res
|
||||||
RM := del /Q
|
RM := del /Q
|
||||||
RMDIR := rmdir /S /Q
|
RMDIR := rmdir /S /Q
|
||||||
MKDIR := mkdir
|
MKDIR := mkdir
|
||||||
@@ -95,7 +96,7 @@ all: $(TARGET_FILE)
|
|||||||
$(TARGET_FILE): $(APP_SOURCES)
|
$(TARGET_FILE): $(APP_SOURCES)
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
@if not exist build $(MKDIR) build
|
@if not exist build $(MKDIR) build
|
||||||
@if not exist release\\asteroids.res $(WINDRES) release\\asteroids.rc -O coff -o release\\asteroids.res
|
@if not exist release\\orni.res $(WINDRES) release\\orni.rc -O coff -o release\\orni.res
|
||||||
$(CXX) $(CXXFLAGS) $(INCLUDES) $(APP_SOURCES) $(RESOURCE_FILE) $(LDFLAGS) -o $(TARGET_FILE).exe
|
$(CXX) $(CXXFLAGS) $(INCLUDES) $(APP_SOURCES) $(RESOURCE_FILE) $(LDFLAGS) -o $(TARGET_FILE).exe
|
||||||
else
|
else
|
||||||
@$(MKDIR) build
|
@$(MKDIR) build
|
||||||
|
|||||||
@@ -5,19 +5,19 @@
|
|||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>en</string>
|
<string>en</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>Asteroides</string>
|
<string>Orni Attack</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>asteroids</string>
|
<string>orni</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>icon</string>
|
<string>icon</string>
|
||||||
<key>CFBundleIconName</key>
|
<key>CFBundleIconName</key>
|
||||||
<string>icon</string>
|
<string>icon</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>org.jailgames.asteroids</string>
|
<string>org.jailgames.orni</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>Asteroides</string>
|
<string>Orni Attack</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
|
|||||||
212
source/core/rendering/sdl_manager.cpp
Normal file
212
source/core/rendering/sdl_manager.cpp
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
// sdl_manager.cpp - Implementació del gestor SDL3
|
||||||
|
// © 2025 Port a C++20 amb SDL3
|
||||||
|
|
||||||
|
#include "sdl_manager.hpp"
|
||||||
|
#include "core/defaults.hpp"
|
||||||
|
#include "project.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <format>
|
||||||
|
|
||||||
|
SDLManager::SDLManager()
|
||||||
|
: finestra_(nullptr)
|
||||||
|
, renderer_(nullptr)
|
||||||
|
, current_width_(Defaults::Window::WIDTH)
|
||||||
|
, current_height_(Defaults::Window::HEIGHT)
|
||||||
|
, is_fullscreen_(false)
|
||||||
|
, max_width_(1920)
|
||||||
|
, max_height_(1080)
|
||||||
|
{
|
||||||
|
// Inicialitzar SDL3
|
||||||
|
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||||
|
std::cerr << "Error inicialitzant SDL3: " << SDL_GetError() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calcular mida màxima des del display
|
||||||
|
calculateMaxWindowSize();
|
||||||
|
|
||||||
|
// Construir títol dinàmic igual que en pollo
|
||||||
|
std::string window_title = std::format("{} v{} ({})",
|
||||||
|
Project::LONG_NAME,
|
||||||
|
Project::VERSION,
|
||||||
|
Project::COPYRIGHT
|
||||||
|
);
|
||||||
|
|
||||||
|
// Crear finestra CENTRADA (SDL ho fa automàticament amb CENTERED)
|
||||||
|
finestra_ = SDL_CreateWindow(
|
||||||
|
window_title.c_str(),
|
||||||
|
current_width_,
|
||||||
|
current_height_,
|
||||||
|
SDL_WINDOW_RESIZABLE // Permetre resize manual també
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!finestra_) {
|
||||||
|
std::cerr << "Error creant finestra: " << SDL_GetError() << std::endl;
|
||||||
|
SDL_Quit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IMPORTANT: Centrar explícitament la finestra
|
||||||
|
SDL_SetWindowPosition(finestra_, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
|
||||||
|
|
||||||
|
// Crear renderer amb acceleració
|
||||||
|
renderer_ = SDL_CreateRenderer(finestra_, nullptr);
|
||||||
|
|
||||||
|
if (!renderer_) {
|
||||||
|
std::cerr << "Error creant renderer: " << SDL_GetError() << std::endl;
|
||||||
|
SDL_DestroyWindow(finestra_);
|
||||||
|
SDL_Quit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CRÍTIC: Configurar viewport scaling
|
||||||
|
updateLogicalPresentation();
|
||||||
|
|
||||||
|
std::cout << "SDL3 inicialitzat: " << current_width_ << "x" << current_height_
|
||||||
|
<< " (logic: " << Defaults::Game::WIDTH << "x" << Defaults::Game::HEIGHT << ")" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDLManager::~SDLManager() {
|
||||||
|
if (renderer_) {
|
||||||
|
SDL_DestroyRenderer(renderer_);
|
||||||
|
renderer_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (finestra_) {
|
||||||
|
SDL_DestroyWindow(finestra_);
|
||||||
|
finestra_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Quit();
|
||||||
|
std::cout << "SDL3 netejat correctament" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLManager::calculateMaxWindowSize() {
|
||||||
|
SDL_DisplayID display = SDL_GetPrimaryDisplay();
|
||||||
|
const SDL_DisplayMode* mode = SDL_GetCurrentDisplayMode(display);
|
||||||
|
|
||||||
|
if (mode) {
|
||||||
|
// Deixar marge de 100px per a decoracions de l'OS
|
||||||
|
max_width_ = mode->w - 100;
|
||||||
|
max_height_ = mode->h - 100;
|
||||||
|
std::cout << "Display detectat: " << mode->w << "x" << mode->h
|
||||||
|
<< " (max finestra: " << max_width_ << "x" << max_height_ << ")" << std::endl;
|
||||||
|
} else {
|
||||||
|
// Fallback conservador
|
||||||
|
max_width_ = 1920;
|
||||||
|
max_height_ = 1080;
|
||||||
|
std::cerr << "No s'ha pogut detectar el display, usant fallback: "
|
||||||
|
<< max_width_ << "x" << max_height_ << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLManager::updateLogicalPresentation() {
|
||||||
|
// AIXÒ ÉS LA MÀGIA: El joc SEMPRE dibuixa en 640x480,
|
||||||
|
// SDL escala automàticament a la mida física de la finestra
|
||||||
|
SDL_SetRenderLogicalPresentation(
|
||||||
|
renderer_,
|
||||||
|
Defaults::Game::WIDTH, // 640 (lògic)
|
||||||
|
Defaults::Game::HEIGHT, // 480 (lògic)
|
||||||
|
SDL_LOGICAL_PRESENTATION_LETTERBOX // Mantenir aspect ratio 4:3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLManager::increaseWindowSize() {
|
||||||
|
if (is_fullscreen_) return; // No operar en fullscreen
|
||||||
|
|
||||||
|
int new_width = current_width_ + Defaults::Window::SIZE_INCREMENT;
|
||||||
|
int new_height = current_height_ + Defaults::Window::SIZE_INCREMENT;
|
||||||
|
|
||||||
|
// Clamp a màxim
|
||||||
|
new_width = std::min(new_width, max_width_);
|
||||||
|
new_height = std::min(new_height, max_height_);
|
||||||
|
|
||||||
|
if (new_width != current_width_ || new_height != current_height_) {
|
||||||
|
applyWindowSize(new_width, new_height);
|
||||||
|
std::cout << "F2: Finestra augmentada a " << new_width << "x" << new_height << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLManager::decreaseWindowSize() {
|
||||||
|
if (is_fullscreen_) return;
|
||||||
|
|
||||||
|
int new_width = current_width_ - Defaults::Window::SIZE_INCREMENT;
|
||||||
|
int new_height = current_height_ - Defaults::Window::SIZE_INCREMENT;
|
||||||
|
|
||||||
|
// Clamp a mínim
|
||||||
|
new_width = std::max(new_width, Defaults::Window::MIN_WIDTH);
|
||||||
|
new_height = std::max(new_height, Defaults::Window::MIN_HEIGHT);
|
||||||
|
|
||||||
|
if (new_width != current_width_ || new_height != current_height_) {
|
||||||
|
applyWindowSize(new_width, new_height);
|
||||||
|
std::cout << "F1: Finestra reduïda a " << new_width << "x" << new_height << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLManager::applyWindowSize(int new_width, int new_height) {
|
||||||
|
// Obtenir posició actual ABANS del resize
|
||||||
|
int old_x, old_y;
|
||||||
|
SDL_GetWindowPosition(finestra_, &old_x, &old_y);
|
||||||
|
|
||||||
|
int old_width = current_width_;
|
||||||
|
int old_height = current_height_;
|
||||||
|
|
||||||
|
// Actualitzar mida
|
||||||
|
SDL_SetWindowSize(finestra_, new_width, new_height);
|
||||||
|
current_width_ = new_width;
|
||||||
|
current_height_ = new_height;
|
||||||
|
|
||||||
|
// CENTRADO INTEL·LIGENT (algoritme de pollo)
|
||||||
|
// Calcular nova posició per mantenir la finestra centrada sobre si mateixa
|
||||||
|
int delta_width = old_width - new_width;
|
||||||
|
int delta_height = old_height - new_height;
|
||||||
|
|
||||||
|
int new_x = old_x + (delta_width / 2);
|
||||||
|
int new_y = old_y + (delta_height / 2);
|
||||||
|
|
||||||
|
// Evitar que la finestra surti de la pantalla
|
||||||
|
constexpr int TITLEBAR_HEIGHT = 35; // Alçada aproximada de la barra de títol
|
||||||
|
new_x = std::max(new_x, 0);
|
||||||
|
new_y = std::max(new_y, TITLEBAR_HEIGHT);
|
||||||
|
|
||||||
|
SDL_SetWindowPosition(finestra_, new_x, new_y);
|
||||||
|
|
||||||
|
// NO cal actualitzar el logical presentation aquí,
|
||||||
|
// SDL ho maneja automàticament
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLManager::toggleFullscreen() {
|
||||||
|
is_fullscreen_ = !is_fullscreen_;
|
||||||
|
SDL_SetWindowFullscreen(finestra_, is_fullscreen_);
|
||||||
|
|
||||||
|
std::cout << "F3: Fullscreen " << (is_fullscreen_ ? "activat" : "desactivat") << std::endl;
|
||||||
|
|
||||||
|
// En fullscreen, SDL gestiona tot automàticament
|
||||||
|
// En sortir, restaura la mida anterior
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDLManager::handleWindowEvent(const SDL_Event& event) {
|
||||||
|
if (event.type == SDL_EVENT_WINDOW_RESIZED) {
|
||||||
|
// Usuari ha redimensionat manualment (arrossegar vora)
|
||||||
|
// Actualitzar el nostre tracking
|
||||||
|
SDL_GetWindowSize(finestra_, ¤t_width_, ¤t_height_);
|
||||||
|
std::cout << "Finestra redimensionada manualment a "
|
||||||
|
<< current_width_ << "x" << current_height_ << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLManager::neteja(uint8_t r, uint8_t g, uint8_t b) {
|
||||||
|
if (!renderer_) return;
|
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(renderer_, r, g, b, 255);
|
||||||
|
SDL_RenderClear(renderer_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLManager::presenta() {
|
||||||
|
if (!renderer_) return;
|
||||||
|
|
||||||
|
SDL_RenderPresent(renderer_);
|
||||||
|
}
|
||||||
49
source/core/rendering/sdl_manager.hpp
Normal file
49
source/core/rendering/sdl_manager.hpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// sdl_manager.hpp - Gestor d'inicialització de SDL3
|
||||||
|
// © 2025 Port a C++20 amb SDL3
|
||||||
|
|
||||||
|
#ifndef SDL_MANAGER_HPP
|
||||||
|
#define SDL_MANAGER_HPP
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
class SDLManager {
|
||||||
|
public:
|
||||||
|
SDLManager();
|
||||||
|
~SDLManager();
|
||||||
|
|
||||||
|
// No permetre còpia ni assignació
|
||||||
|
SDLManager(const SDLManager&) = delete;
|
||||||
|
SDLManager& operator=(const SDLManager&) = delete;
|
||||||
|
|
||||||
|
// [NUEVO] Gestió de finestra dinàmica
|
||||||
|
void increaseWindowSize(); // F2: +100px
|
||||||
|
void decreaseWindowSize(); // F1: -100px
|
||||||
|
void toggleFullscreen(); // F3
|
||||||
|
bool handleWindowEvent(const SDL_Event& event); // Per a SDL_EVENT_WINDOW_RESIZED
|
||||||
|
|
||||||
|
// Funcions principals (renderitzat)
|
||||||
|
void neteja(uint8_t r = 0, uint8_t g = 0, uint8_t b = 0);
|
||||||
|
void presenta();
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
SDL_Renderer* obte_renderer() { return renderer_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDL_Window* finestra_;
|
||||||
|
SDL_Renderer* renderer_;
|
||||||
|
|
||||||
|
// [NUEVO] Estat de la finestra
|
||||||
|
int current_width_; // Mida física actual
|
||||||
|
int current_height_;
|
||||||
|
bool is_fullscreen_;
|
||||||
|
int max_width_; // Calculat des del display
|
||||||
|
int max_height_;
|
||||||
|
|
||||||
|
// [NUEVO] Funcions internes
|
||||||
|
void calculateMaxWindowSize(); // Llegir resolució del display
|
||||||
|
void applyWindowSize(int width, int height); // Canviar mida + centrar
|
||||||
|
void updateLogicalPresentation(); // Actualitzar viewport
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SDL_MANAGER_HPP
|
||||||
26
source/game/constants.hpp
Normal file
26
source/game/constants.hpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/defaults.hpp"
|
||||||
|
|
||||||
|
// Aliases per a backward compatibility amb codi existent
|
||||||
|
// Permet usar Constants::MARGE_ESQ en lloc de Defaults::Game::MARGIN_LEFT
|
||||||
|
|
||||||
|
namespace Constants {
|
||||||
|
// Marges de l'àrea de joc
|
||||||
|
constexpr int MARGE_DALT = Defaults::Game::MARGIN_TOP;
|
||||||
|
constexpr int MARGE_BAIX = Defaults::Game::MARGIN_BOTTOM;
|
||||||
|
constexpr int MARGE_ESQ = Defaults::Game::MARGIN_LEFT;
|
||||||
|
constexpr int MARGE_DRET = Defaults::Game::MARGIN_RIGHT;
|
||||||
|
|
||||||
|
// Límits de polígons i objectes
|
||||||
|
constexpr int MAX_IPUNTS = Defaults::Entities::MAX_IPUNTS;
|
||||||
|
constexpr int MAX_ORNIS = Defaults::Entities::MAX_ORNIS;
|
||||||
|
constexpr int MAX_BALES = Defaults::Entities::MAX_BALES;
|
||||||
|
|
||||||
|
// Velocitats (valors legacy del codi Pascal)
|
||||||
|
constexpr int VELOCITAT = static_cast<int>(Defaults::Physics::ENEMY_SPEED);
|
||||||
|
constexpr int VELOCITAT_MAX = static_cast<int>(Defaults::Physics::BULLET_SPEED);
|
||||||
|
|
||||||
|
// Matemàtiques
|
||||||
|
constexpr float PI = Defaults::Math::PI;
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
// © 2025 Port a C++20 amb SDL3
|
// © 2025 Port a C++20 amb SDL3
|
||||||
|
|
||||||
#include "joc_asteroides.hpp"
|
#include "joc_asteroides.hpp"
|
||||||
|
#include "core/rendering/primitives.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@@ -122,18 +123,6 @@ void JocAsteroides::actualitzar(float delta_time) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEBUG: Mostrar info de la nau (temporal)
|
|
||||||
static float time_accumulator = 0.0f;
|
|
||||||
time_accumulator += delta_time;
|
|
||||||
|
|
||||||
if (time_accumulator >= 1.0f) { // Cada segon
|
|
||||||
std::cout << "Nau: pos(" << nau_.centre.x << "," << nau_.centre.y
|
|
||||||
<< ") vel=" << static_cast<int>(nau_.velocitat) << " px/s"
|
|
||||||
<< " angle=" << static_cast<int>(nau_.angle * 180.0f / Constants::PI) << "°"
|
|
||||||
<< " dt=" << static_cast<int>(delta_time * 1000.0f) << "ms"
|
|
||||||
<< std::endl;
|
|
||||||
time_accumulator -= 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actualitzar moviment i rotació dels enemics (ORNIs)
|
// Actualitzar moviment i rotació dels enemics (ORNIs)
|
||||||
// Basat en el codi Pascal original: lines 429-432
|
// Basat en el codi Pascal original: lines 429-432
|
||||||
@@ -224,60 +213,7 @@ void JocAsteroides::processar_input(const SDL_Event& event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Funcions utilitàries - Geometria i matemàtiques
|
// Funcions de dibuix
|
||||||
// Basades en el codi Pascal original
|
|
||||||
|
|
||||||
float JocAsteroides::modul(const Punt& p) const {
|
|
||||||
// Càlcul de la magnitud d'un vector: sqrt(x² + y²)
|
|
||||||
return std::sqrt(static_cast<float>(p.x * p.x + p.y * p.y));
|
|
||||||
}
|
|
||||||
|
|
||||||
void JocAsteroides::diferencia(const Punt& o, const Punt& d, Punt& p) const {
|
|
||||||
// Resta de vectors (origen - destí)
|
|
||||||
p.x = o.x - d.x;
|
|
||||||
p.y = o.y - d.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JocAsteroides::distancia(const Punt& o, const Punt& d) const {
|
|
||||||
// Distància entre dos punts
|
|
||||||
Punt p;
|
|
||||||
diferencia(o, d, p);
|
|
||||||
return static_cast<int>(std::round(modul(p)));
|
|
||||||
}
|
|
||||||
|
|
||||||
float JocAsteroides::angle_punt(const Punt& p) const {
|
|
||||||
// Càlcul de l'angle d'un punt (arctan)
|
|
||||||
if (p.y != 0) {
|
|
||||||
return std::atan(static_cast<float>(p.x) / static_cast<float>(p.y));
|
|
||||||
}
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void JocAsteroides::crear_poligon_regular(Poligon& pol, uint8_t n, float r) {
|
|
||||||
// Crear un polígon regular amb n costats i radi r
|
|
||||||
// Distribueix els punts uniformement al voltant d'un cercle
|
|
||||||
|
|
||||||
float interval = 2.0f * Constants::PI / n;
|
|
||||||
float act = 0.0f;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < n; i++) {
|
|
||||||
pol.ipuntx[i].r = r;
|
|
||||||
pol.ipuntx[i].angle = act;
|
|
||||||
act += interval;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inicialitzar propietats del polígon
|
|
||||||
pol.centre.x = 320.0f;
|
|
||||||
pol.centre.y = 200.0f;
|
|
||||||
pol.angle = 0.0f;
|
|
||||||
// Convertir velocitat de px/frame a px/s: 2 px/frame × 20 FPS = 40 px/s
|
|
||||||
pol.velocitat = static_cast<float>(Constants::VELOCITAT) * 20.0f;
|
|
||||||
pol.n = n;
|
|
||||||
// Convertir rotació de rad/frame a rad/s: 0.0785 rad/frame × 20 FPS = 1.57 rad/s (~90°/s)
|
|
||||||
pol.drotacio = 0.078539816f * 20.0f;
|
|
||||||
pol.rotacio = 0.0f;
|
|
||||||
pol.esta = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JocAsteroides::linea(int x1, int y1, int x2, int y2, bool dibuixar) {
|
bool JocAsteroides::linea(int x1, int y1, int x2, int y2, bool dibuixar) {
|
||||||
// Algorisme de Bresenham per dibuixar línies
|
// Algorisme de Bresenham per dibuixar línies
|
||||||
@@ -418,38 +354,46 @@ void JocAsteroides::rota_pol(const Poligon& pol, float angul, bool dibuixar) {
|
|||||||
|
|
||||||
void JocAsteroides::mou_orni(Poligon& orni, float delta_time) {
|
void JocAsteroides::mou_orni(Poligon& orni, float delta_time) {
|
||||||
// Moviment autònom d'ORNI (enemic pentàgon)
|
// Moviment autònom d'ORNI (enemic pentàgon)
|
||||||
// Basat en el codi Pascal original: procedure mou_orni
|
// Basat EXACTAMENT en el codi Pascal original: ASTEROID.PAS lines 279-293
|
||||||
|
//
|
||||||
|
// IMPORTANT: El Pascal original NO té canvi aleatori continu!
|
||||||
|
// Només ajusta l'angle quan toca una paret.
|
||||||
|
|
||||||
// Cambio aleatori d'angle (5% probabilitat per crida)
|
// Calcular nova posició PROPUESTA (time-based, però lògica Pascal)
|
||||||
// En el Pascal original: if (random<0.05) then orni.angle:=random*2*pi
|
// velocitat ja està en px/s (40 px/s), multiplicar per delta_time
|
||||||
float random_val = static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);
|
|
||||||
if (random_val < 0.05f) {
|
|
||||||
// Assignar un angle completament aleatori (0-360°)
|
|
||||||
orni.angle = (static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX))
|
|
||||||
* 2.0f * Constants::PI;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calcular nova posició (moviment polar time-based)
|
|
||||||
// velocitat ja està en px/s (40 px/s), només cal multiplicar per delta_time
|
|
||||||
float velocitat_efectiva = orni.velocitat * delta_time;
|
float velocitat_efectiva = orni.velocitat * delta_time;
|
||||||
|
|
||||||
// Calcular desplaçament (angle-PI/2 perquè angle=0 apunta amunt)
|
// Calcular desplaçament (angle-PI/2 perquè angle=0 apunta amunt)
|
||||||
float dy = velocitat_efectiva * std::sin(orni.angle - Constants::PI / 2.0f);
|
float dy = velocitat_efectiva * std::sin(orni.angle - Constants::PI / 2.0f);
|
||||||
float dx = velocitat_efectiva * std::cos(orni.angle - Constants::PI / 2.0f);
|
float dx = velocitat_efectiva * std::cos(orni.angle - Constants::PI / 2.0f);
|
||||||
|
|
||||||
// Acumulació directa amb precisió subpíxel
|
float new_y = orni.centre.y + dy;
|
||||||
orni.centre.y += dy;
|
float new_x = orni.centre.x + dx;
|
||||||
orni.centre.x += dx;
|
|
||||||
|
|
||||||
// Boundary checking amb rebot (reflexió d'angle)
|
// Lògica Pascal: Actualitza Y si dins, sinó ajusta angle aleatòriament
|
||||||
// Si toca paret esquerra/dreta: angle = PI - angle
|
// if (dy>marge_dalt) and (dy<marge_baix) then orni.centre.y:=round(Dy)
|
||||||
if (orni.centre.x < Constants::MARGE_ESQ || orni.centre.x > Constants::MARGE_DRET) {
|
// else orni.angle:=orni.angle+(random(256)/512)*(random(3)-1);
|
||||||
orni.angle = Constants::PI - orni.angle;
|
if (new_y > Constants::MARGE_DALT && new_y < Constants::MARGE_BAIX) {
|
||||||
|
orni.centre.y = new_y;
|
||||||
|
} else {
|
||||||
|
// Pequeño ajuste aleatorio: (random(256)/512)*(random(3)-1)
|
||||||
|
// random(256) = 0..255, /512 = 0..0.498
|
||||||
|
// random(3) = 0,1,2, -1 = -1,0,1
|
||||||
|
// Resultado: ±0.5 rad aprox
|
||||||
|
float rand1 = (static_cast<float>(std::rand() % 256) / 512.0f);
|
||||||
|
int rand2 = (std::rand() % 3) - 1; // -1, 0, o 1
|
||||||
|
orni.angle += rand1 * static_cast<float>(rand2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si toca paret dalt/baix: angle = 2*PI - angle
|
// Lògica Pascal: Actualitza X si dins, sinó ajusta angle aleatòriament
|
||||||
if (orni.centre.y < Constants::MARGE_DALT || orni.centre.y > Constants::MARGE_BAIX) {
|
// if (dx>marge_esq) and (dx<marge_dret) then orni.centre.x:=round(Dx)
|
||||||
orni.angle = 2.0f * Constants::PI - orni.angle;
|
// else orni.angle:=orni.angle+(random(256)/512)*(random(3)-1);
|
||||||
|
if (new_x > Constants::MARGE_ESQ && new_x < Constants::MARGE_DRET) {
|
||||||
|
orni.centre.x = new_x;
|
||||||
|
} else {
|
||||||
|
float rand1 = (static_cast<float>(std::rand() % 256) / 512.0f);
|
||||||
|
int rand2 = (std::rand() % 3) - 1;
|
||||||
|
orni.angle += rand1 * static_cast<float>(rand2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nota: La rotació visual (orni.rotacio += orni.drotacio) ja es fa a actualitzar()
|
// Nota: La rotació visual (orni.rotacio += orni.drotacio) ja es fa a actualitzar()
|
||||||
46
source/game/joc_asteroides.hpp
Normal file
46
source/game/joc_asteroides.hpp
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// joc_asteroides.hpp - Lògica principal del joc
|
||||||
|
// © 1999 Visente i Sergi (versió Pascal)
|
||||||
|
// © 2025 Port a C++20 amb SDL3
|
||||||
|
|
||||||
|
#ifndef JOC_ASTEROIDES_HPP
|
||||||
|
#define JOC_ASTEROIDES_HPP
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
|
#include "core/types.hpp"
|
||||||
|
#include "game/constants.hpp"
|
||||||
|
|
||||||
|
// Classe principal del joc
|
||||||
|
class JocAsteroides {
|
||||||
|
public:
|
||||||
|
JocAsteroides(SDL_Renderer* renderer);
|
||||||
|
~JocAsteroides() = default;
|
||||||
|
|
||||||
|
void inicialitzar();
|
||||||
|
void actualitzar(float delta_time);
|
||||||
|
void dibuixar();
|
||||||
|
void processar_input(const SDL_Event& event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDL_Renderer* renderer_;
|
||||||
|
|
||||||
|
// Estat del joc
|
||||||
|
Triangle nau_;
|
||||||
|
std::array<Poligon, Constants::MAX_ORNIS> orni_;
|
||||||
|
std::array<Poligon, Constants::MAX_BALES> bales_;
|
||||||
|
Poligon chatarra_cosmica_;
|
||||||
|
uint16_t itocado_;
|
||||||
|
|
||||||
|
// Funcions de dibuix
|
||||||
|
bool linea(int x1, int y1, int x2, int y2, bool dibuixar);
|
||||||
|
void rota_tri(const Triangle& tri, float angul, float velocitat, bool dibuixar);
|
||||||
|
void rota_pol(const Poligon& pol, float angul, bool dibuixar);
|
||||||
|
|
||||||
|
// Moviment
|
||||||
|
void mou_orni(Poligon& orni, float delta_time);
|
||||||
|
void mou_bales(Poligon& bala, float delta_time);
|
||||||
|
void tocado();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JOC_ASTEROIDES_HPP
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
// joc_asteroides.hpp - Lògica principal del joc
|
|
||||||
// © 1999 Visente i Sergi (versió Pascal)
|
|
||||||
// © 2025 Port a C++20 amb SDL3
|
|
||||||
|
|
||||||
#ifndef JOC_ASTEROIDES_HPP
|
|
||||||
#define JOC_ASTEROIDES_HPP
|
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
#include <array>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
// Espai de noms per a les constants del joc
|
|
||||||
namespace Constants {
|
|
||||||
constexpr int MARGE_DALT = 20;
|
|
||||||
constexpr int MARGE_BAIX = 460;
|
|
||||||
constexpr int MARGE_ESQ = 20;
|
|
||||||
constexpr int MARGE_DRET = 620;
|
|
||||||
constexpr int MAX_IPUNTS = 30;
|
|
||||||
constexpr int MAX_ORNIS = 15;
|
|
||||||
constexpr int VELOCITAT = 2;
|
|
||||||
constexpr int VELOCITAT_MAX = 6;
|
|
||||||
constexpr int MAX_BALES = 3;
|
|
||||||
constexpr float PI = 3.14159265359f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Estructures de dades (coordenades polars i cartesianes)
|
|
||||||
struct IPunt {
|
|
||||||
float r;
|
|
||||||
float angle;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Punt {
|
|
||||||
float x;
|
|
||||||
float y;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Triangle {
|
|
||||||
IPunt p1, p2, p3;
|
|
||||||
Punt centre;
|
|
||||||
float angle;
|
|
||||||
float velocitat;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Poligon {
|
|
||||||
std::array<IPunt, Constants::MAX_IPUNTS> ipuntx;
|
|
||||||
Punt centre;
|
|
||||||
float angle;
|
|
||||||
float velocitat;
|
|
||||||
uint8_t n;
|
|
||||||
float drotacio;
|
|
||||||
float rotacio;
|
|
||||||
bool esta;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Classe principal del joc
|
|
||||||
class JocAsteroides {
|
|
||||||
public:
|
|
||||||
JocAsteroides(SDL_Renderer* renderer);
|
|
||||||
~JocAsteroides() = default;
|
|
||||||
|
|
||||||
void inicialitzar();
|
|
||||||
void actualitzar(float delta_time);
|
|
||||||
void dibuixar();
|
|
||||||
void processar_input(const SDL_Event& event);
|
|
||||||
|
|
||||||
private:
|
|
||||||
SDL_Renderer* renderer_;
|
|
||||||
|
|
||||||
// Estat del joc
|
|
||||||
Triangle nau_;
|
|
||||||
std::array<Poligon, Constants::MAX_ORNIS> orni_;
|
|
||||||
std::array<Poligon, Constants::MAX_BALES> bales_;
|
|
||||||
Poligon chatarra_cosmica_;
|
|
||||||
uint16_t itocado_;
|
|
||||||
|
|
||||||
// Funcions utilitàries (geometria)
|
|
||||||
void crear_poligon_regular(Poligon& pol, uint8_t n, float r);
|
|
||||||
float modul(const Punt& p) const;
|
|
||||||
void diferencia(const Punt& o, const Punt& d, Punt& p) const;
|
|
||||||
int distancia(const Punt& o, const Punt& d) const;
|
|
||||||
float angle_punt(const Punt& p) const;
|
|
||||||
|
|
||||||
// Funcions de dibuix
|
|
||||||
bool linea(int x1, int y1, int x2, int y2, bool dibuixar);
|
|
||||||
void rota_tri(const Triangle& tri, float angul, float velocitat, bool dibuixar);
|
|
||||||
void rota_pol(const Poligon& pol, float angul, bool dibuixar);
|
|
||||||
|
|
||||||
// Moviment
|
|
||||||
void mou_orni(Poligon& orni, float delta_time);
|
|
||||||
void mou_bales(Poligon& bala, float delta_time);
|
|
||||||
void tocado();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // JOC_ASTEROIDES_HPP
|
|
||||||
@@ -2,12 +2,12 @@
|
|||||||
// © 1999 Visente i Sergi (versió Pascal)
|
// © 1999 Visente i Sergi (versió Pascal)
|
||||||
// © 2025 Port a C++20 amb SDL3
|
// © 2025 Port a C++20 amb SDL3
|
||||||
|
|
||||||
#include "sdl_manager.hpp"
|
#include "core/rendering/sdl_manager.hpp"
|
||||||
#include "joc_asteroides.hpp"
|
#include "game/joc_asteroides.hpp"
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
// Crear gestor SDL amb finestra de 640x480
|
// Crear gestor SDL (finestra centrada 640x480 per defecte)
|
||||||
SDLManager sdl(640, 480, "Asteroides - BETA 2.2");
|
SDLManager sdl;
|
||||||
|
|
||||||
// Crear instància del joc
|
// Crear instància del joc
|
||||||
JocAsteroides joc(sdl.obte_renderer());
|
JocAsteroides joc(sdl.obte_renderer());
|
||||||
@@ -33,7 +33,27 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
// Processar events SDL
|
// Processar events SDL
|
||||||
while (SDL_PollEvent(&event)) {
|
while (SDL_PollEvent(&event)) {
|
||||||
// Processar input del joc
|
// [NUEVO] Manejo de ventana ANTES de lógica del juego
|
||||||
|
if (sdl.handleWindowEvent(event)) {
|
||||||
|
continue; // Evento procesado, siguiente
|
||||||
|
}
|
||||||
|
|
||||||
|
// [NUEVO] Teclas globales de ventana
|
||||||
|
if (event.type == SDL_EVENT_KEY_DOWN) {
|
||||||
|
switch (event.key.key) {
|
||||||
|
case SDLK_F1:
|
||||||
|
sdl.decreaseWindowSize();
|
||||||
|
continue;
|
||||||
|
case SDLK_F2:
|
||||||
|
sdl.increaseWindowSize();
|
||||||
|
continue;
|
||||||
|
case SDLK_F3:
|
||||||
|
sdl.toggleFullscreen();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Procesamiento normal del juego
|
||||||
joc.processar_input(event);
|
joc.processar_input(event);
|
||||||
|
|
||||||
// Detectar tancament de finestra o ESC
|
// Detectar tancament de finestra o ESC
|
||||||
|
|||||||
9
source/project.h.in
Normal file
9
source/project.h.in
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Project {
|
||||||
|
constexpr const char* NAME = "@PROJECT_NAME@";
|
||||||
|
constexpr const char* LONG_NAME = "@PROJECT_LONG_NAME@";
|
||||||
|
constexpr const char* VERSION = "@PROJECT_VERSION@";
|
||||||
|
constexpr const char* COPYRIGHT = "@PROJECT_COPYRIGHT@";
|
||||||
|
constexpr const char* GIT_HASH = "@GIT_HASH@";
|
||||||
|
} // namespace Project
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
// sdl_manager.cpp - Implementació del gestor SDL3
|
|
||||||
// © 2025 Port a C++20 amb SDL3
|
|
||||||
|
|
||||||
#include "sdl_manager.hpp"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
SDLManager::SDLManager(int amplada, int alcada, const char* titol)
|
|
||||||
: finestra_(nullptr), renderer_(nullptr), inicialitzat_(false) {
|
|
||||||
|
|
||||||
// Inicialitzar SDL3
|
|
||||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
|
||||||
std::cerr << "Error inicialitzant SDL3: " << SDL_GetError() << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Crear finestra
|
|
||||||
finestra_ = SDL_CreateWindow(
|
|
||||||
titol,
|
|
||||||
amplada, alcada,
|
|
||||||
SDL_WINDOW_RESIZABLE
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!finestra_) {
|
|
||||||
std::cerr << "Error creant finestra: " << SDL_GetError() << std::endl;
|
|
||||||
SDL_Quit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Crear renderer amb acceleració i vsync
|
|
||||||
// En SDL3, els flags són diferents o s'especifiquen diferent
|
|
||||||
renderer_ = SDL_CreateRenderer(finestra_, nullptr);
|
|
||||||
|
|
||||||
if (!renderer_) {
|
|
||||||
std::cerr << "Error creant renderer: " << SDL_GetError() << std::endl;
|
|
||||||
SDL_DestroyWindow(finestra_);
|
|
||||||
SDL_Quit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
inicialitzat_ = true;
|
|
||||||
std::cout << "SDL3 inicialitzat correctament" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDLManager::~SDLManager() {
|
|
||||||
if (renderer_) {
|
|
||||||
SDL_DestroyRenderer(renderer_);
|
|
||||||
renderer_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (finestra_) {
|
|
||||||
SDL_DestroyWindow(finestra_);
|
|
||||||
finestra_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Quit();
|
|
||||||
std::cout << "SDL3 netejat correctament" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLManager::neteja(uint8_t r, uint8_t g, uint8_t b) {
|
|
||||||
if (!renderer_) return;
|
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(renderer_, r, g, b, 255);
|
|
||||||
SDL_RenderClear(renderer_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLManager::presenta() {
|
|
||||||
if (!renderer_) return;
|
|
||||||
|
|
||||||
SDL_RenderPresent(renderer_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDLManager::processar_events() {
|
|
||||||
if (!inicialitzat_) return false;
|
|
||||||
|
|
||||||
SDL_Event event;
|
|
||||||
while (SDL_PollEvent(&event)) {
|
|
||||||
switch (event.type) {
|
|
||||||
case SDL_EVENT_QUIT:
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case SDL_EVENT_KEY_DOWN:
|
|
||||||
// En SDL3, la tecla està en event.key.key en lloc de event.key.keysym.sym
|
|
||||||
if (event.key.key == SDLK_ESCAPE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
// sdl_manager.hpp - Gestor d'inicialització de SDL3
|
|
||||||
// © 2025 Port a C++20 amb SDL3
|
|
||||||
|
|
||||||
#ifndef SDL_MANAGER_HPP
|
|
||||||
#define SDL_MANAGER_HPP
|
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
class SDLManager {
|
|
||||||
public:
|
|
||||||
SDLManager(int amplada, int alcada, const char* titol);
|
|
||||||
~SDLManager();
|
|
||||||
|
|
||||||
// No permetre còpia ni assignació
|
|
||||||
SDLManager(const SDLManager&) = delete;
|
|
||||||
SDLManager& operator=(const SDLManager&) = delete;
|
|
||||||
|
|
||||||
// Funcions principals
|
|
||||||
void neteja(uint8_t r = 0, uint8_t g = 0, uint8_t b = 0);
|
|
||||||
void presenta();
|
|
||||||
bool processar_events();
|
|
||||||
|
|
||||||
// Getters
|
|
||||||
SDL_Renderer* obte_renderer() { return renderer_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
SDL_Window* finestra_;
|
|
||||||
SDL_Renderer* renderer_;
|
|
||||||
bool inicialitzat_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SDL_MANAGER_HPP
|
|
||||||
Reference in New Issue
Block a user