161 lines
5.5 KiB
C++
161 lines
5.5 KiB
C++
// title_scene.hpp - Escena de títol en 3D real
|
|
// © 2026 JailDesigner
|
|
//
|
|
// Clon de `TitleScene` (2D) que substitueix `Graphics::Starfield` per
|
|
// `Graphics::Starfield` i `Title::ShipAnimator` per `Title::ShipAnimator`,
|
|
// afegint una `Graphics::Camera3D` que projecta l'escena en perspectiva real.
|
|
// Tot el bloc d'overlay 2D (logo "ORNI ATTACK!", "PRESS START TO PLAY", peu
|
|
// "JAILGAMES + copyright") es manté idèntic.
|
|
//
|
|
|
|
#pragma once
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "core/graphics/camera3d.hpp"
|
|
#include "core/graphics/curtain.hpp"
|
|
#include "core/graphics/shape.hpp"
|
|
#include "core/graphics/starfield.hpp"
|
|
#include "core/graphics/vector_text.hpp"
|
|
#include "core/input/input_types.hpp"
|
|
#include "core/rendering/sdl_manager.hpp"
|
|
#include "core/system/game_config.hpp"
|
|
#include "core/system/scene.hpp"
|
|
#include "core/system/scene_context.hpp"
|
|
#include "core/types.hpp"
|
|
#include "game/title/ship_animator.hpp"
|
|
|
|
class TitleScene final : public Scene {
|
|
public:
|
|
explicit TitleScene(SDLManager& sdl, SceneManager::SceneContext& context);
|
|
~TitleScene() override;
|
|
|
|
void handleEvent(const SDL_Event& event) override;
|
|
void update(float delta_time) override;
|
|
void draw() override;
|
|
[[nodiscard]] auto isFinished() const -> bool override;
|
|
|
|
private:
|
|
enum class TitleState : std::uint8_t {
|
|
STARFIELD_FADE_IN,
|
|
STARFIELD,
|
|
MAIN,
|
|
PLAYER_JOIN_PHASE,
|
|
BLACK_SCREEN,
|
|
DEMO_DIVE, // Attract: dive de càmera cap al punt de fuga
|
|
DEMO_CURTAIN, // Attract: cortinilla negra que cau i tapa abans del salt
|
|
};
|
|
|
|
struct LogoLetter {
|
|
std::shared_ptr<Graphics::Shape> shape;
|
|
Vec2 position;
|
|
float width;
|
|
float height;
|
|
float center_offset;
|
|
};
|
|
|
|
SDLManager& sdl_;
|
|
SceneManager::SceneContext& context_;
|
|
GameConfig::MatchConfig match_config_;
|
|
Graphics::VectorText text_;
|
|
Graphics::Curtain curtain_; // Cortinilla negra en saltar a la demo (attract)
|
|
std::unique_ptr<Graphics::Camera3D> camera_;
|
|
std::unique_ptr<Graphics::Starfield> starfield_;
|
|
std::unique_ptr<Title::ShipAnimator> ship_animator_;
|
|
|
|
// Destell que tapa el "pop" final de cada nau quan arriba al VP.
|
|
// Pool fix de 2 (una per nau). Anima escala 0→max→0.
|
|
struct Flash {
|
|
Vec2 position{};
|
|
float timer{0.0F};
|
|
bool active{false};
|
|
};
|
|
std::array<Flash, 2> flashes_{};
|
|
std::shared_ptr<Graphics::Shape> flash_shape_;
|
|
|
|
void triggerFlash(Vec2 pos);
|
|
void updateFlashes(float delta_time);
|
|
void drawFlashes();
|
|
TitleState current_state_{TitleState::STARFIELD_FADE_IN};
|
|
float temps_acumulat_{0.0F};
|
|
float idle_timer_{0.0F}; // Attract mode: inactivitat acumulada al state MAIN
|
|
|
|
// Dive (attract): temps transcorregut i zoom aplicat als elements 2D
|
|
// (logo + peu) mentre la càmera avança cap al punt de fuga.
|
|
float dive_time_{0.0F};
|
|
float dive_zoom_{1.0F};
|
|
|
|
std::vector<LogoLetter> letters_orni_;
|
|
std::vector<LogoLetter> letters_attack_;
|
|
float dynamic_attack_y_{0.0F};
|
|
|
|
std::vector<LogoLetter> letters_jailgames_;
|
|
|
|
float animation_time_{0.0F};
|
|
std::vector<Vec2> original_positions_orni_;
|
|
std::vector<Vec2> original_positions_attack_;
|
|
|
|
float state_time_main_{0.0F};
|
|
bool animation_active_{false};
|
|
float lerp_factor_{0.0F};
|
|
|
|
// Progresos de la intro coreografiada al state MAIN.
|
|
float intro_logo_progress_{0.0F};
|
|
float intro_jailgames_progress_{0.0F};
|
|
float intro_copyright_progress_{0.0F};
|
|
bool press_start_visible_{false};
|
|
bool ships_intro_launched_{false};
|
|
|
|
static constexpr float BRIGHTNESS_STARFIELD = 1.2F;
|
|
static constexpr float DURATION_FADE_IN = 3.0F;
|
|
static constexpr float DURATION_INIT = 4.0F;
|
|
static constexpr float DURATION_TRANSITION = 2.5F;
|
|
static constexpr float LETTER_SPACING = 10.0F;
|
|
static constexpr float BLINK_FREQUENCY = 3.0F;
|
|
static constexpr float DURATION_BLACK_SCREEN = 2.0F;
|
|
static constexpr int MUSIC_FADE = 1500;
|
|
|
|
// Attract mode: temps d'inactivitat al títol (state MAIN) abans de saltar
|
|
// a la demo. Qualsevol input el reseteja.
|
|
static constexpr float TITLE_DEMO_TIMEOUT = 20.0F;
|
|
|
|
static constexpr float ORBIT_AMPLITUDE_X = 4.0F;
|
|
static constexpr float ORBIT_AMPLITUDE_Y = 3.0F;
|
|
static constexpr float ORBIT_FREQUENCY_X = 0.8F;
|
|
static constexpr float ORBIT_FREQUENCY_Y = 1.2F;
|
|
static constexpr float ORBIT_PHASE_OFFSET = 1.57F;
|
|
|
|
static constexpr float SHADOW_DELAY = 0.5F;
|
|
static constexpr float SHADOW_BRIGHTNESS = 0.4F;
|
|
static constexpr float SHADOW_OFFSET_X = 2.0F;
|
|
static constexpr float SHADOW_OFFSET_Y = 2.0F;
|
|
|
|
static constexpr float DURATION_LERP = 2.0F;
|
|
|
|
// Càmera 3D: FOV vertical en radians.
|
|
static constexpr float CAMERA_FOV_Y_RAD = 1.0472F; // 60°
|
|
|
|
void updateLogoAnimation(float delta_time);
|
|
static auto checkSkipButtonPressed() -> bool;
|
|
auto checkStartGameButtonPressed() -> bool;
|
|
void initTitle();
|
|
void inicialitzarJailgames();
|
|
void dibuixarPeuTitol(float spacing) const;
|
|
|
|
void updateStarfieldFadeInState(float delta_time);
|
|
void updateStarfieldState(float delta_time);
|
|
void updateMainState(float delta_time);
|
|
void updatePlayerJoinPhaseState(float delta_time);
|
|
void updateBlackScreenState(float delta_time);
|
|
void updateDemoDiveState(float delta_time);
|
|
void updateDemoCurtainState(float delta_time);
|
|
void handleSkipInput();
|
|
void handleStartInput();
|
|
void triggerExitForJoinedPlayers(bool p1_was_active, bool p2_was_active, const char* log_prefix);
|
|
};
|