No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Refactor del mapa de juego

7/24
Recursos

Aportes 32

Preguntas 4

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Hola!

Lo que hice diferente fue crear un objeto literal del mapa, para poder luego solo usar sus funciones o cambiar las propiedades, que en este caso sería el nivel.
Con este objeto literal creado, ya cuando se ejecuta el juego, solo especifico el nivel y luego le digo que lo renderice.
El otro punto diferente al del profe, es que para limpiar y transformar al mapa como lo necesito, use un match y expresiones regulares, para encontrar directamente cada fila.
Por lo demás está todo igual.

const canvas = document.getElementById('game');
const game = canvas.getContext("2d");
let canvasSize;
let canvasElement;

//creo un objeto literal del mapa, y agrego una propiedad que es el nivel y otra que es una funcion render
const map={
    lvl:0,
    render:function () {
        if(this.lvl>=maps.length){
            return console.log ("Ese mapa no existe")
        }
        // Encontramos el mapa y lo preparamos como queremos
        const Map = maps[this.lvl].match(/[IXO\-]+/g)
            .map(a => a.split(""))
        //  le configuramos las propeidades de los elementos que vamos a dibujar
        game.font = canvasElement + "px Verdana"
        game.textAlign = "end"
        // recorremos el mapa para poder obtener las coordenadas de cada una de las posiciones que necesitamos
        Map.forEach((x, xi) => {
        x.forEach((y, yi) => {
            const posX = canvasElement * (xi + 1)
            const posY = canvasElement * (yi + 1)
            game.fillText(emojis[y], posY, posX)
        })
    })
    }
}

window.addEventListener('load', setCanvasSize);
window.addEventListener('resize', setCanvasSize)


function setCanvasSize() {
    window.innerHeight > window.innerWidth
        ? canvasSize = window.innerWidth * 0.9
        : canvasSize = window.innerHeight * 0.7;


    canvas.setAttribute("height", canvasSize)
    canvas.setAttribute("width", canvasSize)
    canvasElement = canvasSize / 10;
    startGame()
}


function startGame() {
    map.lvl=1
    map.render()

}

