No tienes acceso a esta clase

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

Detectando colisiones fijas

12/24
Recursos

Aportes 47

Preguntas 0

Ordenar por:

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


Mi solución fue cambiar completamente la lógica, de medir pixeles a medir posiciones, eso me solucionó muchos problemas ✨.
Me explico; lo único que hice fue cambiar la posición en X y Y a números enteros. Luego con estos hago todas las comparaciones. c:

Así por ejemplo para que no se salga de la pantalla solo tengo que ver que no bajen los valores de 1 o se pasen de 10.

Así con todo, y con esa sencilla condicional me detecta todas las colisiones.

Aquí dejo el código 📚: https://github.com/ssaldana-dev/game-js

Creo que se debería colocar la lógica en las funciones de moveUp, moveDown, etc. porque ahí se esta modificando la posición del jugador.

lo de las colisiones fue muy fácil solo tuve que comparar el movimiento del jugador con el índex del mapa sin sumar canvasSize ni comparar X ni Y y pues ya 😅

 
La ventaja que veo que tiene mi código es que convertí el map en un arreglo normal de toda la vida intente asemejarlo a lo que normalmente veo en ensamblador por lo que las colisiones no resultan tan engorrosas ni confusas o al menos eso creo 🤔

//contect
const canvas = document.querySelector('#game');
const btnArriba = document.querySelector('#arriba');
const btnAbajo = document.querySelector('#abajo');
const btnDer = document.querySelector('#derecha');
const btnIzq = document.querySelector('#izquierda');

const juego  = canvas.getContext('2d');

//signals: 
window.addEventListener('load', resizeEvent);
window.addEventListener('resize', resizeEvent);


let posJugador     = undefined; let mapa     = Array();  let nivel = 0;
let prePosJugador  = undefined; let celda_t  = 0;        let nivel_actual = undefined;
let puntoDePartida = Number(0); let canvas_t = 0;        var actualizado  = Boolean(false);
let vidas          = Array();

function resizeEvent(){
    actualizado = false;
    canvas_t = (window.innerWidth < window.innerHeight ? window.innerWidth : window.innerHeight) *.75 ;
    canvas.setAttribute('width', canvas_t);
    canvas.setAttribute('height',canvas_t);
    celda_t = canvas_t / 10;
    juego.textAlign='end';
    juego.font = celda_t - celda_t / 10 +'px arial';
    update();}


function update(){
    if(vidas.length == 3 && actualizado) return;
    cargarMapa();
    clear();
    paintEvent();
    paintEventPlayer();
    paintEventGameOver();
    actualizado = true;}


function cargarMapa(){
    if(nivel_actual == nivel) return;

    nivel_actual = nivel;
    mapa = map[nivel].match(/[IOX-]/g);}


function clear(){
    if(!actualizado) {
        juego.clearRect(0,0, canvas_t, canvas_t);
        return;}

    if(posJugador == prePosJugador) return;
    clearRect(posJugador);
    clearRect(prePosJugador);}


function clearRect(indice){
    const x  = posX(indice ) - celda_t / 10;
    const y  = posY(indice ) + celda_t / 5;
    juego.clearRect(x - 1 ,y , - celda_t, - (celda_t + 1));}


function posY(indice){ return (~~(indice/10) + 1) * celda_t - celda_t / 5; }
function posX(indice){ return (indice - (~~(indice/10) * 10) + 1) * celda_t + celda_t / 10;}


function paintEvent(){
    if(!actualizado)
        mapa.forEach((char, idx) => {
            if(char == 'O' && posJugador == undefined) puntoDePartida = posJugador = idx;       
            juego.fillText(emojis[char], posX(idx), posY(idx) );});}


function paintEventPlayer(){
    if(mapa[posJugador] == 'I') {
        nivel = nivel + 1 <= 2 ? ++nivel : 0;
        posJugador = prePosJugador = undefined;
        actualizado = false;
        update();
        return;}

    if(posJugador != undefined && prePosJugador != posJugador){
        juego.fillText(emojis[mapa[prePosJugador]],posX(prePosJugador),posY(prePosJugador));

        if(collisionEvent()) juego.fillText(emojis['PLAYER'], posX(posJugador),posY(posJugador));
        else paintEventGameOver();}}


function collisionEvent(){
    if(vidas.length < 3 && mapa[posJugador] == 'X'){ 
        vidas.push(posJugador);
        juego.fillText(emojis['BOMB_COLLISION'],posX(posJugador),posY(posJugador));
        posJugador = puntoDePartida;}
    if(vidas.length == 3) return false; /*juego terminado*/
    return true; /*continuar con el juego*/}


function paintEventGameOver(){
    juego.textAlign='end';
        vidas.forEach((idx) =>{
            clearRect(idx);
            juego.fillText(emojis['BOMB_COLLISION'],posX(idx),posY(idx));});

    if(vidas.length < 3) return;

    const fuente = celda_t - celda_t / 10 ;
    const media = canvas_t / 2;
    juego.fillStyle = '#000000';
    juego.fillRect(0, media - (fuente /2), canvas_t, fuente);
    juego.textAlign = 'center';
    juego.fillStyle = '#ff5555';
    juego.fillText('Game Over', media, media + fuente/3);}


//signals:
window.addEventListener('keydown',keyMov);
btnArriba.addEventListener('click', movArriba);
btnAbajo.addEventListener('click', movAbajo);
btnDer.addEventListener('click', movDer);
btnIzq.addEventListener('click', movIzq);

//slots:
function keyMov(event){
    switch(event.keyCode){
        case 37: movIzq();    break;//izquierda
        case 38: movArriba(); break;//arriba
        case 39: movDer();    break; //derecha
        case 40: movAbajo();  break;//abajo
        default:              break;}}


function movArriba(){
    prePosJugador = posJugador;
    posJugador -= 10;
    if(posJugador < 0) posJugador = prePosJugador;
    update();}


function movAbajo(){
    prePosJugador = posJugador;
    posJugador += 10;
    if(posJugador >= 100) posJugador = prePosJugador;
    update();}


function movDer(){
    prePosJugador = posJugador;
    const pered = (~~(posJugador / 10)) *10 + 10;
    ++posJugador;
    if(posJugador >= pered) posJugador = prePosJugador;
    update();}


function movIzq(){
    prePosJugador = posJugador;
    const pered  = ~~(posJugador /10) * 10; 
    --posJugador;
    if(posJugador < pered) posJugador = prePosJugador;
    update();}

Y pensar que a mi me salio el error de los decimales en el primer mapa 🤣

