import "./style.css"; import * as logo from "./logo"; import * as welcome from "./welcome"; import * as jugando from "./jugando"; import { Assets, loadAssets } from "./assets"; import { loadSprite, Sprite } from "./sprite"; import { drawText } from "./utils"; export type State = logo.State | welcome.State | jugando.State; export type Juego = { canvas: HTMLCanvasElement; ctx: CanvasRenderingContext2D; assets: Assets; sprites: { [key in | "botonSiguiente" | "botonComenzar" | "botonCompartirPerdiste" | "botonCompartirFelicitaciones" | "instagram" | "twitter" | "facebook" | "logoFPGFDTBlanco" | "logoSalvaLaCostaneraGrande" | "logoSalvaLaCostaneraCostado" | "instrucciones1" | "instrucciones2" | "instrucciones3" | "placaPerdiste" | "placaFelicitaciones" | "dialogoFirma" | "flecha" | "jugadorx" | "jugadorxPresentando" | "baldosa" | "larreta" | "millonarioMalo" | "semilla" | "arbol1" | "arbol2" | "ciudadanx1" | "ciudadanx2" | "ciudadanx3"]: Sprite; }; mouse: { x: number; y: number; down: boolean }; touches: TouchList | null; keyboard: { keys: { [key: string]: boolean } }; state: T; }; function needsRotation(juego: Juego): boolean { return juego.canvas.width < juego.canvas.height; } function update(juego: Juego, dt: number) { if (needsRotation(juego)) return; switch (juego.state.current) { case "logo": logo.update(juego, dt); break; case "welcome": welcome.update(juego, dt); break; case "jugando": jugando.update(juego, dt); break; } } function draw(juego: Juego, timestamp: number) { const { width, height } = juego.canvas; juego.ctx.imageSmoothingEnabled = false; juego.ctx.fillStyle = "white"; juego.ctx.fillRect(0, 0, width, height); juego.ctx.fillStyle = "black"; if (needsRotation(juego)) { drawText( juego, "¡Por favor rotá el dispositivo!", { x: juego.canvas.width / 2, y: juego.canvas.height / 2 }, { align: "center", maxWidth: juego.canvas.width } ); return; } switch (juego.state.current) { case "logo": logo.draw(juego, timestamp); break; case "welcome": welcome.draw(juego, timestamp); break; case "jugando": jugando.draw(juego, timestamp); break; } } function resizeCanvas(canvas: HTMLCanvasElement) { canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; } function touchListener(juego: Juego, event: TouchEvent) { juego.touches = event.touches; } async function initJuego() { const canvas = document.querySelector("#juego")!; const ctx = canvas.getContext("2d", { alpha: false, desynchronized: true, })!; window.addEventListener("resize", () => resizeCanvas(canvas), false); resizeCanvas(canvas); const assets = await loadAssets(); const sprites = { botonComenzar: loadSprite(assets.botonComenzar, { height: (juego) => juego.canvas.height / 8, }), botonSiguiente: loadSprite(assets.botonSiguiente, { height: (juego) => juego.canvas.height / 8, }), botonCompartirPerdiste: loadSprite(assets.botonCompartirPerdiste, { height: (juego) => juego.canvas.height / 8, }), botonCompartirFelicitaciones: loadSprite( assets.botonCompartirFelicitaciones, { height: (juego) => juego.canvas.height / 8, } ), instagram: loadSprite(assets.instagram, { height: (juego) => juego.canvas.height * 0.1, }), facebook: loadSprite(assets.facebook, { height: (juego) => juego.canvas.height * 0.1, }), twitter: loadSprite(assets.twitter, { height: (juego) => juego.canvas.height * 0.1, }), logoFPGFDTBlanco: loadSprite(assets.logoFPGFDTBlanco, { height: (juego) => juego.canvas.height / 6, }), logoSalvaLaCostaneraGrande: loadSprite(assets.logoSalvaLaCostanera, { height: (juego) => juego.canvas.height * 0.45, }), logoSalvaLaCostaneraCostado: loadSprite( assets.logoSalvaLaCostaneraCostado, { height: (juego) => juego.canvas.height / 4 } ), instrucciones1: loadSprite(assets.instrucciones1, { width: (juego) => juego.canvas.width * 0.5, }), instrucciones2: loadSprite(assets.instrucciones2, { width: (juego) => juego.canvas.width * 0.5, }), instrucciones3: loadSprite(assets.instrucciones3, { width: (juego) => juego.canvas.width * 0.5, }), placaPerdiste: loadSprite(assets.placaPerdiste, { height: (juego) => juego.canvas.height * 0.6, }), placaFelicitaciones: loadSprite(assets.placaFelicitaciones, { height: (juego) => juego.canvas.height * 0.6, }), dialogoFirma: loadSprite(assets.dialogoFirma, { height: (juego) => juego.canvas.height / 8, }), flecha: loadSprite(assets.flecha, { height: (juego) => juego.canvas.height / 6, }), jugadorx: loadSprite( assets.jugadorx, { height: (juego) => juego.canvas.height / 4 }, { width: 56, height: 94, } ), jugadorxPresentando: loadSprite(assets.jugadorxPresentando, { height: (juego) => juego.canvas.height * 0.8, }), baldosa: loadSprite(assets.baldosa, { height: (juego) => juego.canvas.height * 0.2, }), larreta: loadSprite( assets.larreta, { height: (juego) => juego.canvas.height / 4 }, { width: 83, height: 131, } ), millonarioMalo: loadSprite( assets.millonarioMalo, { height: (juego) => juego.canvas.height / 4 }, { width: 50, height: 71 } ), semilla: loadSprite(assets.semilla, { height: (juego) => juego.canvas.height / 8, }), arbol1: loadSprite( assets.arbol1, { height: (juego) => juego.canvas.height / 3 }, { width: 72, height: 68, } ), arbol2: loadSprite( assets.arbol2, { height: (juego) => juego.canvas.height / 4 }, { width: 72, height: 56, } ), ciudadanx1: loadSprite( assets.ciudadanx1, { height: (juego) => juego.canvas.height / 4, }, { width: 45, height: 88 } ), ciudadanx2: loadSprite( assets.ciudadanx2, { height: (juego) => juego.canvas.height / 4, }, { width: 45, height: 88 } ), ciudadanx3: loadSprite( assets.ciudadanx3, { height: (juego) => juego.canvas.height / 4, }, { width: 45, height: 86 } ), }; let juego: Juego = { canvas, ctx, assets, sprites, mouse: { x: 0, y: 0, down: false }, touches: null, keyboard: { keys: {} }, state: logo.createState(), }; (window as any).juego = juego; juego.ctx.imageSmoothingEnabled = false; canvas.addEventListener( "mousemove", (e) => { juego.mouse.x = e.clientX; juego.mouse.y = e.clientY; }, false ); canvas.addEventListener( "mousedown", () => { juego.mouse.down = true; }, false ); canvas.addEventListener( "mouseup", () => { juego.mouse.down = false; }, false ); window.addEventListener("keydown", (e) => { juego.keyboard.keys[e.key] = true; }); window.addEventListener("keyup", (e) => { juego.keyboard.keys[e.key] = false; }); window.addEventListener("touchstart", (e) => touchListener(juego, e)); window.addEventListener("touchend", (e) => touchListener(juego, e)); window.addEventListener("touchcancel", (e) => touchListener(juego, e)); window.addEventListener("touchmove", (e) => touchListener(juego, e)); let lastRender = 0; const loop: FrameRequestCallback = (timestamp) => { const progress = timestamp - lastRender; update(juego, progress); draw(juego, timestamp); lastRender = timestamp; window.requestAnimationFrame(loop); }; window.requestAnimationFrame(loop); console.log( "%c¡Hola curiosx! Podés ver el código completo en https://gitea.nulo.in/Nulo/salva-la-costanera. ¡Suerte!", "color:green;font-size:3rem;font-weight:bold" ); } const fullscreenEl = document.getElementById("full-screen")!; if ("requestFullscreen" in document.documentElement) { fullscreenEl.addEventListener("click", async () => { document.documentElement.requestFullscreen && (await document.documentElement.requestFullscreen({ navigationUI: "hide", })); await screen.orientation.lock("landscape"); }); } else { fullscreenEl.hidden = true; } initJuego();