From 5aca78a38e44684fc2ec79df3240030b96fe3591 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Fri, 15 May 2026 21:04:36 +0200 Subject: [PATCH] DX: game over amb typewriter, cuadre de fons i Pepe trist --- config.lua | 9 +++- pepe_runner_dx.lua | 103 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 97 insertions(+), 15 deletions(-) diff --git a/config.lua b/config.lua index 183ec1f..b9481ec 100644 --- a/config.lua +++ b/config.lua @@ -44,7 +44,7 @@ skin = "pintor" -- (Convencio: Inicial Majuscula, resta minuscula.) -- textos.title_press_play = "Prem l'espai per a jugar" --- textos.game_over = "Fi de joc" +-- textos.game_over = "FI DE JOC" -- textos.new_record = "Nou record !" -- textos.score_label = "Punts" -- textos.level_label = "Nivell" @@ -71,6 +71,13 @@ skin = "pintor" -- -- respawn, parpadejant blanc/groc. -- temps.escala_step_frames = 6 -- frames entre cada cel·la nova de -- -- l'escala lateral quan creix. +-- temps.gameover_delay_frames = 80 -- espera abans del typewriter de +-- -- "FI DE JOC" (per a que no es +-- -- solape amb sfx_gameover). +-- temps.typewriter_step_frames = 6 -- frames per cada lletra del +-- -- typewriter al game over. +-- temps.gameover_show_frames = 60 -- temps que el text final es queda +-- -- visible abans de la transicio. -- ==================================================================== -- JINGLES diff --git a/pepe_runner_dx.lua b/pepe_runner_dx.lua index 40712a2..b0e2328 100644 --- a/pepe_runner_dx.lua +++ b/pepe_runner_dx.lua @@ -69,7 +69,7 @@ keys = { -- Tots en sentence case (Inicial Majuscula, resta minuscula). textos = { title_press_play = "Prem l'espai per a jugar", - game_over = "Fi de joc", + game_over = "FI DE JOC", new_record = "Nou record !", score_label = "Punts", -- HUD i pantalla de nou record level_label = "Nivell", @@ -96,7 +96,14 @@ NUM_MALOS = 3 TEMPS_IA = 30 -- iteracions del malo entre canvis de direccio MALO_RATIO = 4 -- els malos van 1/4 del ritme del Pepe (com en RUNNER.PAS) NUM_FASES = 10 -- mapes 1..10 (el 0 esta reservat per al titol) -VIDES_INI = 3 -- l'original arrancava amb 0 (1 vida); 3 es mes raonable +-- VIDES_INI = nombre de reserves (convencio arcade: el HUD mostra reserves, +-- no compta la vida actual). 2 reserves = 3 vides totals (1 actual + 2). +-- L'original arrancava amb 0 (= 1 vida total). +-- TEMPORAL DEBUG: posa'l a 0 per a provar la seqüencia de game over rapid. +VIDES_INI = 0 +-- LEVEL_INI = fase per la que arranca la partida nova (1..NUM_FASES). +-- Util per a depuracio i per a saltar al mapa que vols provar. +LEVEL_INI = 3 -- Tots els temps i durations de les animacions del DX. Sobreescriuibles -- per config.lua (en frames a 60 fps; 60 = 1 segon). @@ -107,6 +114,9 @@ temps = { respawn_delay_frames = 120, -- temps que Pepe queda invisible abans del respawn (2 s) invuln_frames = 180, -- temps invulnerable despres del respawn (3 s) escala_step_frames = 6, -- frames entre cada cel·la nova de l'escala lateral (0.1 s) + gameover_delay_frames = 15, -- espera al entrar a game over abans d'engegar el typewriter + typewriter_step_frames = 8, -- frames per cada lletra del typewriter de "FI DE JOC" + gameover_show_frames = 120, -- frames que el text final queda visible abans de la transicio } -- Estats del joc (maquina d'estats global) @@ -297,6 +307,7 @@ function sfx_die() play("l1o4cl0o3bagfed") end function sfx_malo_die() play("l0o3ao4c") end function sfx_level() play("l1o4ceg") end function sfx_gameover() play("l1o3bal0gfedco2c") end +function sfx_typewriter() sound(2500, 2) end -- tic agut i molt curt per a cada lletra -- Neteja la pantalla amb el color de fons configurat (en lloc de negre). function neteja_fons() @@ -376,16 +387,38 @@ function pintar_pepe() local col = colors.pepe local g = glif[pepe.dibuix] + -- En game over, Pepe queda visible amb la cara trista alternant A/B + -- (parpadeig amb cnt() perque mort_t ja no es decrementa fora de playing). + if estat_joc == ESTAT_GAMEOVER then + if (cnt() % 12) < 6 then + g = glif[PEPE_MORT_A] + col = colors.pepe_mort_a + else + g = glif[PEPE_MORT_B] + col = colors.pepe_mort_b + end + color(col, colors.bg) + print(chr(g), pepe.x, pepe.y) + return + end + if pepe.mort_t > 0 then + -- En l'ultima vida no hi ha respawn_delay: tot el countdown es anim. + local mort_t_max + if pepe.vides == 0 then + mort_t_max = temps.mort_anim_frames + else + mort_t_max = temps.mort_anim_frames + temps.respawn_delay_frames + end + -- Fase d'espera (Pepe invisible, mapa segueix viu): no pintem res. - if pepe.mort_t <= temps.respawn_delay_frames then return end + local fase = mort_t_max - pepe.mort_t -- 0..mort_t_max-1 + if fase >= temps.mort_anim_frames then return end -- Animacio visual de mort, en dos trams desproporcionats (1/4 + 3/4): -- tram curt: parpadeja blanc/roig amb la cara normal del Pepe. -- tram llarg: alterna entre els dos sprites de mort de la skin -- (pepe_mort_a / pepe_mort_b), cada un amb el seu color propi. - local fase = (temps.mort_anim_frames + temps.respawn_delay_frames) - - pepe.mort_t -- 0..mort_anim_frames-1 local tram_curt = flr(temps.mort_anim_frames / 4) if fase < tram_curt then col = (fase % 6 < 3) and colors.malo or colors.pepe @@ -500,12 +533,21 @@ end -- Inicia l'animacio de mort. El timer mort_t cobreix dos trams seguits: -- [delay+1 .. delay+anim] → animacio visual de Pepe morint -- [1 .. delay] → Pepe invisible, mapa segueix viu (pausa) +-- Si es l'ultima vida (vides==0), saltem el delay: l'animacio termina i +-- anem directament a game over, sense pausa invisible. -- Al arribar a 0, update_playing descompta vida i fa el respawn. -- Guarda contra reentrada per a no reiniciar si ja esta morint. function mort_pepe() if pepe.mort_t > 0 then return end - pepe.mort_t = temps.mort_anim_frames + temps.respawn_delay_frames - sfx_die() + if pepe.vides == 0 then + -- Ultima vida: directament sona sfx_gameover (no sfx_die seguit de + -- sfx_gameover, eren molt semblants i es solapaven com a doble eco). + pepe.mort_t = temps.mort_anim_frames + sfx_gameover() + else + pepe.mort_t = temps.mort_anim_frames + temps.respawn_delay_frames + sfx_die() + end end -- Reposiciona Pepe al spawn i activa la invulnerabilitat. @@ -519,7 +561,7 @@ end -- Inicialitza tot per a una nova partida (reset complet) function inicialitzacio() - level = 1 + level = LEVEL_INI score = 0 score_display = 0 pepe.vides = VIDES_INI @@ -626,20 +668,53 @@ end -- ----- GAME OVER ----- function update_gameover() set_music(nil) - -- Render congelat: ultim estat del joc + overlay "GAME OVER" + -- Render congelat: mapa + malos + Pepe trist (pintar_pepe detecta l'estat) neteja_fons() pintar_mapa() pintar_malos() pintar_pepe() - color(colors.title, colors.bg) + -- Typewriter: les lletres apareixen una a una despres d'un petit delay + -- inicial perque no es solapin amb la sonoritat de sfx_gameover(). + -- Aban apareix un cuadre de fons (strlen+2 × 3) per a aillar el text + -- del mapa que queda darrere. local g = textos.game_over - print(g, flr((40 - strlen(g)) / 2), 12) + local t = temps_estat() - temps.gameover_delay_frames + if t >= 0 then + local total_chars = strlen(g) + local frames_typewriter = total_chars * temps.typewriter_step_frames + local text_x = flr((40 - total_chars) / 2) + local text_y = 12 + + -- Cuadre de fons: una fila per damunt i una per davall del text, + -- i una columna a cada costat. Es pinta primer per a que el text + -- quede a sobre. + local box_w = total_chars + 2 + color(colors.hud_bg, colors.hud_bg) + local blank = string.rep(" ", box_w) + for dy = -1, 1 do print(blank, text_x - 1, text_y + dy) end + + -- Lletres del typewriter + local nletres = flr(t / temps.typewriter_step_frames) + 1 + if nletres > total_chars then nletres = total_chars end + color(colors.title, colors.hud_bg) + print(substr(g, 0, nletres), text_x, text_y) + + -- Tic nomes en el frame en que apareix una lletra nova, i nomes + -- mentre el typewriter encara escriu (no en bucle infinit). + if t < frames_typewriter and (t % temps.typewriter_step_frames) == 0 then + sfx_typewriter() + end + end pintar_hud() - -- Despres de 2 segons (120 frames), transicio a title o entername - if not fade_actiu() and temps_estat() > 120 then + -- Quan el typewriter ha acabat i el text ha estat visible un temps, + -- transicionem a title o a la pantalla d'entrar nom (si hi ha record). + local total = temps.gameover_delay_frames + + strlen(g) * temps.typewriter_step_frames + + temps.gameover_show_frames + if not fade_actiu() and temps_estat() > total then if score > hi_score then transicio(function() hi_score = score @@ -708,7 +783,7 @@ function update_playing() if pepe.mort_t == 0 then pepe.vides = pepe.vides - 1 if pepe.vides < 0 then - sfx_gameover() + -- sfx_gameover ja s'ha tocat al inici de l'animacio (mort_pepe) set_estat(ESTAT_GAMEOVER) return end