Pausé un segundo la clase porque no me detectaba la colisión y era por los decimales (yo pensaba que había hecho algo mal). Puse play y dijo que ese era el problema jaja

Hola, les comparto mi solución al desafío.

  1. Creo una variable global para almacenar la posición de todas las bombas let bombs = [ ];

  2. En la función startGame creo el siguiente condicional para agregar las posiciones de las bombas.

  3. Cree una función para verificar si la posición del jugador coincide con alguna bomba

  4. Ahora ejecuto esa función cada vez que se mueve el jugador.

  5. Por último, en la función setCanvasSize reasigno la variable bombs = [ ]

Yo si tuve ese error de los decimales

Una solución que se me ocurre es redondear las coordenadas a dos decimales.

const posX = parseFloat((elementSize * (indexColumn + 1)).toFixed(2));
const posY = parseFloat((elementSize * (indexRow + 1)).toFixed(2));

playerPosition.x = posX;
playerPosition.y = posY;

giftPosition.x = posX;
giftPosition.y = posY;

Para detectar la colisión, cambiar de nivel y dibujar al jugador cree una función mapPlayer 😃
Juego boom

const canvas = document.querySelector("#game");
const game = canvas.getContext("2d");
const up = document.getElementById("up");
const down = document.getElementById("down");
const left = document.getElementById("left");
const right = document.getElementById("right");
let leveltoplay = 0; 
let moveVertical=1;
let moveHorizontal=1;
const playerPosition = {};

window.addEventListener("load",setCanvasSize);
window.addEventListener("resize",setCanvasSize);
// addEventLister movimiento del jugador 
up.addEventListener("click",moveWithButton);
down.addEventListener("click",moveWithButton);
left.addEventListener("click",moveWithButton);
right.addEventListener("click",moveWithButton);
window.addEventListener("keyup",keyDetection);


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" ;
    renderMap(leveltoplay);
    

    
}
function renderMap(level){
    game.clearRect(0,0,canvas.width,canvas.height);
    const  filterMap = maps[level].trim().split("\n");
    const maprender = filterMap.map(function(key){ return key.trim().split("")});
    mapObjetcs(maprender);
    
}
function moveWithButton(event){
    
    if(event.path[0].id == "up"){
        moveVertical--;
    }else if(event.path[0].id == "down"){
        moveVertical++;
    }else if(event.path[0].id == "left"){
        moveHorizontal--;
    }else if(event.path[0].id == "right"){
        moveHorizontal++;
    }
    condicionalPosition();
    console.log({moveHorizontal,moveVertical});
    movePlayer();
}
function keyDetection(event){
    const keyButtonMove = [38,37,39,40];
    
    keyButtonMove.forEach(function(key){
        if(event.keyCode == key){
            
            if(key == 38){
                moveVertical--;
            }else if(key == 40){
                moveVertical++;
            }else if(key == 37){
                moveHorizontal--;
            }else if(key == 39){
                moveHorizontal++;
            }
            condicionalPosition();
            console.log({moveHorizontal,moveVertical});
            movePlayer();
        }
    });    
}
function condicionalPosition(){
    if(moveVertical>10){
        moveVertical =10;
    }else if(moveVertical < 1){
        moveVertical =1;
    }
    if(moveHorizontal>10){
        moveHorizontal =10;
    }else if(moveHorizontal < 1){
        moveHorizontal =1;
    }
}
function movePlayer(){
    renderMap(leveltoplay);
    // game.fillText(emojis['PLAYER'] ,elementSize * moveHorizontal , elementSize * moveVertical);
}
function mapObjetcs(maprender){
   
    const elementSize = canvassize/10;
    for (let i = 0; i < 10; i++) {
        for (let j = 0; j < 10; j++) {

            game.fillText(emojis[maprender[j][i]] ,elementSize * (i+1) , elementSize * (j+1));      
            
        }
        
    }
    
    mapPlayer(elementSize,maprender);
     
}

function mapPlayer(elementSize,maprender){
    const valuegif= [];
    for (let i = 0; i < 10; i++) {
        for (let j = 0; j < 10; j++) {
           

            if(maprender[j][i]=='O'){
                if (!playerPosition["y"]) {
                    playerPosition["y"] = j + 1;
                    moveVertical=j+1;
                } else {
                    playerPosition["y"] = moveVertical;
                }
                if(!playerPosition["x"]){
                    playerPosition["x"] = i + 1;
                    moveHorizontal = i+1;
                }else{
                    playerPosition["x"] = moveHorizontal;
                }
                game.fillText(emojis['PLAYER'] ,elementSize * playerPosition.x , elementSize * playerPosition.y);
                
        
            }
            if(maprender[j][i]=='I'){
                valuegif.push(i+1);
                valuegif.push(j+1);                
                
            }
            
                 
        }
        
    }
    console.log({valuegif,playerPosition});
    if(maprender[playerPosition.y-1][playerPosition.x-1] == "X"){
        
        // game.fillText(emojis['PLAYER'] ,elementSize * moveHorizontal , elementSize * moveVertical);
        setTimeout(() =>{yourDie()},200);
        
    }
    if((valuegif[1])==playerPosition.y && (valuegif[0])==playerPosition.x){
        leveltoplay++;
        if(leveltoplay>2){leveltoplay=0;}
        startGame();
    }
    
    
    

    
}
function yourDie(){
    window.confirm("Moriste");
    playerPosition.x = undefined;
    playerPosition.y = undefined;
    startGame();
}

Creo una variable “bombas” que es una rray vacío:

var bombas = [];

Complemento el condicional que guarda las posiciones con el siguiente código, para que agregue cada par de coordenadas en el array bombas cuando col coincida con X:

 else if (col == 'X') {
                bombas.push(posX, posY);
            }

Dentro de la función movePlayer, agrego el siguiente ciclo for que inicia en 0 y aumenta 2 unidades con cada iteración, para asegurarme siempre mirar una coordenada de X de una bomba. Dentro del ciclo for, un condicional que compare la coordenada x de la bomba con la coordenada x del player, así como la coordenada y de la bomba (cuyo indice siempre será i+1) con la coordenada y del player, y en caso de ser ambos pares iguales, imprima un mensaje en consola:

    for(i=0; i < bombas.length; i=i+2) {
        if(bombas[i].toFixed(3) == playerPosition.x.toFixed(3) && bombas[i+1].toFixed(3) == playerPosition.y.toFixed(3)) {
            console.log("Explosión!!!");
        }
    }
ya se me rompió el jueguito y no encuentro que hice mal

Yo usé Math.trunc para el problema de los decimales

