search
CursosEmpresasBlogLiveConfPrecios
Taller Práctico de JavaScript: ¡Crea tu Primer Videojuego!

Detectando colisiones con arrays

Taller Práctico de JavaScript: ¡Crea tu Primer Videojuego!

Contenido del curso

Introducción

  • 1
    Programemos un juego con JavaScript

    Programemos un juego con JavaScript

    17:13 min

Canvas

  • 2
    ¿Qué es canvas en JavaScript?

    ¿Qué es canvas en JavaScript?

    18:37 min
  • 3
    Tamaño del canvas y sus elementos

    Tamaño del canvas y sus elementos

    17:37 min
  • 4
    Canvas responsive

    Canvas responsive

    12:37 min

Mapa del juego

  • 5
    ¿Qué es un array bidimensional?

    ¿Qué es un array bidimensional?

    05:48 min
  • 6
    Arreglos multidimensionales en JavaScript

    Arreglos multidimensionales en JavaScript

    23:38 min
  • 7
    Refactor del mapa de juego

    Refactor del mapa de juego

    20:48 min

Movimientos del jugador

  • 8
    Eventos y botones

    Eventos y botones

    14:14 min
  • 9
    Objeto playerPosition

    Objeto playerPosition

    11:34 min
  • 10
    Limpieza de movimientos

    Limpieza de movimientos

    09:53 min
  • 11
    No te salgas del mapa

    No te salgas del mapa

    11:15 min

Colisiones

  • 12
    Detectando colisiones fijas

    Detectando colisiones fijas

    13:29 min
  • 13
    Detectando colisiones con arrays

    Detectando colisiones con arrays

    Viendo ahora
  • 14
    Victoria: subiendo de nivel

    Victoria: subiendo de nivel

    07:50 min
  • 15
    Derrota: perdiendo vidas

    Derrota: perdiendo vidas

    11:45 min

Bonus: adictividad

  • 16
    Sistema de vidas y corazones

    Sistema de vidas y corazones

    13:02 min
  • 17
    Sistema de tiempo y puntajes

    Sistema de tiempo y puntajes

    19:30 min
  • 18
    ¿Qué es localStorage?

    ¿Qué es localStorage?

    07:33 min
  • 19
    Guardando records del jugador

    Guardando records del jugador

    18:35 min

Deploy

  • 20
    Depurando errores del juego

    Depurando errores del juego

    23:16 min
  • 21
    Desplegando el juego a GitHub Pages

    Desplegando el juego a GitHub Pages

    07:39 min

Próximos pasos

  • 22
    Reto: reinicio del juego

    Reto: reinicio del juego

    03:36 min
  • 23
    Reto: timeouts de victoria o derrota

    Reto: timeouts de victoria o derrota

    04:14 min
  • 24
    ¿Quieres un simulador laboral?

    ¿Quieres un simulador laboral?

    06:53 min
schoolTomar examen

Detectando colisiones con arrays