mi solución básica (basándome en el principio KISS xD (https://people.apache.org/~fhanik/kiss.html))

Para evitar complicarnos con el índice +1 al momento de renderizar los elementos, podemos utilizar los métodos del canvas: game.textBaseLine define la posición vertical del texto en el canvas, recibe varios atributos que puedes revisar en la documentación. El valor 'top' hace que nuestro tome como superior la ubicación que le damos, de esta forma, si la coordenada y tiene el valor de 0, el texto no se pondrá por encima sino por debajo del 0, así es como quedan alineados de tal forma que se vean completamente en el canvas.

Resumen de la clase

  • Explicación del código





  • Test


Para simplificar el reto.
Solo con el mapRows se puede realizar el recorrimiento.
Ya que se puede recorrer un string colocando el indice de la letra en la variable.
ejemplo mapRows[0][0] me daria la primar letra del primer array.
Ya no se necesitaría usar mapRowCols.

const mapRows = map.trim().split('\n');
  mapRows.forEach((row, rowIndex) => {
    for (let col = 0; col < row.length; col++) {
      const emoji = emojis[row[col]];
      const posX = elementsSize * (col + 1) + 5;
      const posY = elementsSize * (rowIndex + 1) - 10;
      game.fillText(emoji, posX, posY);
    }
  });

Para los que tienen aún problemas en que los emojis se salen de su pantalla (aún no he averiguado exactamente el por qué sucederá esto) pero la solución que descubrí fue modificar los valores que se suman con los índices de “col” y “row”, por ejemplo, en el código de JuanDc es:

const posX = elementsSize * (colI + 1);
const posY = elementsSize * (rowI + 1);

Pero yo le moví y moví los valores hasta que encajaron completamente todos los emojis dentro de los bordes del canvas, quedando el ciclo así:

mapRowCols.forEach((row, rowI) => {
    row.forEach((col, colI) => {
      const emoji = emojis[col];
      const posX = elementsSize * (colI + 1.2);
      const posY = elementsSize * (rowI + 0.85);
      game.fillText(emoji, posX, posY);
    });
  });

Dediquen un rato a buscar los valores que sean acordes a su código, yo probé todo el responsive y funcionó perfecto incluso cambiando literalmente de monitor, así que me funciona y lo dejaré quieto así 😅.

Lo mismo pero más barato :v

No me gustaba que todo quedara algo descuadrado, así que aplique una técnica hecha por un compañero en otra clase y cree las variables según mi criterio para entenderlas mejor:

const canvas = document.querySelector('#game');
const game = canvas.getContext('2d');
let canvas_size;
let elements_size;
let map;
let emoji;
let x;
let y;

window.addEventListener('load', calculate_canvas_size);
window.addEventListener('resize', calculate_canvas_size);

function calculate_canvas_size(){
    window.innerHeight > window.innerWidth
    ? canvas_size = window.innerWidth * 0.8
    : canvas_size = window.innerHeight * 0.8

    canvas.setAttribute('width', canvas_size);
    canvas.setAttribute('height', canvas_size);

    calculate_elements_size();
}

function calculate_elements_size(){
    elements_size = (canvas_size * 0.1) - 1;
    game.font = `${elements_size}px Verdana`;

    map = (maps[0].trim().split('\n')).map(x => x.trim().split(''));
    console.log({map});

    map.forEach((row, ri) => { // element, index
        row.forEach((col, ci) => {
            emoji = emojis[col];
            x = elements_size * ci;
            y = elements_size * (ri+1);

            game.fillText(emoji, x, y);
        });
    });
}

// registro de la consola: console log

Este es una duda que me surgio en mis inicios en el Desarrollo, ¿porque un forEach y no un For normal o un map o cualquier metodo para recorer arrays?, y bien se hacen sobre todo por cuestiones de legibilidad del codigo, un for normal tiene mejor rendimiento en cuestion de CPU, sin embargo los metodos implicitos que poseen ya los lenguajes 1: nos ahorran tiempo para no estar declarnado los ciclos a manito el famoso no volver a inventar la rueda, y 2: los hace mucho mas entendible al momento de leer el codigo. (claramente ya en cuando avances mas te daras cuenta que hay mas factores que se tienen que tomar en cuenta como la mutabilidad pero principalmente estos dos primeros son los mas importantes cuando empiezas y te hacen bolas los ciclos) o ami me sirvio por lo menos

XD soy el unico que toma los cursos de JS sin saber crear una civilizacion super avanzada con dicho lenguaje?

Yo en el paso anterior ya había definido una función para obtener los elementos del mapa

function getMaps(level) {
    const mapRows = maps[level].trim().split('\n');
    const mapCol = mapRows.map(row => row.trim().split(''));
    return mapCol
}

Pero lo del ciclo anidado de for no lo pude desenmarañar sola 🤭🤭

Antes de ver la clase lo hice con un ciclo FOR y .MAP, porque no conocia bien el metodo FOREACH. Asi me habia quedado:

const canvas = document.querySelector("#game");
const context = canvas.getContext("2d");

window.addEventListener("load", setCanvasSize);
window.addEventListener("resize", setCanvasSize);

let canvasSize;
let elementsSize;

function startGame() {
	context.textAlign = "end";
	context.font = elementsSize + "px Verdana";

	const map = maps[2];
	const cleanMap = map.trim().split("\n");
	const matrixMap = cleanMap.map((row) => row.trim().split(""));
	console.log(matrixMap);

	for (let i = 0; i < 10; i++) {
		matrixMap.map((row, indice) =>
			context.fillText(
				emojis[row[i]],
				elementsSize * (i + 1),
				elementsSize * (indice + 1)
			)
		);
	}
}

// context.fillRect(100, 100, 1, 1);
// context.clearRect(50, 0, 100, 50);
// context.font = "30px Cabin";
// context.fillStyle = "green";
// context.textAlign = "center";
// context.fillText("Fabio", 100, 100);

function setCanvasSize() {
	canvasSize;
	if (window.innerWidth >= window.innerHeight) {
		canvasSize = innerHeight * 0.8;
	} else {
		canvasSize = innerWidth * 0.8;
	}

	canvas.setAttribute("width", canvasSize);
	canvas.setAttribute("height", canvasSize);
	elementsSize = canvasSize * 0.1;

	startGame();
}

const mapaPrueba = maps[2].split(’’)
let fila = 1;
let columna = 0;

mapaPrueba.forEach(a =>{
if (a == ‘-’ || a == ‘O’ || a == ‘X’ || a == ‘I’){
if(columna < 10){ columna = columna +1} else{columna = 1}
game.fillText(emojis[a],elementosTamanio * (columna - 1), elementosTamanio * fila)
if(columna ==10){ fila = fila +1}
}
})

Algo que me alegra de ir avanzando en Js es que empiezas a tener mas iniciativa por modificar el codigo que enseñan segun creas conveniente.
En mi caso, mi codigo quedo asi:

function initialPaint(blocksSize) {
  game.font = blocksSize * 0.9 + "px impact";

  const map = maps[2].trim();
  const mapRows = map.split("\n").map((row) => row.trim());

  for (let row = 0.85; row <= mapRows.length; row++) {
    for (let column = 0.05; column < 10; column++) {
      const emoji = emojis[mapRows[Math.floor(row)][Math.floor(column)]];

      game.fillText(emoji, blocksSize * column, blocksSize * row);
    }
  }
}

Las principales diferencias son:

  • El tamaño de mi emoji es del 90% del tamaño de la celda( la celda es el 10% del tamaño del canvas) .
  • Puedo usar la variable de los for para ajustar la posicion de los emojis y que no les quede una parte oculta como se le ve al profe y a otros compañeros que han compartido. Basicamente esta es la razon por la que no use el el codigo refactorizado, si queria poder ajustar la posicion habria tenido que adicionar mas codigo. Supongo q es una cuestion de toma de desiciones y un poco de preferencias.

La desventaja es que debido a que la variable del for no es un entero debo usar Math.floor para convertirlo y usarlo para ubicar el emoji en el array.

Yo lo intenté con dos ciclos for of y fallé. tengo el mismo código del profe solo cambié una parte del código para centras las imágenes dentro del canva.

function startGame () {

    console.log({canvasSize, elementsSize})

    game.font = elementsSize + 'px Verdana';
    game.textAlign = 'center';

    const map = maps[0];
    const mapRows = map.trim().split('\n');
    const columnsOfmapRows = mapRows.map(row => row.trim().split(''));

columnsOfmapRows.forEach((row, rowIndex) => {
    row.forEach((column, columnIndex) => {
        const emoji = emojis[column];
        const positionX = (elementsSize * 0.93)  * (columnIndex + 1) ;
        const positionY =  (elementsSize * 0.97) * (rowIndex + 1); 
        game.fillText(emoji, positionX, positionY)
        console.log(rowIndex)
    });
});

Hola, Yo pude hacerlo usando map y me resulto mucho mas facil

mapRowsCols.map((row, rowIndex) => {
  return row.map((col, colIndex) => {
    game.fillText(emojis[col], elementsSize * colIndex, elementsSize * (rowIndex + 1));
  });
});
function startGame(){
  game.font = elemtSize + 'px Verdana';
  game.textAlign = 'end';
  // for (let i = 1; i <= 10; i++) {
  //   game.fillText(emojis['X'], elemtSize*i+4, elemtSize-10);
  // }

  const map = maps[0];
  const mapRow = map.trim().split('\n');
  const mapRowCol = mapRow.map(row => row.trim().split(''));
  // console.log({mapRowCol})
  
  // for (let x = 1; x <= 10; x++) {
  //   for (let y = 1; y <= 10; y++) {
  //     game.fillText(emojis[mapRowCol[y-1][x-1]],elemtSize*x,elemtSize*y-10);
  //   }
  // }

  mapRowCol.forEach((row, x)=>{
    row.forEach((column, y)=>{
      const emoji=emojis[column]
      game.fillText(emoji,elemtSize*(y+1),elemtSize*(x+1)-10);
    })
  })

}

Les comparto mi solución para esta clase. 😄
He utilizado un ciclo forque cuenta hasta 100 para poder renderizar los caracteres y una serie de contadores que me ayudan a saber en la posición en la que se tienen que dibujar cada carácter.
Les comparto los archivos .jscon los que estoy trabajando, el resultado que obtuve y el link del repositorio en GitHub.

maps.js

export const EMOJIS = {
    '-'              : ' ',
    'O'              : '💻',
    'X'              : '👾',
    'I'              : '✅',
    'PLAYER'         : '👨‍💻',
    'BOMB_COLLISION' : '💥',
    'GAME_OVER'      : '👎',
    'WIN'            : '🏆',
    'LIFE'           : '❤️'
};

const MAPS = [];

MAPS.push(`
    IXXXXXXXXX
    -XXXXXXXXX
    -XXXXXXXXX
    -XXXXXXXXX
    -XXXXXXXXX
    -XXXXXXXXX
    -XXXXXXXXX
    -XXXXXXXXX
    -XXXXXXXXX
    OXXXXXXXXX
  `);
MAPS.push(`
    O--XXXXXXX
    X--XXXXXXX
    XX----XXXX
    X--XX-XXXX
    X-XXX--XXX
    X-XXXX-XXX
    XX--XX--XX
    XX--XXX-XX
    XXXX---IXX
    XXXXXXXXXX
    `);
MAPS.push(`
    I-----XXXX
    XXXXX-XXXX
    XX----XXXX
    XX-XXXXXXX
    XX-----XXX
    XXXXXX-XXX
    XX-----XXX
    XX-XXXXXXX
    XX-----OXX
    XXXXXXXXXX
  `);
MAPS.push(`
    XXXXX----I
    XXXXX-XXXX
    XX----XXXX
    XX-XXXXXXX
    ------XXXX
    -XXXXX-XXX
    -------XXX
    X-XXXXXXXX
    X-----OXXX
    XXXXXXXXXX
  `);

export const MAPS_USE = MAPS.map(map => map.trim().replaceAll(' ', ''));

game.js

import { EMOJIS, MAPS_USE as MAP } from './maps.js';

const startGame = (fontSize, elementSize) => {
    GAME.font = `${fontSize}px sans-serif`;
    GAME.textAlign = 'left';

    let yDraw = elementSize;
    let xPositionEmoji = 0;
    let yPositionEmoji = 0;
    const MAP_EMOJIS = MAP[1]
        .split('\n')
        .map(row => row.split(''));

    for (let i = 0; i < 100; i++) {
        if (i % 10 === 0 && i !== 0) {
            yPositionEmoji++;
            xPositionEmoji = 0;
            yDraw = elementSize * (yPositionEmoji + 1) * 0.98;
        }

        const X_DRAW = elementSize * xPositionEmoji * 1.015;
        const EMOJI_DRAW = MAP_EMOJIS[yPositionEmoji][xPositionEmoji];

        GAME.fillText(EMOJIS[EMOJI_DRAW], X_DRAW, yDraw);
        xPositionEmoji++;
    }
};

const setCanvasSize = () => {
    const WIDTH_WINDOWS = window.innerWidth;
    const HEIGHT_WINDOWS = window.innerHeight;
    const IS_WIDTH_SMALLER = WIDTH_WINDOWS < HEIGHT_WINDOWS && WIDTH_WINDOWS < 550;
    const WIDTH_BASE = window.innerWidth * 0.9;
    const HEIGHT_BASE = window.innerHeight * 0.6;
    const SIDE_CANVAS = (IS_WIDTH_SMALLER)
        ? (WIDTH_BASE).toString()
        : (HEIGHT_BASE).toString();

    CANVAS.setAttribute('width', SIDE_CANVAS);
    CANVAS.setAttribute('height', SIDE_CANVAS);

    const ELEMENT_SIZE = Number(SIDE_CANVAS) / 10.25;
    const FONT_SIZE = ELEMENT_SIZE * 0.82;

    startGame(FONT_SIZE, ELEMENT_SIZE);
};

const CANVAS = document.querySelector('#main__game-container-id');
const GAME = CANVAS.getContext('2d');

window.addEventListener('load', setCanvasSize);
window.addEventListener('resize', setCanvasSize);

Resultado

Asi lo realize:

// * Inicio del juego 
const startGame = () => {

  game.font = elementsSize + 'px Verdana';
  game.textAlign = 'start';
  game.textBaseline = 'top';

  let map = maps[0];
  map = map.trim().split('\n');
  map = map.map(element => element.trim().split(''));

  map.forEach((row, rowIndex) => {
    row.forEach((col, colIndex) => {
      const emoji = emojis[col];
      game.fillText(emoji, elementsSize * colIndex, elementsSize * rowIndex)
    })
  });
};

Yo lo deje así, me parecio más simple de leer:

const canvas = document.querySelector("#game");
const game = canvas.getContext("2d");

window.addEventListener("load",setCanvasSize);
window.addEventListener("resize",setCanvasSize);


let canvassize;

function setCanvasSize(){
    
    if( window.innerWidth > window.innerHeight ){
        canvassize = window.innerHeight*0.70;
    }else{
        canvassize = window.innerWidth*0.60;
        
    }  
    
    canvas.setAttribute("width", canvassize);
    canvas.setAttribute("height", canvassize);
    startGame()
}
function startGame(){
    // Espera que se cargue la página
    // game.fillRect(0,50,100,100);
    // game.clearRect(50,50,100,100);
    // game.fillStyle ="Purple"; 
    // game.font = "25px Verdana";
    // game.textAlign ="center"; //start, end, left, center, right
    // game.fillText("Platzi",50,50,200);
    // const valueheight = window.innerHeight; // height value of windows
    // const valuewidth = window.innerWidth; // width value of windows 

    /* other form to fill the map 
    const valuemaps = Object.keys(emojis);
    console.log(valuemaps);
    let count1 = 1;
    let count2 = 1;
    for (let i = 0; i <maps[0].length; i++) {
        for (let j = 0; j < valuemaps.length; j++) {
           if(maps[0][i] == valuemaps[j]){
            game.fillText(emojis[valuemaps[j]] ,elementSize * count1 , elementSize * count2);
            if(count1 == 10){
                count1 = 1;
                count2++;
            }else{
                count1++;
               
            }          
           }
        }
        if(count2 > 10){
            count2 = 1 ;
        }  
    }
    console.log({count1,count2})
    
    */
    
    const elementSize = canvassize/10;
    console.log({elementSize,game});  
    game.textAlign = "end";
    game.textBaseline = "bottom"; // align text en forma vertical 'top', 'hanging', 'middle', 'alphabetic', 'ideographic', 'bottom'
    game.font = String (elementSize -10) + "px Arial" ;
    
    const mapPerLevel = renderMap(1);
    for (let i = 0; i < 10; i++) {
        for (let j = 0; j < 10; j++) {

            game.fillText(emojis[mapPerLevel[j][i]] ,elementSize * (i+1) , elementSize * (j+1));             
        }
        
    }
    
}
function renderMap(level){

    const  filterMap = maps[level].trim().split("\n");
    const maprender = filterMap.map(function(key){ return key.trim().split("")});
    return maprender;
}
//console.log(renderMap(0));

no será lo mas eficiente pero me gusto como quedo
 

const canvas = document.querySelector('#game');
const juego  = canvas.getContext('2d');

window.addEventListener('load', redimencionar);
window.addEventListener('resize', redimencionar);

function redimencionar(){
    const canvas_t = (window.innerWidth < window.innerHeight ? window.innerWidth : window.innerHeight) *.75 ;
    canvas.setAttribute('width', canvas_t  );
    canvas.setAttribute('height', canvas_t );
    juego.textAlign='end';
    inicia(canvas_t / 10);}

function inicia(size_t = 0){
    juego.font = size_t - size_t / 10 +'px arial';
    const arreglo = map[2].match(/[IOX-]/g);

    arreglo.forEach((char, idx) => {
        const y = (~~(idx/10) + 1) * size_t - size_t / 5;
        const x = (idx - (~~(idx/10) * 10) + 1) * size_t + size_t / 10;
        
        juego.fillText(emojis[char], x, y );});}
```js const canvas = document.getElementById("game-canvas"); const gameCanva = canvas.getContext("2d"); let elementSize; let currentMap; function setMap(mapIndex) { const map = maps[mapIndex]; currentMap = map.map((row) => row.split('')); currentMap.forEach((row, rowIndex )=> { row.forEach((col,colIndex)=>{ const emoji = emojis[col]; const posX = elementSize * (colIndex + 1); const posY = elementSize * (rowIndex + 1); gameCanva.fillText(emoji,posX,posY); }) }); } function setCanvasSize() { //Config canvas size let canvasSize; if (window.innerHeight > window.innerWidth) { canvasSize = window.innerWidth * 0.8; } else { canvasSize = window.innerHeight * 0.8; } canvas.setAttribute("width", canvasSize); canvas.setAttribute("height", canvasSize); elementSize = canvasSize / 10; gameStart(); } function gameStart() { //config elemnts size gameCanva.font = `${elementSize}px Verdana`; gameCanva.textAlign = "end"; setMap(1); } window.addEventListener("load", setCanvasSize); window.addEventListener("resize", setCanvasSize); ```maps.push(\[    "IXXXXXXXXX",    "-XXXXXXXXX",    "-XXXXXXXXX",    "-XXXXXXXXX",    "-XXXXXXXXX",    "-XXXXXXXXX",    "-XXXXXXXXX",    "-XXXXXXXXX",    "-XXXXXXXXX",    "OXXXXXXXXX"  ]);Está es mi solución siguiendo la clase, también mencionar que yo directamente creo las rows como arrays para evitar tanto procesamiento y simplificar la lógica. ```js maps.push([ "IXXXXXXXXX", "-XXXXXXXXX", "-XXXXXXXXX", "-XXXXXXXXX", "-XXXXXXXXX", "-XXXXXXXXX", "-XXXXXXXXX", "-XXXXXXXXX", "-XXXXXXXXX", "OXXXXXXXXX" ]); ```
`const canvas = document.getElementById("game-canvas");const gameCanva = canvas.getContext("2d");let elementSize;let currentMap;` `function setMap(mapIndex) {  const map = maps[mapIndex];  currentMap = map.map((row) => row.split(''));  currentMap.forEach((row, rowIndex )=> {    row.forEach((col,colIndex)=>{      const emoji = emojis[col];      const posX = elementSize * (colIndex + 1);      const posY = elementSize * (rowIndex + 1);      gameCanva.fillText(emoji,posX,posY);          })  });}` `function setCanvasSize() {  ``//Config canvas size``  let canvasSize;  if (window.innerHeight > window.innerWidth) {    canvasSize = window.innerWidth * 0.8;  } else {    canvasSize = window.innerHeight * 0.8;  }  canvas.setAttribute("width", canvasSize);  canvas.setAttribute("height", canvasSize);  elementSize = canvasSize / 10;  gameStart();}` `function gameStart() {  ``//config elemnts size```  gameCanva.font = `${elementSize}px Verdana`;  gameCanva.textAlign = "end";  setMap(1);}`` `window.addEventListener("load", setCanvasSize);window.addEventListener("resize", setCanvasSize);` Está es mi solución siguiendo la clase, todo lo relacionado a crear y configurar el mapa se va a una función aparte, también mencionar que yo pase directamente las rows como Arrays en la creación de los mapas para ahorrar procesamiento en tener que hacer el trim y split en la primera parte y solo tener que hacerlo una vez `maps.push([    "IXXXXXXXXX",    "-XXXXXXXXX",    "-XXXXXXXXX",    "-XXXXXXXXX",    "-XXXXXXXXX",    "-XXXXXXXXX",    "-XXXXXXXXX",    "-XXXXXXXXX",    "-XXXXXXXXX",    "OXXXXXXXXX"  ]);`
Hola, se Cambio el mapRowCols por mapCells, es mas especifico nombrar por celda, por ejemplo en la parte donde esta emojis\[col] es mas preciso colocarle emojis\[cell] ```js // function startGame() { // game.font = elementsSize * 0.75 + "px Verdana"; // game.textAlign = "center"; // const map = maps[0]; // const mapRows = map.trim().split("\n"); // const mapRowCols = mapRows.map((row) => row.trim().split("")); // mapRowCols.forEach((row, rowIndex) => { // row.forEach((col, colIndex) => { // const emoji = emojis[col]; // const posX = elementsSize * (colIndex + 0.5); // const posY = elementsSize * (rowIndex + 0.75); // game.fillText(emoji, posX, posY); // }); // }); // } function startGame() { game.font = elementsSize * 0.75 + "px Verdana"; game.textAlign = "center"; const map = maps[0]; const mapRows = map.trim().split("\n"); const mapCells = mapRows.map((row) => row.trim().split("")); mapCells.forEach((row, rowIndex) => { row.forEach((cell, colIndex) => { const emoji = emojis[cell]; const posX = elementsSize * (colIndex + 0.5); const posY = elementsSize * (rowIndex + 0.75); game.fillText(emoji, posX, posY); }); }); ```

Asi me quedo mi codigo, lo hize guiandome del ejemplo del Compañero Tommy Toala Cox, me gusto su manera de usar el objeto, asi mismo en vez de usar width, use el vmin para darle el ancho y alto al canvas, asi me quedo:

const canvas = document.querySelector('#game');
const game = canvas.getContext('2d');
let canvasSize;
let elementSize;

const gameStart = {
  level: 1,
  render: function () {
    if (this.level >= maps.length) {
      return console.log("Ese mapa no existe")
    }
    const map = maps[this.level].match(/[IXO\-]+/g)
      .map(a => a.split(""))
    game.font = `${elementSize}px Verdana`;
    game.textAlign = 'center';
    game.textBaseline = 'middle';

    map.forEach((row, rowIndex) => {
      row.forEach((col,colIndex)=>{
        const emoji = emojis[col];
        const posX = elementSize * ((colIndex - 0.42) + 1);
        const posY = elementSize * ((rowIndex - 0.32) + 1);
        game.fillText(emoji, posX, posY);
      });
    });
  }
}


window.addEventListener('load', setCanvasSize);
window.addEventListener('resize', setCanvasSize);

function setCanvasSize() {
 canvasSize = Math.min(window.innerWidth, window.innerHeight) * 0.7;

  canvas.setAttribute('width', canvasSize);
  canvas.setAttribute('height', canvasSize);

  elementSize = canvasSize / 10.20;

  startGame();
}


function startGame() {
  gameStart.render()
}

Amo los metodos de Array con las Arrow functions , siempre van a dar una solucion mas clara !!

Usar maps puede ser la mejor opción para si más adelante los mapas tienen otro tamaño, no tener que estar cambiando el tamaño del bucle for manualmente, aunque claro tambien se podría calcular el tamaño previamente.
Como previamente había conseguido el mapa de otra forma, tuve que añadir un array.from()

const map = maps[1].trim().split("\n  ");
map.forEach((row, rowIdx) => {
  Array.from(row).forEach((col, colIdx) => {
    ctx.fillText(
      emojis[col],
      rowIdx * element_size + 2,
      (colIdx + 1) * element_size - 8
    );
  });
});

quedó un poco parecido al de la clase, solo ahorrando algunas variables:

// inicializar juego
function startGame() {
  // tamaño elementos
  game.font = (elementsSize - 6) + 'px Verdana';
  game.textAlign = "end";

  // mapa del juego
  const map = maps[1];

// obtener arreglo de caracteres individuales
  const mapRowCols = map.trim().split('\n').map(row => row.trim().split(''));

  // index: obtener posiciones
  mapRowCols.forEach((row, rowIndex) => {
    row.forEach((col, colIndex) => {
      game.fillText(emojis[col], elementsSize * (colIndex + 1), elementsSize * (rowIndex + 1));
    });
  });
}

game.js

const canvas = document.querySelector("#game");
const game = canvas.getContext("2d");

window.addEventListener("DOMContentLoaded", startGame);
window.addEventListener("resize", setCanvasSize);

let elementsSize;
let map;

function startGame() {
  parseMap();
  setCanvasSize();
}

function setCanvasSize() {
  const canvasSize = Math.min(window.innerHeight, window.innerWidth) * 0.75;

  canvas.width = canvasSize;
  canvas.height = canvasSize;

  elementsSize = Math.floor(canvasSize / 10 - 1);

  game.font = `${elementsSize}px Verdana`;

  drawMap();
}

function drawMap() {
  game.clearRect(0, 0, canvas.width, canvas.height);

  map.forEach((row, y) => {
    row.forEach((emoji, x) => {
      game.fillText(emoji, x * elementsSize, (y + 1) * elementsSize);
    });
  });
}

function parseMap() {
  const mapString = maps[0].trim();
  const lines = mapString.split("\n").map((line) => line.trim());

  map = lines.map((line) => line.split("").map((symbol) => emojis[symbol]));
}

Interesante manera de usar los forEach anidados 😃

Con respecto a mi code anterior…solo quite el for y agregue un parametro a la función renderMap para que imprima el mapa que se envie como argumento.

function startGame(){
    game.font = elementSize + 'px Verdana';
    game.textAlign = 'end';

    const mapper = maps[0].match(/[IXO\-]+/g).map(x => x.split(""));

    mapper.forEach((row, y) => {
        row.forEach((col, x)  => {
            const emoji = emojis[col];
            const posX = elementSize *(x+1);
            const posY = elementSize *(y+1);
            game.fillText(emoji, posX, posY);
        });
        
    });