<function movePlayer(){
    const giftCollsionX = Math.trunc(playerPosition.x) == Math.trunc(giftPosition.x);
    const giftCollsionY = Math.trunc(playerPosition.y) == Math.trunc(giftPosition.y);
    const giftCollision = giftCollsionX && giftCollsionY

    if(giftCollision){
        alert("Ganaste")
    }

    game.fillText(emojis["PLAYER"], playerPosition.x, playerPosition.y)

}> 

Mi solución paso a paso

  • Pasos:
























Yo creé una variable ‘bombArr’ que se inicializa en la función startGame() como un arreglo vacío y cuando se pinta el mapa agrega por cada bomba un objeto con la posición en ‘X’ y ‘Y’ de la misma.

if (col == 'X') {
				bombArr.push({ x: posX, y: posY });
			}

Entonces se valida si al mover el personaje algún objeto del arreglo coincide en X y en Y con el personaje.

function movePlayer() {
	const giftCollisionX = Math.trunc(playerPosition.x) == Math.trunc(giftPosition.x);
	const giftCollisionY = Math.trunc(playerPosition.y) == Math.trunc(giftPosition.y);

	const bombCollisionX = bombArr.find(bomb => Math.trunc(bomb.x) == Math.trunc(playerPosition.x));
	const bombCollisionY = bombArr.find(bomb => Math.trunc(bomb.y) == Math.trunc(playerPosition.y));

	if (giftCollisionX && giftCollisionY) {
		console.log('ganaste!');
	} else if (bombCollisionX && bombCollisionY) {
		console.log('perdiste!');
	} else {
		game.fillText(emojis['PLAYER'], playerPosition.x, playerPosition.y);
	}
}

Pude detectar las colisiones 😃 asi:

  1. Crear Array
const bombPosition = [];
  1. Llenarlo con cada una de las posiciones de la bombita
// Coordenadas de las bombas
      else if (col==='X'){
        bombPosition.push({

          bombPositionX : posX,
          bombPositionY : posY
          
        })
  1. Recorrerlo
function bombColision(){
  for (let i = 0; i < bombPosition.length; i++) { 
    if(playerPosition.x === bombPosition[i].bombPositionX && playerPosition.y === bombPosition[i].bombPositionY){
      console.log("boom");
    }
  }
}

Pero al momento de que choca con las bombas me imprime varios “BOOM”

Helpp!

Mi solucion fue hacer push de objetos con las coordenadas x,y por cada bomba hacia a un array para luego con un forEach en la funcion movePlayer recorrer dicho array a la vez que se comparan las coordenadas con las del jugador hasta obtener un match.

const obstacleCollision = obstacles.forEach(obstacle => {
    let obstaclePosX = obstacle.x.toFixed() == playerPosition.x.toFixed()
    let obstaclesPosY = obstacle.y.toFixed() == playerPosition.y.toFixed()
    if(obstaclePosX && obstaclesPosY){
      console.log('BOOOOOMMMMM!!!')
    }
  })

game.js

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

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

// Obtener referencias a los botones
const upButton = document.getElementById("up");
const leftButton = document.getElementById("left");
const rightButton = document.getElementById("right");
const downButton = document.getElementById("down");

// Agregar manejadores de eventos a los botones
upButton.addEventListener("click", () => movePlayer("up"));
leftButton.addEventListener("click", () => movePlayer("left"));
rightButton.addEventListener("click", () => movePlayer("right"));
downButton.addEventListener("click", () => movePlayer("down"));

document.addEventListener("keydown", handleKeyDown);

let playerPosition = {
  x: undefined,
  y: undefined,
};
let giftPosition = {
  x: undefined,
  y: undefined,
};
let bombPosition = [];

let startMap = 0;
function handleKeyDown(event) {
  const key = event.key.toLowerCase();
  let direction;

  switch (key) {
    case "arrowup":
    case "w":
      direction = "up";
      break;
    case "arrowleft":
    case "a":
      direction = "left";
      break;
    case "arrowright":
    case "d":
      direction = "right";
      break;
    case "arrowdown":
    case "s":
      direction = "down";
      break;
    default:
      return;
  }

  // Realizar alguna acción basada en la dirección detectada
  // Por ejemplo, llamar a una función para mover al jugador en esa dirección
  movePlayer(direction);
}

let elementsSize;
let map;

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

function movePlayer(direction) {
  // Realizar acciones según la dirección recibida
  switch (direction) {
    case "up":
      if (!(playerPosition.y > 0)) {
        return; // No se cumple la condición, se sale de la función sin hacer nada
      }
      playerPosition.y -= 1;
      // Lógica para mover al jugador hacia arriba
      break;
    case "left":
      if (!(playerPosition.x > 0)) {
        return; // No se cumple la condición, se sale de la función sin hacer nada
      }
      playerPosition.x -= 1;
      // Lógica para mover al jugador hacia la izquierda
      break;
    case "right":
      if (!(playerPosition.x < 9)) {
        return; // No se cumple la condición, se sale de la función sin hacer nada
      }
      playerPosition.x += 1;
      // Lógica para mover al jugador hacia la derecha
      break;
    case "down":
      if (!(playerPosition.y < 9)) {
        return; // No se cumple la condición, se sale de la función sin hacer nada
      }
      playerPosition.y += 1;
      // Lógica para mover al jugador hacia abajo
      break;
    default:
      return;
  }

  if (
    giftPosition.x === playerPosition.x &&
    giftPosition.y === playerPosition.y
  ) {
    startMap++;
    bombPosition = [];
    startGame();
    return;
  } else if (
    bombPosition.some(
      (bombItem) =>
        bombItem.x === playerPosition.x && bombItem.y === playerPosition.y
    )
  ) {
    game.fillText(
      emojis.BOMB_COLLISION,
      playerPosition.x * elementsSize,
      (playerPosition.y + 1) * elementsSize
    );

    playerPosition = {
      x: undefined,
      y: undefined,
    };

    setTimeout(function () {
      startGame();
    }, 600);

    return;
  }

  // Actualizar el juego, dibujar el mapa actualizado, etc.
  drawMap();
}

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);

      if (emoji === "🚪") {
        if (playerPosition.x === undefined && playerPosition.y === undefined) {
          playerPosition = { x, y };
        } // Utiliza object destructuring para simplificar la asignación de coordenadas
      }
      if (emoji === "🎁") {
        giftPosition = { x, y };
      }
      if (emoji === "💣") {
        bombPosition.push({ x, y });
      }
    });
  });

  game.fillText(
    emojis.PLAYER,
    playerPosition.x * elementsSize,
    (playerPosition.y + 1) * elementsSize
  ); // Utiliza la notación de puntos para acceder a las propiedades del objeto emojis
}

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

    map = lines.map((line) => line.split("").map((symbol) => emojis[symbol]));
  } catch (error) {
    startMap = 0;
    playerPosition = {
      x: undefined,
      y: undefined,
    };
    parseMap();
  }
}

