Estructura DX i escena logo JAILGAMES animada
This commit is contained in:
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 118 B |
@@ -0,0 +1,21 @@
|
||||
-- Logo JAILGAMES — bitmap monocromatic 35x5 extret de art/jailgames.gif.
|
||||
--
|
||||
-- '#' = pixel actiu (color del logo)
|
||||
-- '.' = pixel inactiu (fons negre)
|
||||
--
|
||||
-- L'escena 'logo' col.loca aquest bitmap a (origen_x, origen_y) i en
|
||||
-- gestiona l'animacio (entrada per columnes + estable + fade-out).
|
||||
|
||||
return {
|
||||
origen_x = 2,
|
||||
origen_y = 12,
|
||||
width = 35,
|
||||
height = 5,
|
||||
files = {
|
||||
"..#.###.#.#...###.###.#...#.###.###",
|
||||
"..#.#.#.#.#...#...#.#.##.##.#...#..",
|
||||
"..#.#.#.#.#...#.#.#.#.#.#.#.###.###",
|
||||
"..#.###.#.#...#.#.###.#...#.#.....#",
|
||||
"###.#.#.#.###.###.#.#.#...#.###.###",
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
-- Glifs personalitzats compartits per totes les escenes.
|
||||
--
|
||||
-- Cada glif es defineix com 8 bytes (files de 8 px, MSB esquerra). Ens
|
||||
-- reservem el rang 1..15 (caracters de control que no usem) per als
|
||||
-- glifs propis del joc. Aixi no pisem caracters del CP437 que despres
|
||||
-- voldrem imprimir en text.
|
||||
|
||||
local M = {}
|
||||
|
||||
-- Codis simbolics per evitar magic numbers en la resta del codi.
|
||||
-- IMPORTANT: la ROM d'ascii NO es CP437 estandar — chr(176..178) son
|
||||
-- lletres gregues i chr(219) es un patro quadriculat, no els shades
|
||||
-- esperats. Per aixo redefinim els shades nosaltres a un rang lliure.
|
||||
M.PEPE = 1 -- contorn de pinguinet (Pepe)
|
||||
M.MALO = 2 -- enemic
|
||||
M.POT = 3 -- pot de pintura
|
||||
M.GOTA = 4 -- gota caient
|
||||
M.ARR_AMUNT = 5
|
||||
M.ARR_AVALL = 6
|
||||
M.ARR_ESQ = 7
|
||||
M.ARR_DRETA = 8
|
||||
M.SHADE_25 = 9 -- equivalent a CP437 chr(176) — trama clara
|
||||
M.SHADE_50 = 10 -- equivalent a CP437 chr(177) — trama escacs
|
||||
M.SHADE_75 = 11 -- equivalent a CP437 chr(178) — trama densa
|
||||
M.BLOCK = 12 -- equivalent a CP437 chr(219) — bloc ple
|
||||
|
||||
-- Bitmaps. Cada fila es un byte (8 px). 1 = pixel encés.
|
||||
local BITMAPS = {
|
||||
[M.PEPE] = {
|
||||
0x18, -- ..XX....
|
||||
0x3C, -- .XXXX...
|
||||
0x3C, -- .XXXX...
|
||||
0x18, -- ..XX....
|
||||
0x7E, -- .XXXXXX.
|
||||
0x18, -- ..XX....
|
||||
0x24, -- ..X..X..
|
||||
0x42, -- .X....X.
|
||||
},
|
||||
[M.MALO] = {
|
||||
0x3C,
|
||||
0x66,
|
||||
0xDB, -- ulls
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xDB,
|
||||
0x66,
|
||||
0x3C,
|
||||
},
|
||||
[M.POT] = {
|
||||
0x00,
|
||||
0x7E, -- vora superior
|
||||
0x42,
|
||||
0x42,
|
||||
0x42,
|
||||
0x42,
|
||||
0x7E,
|
||||
0x00,
|
||||
},
|
||||
[M.GOTA] = {
|
||||
0x00,
|
||||
0x18,
|
||||
0x18,
|
||||
0x3C,
|
||||
0x3C,
|
||||
0x18,
|
||||
0x00,
|
||||
0x00,
|
||||
},
|
||||
[M.ARR_AMUNT] = {
|
||||
0x18, 0x3C, 0x7E, 0xFF,
|
||||
0x18, 0x18, 0x18, 0x00,
|
||||
},
|
||||
[M.ARR_AVALL] = {
|
||||
0x00, 0x18, 0x18, 0x18,
|
||||
0xFF, 0x7E, 0x3C, 0x18,
|
||||
},
|
||||
[M.ARR_ESQ] = {
|
||||
0x00, 0x10, 0x30, 0x7F,
|
||||
0x7F, 0x30, 0x10, 0x00,
|
||||
},
|
||||
[M.ARR_DRETA] = {
|
||||
0x00, 0x08, 0x0C, 0xFE,
|
||||
0xFE, 0x0C, 0x08, 0x00,
|
||||
},
|
||||
|
||||
-- Shades CP437 per a fades. Patrons alternats de bits.
|
||||
[M.SHADE_25] = {
|
||||
0x88, 0x22, 0x88, 0x22,
|
||||
0x88, 0x22, 0x88, 0x22,
|
||||
},
|
||||
[M.SHADE_50] = {
|
||||
0x55, 0xAA, 0x55, 0xAA,
|
||||
0x55, 0xAA, 0x55, 0xAA,
|
||||
},
|
||||
[M.SHADE_75] = {
|
||||
0x77, 0xDD, 0x77, 0xDD,
|
||||
0x77, 0xDD, 0x77, 0xDD,
|
||||
},
|
||||
[M.BLOCK] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
},
|
||||
}
|
||||
|
||||
function M.instala()
|
||||
for codi, fila in pairs(BITMAPS) do
|
||||
setchar(codi,
|
||||
fila[1], fila[2], fila[3], fila[4],
|
||||
fila[5], fila[6], fila[7], fila[8])
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,71 @@
|
||||
-- Funcions de suavitzat — entrada t in [0, 1], sortida ~[0, 1].
|
||||
-- Algunes (back/bounce) poden sortir de [0,1] temporalment.
|
||||
--
|
||||
-- Referencia: https://easings.net (versions clausurades algebraicament)
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.linear(t)
|
||||
return t
|
||||
end
|
||||
|
||||
function M.inQuad(t)
|
||||
return t * t
|
||||
end
|
||||
|
||||
function M.outQuad(t)
|
||||
local u = 1 - t
|
||||
return 1 - u * u
|
||||
end
|
||||
|
||||
function M.inOutQuad(t)
|
||||
if t < 0.5 then
|
||||
return 2 * t * t
|
||||
else
|
||||
local u = 2 * (1 - t)
|
||||
return 1 - 0.5 * u * u
|
||||
end
|
||||
end
|
||||
|
||||
function M.inCubic(t)
|
||||
return t * t * t
|
||||
end
|
||||
|
||||
function M.outCubic(t)
|
||||
local u = 1 - t
|
||||
return 1 - u * u * u
|
||||
end
|
||||
|
||||
-- Botet: cau, rebota, cau, rebota mes petit, ... fins quedar-se.
|
||||
function M.outBounce(t)
|
||||
local n = 7.5625
|
||||
local d = 2.75
|
||||
if t < 1/d then
|
||||
return n * t * t
|
||||
elseif t < 2/d then
|
||||
local u = t - 1.5/d
|
||||
return n * u * u + 0.75
|
||||
elseif t < 2.5/d then
|
||||
local u = t - 2.25/d
|
||||
return n * u * u + 0.9375
|
||||
else
|
||||
local u = t - 2.625/d
|
||||
return n * u * u + 0.984375
|
||||
end
|
||||
end
|
||||
|
||||
-- Overshoot (es passa del valor i torna).
|
||||
function M.outBack(t)
|
||||
local c1 = 1.70158
|
||||
local c3 = c1 + 1
|
||||
local u = t - 1
|
||||
return 1 + c3 * u * u * u + c1 * u * u
|
||||
end
|
||||
|
||||
function M.inBack(t)
|
||||
local c1 = 1.70158
|
||||
local c3 = c1 + 1
|
||||
return c3 * t * t * t - c1 * t * t
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,63 @@
|
||||
-- Input modern — wrappers per btn/btnp amb un mapejat unic d'accions.
|
||||
--
|
||||
-- Cada accio te una llista de tecles (perque l'usuari puga jugar amb
|
||||
-- fletxes o amb O P Q A indistintament). En cada frame guardem l'estat
|
||||
-- 'held' (mante premut) i 'pressed' (acaba de ser premut). Aixi les
|
||||
-- escenes no han de saber res de KEY_*.
|
||||
|
||||
local M = {}
|
||||
|
||||
M.accions = {
|
||||
amunt = { KEY_UP, KEY_Q },
|
||||
avall = { KEY_DOWN, KEY_A },
|
||||
esq = { KEY_LEFT, KEY_O },
|
||||
dreta = { KEY_RIGHT, KEY_P },
|
||||
accept = { KEY_RETURN, KEY_SPACE, KEY_KP_ENTER },
|
||||
cancel = { KEY_ESCAPE },
|
||||
}
|
||||
|
||||
M.held = {}
|
||||
M.pressed = {}
|
||||
|
||||
local function qualsevol_btn(tecles)
|
||||
for i = 1, #tecles do
|
||||
if btn(tecles[i]) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function qualsevol_btnp(tecles)
|
||||
for i = 1, #tecles do
|
||||
if btnp(tecles[i]) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function M.reset()
|
||||
for nom, _ in pairs(M.accions) do
|
||||
M.held[nom] = false
|
||||
M.pressed[nom] = false
|
||||
end
|
||||
end
|
||||
|
||||
function M.tick()
|
||||
for nom, tecles in pairs(M.accions) do
|
||||
M.held[nom] = qualsevol_btn(tecles)
|
||||
M.pressed[nom] = qualsevol_btnp(tecles)
|
||||
end
|
||||
end
|
||||
|
||||
-- Helpers per a les escenes — mes legibles que llegir taules directament.
|
||||
function M.es_mante(accio) return M.held[accio] == true end
|
||||
function M.acaba_premuda(accio) return M.pressed[accio] == true end
|
||||
|
||||
-- Per a la pantalla titol/logo: «qualsevol tecla» per avançar.
|
||||
local TECLES_AVANCAR = { KEY_RETURN, KEY_SPACE, KEY_KP_ENTER,
|
||||
KEY_O, KEY_P, KEY_Q, KEY_A,
|
||||
KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT }
|
||||
|
||||
function M.qualsevol_tecla()
|
||||
return qualsevol_btnp(TECLES_AVANCAR)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,49 @@
|
||||
-- Maquina d'escenes (FSM simple).
|
||||
--
|
||||
-- Cada escena es una taula amb les funcions opcionals:
|
||||
-- entra(servicis, args) -- en activar-se (rep els servicis globals)
|
||||
-- ix() -- en eixir (per netejar timers, etc)
|
||||
-- update(dt) -- per frame, amb delta en segons
|
||||
-- draw() -- per frame, despres d'update()
|
||||
--
|
||||
-- El motor d'ascii no separa update i draw; ho fem aci nosaltres per
|
||||
-- mantindre el codi de cada escena ordenat.
|
||||
|
||||
local M = {}
|
||||
|
||||
M.servicis = {} -- injectat des de main.lua
|
||||
M.escenes = {} -- nom -> escena
|
||||
M.actual = nil -- escena activa
|
||||
|
||||
function M.registra(nom, escena)
|
||||
M.escenes[nom] = escena
|
||||
end
|
||||
|
||||
function M.canvia(nom, args)
|
||||
local seguent = M.escenes[nom]
|
||||
if not seguent then
|
||||
log("[manager] escena desconeguda: "..tostr(nom))
|
||||
return
|
||||
end
|
||||
if M.actual and M.actual.ix then
|
||||
M.actual.ix()
|
||||
end
|
||||
M.actual = seguent
|
||||
if M.actual.entra then
|
||||
M.actual.entra(M.servicis, args or {})
|
||||
end
|
||||
end
|
||||
|
||||
function M.update(dt)
|
||||
if M.actual and M.actual.update then
|
||||
M.actual.update(dt)
|
||||
end
|
||||
end
|
||||
|
||||
function M.draw()
|
||||
if M.actual and M.actual.draw then
|
||||
M.actual.draw()
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,33 @@
|
||||
-- Delta time helper.
|
||||
--
|
||||
-- L'ascii no exposa delta directament. Calculem en cada frame el temps
|
||||
-- transcorregut amb time() (ms des d'inici). El primer frame retornem 0
|
||||
-- per evitar salts grans, i clampem dt a 1/15 s per protegir-nos de
|
||||
-- pauses (ESC -> consola) o stalls.
|
||||
|
||||
local M = {}
|
||||
|
||||
local DT_MAX = 1.0 / 15.0 -- 66 ms; un parell de frames a 30 fps
|
||||
|
||||
local last_ms = 0
|
||||
local first = true
|
||||
|
||||
function M.reset()
|
||||
last_ms = time()
|
||||
first = true
|
||||
end
|
||||
|
||||
function M.tick()
|
||||
local now = time()
|
||||
local dt = (now - last_ms) / 1000.0
|
||||
last_ms = now
|
||||
if first then
|
||||
first = false
|
||||
return 0.0
|
||||
end
|
||||
if dt > DT_MAX then dt = DT_MAX end
|
||||
if dt < 0 then dt = 0 end
|
||||
return dt
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,49 @@
|
||||
-- Pepe Pintor DX — punt d'entrada
|
||||
-- Carrega els moduls i delega a la maquina d'escenes.
|
||||
|
||||
local BASE = "pepe_pintor_dx/"
|
||||
|
||||
local manager = dofile(BASE.."lib/manager.lua")
|
||||
local timing = dofile(BASE.."lib/timing.lua")
|
||||
local input = dofile(BASE.."lib/input.lua")
|
||||
local glyphs = dofile(BASE.."glyphs.lua")
|
||||
|
||||
-- Les escenes es carreguen una sola volta i es registren al manager
|
||||
-- per nom. Aixi qualsevol escena pot saltar a una altra sense passar
|
||||
-- referencies a mig codi.
|
||||
local escena_logo = dofile(BASE.."scenes/logo.lua")
|
||||
local escena_titol = dofile(BASE.."scenes/titol.lua")
|
||||
local escena_joc = dofile(BASE.."scenes/joc.lua")
|
||||
|
||||
manager.registra("logo", escena_logo)
|
||||
manager.registra("titol", escena_titol)
|
||||
manager.registra("joc", escena_joc)
|
||||
|
||||
-- Servicis injectats a totes les escenes — aixi no han de tornar
|
||||
-- a fer dofile() del manager/input/timing.
|
||||
manager.servicis = {
|
||||
manager = manager,
|
||||
input = input,
|
||||
timing = timing,
|
||||
glyphs = glyphs,
|
||||
}
|
||||
|
||||
function init()
|
||||
mode(1)
|
||||
border(COLOR_BLACK)
|
||||
color(COLOR_WHITE, COLOR_BLACK)
|
||||
cls()
|
||||
|
||||
glyphs.instala()
|
||||
timing.reset()
|
||||
input.reset()
|
||||
|
||||
manager.canvia("logo")
|
||||
end
|
||||
|
||||
function update()
|
||||
local dt = timing.tick()
|
||||
input.tick()
|
||||
manager.update(dt)
|
||||
manager.draw()
|
||||
end
|
||||
@@ -0,0 +1,49 @@
|
||||
-- Escena 'joc' — gameplay.
|
||||
--
|
||||
-- PLACEHOLDER. La intencio es mantindre la mecanica fidel (pintar terra,
|
||||
-- enemics que te perseguixen pel terra pintat, recarrega al pot) pero
|
||||
-- amb tota la implementacio nova: moviment per delta time, FSM interna
|
||||
-- per a fases / mort / fade-ins, etc.
|
||||
--
|
||||
-- Per ara nomes mostra que has entrat al joc i et deixa tornar al titol
|
||||
-- amb ESC, per a poder provar la cadena d'escenes sense haver-ho fet
|
||||
-- tot encara.
|
||||
|
||||
local M = {}
|
||||
|
||||
local manager, input
|
||||
local temps = 0
|
||||
|
||||
function M.entra(servicis, _args)
|
||||
manager = servicis.manager
|
||||
input = servicis.input
|
||||
temps = 0
|
||||
end
|
||||
|
||||
function M.update(dt)
|
||||
temps = temps + dt
|
||||
if input.acaba_premuda("cancel") then
|
||||
manager.canvia("titol")
|
||||
end
|
||||
end
|
||||
|
||||
function M.draw()
|
||||
color(COLOR_WHITE, COLOR_BLACK)
|
||||
cls()
|
||||
|
||||
color(COLOR_LIGHT_GREEN, COLOR_BLACK)
|
||||
print("[ ESCENA JOC ]", 13, 4)
|
||||
|
||||
color(COLOR_LIGHT_GRAY, COLOR_BLACK)
|
||||
print("Aci anira el gameplay DX.", 7, 10)
|
||||
print("Pendent: motor de pintura,", 7, 12)
|
||||
print("enemics, fases, FSM interna.", 7, 13)
|
||||
|
||||
color(COLOR_DARK_GRAY, COLOR_BLACK)
|
||||
print("ESC = tornar al titol", 9, 22)
|
||||
|
||||
color(COLOR_DARK_GRAY, COLOR_BLACK)
|
||||
print(string.format("temps: %.1fs", temps), 1, 28)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,253 @@
|
||||
-- Escena 'logo' — splash JAILGAMES amb animacio.
|
||||
--
|
||||
-- Tres fases:
|
||||
-- ENTRADA -> les 9 lletres entren des de direccions diferents
|
||||
-- (esquerra, dreta, dalt, baix), esglaonades, amb easings
|
||||
-- variats. Una vegada al lloc, queden quietes.
|
||||
-- ESTABLE -> 4 s totalment quiet, logo blanc ple.
|
||||
-- FADE_OUT -> rampa combinada char+paleta de 8 nivells:
|
||||
-- blanc -> groc -> rosa -> vermell -> magenta -> blau
|
||||
-- -> gris fosc -> negre, mentre el char passa de BLOCK
|
||||
-- -> SHADE_75 -> SHADE_50 -> SHADE_25 -> espai.
|
||||
--
|
||||
-- Premer tecla durant ENTRADA o ESTABLE salta al fade. Quan acaba el
|
||||
-- fade, salta a 'titol'.
|
||||
--
|
||||
-- Notes sobre el fade CGA: no recorrem els 16 indexs en ordre lineal.
|
||||
-- Triem una rampa tematica (warm -> cool -> dark) que es el patro
|
||||
-- classic d'apagada de monitor CRT, combinada amb difuminat del char
|
||||
-- per a mes pasos perceptuals (l'ull veu el conjunt com una rampa
|
||||
-- d'intensitat continua).
|
||||
|
||||
local M = {}
|
||||
|
||||
local logo = dofile("pepe_pintor_dx/data/logo.lua")
|
||||
local easing = dofile("pepe_pintor_dx/lib/easing.lua")
|
||||
|
||||
-- Timings
|
||||
local T_PREVI = 1.0 -- pantalla negra abans que comencin a entrar
|
||||
local T_FALL = 0.65 -- durada de l'entrada d'una lletra
|
||||
local T_DELAY = 0.09 -- delay entre lletres consecutives
|
||||
local T_ESTABLE = 2.0
|
||||
local T_FADE = 0.4
|
||||
local T_POST = 1.0 -- pantalla negra despres del fade, abans de saltar
|
||||
|
||||
local FASE_ENTRADA = 1
|
||||
local FASE_ESTABLE = 2
|
||||
local FASE_FADE_OUT = 3
|
||||
local FASE_POST = 4
|
||||
|
||||
-- Lletres del logo com a rangs de columnes del bitmap 35-wide (1-based).
|
||||
local SEGMENTS = {
|
||||
{ c0 = 1, c1 = 3, nom = "J" },
|
||||
{ c0 = 5, c1 = 7, nom = "A" },
|
||||
{ c0 = 9, c1 = 9, nom = "I" },
|
||||
{ c0 = 11, c1 = 13, nom = "L" },
|
||||
{ c0 = 15, c1 = 17, nom = "G" },
|
||||
{ c0 = 19, c1 = 21, nom = "A" },
|
||||
{ c0 = 23, c1 = 27, nom = "M" },
|
||||
{ c0 = 29, c1 = 31, nom = "E" },
|
||||
{ c0 = 33, c1 = 35, nom = "S" },
|
||||
}
|
||||
|
||||
-- Origen i easing per lletra. (dx, dy) son l'offset inicial respecte
|
||||
-- a la posicio final. fn es l'easing a aplicar al progres [0,1].
|
||||
-- Esquerra del logo (1-3) ve de l'esquerra; centre (4-6) ve vertical;
|
||||
-- dreta (7-9) ve de la dreta. Simetric pero no monoton.
|
||||
local ORIGENS = {}
|
||||
local function inicialitza_origens()
|
||||
ORIGENS = {
|
||||
{ dx = -32, dy = 0, fn = easing.outCubic }, -- J <-
|
||||
{ dx = -28, dy = 0, fn = easing.outCubic }, -- A <-
|
||||
{ dx = -24, dy = 0, fn = easing.outCubic }, -- I <-
|
||||
{ dx = 0, dy = -18, fn = easing.outBounce }, -- L v
|
||||
{ dx = 0, dy = 20, fn = easing.outBack }, -- G ^
|
||||
{ dx = 0, dy = -18, fn = easing.outBounce }, -- A v
|
||||
{ dx = 24, dy = 0, fn = easing.outCubic }, -- M ->
|
||||
{ dx = 28, dy = 0, fn = easing.outCubic }, -- E ->
|
||||
{ dx = 32, dy = 0, fn = easing.outCubic }, -- S ->
|
||||
}
|
||||
end
|
||||
|
||||
-- Rampa de fade: 8 nivells. Construida a entra() perque depen de
|
||||
-- glyphs.* (no disponibles al carregar el modul).
|
||||
local RAMPA
|
||||
local NIVELL_MAX = 7
|
||||
|
||||
local function inicialitza_rampa(glyphs)
|
||||
RAMPA = {
|
||||
[7] = { codi = glyphs.BLOCK, ink = COLOR_WHITE },
|
||||
[6] = { codi = glyphs.BLOCK, ink = COLOR_YELLOW },
|
||||
[5] = { codi = glyphs.SHADE_75, ink = COLOR_LIGHT_RED },
|
||||
[4] = { codi = glyphs.SHADE_75, ink = COLOR_RED },
|
||||
[3] = { codi = glyphs.SHADE_50, ink = COLOR_MAGENTA },
|
||||
[2] = { codi = glyphs.SHADE_50, ink = COLOR_BLUE },
|
||||
[1] = { codi = glyphs.SHADE_25, ink = COLOR_BLUE },
|
||||
[0] = { codi = 32, ink = COLOR_BLACK },
|
||||
}
|
||||
end
|
||||
|
||||
local manager, input, glyphs
|
||||
local lletres = {}
|
||||
local fase = FASE_ENTRADA
|
||||
local temps = 0
|
||||
local nivell_actual = NIVELL_MAX
|
||||
local total_entrada = 0
|
||||
|
||||
local function construeix_lletres()
|
||||
lletres = {}
|
||||
for i, seg in ipairs(SEGMENTS) do
|
||||
local px = {}
|
||||
for r = 1, logo.height do
|
||||
local fila = logo.files[r]
|
||||
for c = seg.c0, seg.c1 do
|
||||
if string.sub(fila, c, c) == "#" then
|
||||
px[#px + 1] = { rx = c - seg.c0, ry = r - 1 }
|
||||
end
|
||||
end
|
||||
end
|
||||
local origen = ORIGENS[i]
|
||||
lletres[i] = {
|
||||
base_x = logo.origen_x + (seg.c0 - 1),
|
||||
base_y = logo.origen_y,
|
||||
pixels = px,
|
||||
ox = origen.dx,
|
||||
oy = origen.dy,
|
||||
dx = origen.dx,
|
||||
dy = origen.dy,
|
||||
fn = origen.fn,
|
||||
delay = T_PREVI + (i - 1) * T_DELAY,
|
||||
arribada = false, -- una vegada true, ja no toquem dx/dy
|
||||
}
|
||||
end
|
||||
total_entrada = T_PREVI + (#SEGMENTS - 1) * T_DELAY + T_FALL
|
||||
end
|
||||
|
||||
function M.entra(servicis, _args)
|
||||
manager = servicis.manager
|
||||
input = servicis.input
|
||||
glyphs = servicis.glyphs
|
||||
|
||||
fase = FASE_ENTRADA
|
||||
temps = 0
|
||||
nivell_actual = NIVELL_MAX
|
||||
|
||||
inicialitza_origens()
|
||||
inicialitza_rampa(glyphs)
|
||||
construeix_lletres()
|
||||
|
||||
color(COLOR_WHITE, COLOR_BLACK)
|
||||
cls()
|
||||
end
|
||||
|
||||
local function salta_a_fade()
|
||||
fase = FASE_FADE_OUT
|
||||
temps = 0
|
||||
-- forcem que totes les lletres estiguin a casa, no es mouen mes
|
||||
for _, l in ipairs(lletres) do
|
||||
l.dx = 0
|
||||
l.dy = 0
|
||||
l.arribada = true
|
||||
end
|
||||
end
|
||||
|
||||
local function update_entrada()
|
||||
local totes_acabades = true
|
||||
for _, l in ipairs(lletres) do
|
||||
if not l.arribada then
|
||||
local tl = temps - l.delay
|
||||
if tl < 0 then
|
||||
l.dx, l.dy = l.ox, l.oy
|
||||
totes_acabades = false
|
||||
elseif tl < T_FALL then
|
||||
local p = tl / T_FALL
|
||||
local e = l.fn(p)
|
||||
l.dx = l.ox * (1 - e)
|
||||
l.dy = l.oy * (1 - e)
|
||||
totes_acabades = false
|
||||
else
|
||||
l.dx, l.dy = 0, 0
|
||||
l.arribada = true
|
||||
end
|
||||
end
|
||||
end
|
||||
if totes_acabades then
|
||||
fase = FASE_ESTABLE
|
||||
temps = 0
|
||||
end
|
||||
end
|
||||
|
||||
local function update_estable()
|
||||
-- intencionadament buit — lletres quietes
|
||||
if temps >= T_ESTABLE then
|
||||
salta_a_fade()
|
||||
end
|
||||
end
|
||||
|
||||
local function update_fade()
|
||||
local p = temps / T_FADE
|
||||
if p >= 1 then
|
||||
nivell_actual = 0
|
||||
fase = FASE_POST
|
||||
temps = 0
|
||||
return
|
||||
end
|
||||
-- Mapa el progres [0,1] al nivell [NIVELL_MAX..0] de la rampa.
|
||||
nivell_actual = math.floor(NIVELL_MAX * (1 - p) + 0.5)
|
||||
if nivell_actual < 0 then nivell_actual = 0 end
|
||||
end
|
||||
|
||||
local function update_post()
|
||||
if temps >= T_POST then
|
||||
manager.canvia("titol")
|
||||
end
|
||||
end
|
||||
|
||||
function M.update(dt)
|
||||
temps = temps + dt
|
||||
|
||||
if (fase == FASE_ENTRADA or fase == FASE_ESTABLE) and input.qualsevol_tecla() then
|
||||
salta_a_fade()
|
||||
return
|
||||
end
|
||||
|
||||
if fase == FASE_ENTRADA then
|
||||
update_entrada()
|
||||
elseif fase == FASE_ESTABLE then
|
||||
update_estable()
|
||||
elseif fase == FASE_FADE_OUT then
|
||||
update_fade()
|
||||
else
|
||||
update_post()
|
||||
end
|
||||
end
|
||||
|
||||
function M.draw()
|
||||
color(COLOR_WHITE, COLOR_BLACK)
|
||||
cls()
|
||||
|
||||
local nivell
|
||||
if fase == FASE_FADE_OUT or fase == FASE_POST then
|
||||
nivell = nivell_actual
|
||||
else
|
||||
nivell = NIVELL_MAX
|
||||
end
|
||||
if nivell <= 0 then return end
|
||||
|
||||
local conf = RAMPA[nivell]
|
||||
color(conf.ink, COLOR_BLACK)
|
||||
|
||||
for _, l in ipairs(lletres) do
|
||||
local ox = math.floor(l.dx + 0.5)
|
||||
local oy = math.floor(l.dy + 0.5)
|
||||
for _, p in ipairs(l.pixels) do
|
||||
local x = l.base_x + p.rx + ox
|
||||
local y = l.base_y + p.ry + oy
|
||||
if x >= 0 and x < 40 and y >= 0 and y < 30 then
|
||||
print(chr(conf.codi), x, y)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,85 @@
|
||||
-- Escena 'titol' — menu principal.
|
||||
--
|
||||
-- Tot esta basat en delta time: parpelleig de cursor, animacio del
|
||||
-- subtitol, etc. La llista d'opcions es extensible: nomes cal afegir
|
||||
-- una entrada amb un text i una funcio.
|
||||
|
||||
local M = {}
|
||||
|
||||
local TITOL = "PEPE EL PINTOR DX"
|
||||
local SUBTITOL = "port lliure de PINTOR3 (Sergi Valor, 1999)"
|
||||
local PERIODE_CURSOR = 0.35
|
||||
|
||||
local manager, input
|
||||
local temps = 0
|
||||
local cursor = 1
|
||||
local opcions = {}
|
||||
|
||||
local function fes_opcions()
|
||||
opcions = {
|
||||
{
|
||||
text = "COMENCAR PARTIDA",
|
||||
accio = function() manager.canvia("joc") end,
|
||||
},
|
||||
-- A futur: CONTROLS, CREDITS, OPCIONS, EIXIR...
|
||||
}
|
||||
end
|
||||
|
||||
function M.entra(servicis, _args)
|
||||
manager = servicis.manager
|
||||
input = servicis.input
|
||||
temps = 0
|
||||
cursor = 1
|
||||
fes_opcions()
|
||||
end
|
||||
|
||||
function M.update(dt)
|
||||
temps = temps + dt
|
||||
|
||||
if input.acaba_premuda("amunt") then
|
||||
cursor = cursor - 1
|
||||
if cursor < 1 then cursor = #opcions end
|
||||
end
|
||||
if input.acaba_premuda("avall") then
|
||||
cursor = cursor + 1
|
||||
if cursor > #opcions then cursor = 1 end
|
||||
end
|
||||
if input.acaba_premuda("accept") then
|
||||
local op = opcions[cursor]
|
||||
if op and op.accio then op.accio() end
|
||||
end
|
||||
end
|
||||
|
||||
local function centra(text, y, ink, paper)
|
||||
local x = math.floor((40 - #text) / 2)
|
||||
color(ink, paper)
|
||||
print(text, x, y)
|
||||
end
|
||||
|
||||
function M.draw()
|
||||
color(COLOR_WHITE, COLOR_BLACK)
|
||||
cls()
|
||||
|
||||
-- Marc decoratiu — barres horitzontals de pintura.
|
||||
color(COLOR_LIGHT_RED, COLOR_BLACK)
|
||||
print(string.rep(chr(220), 40), 0, 1)
|
||||
print(string.rep(chr(223), 40), 0, 27)
|
||||
|
||||
centra(TITOL, 6, COLOR_YELLOW, COLOR_BLACK)
|
||||
centra(SUBTITOL, 8, COLOR_LIGHT_GRAY, COLOR_BLACK)
|
||||
|
||||
-- Menu d'opcions
|
||||
local y0 = 14
|
||||
for i, op in ipairs(opcions) do
|
||||
local actiu = (i == cursor)
|
||||
local visible_cursor = math.floor(temps / PERIODE_CURSOR) % 2 == 0
|
||||
local marca = (actiu and visible_cursor) and chr(16) or " "
|
||||
local text = marca .. " " .. op.text
|
||||
local ink = actiu and COLOR_LIGHT_GREEN or COLOR_LIGHT_GRAY
|
||||
centra(text, y0 + (i - 1) * 2, ink, COLOR_BLACK)
|
||||
end
|
||||
|
||||
centra("amunt/avall + enter", 24, COLOR_DARK_GRAY, COLOR_BLACK)
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user