Escuelas

  • Desarrollo Web
    • Fundamentos del Desarrollo Web Profesional
    • Diseño y Desarrollo Frontend
    • Desarrollo Frontend con JavaScript
    • Desarrollo Frontend con Vue.js
    • Desarrollo Frontend con Angular
    • Desarrollo Frontend con React.js
    • Desarrollo Backend con Node.js
    • Desarrollo Backend con Python
    • Desarrollo Backend con Java
    • Desarrollo Backend con PHP
    • Desarrollo Backend con Ruby
    • Bases de Datos para Web
    • Seguridad Web & API
    • Testing Automatizado y QA para Web
    • Arquitecturas Web Modernas y Escalabilidad
    • DevOps y Cloud para Desarrolladores Web
  • English Academy
    • Inglés Básico A1
    • Inglés Básico A2
    • Inglés Intermedio B1
    • Inglés Intermedio Alto B2
    • Inglés Avanzado C1
    • Inglés para Propósitos Específicos
    • Inglés de Negocios
  • Marketing Digital
    • Fundamentos de Marketing Digital
    • Marketing de Contenidos y Redacción Persuasiva
    • SEO y Posicionamiento Web
    • Social Media Marketing y Community Management
    • Publicidad Digital y Paid Media
    • Analítica Digital y Optimización (CRO)
    • Estrategia de Marketing y Growth
    • Marketing de Marca y Comunicación Estratégica
    • Marketing para E-commerce
    • Marketing B2B
    • Inteligencia Artificial Aplicada al Marketing
    • Automatización del Marketing
    • Marca Personal y Marketing Freelance
    • Ventas y Experiencia del Cliente
    • Creación de Contenido para Redes Sociales
  • Inteligencia Artificial y Data Science
    • Fundamentos de Data Science y AI
    • Análisis y Visualización de Datos
    • Machine Learning y Deep Learning
    • Data Engineer
    • Inteligencia Artificial para la Productividad
    • Desarrollo de Aplicaciones con IA
    • AI Software Engineer
  • Ciberseguridad
    • Fundamentos de Ciberseguridad
    • Hacking Ético y Pentesting (Red Team)
    • Análisis de Malware e Ingeniería Forense
    • Seguridad Defensiva y Cumplimiento (Blue Team)
    • Ciberseguridad Estratégica
  • Liderazgo y Habilidades Blandas
    • Fundamentos de Habilidades Profesionales
    • Liderazgo y Gestión de Equipos
    • Comunicación Avanzada y Oratoria
    • Negociación y Resolución de Conflictos
    • Inteligencia Emocional y Autogestión
    • Productividad y Herramientas Digitales
    • Gestión de Proyectos y Metodologías Ágiles
    • Desarrollo de Carrera y Marca Personal
    • Diversidad, Inclusión y Entorno Laboral Saludable
    • Filosofía y Estrategia para Líderes
  • Diseño de Producto y UX
    • Fundamentos de Diseño UX/UI
    • Investigación de Usuarios (UX Research)
    • Arquitectura de Información y Usabilidad
    • Diseño de Interfaces y Prototipado (UI Design)
    • Sistemas de Diseño y DesignOps
    • Redacción UX (UX Writing)
    • Creatividad e Innovación en Diseño
    • Diseño Accesible e Inclusivo
    • Diseño Asistido por Inteligencia Artificial
    • Gestión de Producto y Liderazgo en Diseño
    • Diseño de Interacciones Emergentes (VUI/VR)
    • Desarrollo Web para Diseñadores
    • Diseño y Prototipado No-Code
  • Contenido Audiovisual
    • Fundamentos de Producción Audiovisual
    • Producción de Video para Plataformas Digitales
    • Producción de Audio y Podcast
    • Fotografía y Diseño Gráfico para Contenido Digital
    • Motion Graphics y Animación
    • Contenido Interactivo y Realidad Aumentada
    • Estrategia, Marketing y Monetización de Contenidos
  • Desarrollo Móvil
    • Fundamentos de Desarrollo Móvil
    • Desarrollo Nativo Android con Kotlin
    • Desarrollo Nativo iOS con Swift
    • Desarrollo Multiplataforma con React Native
    • Desarrollo Multiplataforma con Flutter
    • Arquitectura y Patrones de Diseño Móvil
    • Integración de APIs y Persistencia Móvil
    • Testing y Despliegue en Móvil
    • Diseño UX/UI para Móviles
  • Diseño Gráfico y Arte Digital
    • Fundamentos del Diseño Gráfico y Digital
    • Diseño de Identidad Visual y Branding
    • Ilustración Digital y Arte Conceptual
    • Diseño Editorial y de Empaques
    • Motion Graphics y Animación 3D
    • Diseño Gráfico Asistido por Inteligencia Artificial
    • Creatividad e Innovación en Diseño
  • Programación
    • Fundamentos de Programación e Ingeniería de Software
    • Herramientas de IA para el trabajo
    • Matemáticas para Programación
    • Programación con Python
    • Programación con JavaScript
    • Programación con TypeScript
    • Programación Orientada a Objetos con Java
    • Desarrollo con C# y .NET
    • Programación con PHP
    • Programación con Go y Rust
    • Programación Móvil con Swift y Kotlin
    • Programación con C y C++
    • Administración Básica de Servidores Linux
  • Negocios
    • Fundamentos de Negocios y Emprendimiento
    • Estrategia y Crecimiento Empresarial
    • Finanzas Personales y Corporativas
    • Inversión en Mercados Financieros
    • Ventas, CRM y Experiencia del Cliente
    • Operaciones, Logística y E-commerce
    • Gestión de Proyectos y Metodologías Ágiles
    • Aspectos Legales y Cumplimiento
    • Habilidades Directivas y Crecimiento Profesional
    • Diversidad e Inclusión en el Entorno Laboral
    • Herramientas Digitales y Automatización para Negocios
  • Blockchain y Web3
    • Fundamentos de Blockchain y Web3
    • Desarrollo de Smart Contracts y dApps
    • Finanzas Descentralizadas (DeFi)
    • NFTs y Economía de Creadores
    • Seguridad Blockchain
    • Ecosistemas Blockchain Alternativos (No-EVM)
    • Producto, Marketing y Legal en Web3
  • Recursos Humanos
    • Fundamentos y Cultura Organizacional en RRHH
    • Atracción y Selección de Talento
    • Cultura y Employee Experience
    • Gestión y Desarrollo de Talento
    • Desarrollo y Evaluación de Liderazgo
    • Diversidad, Equidad e Inclusión
    • AI y Automatización en Recursos Humanos
    • Tecnología y Automatización en RRHH
  • Finanzas e Inversiones
    • Fundamentos de Finanzas Personales y Corporativas
    • Análisis y Valoración Financiera
    • Inversión y Mercados de Capitales
    • Finanzas Descentralizadas (DeFi) y Criptoactivos
    • Finanzas y Estrategia para Startups
    • Inteligencia Artificial Aplicada a Finanzas
    • Domina Excel
    • Financial Analyst
    • Conseguir trabajo en Finanzas e Inversiones
  • Startups
    • Fundamentos y Validación de Ideas
    • Estrategia de Negocio y Product-Market Fit
    • Desarrollo de Producto y Operaciones Lean
    • Finanzas, Legal y Fundraising
    • Marketing, Ventas y Growth para Startups
    • Cultura, Talento y Liderazgo
    • Finanzas y Operaciones en Ecommerce
    • Startups Web3 y Blockchain
    • Startups con Impacto Social
    • Expansión y Ecosistema Startup
  • Cloud Computing y DevOps
    • Fundamentos de Cloud y DevOps
    • Administración de Servidores Linux
    • Contenerización y Orquestación
    • Infraestructura como Código (IaC) y CI/CD
    • Amazon Web Services
    • Microsoft Azure
    • Serverless y Observabilidad
    • Certificaciones Cloud (Preparación)
    • Plataforma Cloud GCP

