Hoy te diré cómo crear la
lista de tareas pendientes más simple, el juego IDLE incremental más simple en JavaScript, después de haber pasado menos de un día de vacaciones anuales. Para hacer esto, sugiero elegir un juego de
búhos más fácil y no omita los pasos entre el proyecto vacío y el juego terminado.
La gente que sabe hacer tales juegos se aburrirá; personas que conocen JS, recomiendo mirar el código con los dedos (para evitar lesiones) y leer solo sobre mecánica. Debajo del corte, una guía consistente para principiantes.
Los juegos incrementales son juegos basados en el ciclo principal [sin fin], que consiste en la acumulación de recursos, su gasto constante y la aceleración de los ingresos. Su característica principal es el constante crecimiento de los números. Las instrucciones te dirán cómo hacer un juego IDLE (perezoso) en el que los recursos se reponen con un temporizador, en lugar de un clic activo.
Para comenzar, cree un archivo de texto llamado index.html y escriba lo siguiente en él:
<html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <title> </title> <style> </style> </head> <body> : 0<br> </body> </html>
Por el momento, todavía no hay un juego, pero solo hay una inscripción estática.
Enlace al juego en el estado actual:
0df7a27 .
Todos los juegos de este género se basan en dos ciclos de juego condicionalmente infinitos.
El primer ciclo es la acumulación de recursos.
El segundo ciclo es un desperdicio de recursos.
Implementemos el primer ciclo.
: <span id="spnCoppersValue">0</span><br> <script> let coppers = 0; let copperGrowth = 1; myTimer = setInterval(endOfTurnCalc, 2000); function endOfTurnCalc() { coppers = coppers+copperGrowth; document.getElementById("spnCoppersValue").innerHTML = coppers; } </script>
Primera línea
<span id="spnCoppersValue">0</span><br>
nos brinda la posibilidad de acceder a él por su identificación y cambiar el contenido dentro de las etiquetas, en nuestro caso, el valor de las monedas en efectivo.
En segundo lugar, apareció un guión.
Creamos la variable cobres y establecemos su alcance con la palabra clave let. Similar al anuncio de copperGrowth, que será responsable de la tasa de crecimiento de las monedas de cobre.
A continuación, cree un objeto en el que colocamos nuestro temporizador, que extraerá la función endOfTurnCalc cada 2000 ms (2 segundos). La función proporciona un aumento en las monedas de cobre y una actualización de la interfaz. Hurra, la mitad del juego está hecho: tenemos un ciclo de acumulación de recursos. La siguiente tarea es aprender a gastarlo.
Enlace al juego en el estado actual:
e5d96e1 .
Agreguemos un botón que nos permitirá gastar monedas de cobre para mejorar la mina de cobre, sugiero ponerlo al frente de nuestra línea con monedas. Un botón, su nombre, la función que llama el botón, el nombre del botón es el contenido dentro de las etiquetas.
<button id="btnUpgCopperMine" onclick="upgCopperMine()"> , 10 </button><br>
Agregue un código que permita que el botón de actualización funcione:
let coppersUpgCost = 10; let coppersUpgLevel = 1; function upgCopperMine() { if (coppers>coppersUpgCost){ coppers = coppers-coppersUpgCost; coppersUpgLevel = coppersUpgLevel + 1; coppersUpgCost = coppersUpgCost*2; document.getElementById("spnCoppersValue").innerHTML = coppers; document.getElementById("btnUpgCopperMine").innerHTML = " , "; document.getElementById("btnUpgCopperMine").innerHTML += coppersUpgCost.toString(); document.getElementById("btnUpgCopperMine").innerHTML += " "; } }
y un código que afectará la tasa de extracción de nuevas monedas:
function endOfTurnCalc() { coppers = coppers+copperGrowth*coppersUpgLevel;; document.getElementById("spnCoppersValue").innerHTML = coppers; }
Establecemos el precio para mejorar la mina, definimos el nivel de mina predeterminado y escribimos en la función la verificación de la suficiencia de monedas para la actualización de la mina.
Si hay suficiente dinero, cancele el precio de la actualización, aumente el nivel actual de minas, calcule el precio para la próxima mejora; Muestra los valores actuales de las monedas de cobre y el costo de la próxima mejora.
Enlace al juego en el estado actual:
c731ec5 .
Bueno, ya puedes jugar: puedes ahorrar y, más agradablemente, gastar lo acumulado. Pero necesitamos reforzar el éxito: el jugador no solo calcula el aumento en la tasa de acumulación de monedas, restando del nuevo valor de las antiguas, sino que, en el buen sentido, ve inmediatamente la tasa actual de acumulación de monedas. Va a hacer?
Agregue una línea más a la interfaz:
: <span id="spnCoppersRate">1</span> 2 <br>
Ahora nuestra interfaz se describe mediante las siguientes líneas:
<button id="btnUpgCopperMine" onclick="upgCopperMine()" style="width: 240px;"> , 10 </button><br> : <span id="spnCoppersValue">0</span><br> : <span id="spnCoppersRate">1</span> 2 <br>
Realizamos un cambio en el script, en la función upgCopperMine ():
if (coppers>coppersUpgCost){ coppers = coppers-coppersUpgCost; coppersUpgLevel = coppersUpgLevel + 1; coppersUpgCost = coppersUpgCost*2; document.getElementById("spnCoppersValue").innerHTML = coppers; document.getElementById("btnUpgCopperMine").innerHTML = " , "; document.getElementById("btnUpgCopperMine").innerHTML += coppersUpgCost.toString(); document.getElementById("btnUpgCopperMine").innerHTML += " "; document.getElementById("spnCoppersRate").innerHTML = copperGrowth*coppersUpgLevel; }
Enlace al juego en el estado actual:
3ac06b6 .
Genial Tenemos un juego condicionalmente infinito. Ahora tenemos que parar por un segundo y pensarlo: a algunas personas les gusta cuando no hay un objetivo final, y puedes jugar hasta que te canses, la otra parte cree que las condiciones de finitud, alcance del juego deberían ser. Ya hemos hecho un juego para el primero, pero ¿qué nos impide hacer un pequeño cambio para que el juego tenga un objetivo y una condición de victoria? Hagámoslo
let win_condition = 50; myTimer = setInterval(endOfTurnCalc, 2000); function endOfTurnCalc() { if (coppers < win_condition) { coppers = coppers+copperGrowth*coppersUpgLevel; document.getElementById("spnCoppersValue").innerHTML = coppers; } else { clearTimeout(myTimer); alert(" ! "+win_condition.toString()); } }
Agregamos una variable en la que ponemos el valor que necesitamos para lograr y cambiamos la función desde el ciclo, agregando un control para lograr el objetivo. Al alcanzar la meta, borramos el intervalo de nuestro objeto con un temporizador y mostramos un mensaje emergente en el navegador.
Hay un pequeño punto: a algunos antivirus no les gustan las alertas y bloquean la página para su uso.
Enlace al juego en el estado actual:
8fa4041 .
La siguiente funcionalidad que la gente espera de un juego de más de cinco minutos es la capacidad de guardar y cargar el juego. ¡Vamos a dárselos!
Agregamos dos líneas a la interfaz, sin olvidar agregar la etiqueta de avance de línea a la línea anterior:
<button id="btnSaveGame" onclick="saveGame()" style="width: 240px;"> </button><br> <button id="btnLoadGame" onclick="loadGame()" style="width: 240px;"> </button><br>
y ahora expandiremos nuestros scripts para que los botones funcionen:
function saveGame() { localStorage.setItem('coppers', coppers); localStorage.setItem('coppersUpgCost', coppersUpgCost); localStorage.setItem('coppersUpgLevel', coppersUpgLevel); } function loadGame() { coppers = parseInt(localStorage.getItem('coppers')); coppersUpgCost = parseInt(localStorage.getItem('coppersUpgCost')); coppersUpgLevel = parseInt(localStorage.getItem('coppersUpgLevel')); document.getElementById("spnCoppersValue").innerHTML = coppers; document.getElementById("btnUpgCopperMine").innerHTML = " , "; document.getElementById("btnUpgCopperMine").innerHTML += coppersUpgCost.toString(); document.getElementById("btnUpgCopperMine").innerHTML += " "; document.getElementById("spnCoppersRate").innerHTML = copperGrowth*coppersUpgLevel; }
Ponemos todos los recursos mutables en el almacenamiento local del navegador al guardar y mientras leemos los leemos y actualizamos la interfaz.
Enlace al juego en el estado actual:
54b1ea0 .
Todo, la parte principal del juego está lista.
Hasta la fecha, hemos revisado:
- creación de un recurso;
- extracción de recursos;
- pérdida de recursos en una actualización de su sistema de producción;
- reflejo de la velocidad de extracción del recurso;
- condición de victoria;
- Escribir y leer guardar el juego en el almacenamiento local del navegador.
Continuar? Antes de continuar con el siguiente tema, a saber, agregar un segundo recurso a nuestro sistema (plata), sugiero realizar una pequeña refactorización del código actual.
¿Qué se debe hacer como parte de la refactorización?
Primero, creemos un objeto del juego y coloquemos monedas de cobre, el nivel de las minas de cobre, etc. dentro de las propiedades de este objeto. Esto será de gran ayuda en el futuro a medida que expandimos el almacenamiento y la carga a nuevas entidades de juego.
En segundo lugar, haremos que el cálculo del precio de actualización sea dinámico.
En tercer lugar, nos deshacemos de la duplicación de código, que es responsable de actualizar la interfaz.
El código tomará la siguiente forma:
let game = { coppers: 1, copperGrowth: 1, coppersUpgCost: 10, coppersUpgLevel: 1, } let win_condition = 50; myTimer = setInterval(endOfTurnCalc, 2000); function endOfTurnCalc() { if (game.coppers < win_condition) { game.coppers = game.coppers+game.copperGrowth*game.coppersUpgLevel; document.getElementById("spnCoppersValue").innerHTML = game.coppers; } else { clearTimeout(myTimer); alert(" ! "+win_condition.toString()); } } function upgCopperMine() { if (game.coppers>game.coppersUpgCost){ game.coppers = game.coppers-game.coppersUpgCost; game.coppersUpgLevel = game.coppersUpgLevel + 1; game.coppersUpgCost = game.coppersUpgCost*2; document.getElementById("spnCoppersValue").innerHTML = game.coppers; document.getElementById("btnUpgCopperMine").innerHTML = " , "; document.getElementById("btnUpgCopperMine").innerHTML += game.coppersUpgCost.toString(); document.getElementById("btnUpgCopperMine").innerHTML += " "; document.getElementById("spnCoppersRate").innerHTML = game.copperGrowth*game.coppersUpgLevel; } } function saveGame() { localStorage.setItem('coppers', game.coppers); localStorage.setItem('coppersUpgCost', game.coppersUpgCost); localStorage.setItem('coppersUpgLevel', game.coppersUpgLevel); } function loadGame() { game.coppers = parseInt(localStorage.getItem('coppers')); game.coppersUpgCost = parseInt(localStorage.getItem('coppersUpgCost')); game.coppersUpgLevel = parseInt(localStorage.getItem('coppersUpgLevel')); document.getElementById("spnCoppersValue").innerHTML = game.coppers; document.getElementById("btnUpgCopperMine").innerHTML = " , "; document.getElementById("btnUpgCopperMine").innerHTML += game.coppersUpgCost.toString(); document.getElementById("btnUpgCopperMine").innerHTML += " "; document.getElementById("spnCoppersRate").innerHTML = game.copperGrowth*game.coppersUpgLevel; } </script>
Es bastante obvio que creamos el objeto del juego, y dentro del objeto registramos sus propiedades y valores de propiedad. Además, donde solíamos acceder a las variables directamente, ahora nos referimos a las mismas propiedades del objeto del juego.
Enlace al juego en el estado actual:
8a07f4d .
Actualicemos ahora el sistema de guardar y cargar.
function saveGame() { localStorage.setItem('gameTutorial', JSON.stringify(game)); } function loadGame() { game = JSON.parse(localStorage.getItem('gameTutorial')); document.getElementById("spnCoppersValue").innerHTML = game.coppers; document.getElementById("btnUpgCopperMine").innerHTML = " , "; document.getElementById("btnUpgCopperMine").innerHTML += game.coppersUpgCost.toString(); document.getElementById("btnUpgCopperMine").innerHTML += " "; document.getElementById("spnCoppersRate").innerHTML = game.copperGrowth*game.coppersUpgLevel; }
Ahora, en lugar de guardar propiedades individuales, guardamos todo el objeto como un todo. Pero tenga cuidado: si agrega métodos al objeto, no se guardarán de esta manera, y la posterior reescritura del objeto desde el guardado eliminará todos los métodos ...
Enlace al juego en el estado actual:
8eba059 .
Eliminemos la propiedad innecesaria: el precio de la actualización de la mina y creemos una función para calcular la actualización y la llamaremos en los lugares necesarios.
function coppersUpgCost() { return game.coppersUpgLevel*10; } function upgCopperMine() { if (game.coppers>=coppersUpgCost()){ game.coppers = game.coppers-coppersUpgCost(); game.coppersUpgLevel = game.coppersUpgLevel + 1; document.getElementById("spnCoppersValue").innerHTML = game.coppers; document.getElementById("btnUpgCopperMine").innerHTML = " , "; document.getElementById("btnUpgCopperMine").innerHTML += coppersUpgCost().toString(); document.getElementById("btnUpgCopperMine").innerHTML += " "; document.getElementById("spnCoppersRate").innerHTML = game.copperGrowth*game.coppersUpgLevel; } } function saveGame() { localStorage.setItem('gameTutorial', JSON.stringify(game)); } function loadGame() { game = JSON.parse(localStorage.getItem('gameTutorial')); document.getElementById("spnCoppersValue").innerHTML = game.coppers; document.getElementById("btnUpgCopperMine").innerHTML = " , "; document.getElementById("btnUpgCopperMine").innerHTML += coppersUpgCost().toString(); document.getElementById("btnUpgCopperMine").innerHTML += " "; document.getElementById("spnCoppersRate").innerHTML = game.copperGrowth*game.coppersUpgLevel; }
Enlace al juego en el estado actual:
4007924 .
Finalmente, sacamos las partes repetidas del código de actualización de la interfaz en una función separada.
function updateUI() { document.getElementById("spnCoppersValue").innerHTML = game.coppers; document.getElementById("btnUpgCopperMine").innerHTML = " , "; document.getElementById("btnUpgCopperMine").innerHTML += coppersUpgCost().toString(); document.getElementById("btnUpgCopperMine").innerHTML += " "; document.getElementById("spnCoppersRate").innerHTML = game.copperGrowth*game.coppersUpgLevel; }
A su vez, en todos los otros lugares donde accedimos a ciertos objetos DOM, ahora llamaremos a la función updateUI ():
function endOfTurnCalc() { if (game.coppers < win_condition) { game.coppers = game.coppers+game.copperGrowth*game.coppersUpgLevel; updateUI(); } else { clearTimeout(myTimer); alert(" ! "+win_condition.toString()); } } function upgCopperMine() { if (game.coppers>=coppersUpgCost()){ game.coppers = game.coppers-coppersUpgCost(); game.coppersUpgLevel = game.coppersUpgLevel + 1; updateUI(); } } function loadGame() { game = JSON.parse(localStorage.getItem('gameTutorial')); updateUI(); }
Enlace al juego en el estado actual:
2245f97 .
Ahora propongo introducir un segundo recurso: plata, construcción y mejora de minas de plata.
<button id="btnUpgCopperMine" onclick="upgCopperMine()" style="width: 240px;"> , 10 </button><br> : <span id="spnCoppersValue">0</span><br> : <span id="spnCoppersRate">1</span> 2 <br> <button id="btnUpgSilverMine" onclick="upgSilverMine()" style="width: 240px;"> , 50 </button><br> : <span id="spnSilversValue">0</span><br> : <span id="spnSilversRate">1</span> 2 <br> <button id="btnSaveGame" onclick="saveGame()" style="width: 240px;"> </button><br> <button id="btnLoadGame" onclick="loadGame()" style="width: 240px;"> </button><br> <script> let game = { coppers: 1, copperGrowth: 1, coppersUpgLevel: 1, silvers: 0, silverGrowth: 1, silversUpgLevel: 0, } let win_condition = 50; let silverMineBasePriceCoppers = 100; myTimer = setInterval(endOfTurnCalc, 2000); function endOfTurnCalc() { if (game.silvers < win_condition) { game.coppers = game.coppers+game.copperGrowth*game.coppersUpgLevel; game.silvers = game.silvers+game.silverGrowth*game.silversUpgLevel; updateUI(); } else { clearTimeout(myTimer); alert(" ! "+win_condition.toString()); } } function coppersUpgCost() { return game.coppersUpgLevel*10+5; } function silversUpgCost() { return game.silversUpgLevel*10+5; } function upgCopperMine() { if (game.coppers>=coppersUpgCost()){ game.coppers = game.coppers-coppersUpgCost(); game.coppersUpgLevel = game.coppersUpgLevel + 1; updateUI(); } } function upgSilverMine() { if (game.silversUpgLevel===0){ if (game.coppers>=silverMineBasePriceCoppers){ game.coppers = game.coppers-silverMineBasePriceCoppers; game.silversUpgLevel = 1; updateUI(); } } else { if (game.silvers>=silversUpgCost()){ game.silvers = game.silvers-silversUpgCost(); game.silversUpgLevel = game.silversUpgLevel + 1; updateUI(); } } } function updateUI() { document.getElementById("spnCoppersValue").innerHTML = game.coppers; document.getElementById("btnUpgCopperMine").innerHTML = " , "; document.getElementById("btnUpgCopperMine").innerHTML += coppersUpgCost().toString(); document.getElementById("btnUpgCopperMine").innerHTML += " "; document.getElementById("spnCoppersRate").innerHTML = game.copperGrowth*game.coppersUpgLevel; document.getElementById("spnSilversValue").innerHTML = game.silvers; if (game.silversUpgLevel===0) { document.getElementById("btnUpgSilverMine").innerHTML = " , "; document.getElementById("btnUpgSilverMine").innerHTML += silverMineBasePriceCoppers.toString(); document.getElementById("btnUpgSilverMine").innerHTML += " "; } else { document.getElementById("btnUpgSilverMine").innerHTML = " , "; document.getElementById("btnUpgSilverMine").innerHTML += silversUpgCost().toString(); document.getElementById("btnUpgSilverMine").innerHTML += " "; } document.getElementById("spnSilversRate").innerHTML = game.silverGrowth*game.silversUpgLevel; } function saveGame() { localStorage.setItem('gameTutorial', JSON.stringify(game)); } function loadGame() { game = JSON.parse(localStorage.getItem('gameTutorial')); updateUI(); } </script>
Que se hace Se han agregado a la interfaz campos para mostrar monedas de plata, la velocidad de su extracción, un botón para construir o mejorar una mina de plata.
Las propiedades silvers, silverGrowth, silversUpgLevel se duplican dentro del objeto del juego, pero este último se establece en 0, porque no tenemos una mina de plata por defecto.
Se agregó la variable silverMineBasePriceCoppers, que reflejará el precio de construir una mina de plata en monedas de cobre (porque no podemos pagar una mina de plata con plata, que aún no tenemos).
La función coppersUpgCost se ha modificado y duplicado como silversUpgCost para que el precio de actualización no sea cero si el nivel de mina actual es 0.
Cambiamos la función de calcular el final del turno, agregando el cálculo de los ingresos de la mina de plata allí, y también cambiando la condición de victoria; ahora necesitamos comparar no el número de monedas de cobre, sino el número de monedas de plata.
Creamos la función upgSilverMine, en la que reflejamos la lógica de los fondos de débito (si no hay mina, cancele las monedas de cobre, si la mina ya está construida, luego cancele plata para mejorar la mina).
Las líneas necesarias para plata se agregaron a la función updateUI, así como la lógica de la salida de texto se dividió en un botón para mejorar la mina de plata, por lo que un botón funciona tanto para construir como para mejorar la mina.
Las funciones de guardar y cargar permanecieron sin cambios.
Enlace al juego en el estado actual:
03eb0eb .
Puede suceder que se acumulen muchas más monedas de cobre de las necesarias, mientras que la plata aún debe ganarse. Para esto, en tales juegos, por regla general, existe la posibilidad de intercambiar diferentes recursos entre sí.
Agreguemos un par de botones a la interfaz:
<button id="btnUpgCopperMine" onclick="upgCopperMine()" style="width: 240px;"> , 15 </button><br> : <span id="spnCoppersValue">0</span><br> : <span id="spnCoppersRate">1</span> 2 <br> <button id="btnBuySilver" onclick="buySilver()" style="width: 240px;"> 1 100 </button><br> <hr> <button id="btnUpgSilverMine" onclick="upgSilverMine()" style="width: 240px;"> , 50 </button><br> : <span id="spnSilversValue">0</span><br> : <span id="spnSilversRate">0</span> 2 <br> <button id="btnBuySilver" onclick="buyCoppers()" style="width: 240px;"> 100 1 </button><br> <hr> <button id="btnSaveGame" onclick="saveGame()" style="width: 240px;"> </button><br> <button id="btnLoadGame" onclick="loadGame()" style="width: 240px;"> </button><br>
Y agregue un par de funciones a estos botones:
function buySilver() { if (game.coppers>=100) { game.coppers = game.coppers - 100; game.silvers = game.silvers + 1; updateUI(); } } function buyCoppers() { if (game.silvers>=1) { game.coppers = game.coppers + 100; game.silvers = game.silvers - 1; updateUI(); } }
Enlace al juego en el estado actual:
92219b2 .
Entonces, ¿qué más se puede agregar al juego incremental? Equipo de prestigio! Por supuesto, ahora esto es más que un exceso, pero si el juego se desarrolla más, será útil. ¡Los jugadores lo aman!
En diferentes juegos, se hace de manera diferente, pero en general: el mecanismo otorga puntos de Prestigio, ya sea después de completar (pasar) el juego con éxito, o se desbloquea durante el juego después de alcanzar un cierto umbral objetivo.
Con la ayuda de puntos de prestigio, el jugador tiene la oportunidad de comenzar rápidamente o un bono permanente en el mismo juego (es posible que en la próxima misión, si el juego se divide en esos), para que pueda probar otras tácticas, pero pase menos tiempo volviendo a pasar . Por lo tanto, es posible estudiar varios tenedores, haber probado diferentes soluciones y dedicar menos tiempo a esto que si no existiera dicho mecanismo.
¿Qué necesitamos para esto? Necesita un mecanismo de reinicio del juego con valores predeterminados. Como un bono permanente, agregaremos puntos de Prestigio a las propiedades sin cambios anteriores de copperGrowth y silverGrowth.
Agregue las siguientes funciones winGame, restartGameDialog, restartGame, y también cambie endOfTurnCalc para llamar a nuevas funciones y actualizar updateUI:
function endOfTurnCalc() { if (game.silvers < win_condition) { game.coppers = game.coppers+game.copperGrowth*game.coppersUpgLevel; game.silvers = game.silvers+game.silverGrowth*game.silversUpgLevel; updateUI(); } else { winGame(); } } function winGame() { clearTimeout(myTimer); alert(" ! "+win_condition.toString()); myRestartTimer = setInterval(restartGameDialog, 2000); } function restartGameDialog() { if (confirm(' ?')) { restartGame(); } else { clearTimeout(myRestartTimer); } } function restartGame() { game.coppers = 1; game.copperGrowth = game.copperGrowth+1; game.coppersUpgLevel = 1; game.silvers = 0; game.silverGrowth = game.silverGrowth+1; game.silversUpgLevel = 0; clearTimeout(myRestartTimer); myTimer = setInterval(endOfTurnCalc, 2000); updateUI(); } function updateUI() { ... if (game.copperGrowth!==1) { document.getElementById("divLblPrestige").innerHTML = " "+game.copperGrowth.toString(); document.getElementById("divLblPrestige").style.display = "block"; } else { document.getElementById("divLblPrestige").style.display = "none"; } }
La función winGame inicia un temporizador, después del cual se llama a un diálogo de confirmación. En el caso de confirmación, se llama a la función de reinicio, que restablece todos los valores por defecto, pero aumenta las propiedades del crecimiento básico de las monedas.
En general, el juego está listo:
- creación de un recurso;
- extracción de recursos;
- pérdida de recursos en una actualización de su sistema de producción;
- reflejo de la velocidad de extracción del recurso;
- condición de victoria;
- escribir y leer guardar el juego en el almacenamiento local del navegador;
- agregando un recurso más con la producción y actualización de su producción;
- intercambio de recursos;
- mecanismo de reinicio del juego y mecanismo de prestigio.
Enlace al juego en el estado actual:
92219b2 .
Finalmente, lo último en este artículo que quiero mostrar es un mecanismo de almacenamiento diferente, porque el mecanismo actual tiene uno, pero un problema importante.
Imagine que está desarrollando un juego, publicándolo en un servidor web (posiblemente en páginas de github), y la gente lo está jugando. Con el tiempo, realiza cambios en el juego que agregan nuevas propiedades al objeto del juego.
Ahora cuida tus manos.
El jugador ingresa con la vieja salvación, que tiene todas las propiedades de los cobres y platas, pero no, por ejemplo, la propiedad del oro. Nuestro objeto de juego se carga y sobrescribe el que se creó cuando se cargó la página web, y ahora dentro del objeto solo hay aquellas propiedades que se guardaron. ¡Y ya hemos actualizado el código! Y este código se refiere a propiedades actualizadas que no están allí. Por lo tanto, el código comienza a recibir múltiples errores, hasta la inoperancia completa del juego. Sorprendentemente, para solucionar este problema, solo necesita reescribir dos líneas en la función de descarga del juego: function loadGame() { gameTemp = JSON.parse(localStorage.getItem('gameTutorial')); for (var propertyName in gameTemp) { game[propertyName] = gameTemp[propertyName]; } updateUI(); }
Ahora, si agrega el juego = {gold: 1,} y arranca desde su antiguo guardado donde aún no había oro, entonces el oro permanecerá en el objeto y la lógica del juego no se romperá en ningún lado.Enlace al juego en el estado actual: 83c258d .Una cosa mas. Transferencia de guardados entre navegadores, guardemos también. <hr> <button id="btnSaveGame" onclick="saveGame()" style="width: 240px;"> </button><br> <br> <button id="btnExportGame" onclick="exportGame()" style="width: 240px;"> </button><br> <div id="divLblExport" style="display: none"></div> <br> <hr> <button id="btnLoadGame" onclick="loadGame()" style="width: 240px;"> </button><br> <br> <button id="btnImportGame" onclick="importGame()" style="width: 240px;"> </button><br>
Actualiza la interfaz. let countdown = 30; let showExport = 0; function updateUI() { ... if (showExport===1){ document.getElementById("divLblExport").style.display = "block"; } else { document.getElementById("divLblExport").style.display = "none"; } } function exportGame() { exportTimer = setInterval(exportCountdown, 1000); document.getElementById("divLblExport").innerHTML = btoa(JSON.stringify(game)); showExport = 1; updateUI(); } function exportCountdown() { if (countdown > 0) { countdown = countdown - 1; } else { clearTimeout(exportTimer); countdown = 30; showExport = 0; updateUI(); } } function importGame() { let importString = prompt(' '); gameTemp = JSON.parse(atob(importString)); for (var propertyName in gameTemp) { game[propertyName] = gameTemp[propertyName]; } updateUI(); }
Agregamos dos variables de utilidad, actualizamos updateUI (), escribimos tres funciones: exportar, importar y una función que cambia el indicador de visualización de exportación, por lo que la exportación "antigua" se ocultará 30 segundos después de su formación.Eso es todo por hoy.