demo time-based: porta el patro de CCAE (multi-set, index = elapsed_s*60, % size per safe loop), substitueix demo.bin per demo1/2/3.bin
This commit is contained in:
+93
-69
@@ -277,7 +277,8 @@ void Game::init() {
|
||||
|
||||
// Modo demo
|
||||
demo_.recording = false;
|
||||
demo_.counter = 0;
|
||||
demo_.elapsed_s = 0.0F;
|
||||
demo_.index = 0;
|
||||
|
||||
// Inicializa el objeto para el fundido
|
||||
fade_->init(0x27, 0x27, 0x36);
|
||||
@@ -521,34 +522,31 @@ auto Game::loadScoreFile() -> bool {
|
||||
return success;
|
||||
}
|
||||
|
||||
// Carga el fichero de datos para la demo
|
||||
// Carga els fitxers de dades de demo (multi-set) des de Resource. Tots els
|
||||
// blobs es descompacten a DemoData via loadDemoDataFromBytes; si un blob no
|
||||
// te la mida esperada s'omet.
|
||||
auto Game::loadDemoFile() -> bool {
|
||||
// Lee los datos de la demo desde Resource (precargados al arrancar).
|
||||
const auto &bytes = Resource::get()->getDemoBytes();
|
||||
const size_t EXPECTED = sizeof(DemoKeys) * TOTAL_DEMO_DATA;
|
||||
if (bytes.size() >= EXPECTED) {
|
||||
for (int i = 0; i < TOTAL_DEMO_DATA; ++i) {
|
||||
memcpy(&demo_.data_file[i], bytes.data() + (i * sizeof(DemoKeys)), sizeof(DemoKeys));
|
||||
}
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Demo data loaded (" << bytes.size() << " bytes)" << '\n';
|
||||
}
|
||||
} else {
|
||||
// Si no hay datos (bytes vacíos o tamaño inválido), inicializamos a cero.
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Warning: demo data missing or too small, initializing to zero" << '\n';
|
||||
}
|
||||
for (auto &i : demo_.data_file) {
|
||||
demo_.keys.left = 0;
|
||||
demo_.keys.right = 0;
|
||||
demo_.keys.no_input = 0;
|
||||
demo_.keys.fire = 0;
|
||||
demo_.keys.fire_left = 0;
|
||||
demo_.keys.fire_right = 0;
|
||||
i = demo_.keys;
|
||||
demo_.data.clear();
|
||||
const size_t NUM = Resource::get()->getDemoCount();
|
||||
for (size_t i = 0; i < NUM; ++i) {
|
||||
DemoData dd = loadDemoDataFromBytes(Resource::get()->getDemoBytes(i));
|
||||
if (!dd.empty()) {
|
||||
demo_.data.push_back(std::move(dd));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
if (!demo_.data.empty()) {
|
||||
demo_selected_set_ = static_cast<size_t>(rand()) % demo_.data.size();
|
||||
} else {
|
||||
demo_selected_set_ = 0;
|
||||
}
|
||||
if (Options::settings.console) {
|
||||
if (demo_.data.empty()) {
|
||||
std::cout << "Warning: no demo data loaded" << '\n';
|
||||
} else {
|
||||
std::cout << "Demo data loaded (" << demo_.data.size() << " sets, playing #" << demo_selected_set_ << ")" << '\n';
|
||||
}
|
||||
}
|
||||
return !demo_.data.empty();
|
||||
}
|
||||
|
||||
// Guarda el fichero de puntos
|
||||
@@ -577,32 +575,29 @@ auto Game::saveScoreFile() -> bool {
|
||||
return success;
|
||||
}
|
||||
|
||||
// Guarda el fichero de datos para la demo
|
||||
// Guarda el primer set de demo (gravat en mode RECORDING) a demo1.bin.
|
||||
auto Game::saveDemoFile() -> bool {
|
||||
bool success = true;
|
||||
const std::string P = Asset::get()->get("demo.bin");
|
||||
const std::string FILE_NAME = P.substr(P.find_last_of("\\/") + 1);
|
||||
if (demo_.recording) {
|
||||
SDL_IOStream *file = SDL_IOFromFile(P.c_str(), "w+b");
|
||||
if (file != nullptr) {
|
||||
// Guardamos los datos
|
||||
for (auto &i : demo_.data_file) {
|
||||
SDL_WriteIO(file, &i, sizeof(DemoKeys));
|
||||
}
|
||||
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Writing file " << FILE_NAME.c_str() << '\n';
|
||||
}
|
||||
|
||||
// Cerramos el fichero
|
||||
SDL_CloseIO(file);
|
||||
} else {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Error: Unable to save " << FILE_NAME.c_str() << " file! " << SDL_GetError() << '\n';
|
||||
}
|
||||
}
|
||||
if (!demo_.recording || demo_.data.empty()) {
|
||||
return true;
|
||||
}
|
||||
return success;
|
||||
const std::string P = Asset::get()->get("demo1.bin");
|
||||
const std::string FILE_NAME = P.substr(P.find_last_of("\\/") + 1);
|
||||
SDL_IOStream *file = SDL_IOFromFile(P.c_str(), "w+b");
|
||||
if (file == nullptr) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Error: Unable to save " << FILE_NAME << " file! " << SDL_GetError() << '\n';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const auto &dd = demo_.data.at(0);
|
||||
for (const auto &k : dd) {
|
||||
SDL_WriteIO(file, &k, sizeof(DemoKeys));
|
||||
}
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Writing file " << FILE_NAME << '\n';
|
||||
}
|
||||
SDL_CloseIO(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Inicializa las formaciones enemigas
|
||||
@@ -2276,6 +2271,12 @@ void Game::update(float dt_s) {
|
||||
elapsed_s_ += dt_s;
|
||||
counter_ = static_cast<Uint32>(elapsed_s_ * 60.0F);
|
||||
|
||||
// Avenc del temps de la demo (playback o gravacio). Index = elapsed_s * 60
|
||||
if (demo_.enabled || demo_.recording) {
|
||||
demo_.elapsed_s += dt_s;
|
||||
demo_.index = static_cast<int>(demo_.elapsed_s * 60.0F);
|
||||
}
|
||||
|
||||
checkGameInput();
|
||||
updatePlayers(dt_s);
|
||||
updateBackground(dt_s);
|
||||
@@ -2446,10 +2447,33 @@ void Game::checkGameInput() {
|
||||
}
|
||||
}
|
||||
|
||||
// Rama de checkGameInput: reproduce el input grabado en data_file
|
||||
// Rama de checkGameInput: reprodueix l'input gravat al set actiu de la demo.
|
||||
// El index es time-based: index = elapsed_s * 60. L'avenc d'elapsed_s el fa
|
||||
// Game::update() per evitar que el ritme de playback depengui dels frames
|
||||
// que arribin a aquesta funcio.
|
||||
void Game::processDemoInput() {
|
||||
const int INDEX = 0;
|
||||
const DemoKeys &keys = demo_.data_file[demo_.counter];
|
||||
|
||||
// Fi de la demo: salta a Title
|
||||
if (demo_.index >= TOTAL_DEMO_DATA) {
|
||||
section_->name = SECTION_PROG_TITLE;
|
||||
section_->subsection = SUBSECTION_TITLE_INSTRUCTIONS;
|
||||
return;
|
||||
}
|
||||
|
||||
// Si no hi ha dades carregades, sortim al menu
|
||||
if (demo_.data.empty()) {
|
||||
section_->name = SECTION_PROG_TITLE;
|
||||
return;
|
||||
}
|
||||
|
||||
// Accedeix al frame actual del set seleccionat amb % per seguretat
|
||||
// davant de salts puntuals d'index.
|
||||
const auto &dd = demo_.data.at(demo_selected_set_ % demo_.data.size());
|
||||
if (dd.empty()) {
|
||||
return;
|
||||
}
|
||||
const DemoKeys &keys = dd.at(static_cast<size_t>(demo_.index) % dd.size());
|
||||
|
||||
if (keys.left == 1) {
|
||||
players_[INDEX]->setInput(Input::Action::LEFT);
|
||||
@@ -2479,18 +2503,10 @@ void Game::processDemoInput() {
|
||||
players_[INDEX]->setFireCooldown(10);
|
||||
}
|
||||
|
||||
// Si se pulsa cualquier tecla, se sale del modo demo
|
||||
// Si es prem qualsevol tecla, surt del mode demo
|
||||
if (Input::get()->checkAnyInput()) {
|
||||
section_->name = SECTION_PROG_TITLE;
|
||||
}
|
||||
|
||||
// Incrementa el contador de la demo
|
||||
if (demo_.counter < TOTAL_DEMO_DATA) {
|
||||
demo_.counter++;
|
||||
} else {
|
||||
section_->name = SECTION_PROG_TITLE;
|
||||
section_->subsection = SUBSECTION_TITLE_INSTRUCTIONS;
|
||||
}
|
||||
}
|
||||
|
||||
// Rama de checkGameInput: lee inputs reales del teclado/gamepad por jugador
|
||||
@@ -2553,14 +2569,22 @@ void Game::processPlayerLiveInput(Player *player, int i) {
|
||||
section_->subsection = SUBSECTION_GAME_PAUSE;
|
||||
}
|
||||
|
||||
// Grabación de demo
|
||||
if (demo_.counter < TOTAL_DEMO_DATA) {
|
||||
if (demo_.recording) {
|
||||
demo_.data_file[demo_.counter] = demo_.keys;
|
||||
// Gravacio de demo (mode recording). L'index ja s'ha actualitzat a
|
||||
// Game::update() via elapsed_s; aqui nomes escrivim el frame actual al
|
||||
// primer set, redimensionant on demand.
|
||||
if (demo_.recording) {
|
||||
if (demo_.index >= TOTAL_DEMO_DATA) {
|
||||
section_->name = SECTION_PROG_QUIT;
|
||||
} else {
|
||||
if (demo_.data.empty()) {
|
||||
demo_.data.emplace_back();
|
||||
}
|
||||
auto &dd = demo_.data.at(0);
|
||||
if (dd.size() <= static_cast<size_t>(demo_.index)) {
|
||||
dd.resize(demo_.index + 1);
|
||||
}
|
||||
dd.at(demo_.index) = demo_.keys;
|
||||
}
|
||||
demo_.counter++;
|
||||
} else if (demo_.recording) {
|
||||
section_->name = SECTION_PROG_QUIT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2590,7 +2614,7 @@ void Game::renderMessages() {
|
||||
|
||||
// D E M O
|
||||
if (demo_.enabled) {
|
||||
if (demo_.counter % 30 > 14) {
|
||||
if (demo_.index % 30 > 14) {
|
||||
text_nokia_big2_->writeDX(Text::FLAG_CENTER, PLAY_AREA_CENTER_X, PLAY_AREA_FIRST_QUARTER_Y, Lang::get()->getText(37), 0, NO_COLOR, 2, SHADOW_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user