Detectar las colisiones no me resulto dificil lo que si se me complico fue como alojar la ubicacion de las bombas por nivel ya que me generaban duplicados para eso modifique el codigo de esta forma

Variables con la que trabajaremos

const canvas = document.querySelector('#game');
const game = canvas.getContext('2d');
const buttons = {
    up: document.querySelector('#up'),
    left: document.querySelector('#left'),
    right: document.querySelector('#right'),
    down: document.querySelector('#down')
};

let canvasSize;
let elementsSize;
let lvl = 0;
//Utilizamos genX y genY para corregir el problema que el emoji del jugador no sea responsive y provoque problemas de coordenadas y hacemos que el jugador se ubique en medio de la posicion (ej. 0,5) y se desplace en un entorno de 10x10
// x e y siguen siendo las coordenadas contextuadas con el resto de los elementos para detectar colisiones
const playerPosition = {
    x: undefined,
    y: undefined,
    genX: undefined,
    genY: undefined,
};
// Utilizaremos esta constante para ubicar la locacion de la meta en cada uno de los mapas
const giftPosition = {
    x: undefined,
    y: undefined,
};

// Sera la constante donde alojaremos las coordenadas de cada una de las bombas de cada uno de los mapas
const bombsPosition = {

}

// Espera a que cargue el contenido html de la pagina antes de lanzar la funcion
window.addEventListener('load', resizeCanvas);
window.addEventListener('resize', resizeCanvas);

Function de start game

 function startGame (lvl) {
    game.font = elementsSize + 'px Verdana';
    //Situamos los elementos en el medio de la casilla tanto horizontal como verticalmente
    game.textAlign = "center";
    game.textBaseline = 'middle';

    const map = maps[lvl]
//Agarramos el mapa del array de mapas y le quitamos los espacios en blanco al inicio y al final con trim y luego con split creamos un arreglo donde el inicio y el final de cada elemento se marca por los saltos de linea '\n'
    const mapRows = map.trim().split('\n');
//Del array resultante usamos map para recorrer cada uno de sus elementos (rows) limpiando los espacios en blanco con trim y luego separandolos por "filas" con split
    const mapRowCols = mapRows.map(row => row.trim().split(''));
    game.clearRect(0,0,canvasSize, canvasSize);
//Recorremos con for each el array bidimensional a partir del string del map y recibimos dos parametros su valor y su indice
    mapRowCols.forEach((row, rowIndex) => {
//Recorremos las filas iterando sobre cada columna y recibimos su valor y su indice
        row.forEach((col, colIndex) => {
//Declaramos que valor tendra el emoji en esa columna
            const emoji = emojis[col];
//Definimos el posicionamiento que tendra en horizontal y vertical esa columna al alinearse en el canvas (ej: elementsSize vale 60 el elemento se insertara en el medio que seria 30)
            const posX = elementsSize * (colIndex + 1/2);
            const posY = elementsSize * (rowIndex + 1/2);
//Solo le damos coordenadas a la posicion del jugador si aun no fueron dadas (si no fue definida en x no hace falta verificar que no haya sido definida en y ya que siempre se definen las dos)       
            if (col == 'O') {
                if (!playerPosition.x && !playerPosition.y) {
                playerPosition.genX = posX / elementsSize
                playerPosition.genY = posY / elementsSize
                playerPosition.x = posX
                playerPosition.y = posY   
                }}
// Localizamos la ubicacion de la meta para comprobar colision posteriormente
            else if (col == 'I') {
                giftPosition.x = posX
                giftPosition.y = posY
            } 
//Verificamos si el objeto donde se alojan las coordenadas de las bombas ya cuenta con una propiedad con el valor del nivel y si no la tiene la creamos como un array vacio
            else if (col == 'X') {
                if (!bombsPosition.hasOwnProperty(lvl)) {
                    bombsPosition[lvl] = []
                }
//Verificamos que las coordenadas no hayan sido alojadas aun y si no las insertamos en el array de arriba
                const coordExists = bombsPosition[lvl].some(coord => coord[0] === posX && coord[1] === posY);
                if (!coordExists) {
                    bombsPosition[lvl].push([posX, posY]);
                }
            }
//Llenamos en nuestro canvas con cada iteracion
            game.fillText(emoji, posX, posY)
        });
    });
    movePlayer()
}

Funciones de movimiento

function movePlayer() {
// Ubicamos al jugador en la cuadrilla obteniendo su ubicacion por medio de las variables genX/Y
    game.fillText(emojis['PLAYER'], playerPosition.genX * elementsSize, playerPosition.genY * elementsSize);
// Corregimos las coordenadas x e y del jugador para que coincidan con su ubicacion actual
    playerPosition.x = ((playerPosition.genX) * elementsSize);
    playerPosition.y = ((playerPosition.genY) * elementsSize);
// Detectamos la colision con las bombas y la meta
    bombsDetection()
    giftDetection()
}

window.addEventListener('keydown', moveByKeys);
buttons.up.addEventListener('click', moveUp);
buttons.left.addEventListener('click', moveLeft);
buttons.right.addEventListener('click', moveRight);
buttons.down.addEventListener('click', moveDown);
 
function moveByKeys(event) {
    if (event.key == 'ArrowUp') moveUp();
    else if (event.key == 'ArrowLeft') moveLeft();
    else if (event.key == 'ArrowRight') moveRight();
    else if (event.key == 'ArrowDown') moveDown();
}
function moveUp() {
    playerPosition.genY -= 1;
//Si el jugador se desplaza fuera del canvas lo volvemos a insertar en la primera posicion de la coordenada y
    if (playerPosition.genY < 0) {
        playerPosition.genY = 0.5;
    }
    startGame(lvl);
}
function moveLeft() {
    playerPosition.genX -= 1;
//Si el jugador se desplaza fuera del canvas lo volvemos a insertar en la primera posicion de la coordenada x
    if (playerPosition.genX < 0) {
        playerPosition.genX = 0.5;
    }
    startGame(lvl);
}
function moveRight() {
    playerPosition.genX += 1;
//Si el jugador se desplaza fuera del canvas lo volvemos a insertar en la ultima posicion de la coordenada x
    if (playerPosition.genX > 10) {
        playerPosition.genX = 9.5;
    }
    startGame(lvl);
}
function moveDown() {
    playerPosition.genY += 1;
//Si el jugador se desplaza fuera del canvas lo volvemos a insertar en la ultima posicion de la coordenada y
    if (playerPosition.genY > 10) {
        playerPosition.genY = 9.5;
    }
    startGame(lvl);
}

