commit cb00aed53154401ded0febfacce241b5a3a17791 Author: Eidan T. Date: Sat May 9 12:17:01 2026 -0400 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..bb0789d --- /dev/null +++ b/README.md @@ -0,0 +1,548 @@ +# Juego de Memoria - HTML, CSS y JavaScript + +Juego de memoria interactivo desarrollado únicamente con HTML, CSS y JavaScript puro. + +El proyecto incluye: + +- Sistema de cartas con animaciones +- Barajado automático +- Pantalla completa +- Confetti al ganar +- Diseño responsive +- Sistema de comparación de pares + +--- + +# Tecnologías Utilizadas + +- HTML5 +- CSS3 +- JavaScript Vanilla +- Canvas Confetti (CDN) + +--- + +# Estructura del Proyecto + +```txt +/ +├── index.html +├── style.css +├── script.js +├── fullscreen-icon.png +└── images/ + ├── back.png + ├── img-1.png + ├── img-2.png + ├── img-3.png + ├── img-4.png + ├── img-5.png + └── img-6.png +``` + +--- + +# Estructura HTML Principal + +## Contenedor del Juego + +```html +
+``` + +--- + +## Tablero de Cartas + +```html + +``` + +--- + +## Carta Individual + +```html +
  • +``` + +--- + +## Frente de la Carta + +```html +
    + +
    +``` + +--- + +## Dorso de la Carta + +```html +
    + +
    +``` + +--- + +## Botón de Pantalla Completa + +```html + +``` + +--- + +# Funciones Principales + +El archivo `script.js` contiene las funciones principales del juego. + +| Función | Descripción | +| -------------------------- | ---------------------------------- | +| `shuffleCard()` | Baraja y reinicia las cartas | +| `flipCard()` | Voltea una carta | +| `matchCards()` | Compara dos cartas | +| `toggleFullScreen()` | Activa/desactiva pantalla completa | +| `mostrarConfetiConTexto()` | Muestra confetti al ganar | + +--- + +# Instalación + +## Opción 1 — Abrir Directamente + +1. Descomprimir el proyecto +2. Abrir `index.html` + +Ideal para pruebas rápidas. + +--- + +## Opción 2 — Localhost con XAMPP + +Copiar el proyecto a: + +```txt +C:\xampp\htdocs\version3x4\ +``` + +Iniciar Apache y abrir: + +```txt +http://localhost/version3x4/ +``` + +--- + +## Opción 3 — Node.js + +Instalar `serve`: + +```bash +npm i -g serve +``` + +Ejecutar: + +```bash +serve . +``` + +--- + +## Opción 4 — Producción Apache + +### Crear carpeta + +```bash +sudo mkdir -p /var/www/version3x4 +``` + +### Copiar archivos + +```bash +sudo cp -r ./Version3x4/* /var/www/version3x4/ +``` + +### Permisos + +```bash +sudo chown -R www-data:www-data /var/www/version3x4 +``` + +### VirtualHost + +```apache + + ServerName juego.midominio.com + DocumentRoot /var/www/version3x4 + + + Options Indexes FollowSymLinks + AllowOverride None + Require all granted + + +``` + +### Activar sitio + +```bash +sudo a2ensite juego.midominio.com +sudo systemctl reload apache2 +``` + +--- + +## Opción 5 — Producción Nginx + +```nginx +server { + server_name juego.midominio.com; + + root /var/www/version3x4; + index index.html; + + location / { + try_files $uri $uri/ =404; + } +} +``` + +Reiniciar Nginx: + +```bash +sudo systemctl reload nginx +``` + +--- + +# Funcionamiento del Juego + +## Tablero + +- Formato 3×4 +- 12 cartas +- 6 pares + +--- + +## Mecánica + +### Volteo + +Cuando el usuario hace click: + +- se ejecuta `flipCard()` +- la carta gira + +--- + +### Comparación + +`matchCards()` compara: + +```javascript +.back-view img +``` + +--- + +### Acierto + +Si coinciden: + +- permanecen abiertas +- aumenta contador `matched` + +--- + +### Fallo + +Si no coinciden: + +- se aplica `.shake` +- se espera un tiempo +- las cartas se vuelven a tapar + +--- + +### Victoria + +Cuando todos los pares son encontrados: + +```javascript +mostrarConfetiConTexto("..."); +``` + +--- + +### Pantalla Completa + +El botón: + +```html +#fullscreen-btn +``` + +ejecuta: + +```javascript +toggleFullScreen(); +``` + +--- + +# Ediciones Frecuentes + +## Cambiar Imágenes + +Reemplazar: + +```txt +images/img-1.png +images/img-2.png +... +``` + +manteniendo: + +- nombres +- formato + +--- + +## Cambiar Reverso + +Modificar: + +```txt +images/back.png +``` + +--- + +## Cambiar Layout 3×4 a 4×4 + +### Agregar más cartas + +Duplicar: + +```html +
  • +``` + +--- + +### Agregar nuevas imágenes + +```txt +images/img-7.png +images/img-8.png +``` + +--- + +### Cambiar Grid CSS + +```css +.cards { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 10px; +} +``` + +--- + +# Ajustar Dificultad + +## Velocidad de Animación + +Modificar: + +```css +.card .view +``` + +--- + +## Sacudida de Error + +Editar: + +```css +.card.shake +``` + +y: + +```css +@keyframes shake; +``` + +--- + +## Tiempo de Error + +Modificar `setTimeout()` dentro de `script.js`. + +--- + +# Cambiar Mensaje de Victoria + +Editar: + +```javascript +mostrarConfetiConTexto("Mensaje"); +``` + +--- + +# Pantalla Completa + +La función utiliza: + +```javascript +document.documentElement.requestFullscreen(); +``` + +y: + +```javascript +document.exitFullscreen(); +``` + +--- + +# Checklist de Pruebas + +## Validaciones Básicas + +- [ ] Las 12 cartas aparecen +- [ ] Las cartas giran +- [ ] Los pares permanecen abiertos +- [ ] El shake funciona +- [ ] El tablero se baraja +- [ ] El fullscreen funciona +- [ ] Responsive correcto + +--- + +# Problemas Comunes + +| Problema | Causa | Solución | +| -------------------- | --------------- | ------------------- | +| Cartas blancas | Ruta incorrecta | Revisar `/images` | +| No funciona el juego | Error JS | Revisar consola F12 | +| No aparece confetti | CDN bloqueado | Revisar conexión | +| Fullscreen falla | Sin interacción | Ejecutar tras click | +| Responsive roto | Grid incorrecto | Ajustar CSS | + +--- + +# Mejoras Opcionales + +## Contador de Movimientos + +Agregar: + +```html +
    +``` + +--- + +## Temporizador + +Agregar: + +```html +
    +``` + +--- + +## Botón Reiniciar + +Crear botón que llame: + +```javascript +shuffleCard(); +``` + +--- + +## Sonidos + +Usar: + +```javascript +HTMLAudioElement; +``` + +--- + +## Mejor Tiempo + +Guardar datos con: + +```javascript +localStorage; +``` + +--- + +# Guía Express de Edición + +## Cambiar imágenes + +Reemplazar: + +```txt +images/img-*.png +``` + +--- + +## Añadir más pares + +1. Duplicar cartas +2. Añadir nuevas imágenes +3. Ajustar grid CSS + +--- + +## Cambiar dificultad + +Modificar: + +- `setTimeout()` +- animaciones CSS + +--- + +## Cambiar texto de victoria + +Editar: + +```javascript +mostrarConfetiConTexto(); +``` + +--- + +# Características Técnicas + +- No utiliza backend +- No requiere base de datos +- Todo funciona en el navegador +- Proyecto completamente frontend +- Compatible con hosting estático + +--- diff --git a/fullscreen-icon.png b/fullscreen-icon.png new file mode 100644 index 0000000..863fdb7 Binary files /dev/null and b/fullscreen-icon.png differ diff --git a/images/back.png b/images/back.png new file mode 100644 index 0000000..b285ff1 Binary files /dev/null and b/images/back.png differ diff --git a/images/img-1.png b/images/img-1.png new file mode 100644 index 0000000..8141733 Binary files /dev/null and b/images/img-1.png differ diff --git a/images/img-2.png b/images/img-2.png new file mode 100644 index 0000000..6bfa991 Binary files /dev/null and b/images/img-2.png differ diff --git a/images/img-3.png b/images/img-3.png new file mode 100644 index 0000000..c2aa10e Binary files /dev/null and b/images/img-3.png differ diff --git a/images/img-4.png b/images/img-4.png new file mode 100644 index 0000000..e2547b5 Binary files /dev/null and b/images/img-4.png differ diff --git a/images/img-5.png b/images/img-5.png new file mode 100644 index 0000000..221b5f2 Binary files /dev/null and b/images/img-5.png differ diff --git a/images/img-6.png b/images/img-6.png new file mode 100644 index 0000000..364ca85 Binary files /dev/null and b/images/img-6.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..9e84816 --- /dev/null +++ b/index.html @@ -0,0 +1,103 @@ + + + + + Juego De Memoria - ePromo + + + + +
    + +
    + + + + \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..be7a511 --- /dev/null +++ b/script.js @@ -0,0 +1,109 @@ +const cards = document.querySelectorAll(".card"); + +let matched = 0; +let cardOne, cardTwo; +let disableDeck = false; + +function flipCard({target: clickedCard}) { + if(cardOne !== clickedCard && !disableDeck) { + clickedCard.classList.add("flip"); + if(!cardOne) { + return cardOne = clickedCard; + } + cardTwo = clickedCard; + disableDeck = true; + let cardOneImg = cardOne.querySelector(".back-view img").src, + cardTwoImg = cardTwo.querySelector(".back-view img").src; + matchCards(cardOneImg, cardTwoImg); + } +} + +function matchCards(img1, img2) { + if(img1 === img2) { + matched++; + if(matched == 6) { + setTimeout(() => { + mostrarConfetiConTexto(); + shuffleCard(); + }, 1000); + } + cardOne.removeEventListener("click", flipCard); + cardTwo.removeEventListener("click", flipCard); + cardOne = cardTwo = ""; + return disableDeck = false; + } + setTimeout(() => { + cardOne.classList.add("shake"); + cardTwo.classList.add("shake"); + }, 400); + + setTimeout(() => { + cardOne.classList.remove("shake", "flip"); + cardTwo.classList.remove("shake", "flip"); + cardOne = cardTwo = ""; + disableDeck = false; + }, 1200); +} + +function shuffleCard() { + matched = 0; + disableDeck = false; + cardOne = cardTwo = ""; + let arr = [1,1,2,2,3,3,4,4,5,5,6,6]; + arr.sort(() => Math.random() > 0.5 ? 1 : -1); + cards.forEach((card, i) => { + card.classList.remove("flip"); + let imgTag = card.querySelector(".back-view img"); + imgTag.src = `images/img-${arr[i]}.png`; + card.addEventListener("click", flipCard); + }); +} + +shuffleCard(); + +cards.forEach(card => { + card.addEventListener("click", flipCard); +}); + +function toggleFullScreen() { + if (!document.fullscreenElement) { + document.documentElement.requestFullscreen().catch(err => { + console.log(`Error al intentar activar pantalla completa: ${err.message}`); + }); + } else { + document.exitFullscreen(); + } +} + +document.addEventListener("DOMContentLoaded", function () { + document.getElementById("fullscreen-btn").addEventListener("click", toggleFullScreen); +}); + +// Mostrar confeti con texto +function mostrarConfetiConTexto(texto) { + const duration = 5 * 1000; + const end = Date.now() + duration; + + (function frame() { + confetti({ + particleCount: 7, + angle: 60, + spread: 55, + origin: { x: 0 }, + scalar: 1.2, + }); + confetti({ + particleCount: 7, + angle: 120, + spread: 55, + origin: { x: 1 }, + scalar: 1.2, + }); + + if (Date.now() < end) { + requestAnimationFrame(frame); + } + })(); + + console.log("¡Felicidades! Ganaste: " + texto); + } \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..426bc26 --- /dev/null +++ b/style.css @@ -0,0 +1,130 @@ +/* Import Google Font - Poppins */ +@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap'); +*{ + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Poppins', sans-serif; +} +body{ + display: flex; + align-items: center; + justify-content: center; + min-height: 100vh; + background: #E9AD14 /*url(https://portal.gomezleemarketing.com/wp-content/uploads/2024/02/BANNER-SUPERIOR-GRANDE.png) repeat center center*/; +} +.wrapper{ + padding: 10px; + border-radius: 10px; + background: #727272; + box-shadow: 0 10px 30px rgba(0,0,0,0.1); +} +.cards, .card, .view{ + display: flex; + align-items: center; + justify-content: center; +} +.cards{ + height: 800px; + width: 800px; + flex-wrap: wrap; + justify-content: space-between; +} +.cards .card{ + cursor: pointer; + list-style: none; + user-select: none; + position: relative; + perspective: 1000px; + transform-style: preserve-3d; + height: calc(100% / 4 - 10px); + width: calc(100% / 3 - 10px); +} +.card.shake{ + animation: shake 0.35s ease-in-out; +} +@keyframes shake { + 0%, 100%{ + transform: translateX(0); + } + 20%{ + transform: translateX(-13px); + } + 40%{ + transform: translateX(13px); + } + 60%{ + transform: translateX(-8px); + } + 80%{ + transform: translateX(8px); + } +} +.card .view{ + width: 100%; + height: 100%; + position: absolute; + border-radius: 7px; + background: #fff; + pointer-events: none; + backface-visibility: hidden; + box-shadow: 0 3px 10px rgba(0,0,0,0.1); + transition: transform 0.25s linear; +} +.card .front-view img{ + width: 80px; +} +.card .back-view img{ + max-width: 150px; +} +.card .back-view{ + transform: rotateY(-180deg); +} +.card.flip .back-view{ + transform: rotateY(0); +} +.card.flip .front-view{ + transform: rotateY(180deg); +} + +@media screen and (max-width: 700px) { + .cards{ + height: 400px; + width: 400px; + } + .card .front-view img{ + width: 45px; + } + .card .back-view img{ + max-width: 80px; + } +} + +@media screen and (max-width: 530px) { + .cards{ + height: 400px; + width: 400px; + } + .card .front-view img{ + width: 45px; + } + .card .back-view img{ + max-width: 80px; + } +} + +#fullscreen-btn { + position: fixed; + top: 10px; + right: 10px; + background: none; + border: none; + cursor: pointer; + z-index: 1000; +} + +#fullscreen-btn img { + width: 40px; + height: 40px; +} +