Platzi y comunidad

  • Platzi Business
  • Live Classes
  • Lanzamientos
  • Executive Program
  • Trabaja con nosotros
  • Podcast

Recursos

  • Manual de Marca

Soporte

  • Preguntas Frecuentes
  • Contáctanos

Legal

  • Términos y Condiciones
  • Privacidad
  • Tyc promociones
Reconocimientos
Reconocimientos
Logo reconocimientoTop 40 Mejores EdTech del mundo · 2024
Logo reconocimientoPrimera Startup Latina admitida en YC · 2014
Logo reconocimientoPrimera Startup EdTech · 2018
Logo reconocimientoCEO Ganador Medalla por la Educación T4 & HP · 2024
Logo reconocimientoCEO Mejor Emprendedor del año · 2024
De LATAM conpara el mundo
YoutubeInstagramLinkedInTikTokFacebookX (Twitter)Threads

Comentarios36

Manuel Araujo

Manuel Araujo

Estudiante
Hace 4 años
    Gianluca Enzo Procopio

    Gianluca Enzo Procopio

    Estudiante
    Hace 3 años
    JUAN DAVID MARIN URIBE

    JUAN DAVID MARIN URIBE

    Estudiante
    Hace 3 años
Angel David Velasco Bonifaz

Angel David Velasco Bonifaz