Funciones de deteccion

function bombsDetection () {
//Buscamos una coincidencia en el array contenido en la propiedad lvl(ej. 0) y en caso de que la posicion del jugador coincida con alguna de las bombas reseteamos su posicion al inicio del mapa 
    bombsDetected = bombsPosition[lvl].find(bomb => bomb[0] == playerPosition.x && bomb[1] == playerPosition.y)
    if (bombsDetected) {
        console.log("collision detected")
        playerPosition.x =  undefined;
        playerPosition.y =  undefined;
        startGame(lvl)
      }
}

function giftDetection () {
//Verificamos si la posicion del jugador y la meta son identicas y si lo son lo desplazamos al siguiente nivel, si llegamos al ultimo nivel volvemos al primero
    if (playerPosition.x == giftPosition.x && playerPosition.y == giftPosition.y) {
        console.log("gift detected")
        if (lvl < (maps.length - 1)) {
            lvl += 1;
        } else {
            playerPosition.x =  undefined;
            playerPosition.y =  undefined;
            lvl = 0
        }
        startGame(lvl)
        } 
}

Funcion de resize

function resizeCanvas () {
    windowHeight = window.innerHeight * 0.8
    windowWidth = window.innerWidth * 0.8
//Dependiendo del tamaño de la pantalla, va a colocar el tamaño cuadrado del canvas
//Al dividir entre 10 y luego aproximar el valor a un entero garantiza que el canvas será un entero múltiplo de 10. Finalmente se multiplica la expresión por 10 para obtener el dato real del canvas
//Con Math.ceil nos ahorramos el problema de los decimales
    if (window.innerHeight > window.innerWidth) {
        if ((windowWidth % 10) !== 0) {
             canvasSize = Math.ceil(windowWidth / 10) * 10;
        } else {
             canvasSize = windowWidth;
        }} 
    else {
        if ((windowHeight % 10) !== 0) {
             canvasSize = Math.ceil(windowHeight / 10) * 10;
        } else {
             canvasSize = windowHeight;
        }
    }

     canvas.setAttribute('width', canvasSize);
     canvas.setAttribute('height', canvasSize);
     elementsSize = (canvasSize / 10);
     startGame(lvl)
     
 }

Yo cambie las variables del maps a let y agregue un indeci

let indexMap = 0;
let map;
let mapRows;
let mapCols;

Cree una función para convertir el mapa siguiente

function convertMap(){
    map = maps[indexMap];
    mapRows = map.trim().split('\n');
    mapCols = mapRows.map(row=>row.trim().split(''));
}

A la posición del jugador ingresé una bandera i, esta se resetea al iniciar el juego o cuando colisiona con una bomba

const playerPosition={
    x: undefined,
    y: undefined,
    i: 0,
};

Y cada movimiento de jugador agregué lo siguiente

