feat(demo): demos a 1 i 2 jugadors, esquiva de bales enemigues i vides infinites
This commit is contained in:
@@ -32,11 +32,9 @@ using SceneType = SceneContext::SceneType;
|
||||
using Option = SceneContext::Option;
|
||||
|
||||
namespace {
|
||||
// Attract mode: duració màxima de la demo i marge perquè es vegi l'explosió
|
||||
// de la nau abans de saltar al logo (menor que DEATH_DURATION=3s per evitar
|
||||
// la seqüència de respawn/continue).
|
||||
// Attract mode: durada fixa de la demo. Amb vides infinites, sempre dura
|
||||
// això (les morts respawnegen); només input o aquest timeout la tallen.
|
||||
constexpr float DEMO_DURATION = 35.0F;
|
||||
constexpr float DEMO_DEATH_LINGER = 2.0F;
|
||||
|
||||
// Qualsevol d'aquestes accions trenca la demo i torna al títol.
|
||||
constexpr std::array<InputAction, 5> DEMO_EXIT_ACTIONS = {
|
||||
@@ -160,10 +158,11 @@ GameScene::GameScene(SDLManager& sdl, SceneContext& context)
|
||||
if (match_config_.mode == GameConfig::Mode::DEMO) {
|
||||
// Attract mode: arrencar directament en PLAYING a l'escenari curat
|
||||
// actual (partida "ja començada") i avançar l'índex perquè la pròxima
|
||||
// demo mostri un escenari diferent.
|
||||
const uint8_t DEMO_STAGE = Systems::Demo::scenarioStage(context_.demoScenarioIndex());
|
||||
// demo mostri un escenari diferent. El nombre de jugadors ja l'ha fixat
|
||||
// TitleScene al match_config llegint el mateix escenari.
|
||||
const Systems::Demo::Scenario SC = Systems::Demo::scenario(context_.demoScenarioIndex());
|
||||
context_.advanceDemoScenario();
|
||||
stage_manager_->initDemo(DEMO_STAGE);
|
||||
stage_manager_->initDemo(SC.stage);
|
||||
demo_timer_ = DEMO_DURATION;
|
||||
} else {
|
||||
stage_manager_->init();
|
||||
@@ -339,10 +338,10 @@ void GameScene::updateShipsControl(float delta_time) {
|
||||
if (!ACTIU || hit_timer_per_player_[i] != 0.0F) {
|
||||
continue;
|
||||
}
|
||||
// En demo, la P1 es mou amb el pilot IA (control calculat a stepDemo);
|
||||
// la resta de casos llegeixen Input com sempre.
|
||||
if (DEMO && i == 0) {
|
||||
ships_[0].applyMovement(demo_ctrl_.left, demo_ctrl_.right, demo_ctrl_.thrust, delta_time);
|
||||
// En demo, cada nau activa es mou amb el seu pilot IA (control calculat
|
||||
// a stepDemo); la resta de casos llegeixen Input com sempre.
|
||||
if (DEMO) {
|
||||
ships_[i].applyMovement(demo_ctrls_[i].left, demo_ctrls_[i].right, demo_ctrls_[i].thrust, delta_time);
|
||||
} else {
|
||||
ships_[i].processInput(delta_time, i);
|
||||
}
|
||||
@@ -357,22 +356,30 @@ auto GameScene::stepDemo(float delta_time) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
// En morir la nau, escurçar el timer perquè es vegi l'explosió i després
|
||||
// saltar al logo (sense passar per CONTINUE/GAME_OVER ni parar la música).
|
||||
if (hit_timer_per_player_[0] > 0.0F) {
|
||||
demo_timer_ = std::min(demo_timer_, DEMO_DEATH_LINGER);
|
||||
}
|
||||
|
||||
// Vides infinites: la demo dura sempre el temps fix; en morir, stepDeathSequence
|
||||
// respawneja (no acaba ni passa per CONTINUE/GAME_OVER).
|
||||
demo_timer_ -= delta_time;
|
||||
if (demo_timer_ <= 0.0F) {
|
||||
endDemo();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Control del pilot per al frame; el disparo el dispara GameScene.
|
||||
demo_ctrl_ = demo_pilot_.compute(ships_[0], enemies_, Defaults::Zones::PLAYAREA, delta_time);
|
||||
if (demo_ctrl_.shoot) {
|
||||
fireBullet(0);
|
||||
// Control de cada nau activa per al frame; el disparo el dispara GameScene.
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
const bool ACTIU = (i == 0) ? match_config_.player1_active : match_config_.player2_active;
|
||||
if (!ACTIU || hit_timer_per_player_[i] != 0.0F) {
|
||||
demo_ctrls_[i] = {}; // nau inactiva/morta: sense control
|
||||
continue;
|
||||
}
|
||||
demo_ctrls_[i] = demo_pilots_[i].compute(
|
||||
ships_[i],
|
||||
enemies_,
|
||||
bullets_,
|
||||
Defaults::Zones::PLAYAREA,
|
||||
delta_time);
|
||||
if (demo_ctrls_[i].shoot) {
|
||||
fireBullet(i);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -491,6 +498,15 @@ void GameScene::stepDeathSequence(float delta_time) {
|
||||
}
|
||||
|
||||
// *** PHASE 3: RESPAWN OR GAME OVER ***
|
||||
// Mode demo: vides infinites. Respawn sempre, sense decrementar vides ni
|
||||
// passar mai per CONTINUE/GAME_OVER — la demo dura el seu temps fix.
|
||||
if (match_config_.mode == GameConfig::Mode::DEMO) {
|
||||
Vec2 spawn_pos = getSpawnPoint(i);
|
||||
ships_[i].init(&spawn_pos, /*activar_invulnerabilitat=*/true);
|
||||
hit_timer_per_player_[i] = 0.0F;
|
||||
continue;
|
||||
}
|
||||
|
||||
lives_per_player_[i]--;
|
||||
if (lives_per_player_[i] > 0) {
|
||||
Vec2 spawn_pos = getSpawnPoint(i);
|
||||
|
||||
@@ -102,10 +102,10 @@ class GameScene final : public Scene {
|
||||
// Control de sons de animación INIT_HUD
|
||||
bool init_hud_rect_sound_played_{false}; // Flag para evitar repetir sonido del rectángulo
|
||||
|
||||
// Attract mode (mode DEMO): un pilot IA controla la nau P1.
|
||||
Systems::Demo::DemoPilot demo_pilot_;
|
||||
Systems::Demo::Control demo_ctrl_{}; // Control del pilot per al frame actual
|
||||
float demo_timer_{0.0F}; // Temps restant de la demo (→ LOGO en esgotar-se)
|
||||
// Attract mode (mode DEMO): un pilot IA per nau activa (1 o 2 jugadors).
|
||||
std::array<Systems::Demo::DemoPilot, 2> demo_pilots_;
|
||||
std::array<Systems::Demo::Control, 2> demo_ctrls_{}; // Control per nau al frame actual
|
||||
float demo_timer_{0.0F}; // Temps restant de la demo (→ LOGO)
|
||||
|
||||
// Funciones privades
|
||||
// bullet_velocity: velocitat de la bala que ha causat la mort (Vec2{} si no
|
||||
@@ -144,7 +144,7 @@ class GameScene final : public Scene {
|
||||
void stepPhysics(float delta_time);
|
||||
void stepShootingInput();
|
||||
void stepMidGameJoin();
|
||||
// Mueve las naves activas: en mode DEMO la P1 usa el pilot IA (demo_ctrl_),
|
||||
// Mueve las naves activas: en mode DEMO cada nau usa su pilot IA (demo_ctrls_),
|
||||
// el resto usa processInput (Input). Compartido por los 3 estados jugables.
|
||||
void updateShipsControl(float delta_time);
|
||||
// Mode DEMO: gestiona salida (input→título, timeout/muerte→logo) y calcula
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "core/rendering/shape_renderer.hpp"
|
||||
#include "core/system/scene_context.hpp"
|
||||
#include "core/system/service_menu.hpp"
|
||||
#include "game/systems/demo_pilot.hpp"
|
||||
#include "project.h"
|
||||
|
||||
using SceneManager::SceneContext;
|
||||
@@ -359,9 +360,12 @@ void TitleScene::update(float delta_time) {
|
||||
idle_timer_ += delta_time;
|
||||
}
|
||||
if (idle_timer_ >= TITLE_DEMO_TIMEOUT) {
|
||||
// L'escenari curat (mateix índex que llegirà GameScene) decideix
|
||||
// quants jugadors IA hi ha. No avancem l'índex ací: ho fa GameScene.
|
||||
const Systems::Demo::Scenario SC = Systems::Demo::scenario(context_.demoScenarioIndex());
|
||||
GameConfig::MatchConfig demo_cfg;
|
||||
demo_cfg.player1_active = true;
|
||||
demo_cfg.player2_active = false;
|
||||
demo_cfg.player2_active = (SC.players >= 2);
|
||||
demo_cfg.mode = GameConfig::Mode::DEMO;
|
||||
context_.setMatchConfig(demo_cfg);
|
||||
context_.setNextScene(SceneType::GAME);
|
||||
|
||||
Reference in New Issue
Block a user