Estudiante
Hace 4 años
    César Augusto Cortés Labrada

    César Augusto Cortés Labrada

    Estudiante
    Hace 4 años
    Luis Palomo

    Luis Palomo

    Estudiante
    Hace 4 años
marco antonio

marco antonio

Estudiante
Hace 4 años
    Aaron Santiago Loyo Zabala

    Aaron Santiago Loyo Zabala

    Estudiante
    Hace 3 años
    Emilio Sala

    Emilio Sala

    Estudiante
    Hace 3 años
Valeria Soledad Paez

Valeria Soledad Paez

Estudiante
Hace 4 años
Eduard Barrios

Eduard Barrios

Estudiante
Hace 4 años
Jhon Eduard Bocanegra Ortiz

Jhon Eduard Bocanegra Ortiz

Estudiante
Hace 4 años
Gianluca Enzo Procopio

Gianluca Enzo Procopio

Estudiante
Hace 3 años
Luis Palomo

Luis Palomo

Estudiante
Hace 4 años
    Gianluca Enzo Procopio

    Gianluca Enzo Procopio

    Estudiante
    Hace 3 años
Hector Maluy Fernandez

Hector Maluy Fernandez

Estudiante
Hace 4 años
leonardo alies fuentes

leonardo alies fuentes

Estudiante
Hace 3 años
    Rubén Cuello

    Rubén Cuello

    Estudiante
    Hace 3 años
    Juan camilo piedrahita londoño

    Juan camilo piedrahita londoño

    Estudiante
    Hace 3 años
Nestor Rios Garcia

Nestor Rios Garcia

Estudiante
Hace 3 años
Mauricio Combariza

Mauricio Combariza

Estudiante
Hace 3 años
Alejandro Ramos

Alejandro Ramos

Estudiante
Hace 3 años
Carlos Andres Alavez Santiago

Carlos Andres Alavez Santiago

Estudiante
Hace 3 años
David Fernando Estacio Quiroz

David Fernando Estacio Quiroz

Estudiante
Hace 3 años
David Ochoa

David Ochoa

Estudiante
Hace 4 años
Ivo Zayas

Ivo Zayas

Estudiante
Hace 4 años
Cristian Zapata

Cristian Zapata

Estudiante
Hace 4 años
Andres Eduardo Maneiro Antunez

Andres Eduardo Maneiro Antunez

Estudiante
Hace 4 años
Sergio Javier Lopez Olivera

Sergio Javier Lopez Olivera

Estudiante
Hace 4 años

Tranquilo Juan, el error de los decimales me pasó desde la primera vez que probé el código jejeje. Te creemos!

X2 jajajaj

x3 Despues de un rato debugueando me di cuenta lo que pasaba, sin saber que en los ultimos 3 minutos del video estaba la explicaion jajaj

Para no volver hacer el array en cada movimiento y estar limpiando, solo coloque una variable bandera.

let flag=true;

y donde asignamos las posiciones de las bombas se pone un condicional.

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

y afuera del ciclo for each de las rows, colocamos la bandera en falso

flag=false;

con eso cuando se vuelva a pasar ya no agregara otra vez las bombas

Me parece una solución bastante acertada.

Si, yo pensé lo mismo. Si el array fuera más largo estaríamos renderizando siempre eso.


ver tanta re-iteración hace que me duela la ram y me lastime el procesador XD, Ya hablando en serio el código de la clase se ve un poco.. rebelde, me cuesta seguirlo

