Rubén Ernesto Aragón Gil
EstudianteJuan Castro
ProfesorJesus Marquez Martini
Estudiantemarco antonio
EstudianteJuan Castro
ProfesorJuan Jose Sepulveda Calderon
EstudianteEliezer Hernandez
EstudianteDiego Hanssel Perez
EstudianteEliezer Hernandez
EstudianteCésar Augusto Cortés Labrada
EstudianteCristian Zapata
EstudianteNestor Luis Álvarez Rojas
EstudianteJorge Alejandro Suárez Rivera
EstudianteRaúl Adolfo Sánchez Rodríguez
EstudianteMiguel Angel Hernandez Colombo
EstudianteHector Maluy Fernandez
EstudianteJuan Castro
ProfesorOscar Gutiérrez
EstudianteRaúl Adolfo Sánchez Rodríguez
EstudianteAdhemar Duran Gahuincha
EstudianteOscar Israel Román Quispe
EstudianteMauricio Combariza
EstudianteDavid Alvarez
EstudianteJonathan Meixueiro
EstudianteMiguel Enrique Velásquez Millán
EstudianteJuan Castro
ProfesorMiguel Enrique Velásquez Millán
EstudianteAlejandro Ramos
EstudianteOscar Gutiérrez
EstudianteAntonio Mateos Mariscal
EstudianteRaúl Adolfo Sánchez Rodríguez
EstudianteMinuto 3:48
ALGUIEN ENTENDIÓ POR FIN
la moskeramienta
Le construí un format para que se lea mejor ;)
//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 viewlive = document.querySelector('#lives'); const viewTime = document.querySelector('#time'); const juego = canvas.getContext('2d'); //signals: window.addEventListener('load', loadEvent); 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; let timeStart = undefined; let timeInterval = undefined; let playerTime = 0; const re_iniciar = {'select': 'si', 'resetStart': 'indeciso','exec' : false}; function loadEvent(){ viewTime.innerHTML = '0:0:0'; timeEvent(); resizeEvent();} 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 = font_t() +'px arial'; liveEvent(); update();} function font_t(){ return celda_t - celda_t / 10;} function liveEvent(){ const corazon = Array(vidas).fill(emojis['HEART']); viewlive.innerHTML = corazon.join('');} function timeFormat(time_msec){ const time = ~~(time_msec /1000); const min = (time / 60) | 0; const sec = time - (min * 60); const msec = ((time_msec / 10) | 0) - (time * 100); return min +':'+ ((sec < 10 ? '0' : 0) + sec) + ':' + ((msec < 10 ? '0' : 0) + msec);} function paintTimeEvent(){ playerTime = Date.now() - timeStart; viewTime.innerHTML = timeFormat(playerTime);} function timeEvent(var_function = paintTimeEvent){ if(!timeInterval){ timeStart = Date.now(); timeInterval = setInterval(var_function, 100);} else{ clearInterval(timeInterval); timeStart = undefined; timeInterval = undefined;}} function resetStartEvent(){ posJugador = prePosJugador = undefined; nivel = 0; nivel_actual = undefined; puntoDePartida = 0; vidas = 3; actualizado = false; explociones = Array(); re_iniciar['select'] = 'si'; re_iniciar['exec'] = false; re_iniciar['resetStart'] = 'indeciso'; timeEvent(); liveEvent(); playerTime = 0; update();} function update(){ if(re_iniciar['exec']){paintScreenFinal(); return;} cargarMapa(); clear(); paintEvent(); paintEventPlayer(); paintEventExplosion(); 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) mapa.forEach((char, idx) => { if(char == 'O' && posJugador == undefined) puntoDePartida = posJugador = idx; juego.fillText(emojis[char], posX(idx), posY(idx) );});} function paintEventPlayer(){ if(victoryEvent()) paintScreenEvent(); else { if(posJugador != undefined && prePosJugador != posJugador){ juego.fillText(emojis[mapa[prePosJugador]],posX(prePosJugador),posY(prePosJugador)); if(!gameOverEvent()) juego.fillText(emojis['PLAYER'], posX(posJugador),posY(posJugador)); else paintScreenEvent();}}} function gameOverEvent(){ if(vidas && mapa[posJugador] == 'X'){ explociones.push(posJugador); --vidas; liveEvent(); juego.fillText(emojis['BOMB_COLLISION'],posX(posJugador),posY(posJugador)); posJugador = puntoDePartida;} if(gameFinishEvent()) { explociones = Array(); return true;} /*juego terminado*/ return false; /*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(gameFinishEvent()) return true;/*juego terminado*/ posJugador = prePosJugador = undefined; actualizado = false; update(); return false;/*continuar con el juego*/} function Victoria(){return nivel >= map.length;} function gameFinishEvent(){ if(!(nivel >= map.length) == (vidas <= 0) && !re_iniciar['exec']) { timeEvent(); re_iniciar['exec'] = true;} return !(nivel >= map.length) == (vidas <= 0);} function paintScreenEvent(){ if(!re_iniciar['exec']) return; paintScreen(Victoria() ? 'WIN': 'GAME_OVER'); paintScreenFinal();} function paintScreenFinal(){ if(!re_iniciar['exec']) return; if(!actualizado) paintScreen(Victoria() ? 'WIN': 'GAME_OVER'); if(!timeInterval && !Victoria() && re_iniciar['select'] != 'exit') { timeEvent(paintScreenFinal);} const media = canvas_t / 2; const media_alta = media - font_t() + 1; const media_baja = media + font_t() - 1; let color, backgroundColor, text = 'continuar', y = media_alta; if(Victoria()){ color = '#ffd700'; backgroundColor = '#01433A';} else { color = '#FF2F22'; backgroundColor = '#211A27';} if(re_iniciar['resetStart'] == 'no' || re_iniciar['select'] == 'exit'){ if(actualizado)paintScreen(Victoria() ? 'WIN': 'GAME_OVER'); if(timeStart) timeEvent(); text = Victoria() ? 'Has Ganado' : 'Game Over'; y = media + (font_t() / 2); re_iniciar['select'] = 'exit';} else if(re_iniciar['resetStart'] == 'si') { timeEvent(); resetStartEvent(); return;} else{ if(timeStart){ const contador = 10 - (((Date.now() - timeStart) / 1000) | 0); text = text + ' ' + contador; if(contador < 0){ timeEvent(); re_iniciar['resetStart'] = 'no'; update(); return;}} paintScreen(Victoria() ? 'WIN': 'GAME_OVER'); paintRectText('', '' , backgroundColor,'center',media, media); paintRectText('', '' , backgroundColor,'center',media, media_baja); let siCa = color, siCb = backgroundColor; let noCa = color, noCb = backgroundColor; if(re_iniciar['select'] == 'no'){ noCa = backgroundColor; noCb = color;} else { siCa = backgroundColor; siCb = color;} paintRectText('no', noCa, noCb,'center',media + font_t(), media + (font_t() / 2)); paintRectText('si', siCa, siCb,'center',media - font_t(), media + (font_t() / 2));} paintRectText('', '' , backgroundColor,'center',media, y); paintRectText(text, color , '','center',media, y);} function paintScreen(emoji){ 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));});} function paintRectText(txt, color = '', backgroundColor = '', aling = 'center', x = 0,y = 0){ if(aling) juego.textAlign = aling; if(backgroundColor){ const rect = rectBgText(txt, x, y, aling); juego.fillStyle = backgroundColor; juego.fillRect(rect['x'], rect['y'], rect['width'], rect['height']);} if(color) juego.fillStyle = color; if(txt) juego.fillText(txt, x, y); juego.textAlign = 'end';} function rectBgText(txt, x = 0, y = 0, align=''){ const height = font_t(); const width = txt == ''|| txt == ' ' ? canvas_t : (font_t()*.75)* txt.length; let px = x; let py = y - (height - (height / 6)); if(align == 'center'){px = x - (width / 2);} else if(align != 'left')px = x - width; return {'width': width, 'height':height, 'x': px, 'y' : py};} //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){ //enter S N Y case 13: case 83: case 78: case 89: selectOptionEvent(event.keyCode); break;//selecionar opciones case 37: movIzq(); break;//izquierda case 38: movArriba(); break;//arriba case 39: movDer(); break; //derecha case 40: movAbajo(); break;//abajo default: break;}} function selectOptionEvent(key){ if(key == 83 || key == 89) re_iniciar['resetStart'] = 'si'; else if(key == 78) re_iniciar['resetStart'] = 'no'; else re_iniciar['resetStart'] = re_iniciar['select']; update();} 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(){ if(re_iniciar['exec']) re_iniciar['select'] = 'no'; else{ prePosJugador = posJugador; const pered = (~~(posJugador / 10)) *10 + 10; ++posJugador; if(posJugador >= pered) posJugador = prePosJugador;} update();} function movIzq(){ if(re_iniciar['exec']) re_iniciar['select'] = 'si'; else{ prePosJugador = posJugador; const pered = ~~(posJugador /10) * 10; --posJugador; if(posJugador < pered) posJugador = prePosJugador;} update();}
Me encanta la idea del counter hacia atrás para reanudar el juego. :clap:
Date.now()
El método estático Date.now() devuelve el número de milisegundos transcurridos desde el 1 de enero de 1970 a las 00:00:00 UTC.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now
Hola Eliezer, que fue lo que guardaste en ms? me gusto mucho tu solución y me gustaría implementarla.
Hola @diego-hanssel-perez, disculpa la demora de mi respuesta. “ms” son los milisegundos, por lo que le puedes pasar a la funcion el tiempo en milisegundos como argumento y la function se encargara de llevar el tiempo representado en esa unidad(ms) al formato que todos solemos utilizar para representar el tiempo de forma mas legible, mostrando las horas, minutos, segundos y centisegundos como se ve arriba en el gif de la misma manera que lo hace un relog digital.
Ejemplo: -1000 milisegundos equivalen a 1 segundo por lo que deberia verse de la siguiente manera 00:00:01:00. -250000 milisegundos equivalen a 4 minutos con 10 segundos exactos por lo que deberia verse 00:04:10:00. . Si gustas puedes mejorar la función yo realmente no lo hice en su momento porque me encontraba realmente corto de tiempo, por ejemplo la función tiene muchos “magics numbers” que estoy seguro de que más de uno no tendrá claro el contexto de estos números, también podrías sustituir el uso del metodo slice por algún otro metodo lo que podría dar una idea más clara de porque lo estoy usando por ejemplo por el metodo padStart:
function formatTime(ms){ const cs = parseInt(ms/10) % 100 const seg = parseInt(ms/1000) % 60 const min = parseInt(ms/60000) % 60 const hr = parseInt(ms/3600000) % 24 const csStr = `${cs}`.padStart(2,"0") const segStr = `${seg}`.padStart(2,"0") const minStr = `${min}`.padStart(2,"0") const hrStr = `${hr}`.padStart(2,"0") return`${hrStr}:${minStr}:${segStr}:${csStr}` }
Gracias por comentar y espero haber resultado de ayuda compañero, nos vemos mas adelante en proximos cursos o en este mismo aporte si tienes alguna pregunta mas no dudes escribirla. Un saludo.
Utilicé una conversión para que se vea mejor el tiempo.
function showTime(){ textTime.innerText = +((Date.now()-timeStart)/1000); }
Además especifiqué en la etiqueta <p> que el tiempo es en segundos. Este curso está super.
Con formato fácil:
Se crea una función:
function formatTime(ms){ const cs = parseInt(ms/10) % 100 const seg = parseInt(ms/1000) % 60 const min = parseInt(ms/60000) % 60 const csStr = `${cs}`.padStart(2,"0") const segStr = `${seg}`.padStart(2,"0") const minStr = `${min}`.padStart(2,"0") return`${minStr}:${segStr}:${csStr}` }
Se modifica el string de showTime():
function showTime(){ spanTime.innerHTML = formatTime(Date.now()-timeStart); }
Time: mm:ss:ms
¡Que maravilloso profesor eres, Juan!
Yo lo que hice fué cambiar el formato de tiempo a como se conoce normalmente ya que como aparece sin dos puntos ni nada de eso no me parece legible, entonces mi solución es que el tiempo tenga esto
function showTime() { const time = Date.now() - timeStart; const minutes = Math.floor(time / 60000); const seconds = Math.floor((time % 60000) / 1000); const milliseconds = time % 1000; spanTime.innerHTML = `${minutes}:${seconds}.${milliseconds}`; }
eso es lo que cambiaria en la función de showTime, el código completo es este obviamente sin contar lo de las próximas clases
const canvas = document.getElementById('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 spanLives = document.getElementById('lives'); const spanTime = document.getElementById('time'); let canvasSize; let elementsSize; let level = 0; let lives = 3; let timeStart; let timePlayer; let timeInterval; const playerPos = { x: undefined, y: undefined, }; const finishPos = { x: undefined, y: undefined, } let enemiesPos = []; window.addEventListener("load", setCanvasSize); window.addEventListener("resize", setCanvasSize); function setCanvasSize() { if (window.innerHeight > window.innerWidth) { canvasSize = window.innerWidth * 0.8; } else { canvasSize = window.innerHeight * 0.8; } canvas.setAttribute('width', canvasSize); canvas.setAttribute('height', canvasSize); elementsSize = canvasSize / 10; startGame(); } function startGame() { game.font = (elementsSize - 12) + 'px Verdana'; game.textAlign = 'end'; game.textBaseline = 'bottom'; const map = maps[level]; if (!map) { gameWin(); return; } if(!timeStart) { timeStart=Date.now();timeInterval=setInterval(showTime,100); } const mapRows = map.trim().split('\n'); const mapRowCols = mapRows.map(row => row.trim().split('')); showLives(); enemiesPos = []; game.clearRect(0,0, canvasSize, canvasSize); mapRowCols.forEach((row, rowI) => { row.forEach((col, colI) => { const emoji = emojis[col]; const posX = elementsSize * (colI + 1); const posY = elementsSize * (rowI + 1); if(col == "O"){ if (!playerPos.x && !playerPos.y) { playerPos.x = posX; playerPos.y = posY; } } else if(col == "I"){ finishPos.x = posX; finishPos.y = posY; } else if (col == 'X') { enemiesPos.push({ x: posX, y: posY, }); } game.fillText(emoji, posX, posY); }); }); movePlayer(); } function movePlayer(){ const giftColX = playerPos.x.toFixed(2) == finishPos.x.toFixed(2); const giftColY = playerPos.y.toFixed(2) == finishPos.y.toFixed(2); const giftCol = giftColX && giftColY; if (giftCol) { levelWin(); } const enemiesCol = enemiesPos.find( enemy => { const enemyColX = enemy.x.toFixed(2) == playerPos.x.toFixed(2); const enemyColY = enemy.y.toFixed(2) == playerPos.y.toFixed(2); return enemyColX && enemyColY; }); if (enemiesCol) { levelFail(); } game.fillText(emojis['PLAYER'], playerPos.x, playerPos.y); } function levelWin() { console.log('Subiste de nivel'); level++; startGame(); } function levelFail() { console.log('Chocaste'); lives--; timeStart=undefined; console.log(lives); if (lives <= 0) { level = 0; lives = 3; } playerPos.x = undefined; playerPos.y = undefined; startGame(); } function gameWin() { console.log('¡Terminaste el juego!'); clearInterval(timeInterval); } function showLives() { spanLives.innerHTML = emojis["HEART"].repeat(lives) } function showTime() { const time = Date.now() - timeStart; const minutes = Math.floor(time / 60000); const seconds = Math.floor((time % 60000) / 1000); const milliseconds = time % 1000; spanTime.innerHTML = `${minutes}:${seconds}.${milliseconds}`; } window.addEventListener('keydown', moveKeysDir); btnUp.addEventListener('click', moveUp); btnLeft.addEventListener('click', moveLeft); btnRight.addEventListener('click', moveRight); btnDown.addEventListener('click', moveDown); function moveKeysDir(event){ if (event.code == "KeyW" || event.code == "ArrowUp") { moveUp(); } else if (event.code == "KeyA" || event.code == "ArrowLeft") { moveLeft(); } else if (event.code == "KeyD" || event.code == "ArrowRight") { moveRight(); } else if (event.code == "KeyS" || event.code == "ArrowDown") { moveDown(); } } function moveUp(){ if ((playerPos.y - elementsSize) < elementsSize ) { } else { playerPos.y -= elementsSize; startGame(); } } function moveLeft(){ if ((playerPos.x - elementsSize) < elementsSize ) { } else { playerPos.x -= elementsSize; startGame(); } } function moveRight(){ if ((playerPos.x + elementsSize) > canvasSize ) { } else { playerPos.x += elementsSize; startGame(); } } function moveDown(){ if ((playerPos.y + elementsSize) > canvasSize ) { } else { playerPos.y += elementsSize; startGame(); } }
Solución a contador de tiempo de juego a partir de minuto 11:40 de la clase
Solución
Paso a paso
hice los tres niveles en 10 segundos ajajajajaj
¿Sería lo mismo si a timeStart lo seteas a null o a false en lugar de undefined?
Yep
Si ya que tanto undefined como null o 0 (entre otros) son valores falsy lo que significa que representa un valor falso en un contexto booleano
Función global: clearInterval( )
_
En la función levelFail se debería aumentar:
if (lives <= 0) { level = 0; lives = 3; clearInterval(timeInterval); timeStart = undefined; }
Para evitar una memory leak.
Muy bien. Tu aporte sirve para evitar que el contador siga contando cuando el jugador gane los 3 mapas luego de reiniciado los mapas (muerto 3 veces).
La variable fecha incluye el tiempo en milisegundos por lo que una diferencia entre la fecha en que inicio y en la que termino, puede ser la medida de tiempo.
// Al iniciar el juego, se guarda el tiempo actual startTime = new Date();
Esta se coloca en movePlayer cuando sale de O, y esta sería la función de winLevel:
function winLevel() { const endTime = new Date(); const elapsedSeconds = Math.floor((endTime.getTime() - (startTime as Date).getTime()) / 1000); console.log('Ganaste eeee'); console.log('Tiempo transcurrido:', elapsedSeconds, 'segundos'); if (level >= 0 && level < maps.length -1) { level += 1 mapaActual = [] startGame() } else { console.error('Fin del juego Ganaste!!'); } }
Para insertar emojies usar tecla de Windows y .
Reinventando la rueda para formatear el timer 😅
function showTime() { const msToSec = (Date.now() - timeStart) / 1000; const milliseconds = (String(msToSec - Math.floor(msToSec)).split('.')[1]).substring(0,2); const milliInterval = Date.now() - timeStart; let seconds = Math.floor(milliInterval / 1000); let minutes = Math.floor(seconds / 60); seconds = (seconds % 60) < 10 ? `0${seconds % 60}` : seconds % 60; minutes = (minutes % 60) < 10 ? `0${minutes % 60}` : minutes % 60; spanTime.innerHTML = `${minutes}:${seconds}:${milliseconds}`; }
¿Hay alguna razón especial por la que usamos Date.now()? 🤔. · Lo pregunto porque pienso que quizás sería mucho más sencillo contabilizar el tiempo de los jugadores directamente con el setInterval en vez de estar usando el Date.now(), je je.
¿Cómo lo harías con setInterval? :o
Así~
let totalGameTime = 0; let currentTimer = null; const timeShown = document.querySelector("#time"); function startTimer() { currentTimer = setInterval( () => { totalGameTime++; timeShown.innerText = totalGameTime; }, 1000 ); }
Pienso que de esta forma tendríamos un contador que muestra en pantalla el tiempo que ha transcurrido de la partida actual solo usando el setInterval, je je.
·
¿El Date.now() tiene alguna cosita especial que lo haga más eficiente o algo así? Yo en mi código usé este forma ya que me parece más sencillita, je je. Incluso luego le di un formato al totalGameTime con otra función para que se viera más bonito~
Y como le damo formato al tiempo ;_;
Depende del tipo de formato que quieras darle. Por ejemplo si quieres que se muestre los segundos solamente, podrías utilizar la siguiente sintaxis:
spanTime.innerHTML = ((Date.now() - timeStart) / 1000).toFixed(0);
Para añadir mayor dificultad al juego, en lugar de crear un cronómetro, he decidido poner un temporizador en el que el tiempo vaya hacia atrás y cuando llegue a 0 el jugador pierda la partida.
Para ello, he creado las variables:
let totalTime; let timeInterval;
He añadido el siguiente condicional dentro de la función startGame:
if (!timeInterval) { timeInterval = setInterval(showTime, 100); }
Y he creado la siguiente función, en la que establezco el tiempo inicial multiplicando el número total de mapas por 5 segundos cada uno, y posteriormente se van restando 10 al tiempo total cada 10 milisegundos hasta llegar a 0, momento en el que limpio el canvas con clearRect y reinicio los valores de la posición del jugador, del tiempo total, el nivel y el número de vidas:
function showTime() { if (!totalTime) { totalTime = maps.length * 500; } else { if (totalTime > 10) { totalTime -= 10; } else { game.clearRect(0, 0, canvasSize, canvasSize); playerPosition.col = undefined; playerPosition.row = undefined; totalTime = null; level = 0; lives = 3; startGame(); } } spanTime.innerText = totalTime; }
Contador de tiempo utilizando ++setInterval++ y ++clearInterval++