No te salgas del mapa
Clase 11 de 24 • Taller Práctico de JavaScript: ¡Crea tu Primer Videojuego!
Contenido del curso
Eduard Barrios
Santiago Velásquez Serna
Fernando Yutiz
Laura Roa
Juan Castro
Laura Roa
Luis Angel Santillan
Tommy Toala Cox
Jhon Eduard Bocanegra Ortiz
ANA RAMIREZ
Fernando Steven Ochoa Montoya
Emilio Sala
Miguel Enrique Velásquez Millán
Nestor Rios Garcia
Matías Wasiak
Sara Paola Segura Devia
Juan José Gómez Aguirre
Juan Mercado
Rodrigo Alejandro Alvarado Liñan
Cristian Zapata
Andrés Toledo Margalef
Victor Hugo Cruz Carballo
cuando lo cambiaba de pantalla de un monitor a otro se rompía y se salía, así que esta fue mi solución:
function moveUp(){ if(Math.floor(playerPosicion.y) > elementSize){ playerPosicion.y = (playerPosicion.y - elementSize) movePlayer() } } function moveLeft(){ if(Math.floor(playerPosicion.x) > elementSize){ playerPosicion.x = (playerPosicion.x - elementSize) movePlayer() } } function moveRight(){ if(Math.ceil(playerPosicion.x)< 10*elementSize){ playerPosicion.x = (playerPosicion.x + elementSize) movePlayer() } } function moveDown(){ if(Math.ceil(playerPosicion.y) < 10*elementSize){ playerPosicion.y = (playerPosicion.y + elementSize) movePlayer() } }
Yo lo hice directamente en la función movePlayer; De cualquier forma ella es la encargada de renderizar la calavera
Estoy pensando en darle otro enfoque. En vez de verificar coordenadas de Canvas, quizá mejor sea ver los limites en el array bidimensional que seria el verdadero mapa del juego.
No se si sea la unica pero esto me pasa, incluso borrando todo mi codigo y pegando el del profe la calabera no sube desde la linea azul de la imagen. Les ha pasado lo mismo?
Lau, eso también me pasó por los decimales. Compártenos por fa tu código y te ayudamos a revisar. En resumen hay que quitar todos los decimales posibles de todas las partes posibles del código para que en nuestros condicionales no pase nada raro y nos permita movernos correctamente. Mira: https://platzi.com/clases/3573-javascript-practico-videojuegos/52359-depurando-errores-del-juego/
Que bueno profe saber que el error lo corregimos mas adelante! Debido a que la pantalla de mi monitor es muy grande tuve el problema desde el inicio (Me tocaba achiquitar la pantalla para que funcionara) Ya vi la clase Depurando errores del juego e hice lo que recomendaste y el codigo funciono! Este es el resultado: (cambie unas variables a ingles!)
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="./styles.css"> <title>VideoGame Project</title> </head> <body> <div class="game-container"> <canvas id="game"></canvas> <div class="btns"> <button id="up">Up</button> <button id="left">Left</button> <button id="right">Right</button> <button id="down">Down</button> </div> <div class="messages"> <p>lives: <span id="lives"></span></p> <p>Time: ⏰: <span id="time"></span></p> <p>Record: 🏁<span id="record"></span></p> <p id="result"></p> </div> </div> <script src="./maps.js"></script> <script src="./game.js"></script> </body> </html>
game.js
const canvas = document.querySelector('#game'); const game = canvas.getContext('2d'); const upButton = document.querySelector ('#up'); const rightButton = document.querySelector ('#right'); const leftButton = document.querySelector ('#left'); const downButton = document.querySelector ('#down'); const spanLives = document.querySelector('#lives') const spanTime = document.querySelector('#time'); const spanRecord = document.querySelector('#record'); const pResult = document.querySelector('#result'); let canvasSize; let elementsSize; let level = 0; let lives = 3; let timeStart; let timePlayer; let timeInterval; const playerPosition = { x: undefined, y: undefined, }; const giftPosition = { x: undefined, y: undefined, }; let enemyPositions = []; window.addEventListener('load', setCanvasSize); window.addEventListener('resize', setCanvasSize); function fixNumber(n) { return Number(n.toFixed(0)); } function setCanvasSize() { if (window.innerHeight > window.innerWidth) { canvasSize = window.innerWidth * 0.7; } else { canvasSize = window.innerHeight * 0.7; } canvasSize = Number(canvasSize.toFixed(0)); canvas.setAttribute('width', canvasSize); canvas.setAttribute('height', canvasSize); elementsSize = fixNumber(canvasSize / 10); playerPosition.x = undefined; playerPosition.y = undefined; startGame(); } function startGame() { console.log({ canvasSize, elementsSize }); console.log(window.innerWidth, window.innerHeight); game.font = elementsSize + 'px Verdana'; game.textAlign = 'end'; const map = maps[level]; if (!map) { gameWin(); return; } if (!timeStart) { timeStart = Date.now(); timeInterval = setInterval(showTime, 100); showRecord(); } const mapRows = map.trim().split('\n'); const mapRowCols = mapRows.map(row => row.trim().split('')); console.log({map, mapRows, mapRowCols}); showLives(); enemyPositions = []; game.clearRect(0, 0, canvasSize, canvasSize); mapRowCols.forEach((row, rowI) => { row.forEach((col, colI) => { const emoji = emojis[col]; const posX = fixNumber(elementsSize * (colI + 1)); const posY = fixNumber(elementsSize * (rowI + 1)); if (col == 'O') { if (!playerPosition.x && !playerPosition.y) { playerPosition.x = fixNumber(posX); playerPosition.y = fixNumber(posY); console.log({playerPosition}); } } else if (col == 'I') { giftPosition.x = fixNumber(posX); giftPosition.y = fixNumber(posY); } else if(col == 'X') { enemyPositions.push ({ x: fixNumber(posX), y: fixNumber(posY), }); } game.fillText(emoji, posX, posY); }); }); movePlayer(); } function movePlayer() { const giftCollisionX = playerPosition.x.toFixed(3) == giftPosition.x.toFixed(3); const giftCollisionY = playerPosition.y.toFixed(3) == giftPosition.y.toFixed(3); const giftCollision = giftCollisionX && giftCollisionY; if(giftCollision) { winningLevel(); } const enemyCollision = enemyPositions.find(enemy => { const enemyCollisionX = enemy.x.toFixed(3) == playerPosition.x.toFixed(3); const enemyCollisionY = enemy.y.toFixed(3) == playerPosition.y.toFixed(3); return enemyCollisionX && enemyCollisionY; }); if(enemyCollision) { levelFail(); } game.fillText(emojis['PLAYER'], playerPosition.x, playerPosition.y); } function winningLevel() { console.log('Level up'); level ++; startGame(); } function levelFail() { console.log("ENEMY!") lives--; console.log(lives) if(lives <= 0) { level = 0; lives = 3; timeStart= undefined; } playerPosition.x = undefined; playerPosition.y = undefined; startGame(); } function gameWin() { console.log('¡Terminaste el juego!'); clearInterval(timeInterval); const recordTime = localStorage.getItem('record_time'); const playerTime = Date.now() - timeStart; if (recordTime) { if (recordTime >= playerTime) { localStorage.setItem('record_time', playerTime) pResult.innerHTML ='you made a new record! Congratulations!'; } else { pResult.innerHTML ='Sorry, this is not a record'; } } else { localStorage.setItem('record_time', playerTime) pResult.innerHTML = 'first time playing? Try to get a new record'; } console.log({recordTime, playerTime}); } function showLives() { const heartsArray = Array(lives).fill(emojis['HEART']); console.log(heartsArray); spanLives.innerHTML = ""; heartsArray.forEach(heart => spanLives.append(heart)) } function showTime() { spanTime.innerHTML = Date.now() - timeStart; } function showRecord() { spanRecord.innerHTML = localStorage.getItem('record_time'); } //rowI and colI are the index // for (let row = 1; row <= 10; row++) { // for (let col = 1; col <= 10; col++) { // game.fillText(emojis[mapRowCols[row - 1][col - 1]], elementsSize * col, elementsSize * row); // } // } window.addEventListener('keydown', moveByKeys); upButton.addEventListener('click', moveUp); rightButton.addEventListener('click', moveRight); leftButton.addEventListener('click', moveLeft); downButton.addEventListener('click', moveDown); function moveByKeys (event) { if(event.key == 'ArrowUp') moveUp(); else if (event.key == 'ArrowRight') moveRight(); else if (event.key == 'ArrowLeft') moveLeft(); else if (event.key == 'ArrowDown') moveDown(); } //console.log(event) function moveUp() { console.log('Moving up'); if ((playerPosition.y - elementsSize) < elementsSize) { console.log('OUT'); } else { playerPosition.y -= elementsSize; startGame(); } } function moveLeft() { console.log('moving left'); if ((playerPosition.x - elementsSize) < 20) { console.log('OUT'); } else { playerPosition.x -= elementsSize; startGame(); } } function moveRight() { console.log('moving right'); if ((playerPosition.x + elementsSize) > canvasSize) { console.log(elementsSize) console.log('OUT'); } else { playerPosition.x += elementsSize; startGame(); } } function moveDown() { console.log('moving down'); if ((playerPosition.y + elementsSize) > canvasSize) { console.log('OUT'); } else { playerPosition.y += elementsSize; startGame(); } }
Por alguna extranha razon no me funcionaba como se resolvio en este video de ejemplo entonces opte por hacer lo siguiente....
Yo ps solo le puse con ternarias, y en lugar del mensaje, le puse que esa posición sea igual al tamaño del elemento, porque me estaba dando unos decimales diferentes.
function moveUp() { console.log(canvasElement, map.playerPosition.x) map.playerPosition.x - canvasElement<canvasElement ? map.playerPosition.x = canvasElement : map.playerPosition.x -= canvasElement startGame() } function moveLeft() { map.playerPosition.y - canvasElement<canvasElement ? map.playerPosition.y = canvasElement : map.playerPosition.y -= canvasElement startGame() } function moveRight() { map.playerPosition.y + canvasElement>canvasSize ? map.playerPosition.y = canvasSize : map.playerPosition.y += canvasElement startGame() } function moveDown() { map.playerPosition.x + canvasElement>canvasSize ? map.playerPosition.x = canvasSize : map.playerPosition.x += canvasElement startGame() }
Asi lo hice:
yo solucioné de esta forma:
Hola , les comparto una manera que yo pienso es un poco mas corta , pero funciona.
function moveUp() { console.log("moveUp"); playerPosition.y -= elementSize; if (playerPosition.y < 0) { playerPosition.y += elementSize; } startGame(); } function moveDown(){ console.log("moveDown"); playerPosition.y += elementSize; if (playerPosition.y > elementSize * 10) { playerPosition.y -= elementSize; } startGame(); } function moveRight(){ console.log("moveRight"); playerPosition.x += elementSize; if (playerPosition.x > elementSize * 11) { playerPosition.x -= elementSize; } startGame(); } function moveLeft() { console.log("moveLeft"); playerPosition.x -= elementSize; if (playerPosition.x <= elementSize) { playerPosition.x += elementSize; } startGame(); }
Para que sea responsive cambié la posicion del jugador de absoluta como lo hizo en clase a posicion de la matriz
if (col === "O" && playerPos.x === undefined && playerPos.y === undefined) { playerPos.x = colIdx; playerPos.y = rowIdx+1; //hay un +1 por la forma de mi matriz }
entonces la funcion mover arriba, abajo etc sería en unidades
function moveUp() { if (playerPos.y > 1) { playerPos.y -= 1; drawMap(); } } function moveDown() { if (playerPos.y < 10) { playerPos.y += 1; drawMap(); } }
No sé si mi solución quizás sea demasiado rebuscada, pero al menos a mí me gusta, je je, e igualmente funciona~ La dejaré por aquí:
let mapLimits = { up: null, left: null, right: null, down: null }; // Este es un objeto global que indica los límites del mapa~ startGame() { ... mapLimits.up = elementSize * 1; mapLimits.left = elementSize * 1; mapLimits.right = elementSize * 10; mapLimits.down = elementSize * 10; ... } // Dentro de la función "startGame" se indican cuáles son esos límites una vez ya sabemos el tamaño del Canvas (acorde al tamaño de la pantalla del usuario).
function moveByKeys(keyEvent) { switch (keyEvent.code){ case "ArrowUp": movePlayer("up"); // console.log("arriba"); break; case "ArrowLeft": movePlayer("left"); // console.log("izquierda"); break; case "ArrowRight": movePlayer("right"); // console.log("derecha"); break; case "ArrowDown": movePlayer("down"); // console.log("abajo"); break; } } // En vez de tener una 4 funciones diferentes (moveUp, moveLeft, moveRight, moveDown), tengo una sola función "movePlayer" que recibe como parámetro la dirección a la cual se quiere mover el jugador.
function movePlayer(direction) { switch(direction) { case "up": if ( (playerPos.y - gridSize) >= mapLimits.up ) { playerPos.y -= gridSize; renderPlayer(); } break; case "left": if ( (playerPos.x - gridSize) >= mapLimits.left) { playerPos.x -= gridSize; renderPlayer(); } break; case "right": if ( (playerPos.x + gridSize) <= mapLimits.right) { playerPos.x += gridSize; renderPlayer(); } break; case "down": if ( (playerPos.y + gridSize) <= mapLimits.down) { playerPos.y += gridSize; renderPlayer(); } break; } function renderPlayer() { startGame(); game.fillText(emojis["PLAYER"], playerPos.x, playerPos.y); } } // Y dentro de esta función se verifica si la dirección a la cual se quiere mover el jugador se encuentra dentro de los límites del mapa. Si es así, se mueve sin problemas, pero si no, entonces no se mueve.
Así lo solucioné
function mapLimit() { const canvasLimit = elementSize* 10 if (playerPosition.x >= canvasLimit) { playerPosition.x -= elementSize } if (playerPosition.x < 0) { playerPosition.x += elementSize } if (playerPosition.y >= canvasLimit) { playerPosition.y -= elementSize } if (playerPosition.y < 0) { playerPosition.y += elementSize } }
La llamaría después de detectar el movimiento
function movePlayer(direction) { moves++ switch (direction) { case 'moveUp': playerPosition.y -= elementSize break; case 'moveLeft': playerPosition.x -= elementSize break; case 'moveRight': playerPosition.x += elementSize break; case 'moveDown': playerPosition.y += elementSize break; default: break; } mapLimit() printMap() game.fillText(emojis['PLAYER'], playerPosition.x, playerPosition.y) }
Una alternativa
function startGame() { game.font = `${elementsSize}px Verdana`; game.textAlign = "end"; const map = maps[0]; const mapRows = map.trim().split("\n"); const mapRowCols = mapRows.map((row) => row.trim().split("")); game.clearRect(0, 0, canvasSize, canvasSize); mapRowCols.forEach((row, rowIndex) => { row.forEach((col, colIndex) => { if (col == "O") { if (playerPosition.x === undefined) { playerPosition.x = colIndex; playerPosition.y = rowIndex; } } game.fillText( emojis[col], elementsSize * (colIndex + 1), elementsSize * (rowIndex + 1) ); }); }); movePlayer(); } function movePlayer() { game.fillText( emojis["PLAYER"], elementsSize * (playerPosition.x + 1), elementsSize * (playerPosition.y + 1) ); } window.addEventListener("keydown", move); btnUp.addEventListener("click", moveUp); btnLeft.addEventListener("click", moveLeft); btnRight.addEventListener("click", moveRight); btnDown.addEventListener("click", moveDown); function move(event) { switch (event.key) { // UP case "ArrowUp": moveUp(); break; case "w": moveUp(); break; // LEFT case "ArrowLeft": moveLeft(); break; case "a": moveLeft(); break; // RIGHT case "ArrowRight": moveRight(); break; case "d": moveRight(); break; // DOWN case "ArrowDown": moveDown(); break; case "s": moveDown(); break; } } function moveUp() { if (playerPosition.y === 0) { return; } playerPosition.y--; startGame(); } function moveLeft() { if (playerPosition.x === 0) { return; } playerPosition.x--; startGame(); } function moveRight() { if (playerPosition.x === 9) { return; } playerPosition.x++; startGame(); } function moveDown() { if (playerPosition.y === 9) { return; } playerPosition.y++; startGame(); }
Esta fue mi solución
<function moveUp() { if (playerPosition.y < elementsSize) return console.log("Llegamos al limite"); playerPosition.y -= elementsSize; console.log("Me quiero mover hacia arriba"); startGame(); } function moveLeft() { if (playerPosition.x == elementsSize) return console.log("Llegamos al limite"); playerPosition.x -= elementsSize; console.log("Me quiero mover hacia izquierda"); startGame(); } function moveRight() { if (playerPosition.x > canvasSize) return console.log("Llegamos al limite"); playerPosition.x += elementsSize; console.log("Me quiero mover hacia derecha"); startGame(); } function moveDown() { if (playerPosition.y == canvasSize) return console.log("Llegamos al limite"); playerPosition.y += elementsSize; console.log("Me quiero mover hacia abajo"); startGame(); }>
Por temas de legibilidad y complejidad el if que se tiene para cada metodo que mueve el jugador se puede optimizar, ya que, que si no queremos que imprima ''OUT'' por ejemplo quedaria vació, por lo que se puede optimizar de la siguiente manera.
if (!(playerPosition.x - elementsSize) < elementsSize) { playerPosition.x -= elementsSize; startGame(); }
Mi triste solucion :(
if(emoji == 'O'){ if(playerPosition.x > canvasSize){ playerPosition.x = canvasSize - 10 alert('NO TE SALGAS DEL MAPAAAAA!') }else if(playerPosition.y > canvasSize){ playerPosition.y = canvasSize - 10 alert('NO TE SALGAS DEL MAPAAAAA!') }else if( playerPosition.y <= 0){ playerPosition.y = playerPosition.y + elementsSize alert('NO TE SALGAS DEL MAPAAAAA!') }else if(playerPosition.x <=0){ playerPosition.x = playerPosition.x + elementsSize alert('NO TE SALGAS DEL MAPAAAAA!') }else{ if(!playerPosition.x && !playerPosition.y){ playerPosition.x = posX playerPosition.y = posY } }
Una alternativa que se me ocurrió, no sé que tan bien este:
function startGame() { game.font = elementsSize + 'px Verdana'; game.textAlign = 'end'; const map = maps[0]; const mapRows = map.trim().split('\n'); const mapRowsCols = mapRows.map( row => row.trim().split('')); game.clearRect(0,0,canvasSize, canvasSize) mapRowsCols.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(!playerPosition.x && !playerPosition.y) { playerPosition.x = posX; playerPosition.y = posY; console.log({playerPosition}); } } game.fillText(emoji, posX, posY); }); }); if(playerPosition.x > canvasSize) playerPosition.x -= elementsSize; if(playerPosition.x < (elementsSize)-1) playerPosition.x += elementsSize; if(playerPosition.y > canvasSize) playerPosition.y -= elementsSize if(playerPosition.y < (elementsSize)-1) playerPosition.y += elementsSize movePlayer(); }
Mi solución aprovechando la variable canvasSize que ya tenemos:
function moveUp(){ if(playerPosition.y > elementsSize) { playerPosition.y -= elementsSize; startGame(); } } function moveLeft(){ if(playerPosition.x > elementsSize){ playerPosition.x -= elementsSize; startGame(); } } function moveRight(){ if(playerPosition.x < canvasSize){ playerPosition.x += elementsSize; startGame(); } } function moveDown(){ if(playerPosition.y < canvasSize) { playerPosition.y += elementsSize; startGame(); } }
Yo tengo el game.textAlign = "start"
entonces, tuve que modificar el codigo
function moveUp() { if(playerPosition.y > elementsSize ){ playerPosition.y -= elementsSize startGame() } } function moveLeft() { if(!playerPosition.x == 0 ){ playerPosition.x -= elementsSize startGame()} } function moveRight() { if(playerPosition.x < (canvasSize -elementsSize) ){ playerPosition.x += elementsSize startGame()} } function moveDown() { if(playerPosition.y < (canvasSize -elementsSize) ){ playerPosition.y += elementsSize startGame()} }
function moveUp(){ console.log('arriba') if(elemtSize<playerPos.y){ playerPos.y -= elemtSize; startGame(); } } function moveLeft(){ console.log('izquierda') if(elemtSize<playerPos.x-elemtSize){ playerPos.x -= elemtSize; startGame(); } } function moveRight(){ console.log('derecha') if(canvasSize>playerPos.x){ playerPos.x += elemtSize; startGame(); } } function moveDown(){ console.log('abajo') if(canvasSize>playerPos.y+elemtSize){ playerPos.y += elemtSize; startGame(); } }