como sea agregue algunas cosillas a mi código y lo he hecho un poquito mas eficiente creo que esta listo para que lo encapsule en una clase y haga unas modificaciones finales para que sea adaptativo
//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 explociones = Array(); let vidas = 3; 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(Victoria() && actualizado) return; cargarMapa(); clear(); paintEvent(); paintEventPlayer(); paintEventExplosion(); paintEventGameOver(); paintEventVictory(); actualizado = true;} function cargarMapa(){ if(nivel_actual == nivel || Victoria()) 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 && !Victoria()) mapa.forEach((char, idx) => { if(char == 'O' && posJugador == undefined) puntoDePartida = posJugador = idx; juego.fillText(emojis[char], posX(idx), posY(idx) );});} function paintEventPlayer(){ if(victoryEvent()) paintEventVictory(); else { 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 && mapa[posJugador] == 'X'){ explociones.push(posJugador); --vidas; juego.fillText(emojis['BOMB_COLLISION'],posX(posJugador),posY(posJugador)); posJugador = puntoDePartida;} if(!vidas) { explociones = Array(); return false;} /*juego terminado*/ return true; /*continuar con el juego*/} function paintEventExplosion(){ if(!explociones.length) return; explociones.forEach((pos) =>{ clearRect(pos); juego.fillText(emojis['BOMB_COLLISION'],posX(pos),posY(pos));});} function victoryEvent(){ if(mapa[posJugador] != 'I') return false; else if(nivel < map.length) ++nivel; explociones = Array(); if(Victoria()) return true; posJugador = prePosJugador = undefined; actualizado = false; update(); return false;} function paintEventGameOver(){ if(vidas) return; paintScreen('Game Over','GAME_OVER', '#FF2F22', '#211A27');} function paintEventVictory(){ if(!Victoria()) return; paintScreen('Has Ganado','WIN','#ffd700','#01433A');} function Victoria(){return nivel >= map.length;} function paintScreen(txt, emoji, colortxt = '#fff', backgroundColor ='#000'){ juego.clearRect(0,0, canvas_t, canvas_t); mapa.forEach((char, idx) =>{ if(char == 'X') char = emoji; juego.fillText(emojis[char],posX(idx),posY(idx));}); const fuente = celda_t - celda_t / 10 ; const media = canvas_t / 2; juego.fillStyle = backgroundColor; juego.fillRect(0, media - (fuente /2), canvas_t, fuente); juego.textAlign = 'center'; juego.fillStyle = colortxt; juego.fillText(txt, media, media + fuente/3); juego.textAlign='end';} //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();}

Mucho Texto

tal vez el propósito de la clase es enseñarnos lo que no debemos hacer y buscar mejor formas de resolver los problemas que nos van surgiendo por nuestra cuenta. en los aportes hay muy buenas formas de avanzar

para no cambiar el const del array

enemyPosition.splice(0, enemyPosition.length);

jajajaja me da risa que a Juan no le parece el error pero a mi me apreció antes de que él lo mencionara y lo solucioné luego él lo menciona pero no le sale y a mi me sale cada que muevo al jugador

lalala.png

Para detectar una colisión hice una validación true/false con el método SOME de arrays. Lo vimos en el curso de manipulación de arrays. Pero si no lo viste, el metodo some se trata de que si al menos un elemento del array cumple con la condición, devuelve true.

if(enemyPosition.some(item => item.x == playerPosition.x && item.y == playerPosition.y)){ alert("Chocaste con una bomba") }

Juan! A mi me pasó el error que decías. Incluso lo arreglé antes que lo mencionaras y me rascaba la cabeza pensando porque a mi no me funcionaba y a vos si. Así que te entiendo jaja.

X2 jajajajaja

Mejor ponemos todas las coordenadas a dos decimales y nos quitamos de problemas.

platzi.png

la verdad no me funciona el código copie y pegue el tuyo y tampoco me funciono mmm no por cual motivo