function moveUp(){
    if(playerPosition.y>elementSize){
        playerPosition.y-=elementSize;
        detectarObjeto();
    }
    setCanvasSize();
    
}
function moveLeft(){
    if(playerPosition.x > elementSize+1){
        playerPosition.x -= elementSize;
        detectarObjeto();
    }
    setCanvasSize();
}
function moveRight(){
    if(playerPosition.x<elementSize*10){
        playerPosition.x+=elementSize;
        detectarObjeto();
    } 
    setCanvasSize();
}
function moveDown(){
    if(playerPosition.y < elementSize*10){
        playerPosition.y+=elementSize;
        detectarObjeto();
    }
    
    setCanvasSize();
}
function detectarObjeto(){
    posX = Math.round(playerPosition.x/elementSize)-1;
    posY = Math.round(playerPosition.y/elementSize)-1;
    if(mapCols[posY][posX]==='X'){
        playerPosition.i=0;
    }
    else if(mapCols[posY][posX]==='I'){
        if(indexMap< (maps.length-1)){
            indexMap++;
        }
        
    }

}```


yo me encontre con el mismo error, y tuve pausado el video, cuando volvi a poner el video lo entendi todo jaja, lo unico que no me queda claro es por que tuve que cambiar las validaciones en los movimientos, pero bueno, ahi voy entendiendo de a poco, muy bueno!!!

Mi solución:
Genere una función collision la cual comparta la posición actual del jugador contra el array del mapa (variable global)
la cual es llamada desde cada función de movimiento

Saludos!

Ubiqué el condiconal de coordenadas en la función de aparecer al jugador, así solo la escribo una vez y me detecta solo el caso cuando las coordenadas del jugador y regalito coinciden:

function movePlayer() {
    game.fillText(emojis['PLAYER'], playerPos.x, playerPos.y);
    if (playerPos.x == giftPos.x && playerPos.y == giftPos.y){
        console.log("you're here!")
    }
}

También se podría realizar la colusión cuando el player abandone el camino libre de obstáculos.

Muy buena la explicación del const para un objeto.
Ahora me surge una duda. Seria lo mismo declarar el objeto con let ?

Les comparto mi solución a los retos que se presentaron hasta el momento… Me da pereza explicar ya que mi código está quedando bastante diferente del de la clase, pero intenté que sea lo más claro posible. Las posiciones las manejo con números enteros y no vuelvo a hacer render de todo el mapa cada vez que se mueve el personaje.

const canvas = document.querySelector('#game');
const game = canvas.getContext('2d');
const btnUp = document.getElementById('up');
const btnLeft = document.getElementById('left');
const btnRight = document.getElementById('right');
const btnDown = document.getElementById('down');
const vidas = document.getElementById('vidas')

let canvasSize = Math.min(window.innerHeight, window.innerWidth)*0.8;
let elementSize = canvasSize/10;

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

let lvl = 0;
let lives = 3;

const initialPosition = {
  posX: undefined,
  posY: undefined,
}

const position = {
  posX: undefined,
  posY: undefined,
}

window.addEventListener('load', renderMap);
window.addEventListener('resize', resizeMap);

function resizeMap() {
  canvasSize = Math.min(window.innerHeight, window.innerWidth)*0.8;
  elementSize = canvasSize/10;
  
  canvas.setAttribute('width', canvasSize);
  canvas.setAttribute('height', canvasSize);

  renderMap();
}

function renderMap() {
  game.font = (`${elementSize * 0.85}px verdana`);
  game.textAlign = 'end' 

  const map = maps[lvl];
  const mapRow = map.trim().replaceAll(' ', '').split('\n');
  const mapRowCol = mapRow.map( row => row.split(''));
  
  mapRowCol.forEach((row, rowI) => {
    row.forEach((col, colI) => {
      const emoji = emojis[col];
      const posX = elementSize * (colI + 1);
      const posY = elementSize * (rowI + 1);
      game.fillText(emoji, posX, posY);
      if (col === 'O') {
        //Divido todo por elementSize para que las posiciones queden definidas del 1 al 10
        initialPosition.posX = posX/elementSize;
        initialPosition.posY = posY/elementSize;
        
        if (!position.posX){
          position.posX = posX/elementSize;
          position.posY = posY/elementSize;
        }
      }
    })
  });
  game.fillText(emojis['PLAYER'], position.posX * elementSize, position.posY * elementSize);
}

function startGame() {
  lives = 3;
  lvl = 0;
  vidas.innerText = `Vidas: ${lives}`;
  position.posX = undefined;
  position.posY = undefined;
  game.clearRect(0, 0, canvasSize, canvasSize);
  renderMap();
}

btnUp.addEventListener('click', moveUp);
btnLeft.addEventListener('click', moveLeft);
btnRight.addEventListener('click', moveRight);
btnDown.addEventListener('click', moveDown);
window.addEventListener('keydown', (event) => {
  switch (event.key) {
    case 'ArrowUp':
      moveUp()
      break;
    
    case 'ArrowLeft':
      moveLeft()
      break;

    case 'ArrowRight':
      moveRight()
      break;

    case 'ArrowDown':
      moveDown()
      break;
    default:
        break;
  }
})

function moveUp() {
  move('up');
}
function moveLeft() {
  move('left');
}
function moveRight() {
  move('right');
}
function moveDown() {
  move('down');
}

function clear(position) {
  const startClearX = position.posX * elementSize - elementSize;
  const startClearY = position.posY * elementSize - (elementSize * .83);
  const endClearX = elementSize;
  const endClearY = (elementSize * 1.08);
  game.clearRect(startClearX, startClearY, endClearX, endClearY);
}

function move(dir) {
  if (lives == 0){
    startGame();
    return
  }

  const previousPosition = {
    posX: position.posX,
    posY: position.posY,
  }

  if (dir === 'up') position.posY -= 1;
  else if (dir === 'left') position.posX -= 1;
  else if (dir === 'right') position.posX += 1;
  else if (dir === 'down') position.posY += 1;
  
  if (position.posX < 1 || position.posY < 1 || position.posX > 10 || position.posY > 10) {
    position.posX = previousPosition.posX;
    position.posY = previousPosition.posY;
    return
  }

  clear(previousPosition);
  
  if (previousPosition.posX == initialPosition.posX && previousPosition.posY == initialPosition.posY) {
    game.fillText(emojis['O'], previousPosition.posX * elementSize, previousPosition.posY * elementSize)
  }
  
  const map = maps[lvl];
  const mapRow = map.trim().replaceAll(' ', '').split('\n');
  const mapRowCol = mapRow.map( row => row.split(''));
  const emoji = mapRowCol[position.posY - 1][position.posX - 1];

  if (emoji === 'X'){
    clear(position);
    game.fillText(emojis['BOMB_COLLISION'], position.posX * elementSize, position.posY * elementSize);
    lives -= 1;
    vidas.innerText = `Vidas: ${lives}`
    if (lives == 0) {
      game.clearRect(0, 0, canvasSize, canvasSize);
      game.fillText('YOU LOSE!!!   \n'+ emojis['GAME_OVER'], canvasSize*0.8, canvasSize*0.5 )
      return
    }
    position.posX = initialPosition.posX;
    position.posY = initialPosition.posY;
  }

  if (emoji === 'I') {
    lvl += 1;
    game.clearRect(0, 0, canvasSize, canvasSize);
    if (lvl == maps.length) {
      game.fillText('YOU WIN!!!   \n'+ emojis['WIN'], canvasSize*0.8, canvasSize*0.5 )
      lives = 0
      return
    }
    renderMap();
    return
  }

  game.fillText(emojis['PLAYER'], position.posX * elementSize, position.posY * elementSize);
}
mi solución para las colisiones la implemente en la función startGame() ![](https://static.platzi.com/media/user_upload/code-b040fed5-482e-4164-97c9-3091ad5a05a4.jpg)![](https://static.platzi.com/media/user_upload/code1-e4f84263-139d-4025-999d-07ccb07007c1.jpg)
Para prevenir varios de estos errores lo que se puede hacer es un Math.floor al elementSize, a mi me funciono para varias pantallas; `  elementSize = Math.floor( canvasSize / 10) ;``// Set te values to int number and prevent errors`

if(colision){
console.log(“hay colicion”)
if(mapaActual < maps.length){
mapaActual = mapaActual +1
map = maps[mapaActual];
console.log(mapaActual)
startGame();
}
}

yo lo hice haciendo a maps gloval y haciendo esta funcion

como solucione si colisiona con el reglo

function movePlayer (){
    game.fillText(emojis['PLAYER'], playerPositions.x, playerPositions.y )
    if (playerPositions.x == giftPosition.x && playerPositions.y == giftPosition.y) {
        console.log('pasate de nivel')

    }
}```
Solucion apra collision con las bomb (aunque estoy usando otro emojie) Casi completo el juego XD, hice quqe cada vez que el jugador cae en un veneno, pues, cambie el caracter del player. Podran ver que la manera en como determino la posicion de las bombas, es agregandolas como un objeto. es un array que continee objetos por cada bomba, dentro de esos objeto tengo las posiciones x,y, de ese objec (bomba) o veneno... ```js function deadPlayer(collision){  if(collision){    const deadPlayer = emojis\['GAME\_OVER'];      game.fillText(deadPlayer,playerPosition.x,playerPosition.y);  }} //Function to check possible collision: //every bombPosition element array is an object, and that object has a property x and yfunction isBombCollision(x,y){  let collision = false;  bombPosition.forEach((element)=>{      if((element.x == x) && (element.y == y)){        collision = true;        deadPlayer(collision);      }  });   return collision;} //como determine las posiciones de las bombas: else if(col=='X'){            //bomb positons            bombPosition.push({              x:posX,              y:posY             }); ```
Hola, no he visto el video aun, pero aqui esta como yo lo hice. Antes de, estoy llevando el proyecto con git, y lo que hice fue que antes de ver el video he creado una rama aparte, alli me puse a intentar hacerlo yo.. en verdad no era tan dificil. Una vez que se llega al objetivo, pues, hago un clear completo y felicito al jugador, me gustaria agregar un boton "next level" o algo asi. Vamos a ver como lo hace el gran Juan David! ```js function collisionGift(){    let playerPosTotal = playerPosition.x + playerPosition.y;    let giftPositionTotal = giftPosition.x + giftPosition.y;       if(playerPosTotal === giftPositionTotal){        game.clearRect(0,0,canvasSize,canvasSize);        game.font = '15px verdana';        game.fillText('Congratulation, you just Won!',200,150);      }} ```
function movePlayer() {
  const giftCollisionX = Math.floor(playerPosition.x) == Math.floor(giftPosition.x);
  const giftCollisionY = Math.floor(playerPosition.y) == Math.floor(giftPosition.y);
  const giftCollision = giftCollisionX && giftCollisionY;

  if (giftCollision) {
    console.log('Subiste de nivel');
  }
  game.fillText(emojis['PLAYER'],playerPosition.x,playerPosition.y)
}

me gusto mucho el ejemplo de Sergio Alejandro Saldaña Rangel, el uso los indices de los elementos, en vez de usar los pixeles, y tambien creo una funcion que ayuda a calcular la posicion de cada elemento las cuales son (getx y getY), al hacer esto se vuelve el juego mucho mas personalizable y es muchisimo mas facil calcular las coliciones, asi mismo cambie algunas cosas, como el bombPosition, en vez de usar simples variables, a X y a Y les puse un array y pongo cada cordenada de las bombas en ellos, para luego con un ciclo for recorrerlos y hacer la comparacion de las bombas, asi va mi codigo:

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

const playerRender = {
  level: 2,
  playerPosition: {
    x: undefined,
    y: undefined,
  },
  giftPosition: {
    x: undefined,
    y: undefined,
  },
  bombPosition: {
    x: [],
    y: [],
  },
  movePlayer: function () {
    const x = this.getX('PLAYER', this.playerPosition.x)
    const y = this.getY('PLAYER', this.playerPosition.y)

    game.fillText(emojis['PLAYER'], x, y);
  },
  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';

    game.clearRect(0, 0, canvasSize, canvasSize)
    map.forEach((row, rowIndex) => {
      row.forEach((col, colIndex) => {
        const emoji = emojis[col];
        const posX = this.getX(col, colIndex + 1);
        const posY = this.getY(col, rowIndex + 1);


        if (col == 'O') {
          if (!this.playerPosition.x && !this.playerPosition.y) {
            this.playerPosition.x = colIndex + 1;
            this.playerPosition.y = rowIndex + 1;
          }
        } else if (col == 'I') {
          this.giftPosition.x = colIndex + 1;
          this.giftPosition.y = rowIndex + 1;
        } else if (col == 'X') {
          this.bombPosition.x.push(colIndex + 1);
          this.bombPosition.y.push(rowIndex + 1);
        }


        game.fillText(emoji, posX, posY);
      });
    });
    this.movePlayer();
  },
  getX: function (icon, posicionNumber) {
    if (icon === 'X') {
      return elementSize * ((posicionNumber - 0.42));
    } else if (icon === 'I') {
      return elementSize * ((posicionNumber - 0.48));
    } else if (icon === 'O') {
      return elementSize * ((posicionNumber - 0.48));
    } else if (icon === 'PLAYER') {
      return elementSize * ((posicionNumber - 0.48));
    } else if (icon === 'BOMB_COLLISION') {
      return elementSize * ((posicionNumber - 0.42));
    }
  },
  getY: function (icon, posicionNumber) {
    if (icon === 'X') {
      return elementSize * ((posicionNumber - 0.32));
    } else if (icon === 'I') {
      return elementSize * ((posicionNumber - 0.28));
    } else if (icon === 'O') {
      return elementSize * ((posicionNumber - 0.32));
    } else if (icon === 'PLAYER') {
      return elementSize * ((posicionNumber - 0.20));
    } else if (icon === 'BOMB_COLLISION') {
      return elementSize * ((posicionNumber - 0.32));
    }
  }

}

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() {
  playerRender.render()
}

// Mapeo entre teclas y direcciones
const keyToDirection = {
  ArrowUp: 'up',
  ArrowLeft: 'left',
  ArrowDown: 'down',
  ArrowRight: 'right',
  w: 'up',
  a: 'left',
  s: 'down',
  d: 'right'
};

const directionToButton = {
  up: document.querySelector('#up'),
  left: document.querySelector('#left'),
  down: document.querySelector('#down'),
  right: document.querySelector('#rigth'),
};

Object.keys(directionToButton).forEach(direction => {
  directionToButton[direction].addEventListener('click', () => {
    move(direction);
  });
});

window.addEventListener('keydown', moveByKey);

function moveByKey(event) {
  const direction = keyToDirection[event.key];
  if (direction) {
    move(direction);
  }
}

function move(direction) {
  if (direction == 'up') {
    if ((playerRender.playerPosition.y) >= 2) playerRender.playerPosition.y -= 1
  } else if (direction == 'left') {
    if ((playerRender.playerPosition.x) >= 2) playerRender.playerPosition.x -= 1
  } else if (direction == 'right') {
    if (playerRender.playerPosition.x <= 9) playerRender.playerPosition.x += 1
  } else if (direction == 'down') {
    if (playerRender.playerPosition.y <= 9) playerRender.playerPosition.y += 1
  }
  
  if (playerRender.playerPosition.x == playerRender.giftPosition.x && playerRender.playerPosition.y == playerRender.giftPosition.y) {
    console.log('colision jugador con regalo')
  }
  playerRender.bombPosition.x.forEach((xBombs, indexBomb) =>{
    let yBombs = playerRender.bombPosition.y[indexBomb]

    if (playerRender.playerPosition.x == xBombs && playerRender.playerPosition.y == yBombs) {
      console.log('Colision Jugador con bombas')
    }

  })
  
  console.log('Posicion jugador', playerRender.playerPosition, 'Posicion bomba', playerRender.bombPosition)

  playerRender.movePlayer();
  startGame();
}

Yo lo hice así all in one 😎

Psdt. Puse un setTimeout para poner el jugador por encima de todos los obstaculos

reto superado. 🚀

Yo lo solucioné en los movimientos del usuario para que evalúe si la posición es igual a la del objecto (emoji).

Yo también me topé con el error de los decimales y lo solucioné desde el principio con Math.round() y me funciona muy bien