Hola @leoaliesf397. ¿Podrías compartirnos tu código y una descripción un poco más detallada sobre qué es lo que no funciona? De esta manera estoy seguro de que podremos ayudarte.

Colocastes el toFixed(3)? A mi no me estaba funcionando. Pero con toFixed(3). No hubo problema

Yo tengo un contador de movimientos

let moves = 0;

Y aumenta cada vez que se mueve el jugador

function movePlayer(direction) { moves++ . . .

Asi que si integro mi contador en el condicional solo se ejecutara una vez

if (column === 'X' && moves === 0) { bombsPositions.push({ x: xPosition, y: yPosition }) }

Yo cree una funcion render, una start game y una movePlayer y en la de startGame cree el array con todos los elementos, incluyendo los espacios y los regalos y lo que pongamos después, en el render no creo ningun array. Este es mi código:

function startGame() { console.log('Mapas:', mapa, mapRows, mapRowCols) mapa = maps[level] mapRows = mapa.trim().split('\n') mapRowCols = mapRows.map(row => row.trim().split('')) if (!game) { console.error('El contexto del lienzo no está disponible'); return; } game.font= elementSize + 'px Verdana' mapRowCols.forEach((row, i) => { row.forEach((col, j) => { const emoji = emojis[col] let posX = j * elementSize let posY = (i+1) * elementSize element = { elem: col, x: posX, y: posY } mapaActual.push(element) if (col == 'O'){ playerPosition = { x: posX, y: posY } // Se crea un array con el valor y las coordenadas } game.fillText(emoji, posX, posY) movePlayer() }) }) } function renderGame() { if (!game) return; game.clearRect(0, 0, canvas.width, canvas.height); mapRowCols.forEach((row, i) => { row.forEach((col, j) => { const emoji = emojis[col]; let posX = j * elementSize; let posY = (i + 1) * elementSize; if (col === 'I'){ winPosition = { x: posX, y: posY } } game.fillText(emoji, posX, posY); }); }); } function movePlayer() { if (!game) return renderGame() game.fillText(player, playerPosition.x, playerPosition.y); mapaActual.map(item => { let actualPositionX = Math.floor(playerPosition.x) === Math.floor(item.x) let actualPositionY = Math.floor(playerPosition.y) === Math.floor(item.y) let actualPosition = actualPositionX && actualPositionY if (actualPosition){ console.log(item.elem) if(item.elem === 'X') { console.log('Perdiste') level = 0 // setCanvasSize() } if(item.elem === 'I') { console.log('Ganaste eeee') if(level > maps.length - 1){ console.log('Fin del juego Ganaste!!') } else { level += 1 mapaActual = [] startGame() } } } }) }

yo estoy usando Math.Floor en lugar del toFixed e.e

Convertí los maps a Let, agregue un index para cambiar de mapa, para checar si es bomba o regalo, convertí las coordenadas a posición de un arrglo, para solucionar el problema de los decimales, usé Math.Round.

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++; } } }

Aquí dejo el resto del programa, donde incluso reinicio de niviel con un index al playerPosition, que se resetea cada que encuentra bomba.

Dejo todo el programa porque hice varios cambios

const canvas= document.querySelector('#game'); const game = canvas.getContext('2d'); const btnUp = document.querySelector('#up'); const btnLeft = document.querySelector('#left'); const btnRight = document.querySelector('#right'); const btnDown = document.querySelector('#down'); let canvasSize; let elementSize; let indexMap = 0; let map; let mapRows; let mapCols; let posX; let posY; const playerPosition={ x: undefined, y: undefined, i: 0, }; window.addEventListener('load', setCanvasSize); window.addEventListener('resize',setCanvasSize); function setCanvasSize(){ if (window.innerHeight > window.innerWidth){ canvasSize = window.innerWidth * 0.80; } else{ canvasSize = window.innerHeight * 0.80; } canvas.setAttribute('width', canvasSize); canvas.setAttribute('height', canvasSize); elementSize = canvasSize/10; startGame(); } function startGame(){ game.font = elementSize-10 + 'px Verdana'; game.textAlign = 'end'; convertMap(); game.clearRect(0,0,canvasSize,canvasSize); mapCols.forEach((rows,rowsI) => { rows.forEach((item, itemI)=>{ if(item == 'O' && playerPosition.i==0){ playerPosition.x = elementSize*(itemI+1); playerPosition.y = elementSize*(rowsI+1); playerPosition.i = 1; //console.log(elementSize*(itemI+1), elementSize*(rowsI+1)); } game.fillText(emojis[item], elementSize*(itemI+1), elementSize*(rowsI+1)); }); }); movePlayer(); /* for(let i=1; i<=10;i++){ for(let j=1; j<=10; j++){ game.fillText(emojis[mapCols[i-1][j-1]], elementSize*j, elementSize*i); } } */ } function convertMap(){ map = maps[indexMap]; mapRows = map.trim().split('\n'); mapCols = mapRows.map(row=>row.trim().split('')); } function movePlayer(){ game.fillText(emojis['PLAYER'], playerPosition.x, playerPosition.y); } window.addEventListener('keydown', moveByKeys); btnUp.addEventListener('click',moveUp); btnLeft.addEventListener('click',moveLeft); btnRight.addEventListener('click',moveRight); btnDown.addEventListener('click',moveDown); function moveByKeys(event){ if(event.key=='ArrowUp'){ moveUp(); } else if(event.key=='ArrowDown'){ moveDown(); } else if(event.key=='ArrowRight'){ moveRight(); } if(event.key=='ArrowLeft'){ moveLeft(); } } 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 decidí hacer algo diferente, en lugar de guardar la posición del jugador en pixeles guardé la posición por filas y columnas:

if(!playerPosition.X && key == 'O'){ playerPosition.X = i; playerPosition.Y = j; }

Uso esta funcion para renderizar al jugador:

function renderPlayer() { console.log(playerPosition) game.fillText( emojis['PLAYER'] , Math.floor(elementSize * playerPosition.X+1), Math.floor(elementSize * playerPosition.Y+1) ); }

Y luego, para detectar las colisiones, uso un condicional en cada movimiento que invoca a una función:

function isColliding(newRow, newColumn) { switch (columns[newRow][newColumn]) { case 'O': console.log('Returned to the start'); (nivel-1 < 0) ? nivel=nivel : nivel-=1; break; case 'X': console.log('Collided'); return true; case 'I': console.log('Finished level'); (nivel+1 == maps.length) ? nivel=nivel : nivel+=1; break; default: break; } return false }

Para evitar el problema de que las posiciones no coincidan, lo solucione almacenando los indices de cada bomba y del regalo en lugar de su valor "x" y "y"

if (col == "I") { giftIndex = { ix: colI, iy: rowI, }; } if (col == "X") { bombIndexes.push({ ix: colI, iy: rowI }); }

De igual manera mi objeto de player position almacena el indice en el que se encuentra

if (col == "O") { if (!playerPosition.x && !playerPosition.y) { playerPosition = { x: posX, y: posY, ix: colI, iy: rowI, }; } }

Y finalmente se realiza la comparación con los índices

function checkCollision() { const giftCollitionX = giftIndex.ix == playerPosition.ix; const giftCollitionY = giftIndex.iy == playerPosition.iy; const isGift = giftCollitionX && giftCollitionY; if (isGift) { console.log("Ganaste!"); return; } const isBomb = bombIndexes.find((bomb) => { const collitionX = bomb.ix == playerPosition.ix; const collitionY = bomb.iy == playerPosition.iy; return collitionX && collitionY; }); if (isBomb) { console.log("Colision"); return; } }

Espero haber ayudado a alguien 😉

Hola amiguitos!!! comparto mi solución que creo que es más práctica:

if (col == 'O') { if (!playerPosition.x && !playerPosition.y){ playerPosition.x = posX playerPosition.y = posY } } else if(col == 'I'){ checkGiftCollision(posX, posY) } else if(col == 'X'){ checkBombCollision(posX, posY) }

Cuando estoy fijándome dentro del forEach() si el indice actual es una bomba o un regalo, llamo a las funciones 'chackBombCollision()' o 'checkGiftCollision()' dependiedno el caso. Estas reciben como parámetro la posición actual de 'col' (posX y posY).

function checkGiftCollision(giftX, giftY){ if (giftY.toFixed(3) == playerPosition.y.toFixed(3) && giftX.toFixed(3) == playerPosition.x.toFixed(3)) { console.log('Felicidades'); } }

function checkBombCollision(bombX, bombY) { if (bombY.toFixed(3) == playerPosition.y.toFixed(3) && bombX.toFixed(3) == playerPosition.x.toFixed(3)) { console.log('Perdiste'); } }

Entonces comparo 'playerPosition.x' y 'playerPosition.y' con 'giftX' y 'giftY' o 'bombX' y 'bombY' y listo el pollo pelada la gallina!!! Por ahora creo que funciona, no se si se va a complicar más adelante. Aparte puedo prescindir de los objetos 'giftPosition' y 'enemyPositions' que necesitaba el profe para su solución.

No es que no le salga el error, es que la consola no saca el error sino que no se ejecuta el console.log

mi solucion es que no cree ningun array, me aparecio mas simple realizar condicionales cuando se renderiza el mapa

la logica es mas simple, cuando se realiza un movimiento del jugador llama la function de render, y en el renderizado compara tan la "I" que es el regalo y la "X" que es el obstaciulo, llama a una funcion de vicoria o de derrota

function renderMap() { game.font = `${elementsSize}px Verdana`; game.textAlign = 'end'; const map = maps[level]; game.clearRect(0, 0, canvasSize, canvasSize); const mapRows = map.trim().split('\n'); //trim() es un metodo que remueve los espacios en blanco de los treing y lo devuelve en un nuevo `string` sin modificar el original, el .split, elimina el caracter que se le indique en el argumento const mapRowsCols = mapRows.map(row => row.trim().split('')); game.clearRect(0, 0, canvasSize, canvasSize); mapRowsCols.forEach((row, rowIndex) => { row.forEach((col, colIndex) => { const emoji = emojis[col]; const posX = (elementsSize * (colIndex + 1))+12; const posY = elementsSize * (rowIndex + 1); if (col == 'O') { playerPosition.initialX = posX; playerPosition.initialY = posY; }; if (col == 'I') { if(playerPosition.x == posX && playerPosition.y == posY) { win(); return } } if (col == 'X') { if(playerPosition.x == posX && playerPosition.y == posY) { lose() return } } game.fillText(emoji, posX, posY); }); }); return

Hice un objeto bomb position que por dentro tiene como arrays las coordenadas x / y de cada 'X' que se encuentre en el render del startGame(), además de un indicador de flag para que no se llenen nuevamente las mismas posiciones de las bombas dentro del render de la pantalla:

const bombsPos = { x: [], y: [], }; let bombFlag = true; ... function startGame(){ ... if (col == 'X' && bombFlag == true) { bombsPos.x.push(posX); bombsPos.y.push(posY); } ... bombFlag = false; } ... //mas adelante function movePlayer() { game.fillText(emojis['PLAYER'], playerPos.x, playerPos.y); let bombExpX = bombsPos.x.find( bomb => bomb == playerPos.x); let bombExpY = bombsPos.y.find( bomb => bomb == playerPos.y); if (playerPos.x == giftPos.x && playerPos.y == giftPos.y){ level += 1; startGame(); } else if (bombExpX == playerPos.x && bombExpY == playerPos.y) { console.log('BOOOOM') } //esto nos permite además de la colision del regalito y pasar a otro nivel, también detectar la colision con las bombas sabiendo su coordenada }