a mi no me detectaron!! =(

Si me llegó a pasar lo de que los decimales no coincidían xd

Para la colisión de bombas creé un array para almacenar las posiciones de cada bomba y luego verificar si existe colisión

Agregué la colisión entre el jugador y el regalo en la función de movePlayer()

Hice una funcion para detectar colisiones o coincidencias en general( uso la misma función para saber si llego al regalo o si esta en la entrada):

  • La función recibe un solo parametro que es el objeto con el que queremos comparar su posicion respecto al jugador.
  • El condicional evalua si el objeto pasado en el parametro esta en el area de nuestro jugador.
  • Con la evaluacion retornar un true o false que puedo usar en otra condicional para decidir que hacer
function detectColission({ x, y }) {
  if (
    playerPosition.x - x <= blocksSize * 0.05 &&
    playerPosition.y - y <= blocksSize * 0.05 &&
    playerPosition.x + blocksSize - x >= blocksSize * 0.05 &&
    playerPosition.y + blocksSize - y >= blocksSize * 0.05
  ) {
    return true;
  } else {
    return false;
  }
}
  • Usandolo para reconocer bombas seria asi:

Tengamos en cuenta que bombsPosition es un array de objetos con la posición de las bombas

 bombsPosition.forEach((bomb) => {
    if (detectColission(bomb)) {
      console.log("You lose!!");
    }
  });

No creo que sea la manera mas optima evaluar con cada movimiento y comparar con todas las posiciones pero pensare en algo mientras continuo el curso.

Si usamos la lógica, claramente el mejor lugar de nuestro código para colocar el condicional que detecta las colisiones es en la función movePlayer().

¿Por qué?
Pues precisamente porque, hasta que no movamos nuestro jugador no sabremos si está en una u otra posición y por lo tanto el momento exacto en el que nos desplazamos es el ideal para analizar si hay una colisión.

Agregué un array vacío para guardar las posisiones

let bombPositions = [];

luego cuando iteramos las posisiones en el mapa asignamos las coordenadas de x , y y hacemos push al array con cada posisión

mapRowToCol.forEach( (row, rowIndex) => {
        row.forEach( (col, colIndex) => {

            let posX = elementSize * (colIndex + 1);
            let posY = elementSize * (rowIndex + 1);        
            let emoji = emojis [col];

            let bombPosition = {
                X: undefined,
                Y: undefined,
            }
          
            if (col == 'O') {
                if(!playerPosition.X && !playerPosition.Y){
                    playerPosition.X = posX;
                    playerPosition.Y = posY;
                };
            } else if (col == 'I') {
                giftPosition.X = posX;
                giftPosition.Y = posY;
            } else if (col == 'X') {
                bombPosition.X = posX;
                bombPosition.Y = posY;

                bombPositions.push(bombPosition);
            
            } 

La razon por la cual los objetos constantes despues se pueden cambiar, es porque nunca cambiamos el tipo de dato.

const myObject = {
x : undefined
}

myObject.x = 10 //Estamos modificando la propiedad del objeto. pero sigue siendo un objeto.

myObject = new Array(1,2) //Error: ¿Porque? Porque estamos intentando cambiar el “TIPO” de dato

el dato curioso sobre los objetos en javascript no la sibia. Gracias Juan David

Como estoy un objeto literal de mi mapa, entonces ahi le inserte el array de las bombas

const map= {
...
bombPosition: [],
...
}

Y para que se agregue cada posición de la bomba
En el funcion render que esta dentro de mi objeto map, hago

if (y === "X") {
                    this.bombPosition.push({ x: posX, y: posY })
                }

Así pues ya se guarda todas las posiciones de las bombas

Ahora me puse el reto de que se renderice el siguiente mapa, cuando gane,
tomar en cuenta

  • Cuando pase de nivel se tiene que
  1. renderizar el nuevo mapa, con el personaje en la puerta
  2. El arreglo de las posiciones de las bombas tienes que reiniicarse, ya que seran otras posiciones

Para lo que agregre una nueva funcion que se llama lvlUp().
Esta funcion le aumenta el lvl, resetea el array de las bombas, puesto que en cada nivel tendremos diferentes posiciones, y vuelve a renderizar el game, con el siguiente nivel.
Es importante la parte de limpiar el array de bombas que creamos

function lvlUp() {
    if (map.lvl < maps.length - 1) {
        map.lvl += 1;
        map.bombPosition = []
        startGame()
    }

}

Entonces como estamos haciendo prácticamente todo cuando se mueve el jugador,
mi funcion que lo renderiza(si están haciendo como el profe, seria su movePlayer), queda asi

  playerPosition: {
        x: undefined,
        y: undefined,
        render: function () {
            game.fillText(emojis["PLAYER"], this.y, this.x);
            const coincideX = Math.floor(this.x) === Math.floor(map.giftPosition.x);
            const coincideY = Math.floor(this.y) === Math.floor(map.giftPosition.y);

            if (coincideY && coincideX) {
                console.log("Subiste de nivel")
                lvlUp()
            }
            endGame()
        }

    }

Ah, tambien cree la funcion endGame, que está lo que hace es decirme cuando perdi, y tambien va dentro del render del jugador

function endGame() {
    for (let bomb of map.bombPosition) {
        const coincideX = Math.floor(map.playerPosition.x) === Math.floor(bomb.x);
        const coincideY = Math.floor(map.playerPosition.y) === Math.floor(bomb.y);

        if (coincideY && coincideX) {
            console.log("perdiste")
        }
    }
}

Con todo esto, ya subo de nivel, y tambien me dice cuando perdi
Sin embargo el bug que me esta corriendo es que, cuando paso por encima de una bomba, me aparece como si hubiera pasado varias veces

Lo que hice fue crear un array con objetos de las posiciones de las bombas, en el mismo lugar que hicimos lo de PLAYER y GIF
y una variable global
let bombasPosition = [];

      if (col == "X") {
        bombasPosition.push({
          x: posX,
          y: posY,
        });
      }

y abajo de donde se agrego la colisión de gif
EL siguiente codigo.

const bombaColision = bombasPosition.find((position) => {
    const bombaColisionX = playerPosition.x.toFixed(3) == position.x.toFixed(3);
    const bombaColisionY = playerPosition.y.toFixed(3) == position.y.toFixed(3);
    return playerPosition.x
    ? bombaColisionX && bombaColisionY
    : false;
  });
  console.log("colision",bombaColision);
  if(bombaColision) console.log("Bomba Perdiste");
};

Con el find en el memento que encuentra la colisión termina de buscar.