Esta entrada pertenece a la serie ‘Aprende Javascript con 7 juegos‘.
Vamos a implementar un juego de memoria, en el que tenemos que emparejar cartas.
Imágenes
Las imágenes de las cartas las guardamos en una carpeta llamada ‘images’
Ficheros y carpetas
HTML
Creamos el ficher index.html en la carpeta raíz
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Memory Game</title>
<link rel="stylesheet" href="style.css"></link>
<script src="app.js" charset="utf-8"></script>
</head>
<body>
<h3>Score: <span id="result"></span></h3>
<div class="grid">
</div>
</body>
</html>
CSS
Creamos el fichero style.css
.grid {
width: 400px;
height: 300px;
display: flex;
flex-wrap: wrap;
}
JavaScript
Creamos el fichero app.js
Creamos el fichero app.js con Evento DomContentLoaded
document.addEventListener('DOMContentLoaded', () => {
// pondremos aquí todo nuestro código
})
Array de cartas: cardArray
Cada elemento del array tendrá un nombre y la ruta de una imagen
document.addEventListener('DOMContentLoaded', () => {
//card options
const cardArray = [
{
name: 'fries',
img: 'images/fries.png'
},
{
name: 'cheeseburger',
img: 'images/cheeseburger.png'
},
{
name: 'ice-cream',
img: 'images/ice-cream.png'
},
{
name: 'pizza',
img: 'images/pizza.png'
},
{
name: 'milkshake',
img: 'images/milkshake.png'
},
{
name: 'hotdog',
img: 'images/hotdog.png'
},
{
name: 'fries',
img: 'images/fries.png'
},
{
name: 'cheeseburger',
img: 'images/cheeseburger.png'
},
{
name: 'ice-cream',
img: 'images/ice-cream.png'
},
{
name: 'pizza',
img: 'images/pizza.png'
},
{
name: 'milkshake',
img: 'images/milkshake.png'
},
{
name: 'hotdog',
img: 'images/hotdog.png'
}
]
})
Ordenamos el array de forma aleatoria
//card options
const cardArray = [
{
name: 'fries',
img: 'images/fries.png'
},
{
name: 'cheeseburger',
img: 'images/cheeseburger.png'
},
{
name: 'ice-cream',
img: 'images/ice-cream.png'
},
{
name: 'pizza',
img: 'images/pizza.png'
},
{
name: 'milkshake',
img: 'images/milkshake.png'
},
{
name: 'hotdog',
img: 'images/hotdog.png'
},
{
name: 'fries',
img: 'images/fries.png'
},
{
name: 'cheeseburger',
img: 'images/cheeseburger.png'
},
{
name: 'ice-cream',
img: 'images/ice-cream.png'
},
{
name: 'pizza',
img: 'images/pizza.png'
},
{
name: 'milkshake',
img: 'images/milkshake.png'
},
{
name: 'hotdog',
img: 'images/hotdog.png'
}
]
// ordenamos el array de forma aleatoria
cardArray.sort(() => 0.5 - Math.random())
})
Referencias html y arrays
Creamos una referencia al elemento HTML que contiene la cuadrícula donde visualizaremos las cartas, y otra al resultado que visualiza las parejas descubiertas. Además, creamos tres arrays:
- cardsChosen y cardsChosenId : para almacenar las dos cartas que hemos elegido en cada intento y sus correspondientes identificadores
- cardsWon : para almacenar las cartas que hemos conseguido emparejar
document.addEventListener('DOMContentLoaded', () => {
//card options
const cardArray = [
{
name: 'fries',
img: 'images/fries.png'
},
{
name: 'cheeseburger',
img: 'images/cheeseburger.png'
},
{
name: 'ice-cream',
img: 'images/ice-cream.png'
},
{
name: 'pizza',
img: 'images/pizza.png'
},
{
name: 'milkshake',
img: 'images/milkshake.png'
},
{
name: 'hotdog',
img: 'images/hotdog.png'
},
{
name: 'fries',
img: 'images/fries.png'
},
{
name: 'cheeseburger',
img: 'images/cheeseburger.png'
},
{
name: 'ice-cream',
img: 'images/ice-cream.png'
},
{
name: 'pizza',
img: 'images/pizza.png'
},
{
name: 'milkshake',
img: 'images/milkshake.png'
},
{
name: 'hotdog',
img: 'images/hotdog.png'
}
]
cardArray.sort(() => 0.5 - Math.random())
const grid = document.querySelector('.grid')
const resultDisplay = document.querySelector('#result')
let cardsChosen = []
let cardsChosenId = []
let cardsWon = []
})
Función para crear el tablero
La función contiene un bucle que añadirá a cada carta:
- su imagen correspondiente
- un identificador numérico que corresponde con su posición en el array
- un ‘Event Listener’ que llamará a una función llamada flipCard
- la añadirá a la cuadrícula
//create your board
function createBoard() {
for (let i = 0; i < cardArray.length; i++) {
const card = document.createElement('img')
card.setAttribute('src', 'images/blank.png')
card.setAttribute('data-id', i)
card.addEventListener('click', flipCard)
grid.appendChild(card)
}
}
Función para darle la vuelta a una carta
La función flipCard será llamada al hacer click en una de las cartas, por lo que pertenece a la propia carta y podemos utilizar ‘this’ para referirnos a la carta que ha sido clicada y obtener su identificador (cardId) que también indica su posición en el array de cartas.
Añadimos utilizando la función ‘push()’ el nombre y el identificador de la carta elegida en cardsChosen y cardsChosenId. Además, actualizamos el atributo ‘src’ con la imagen de la carta para visualizar la carta elegida.
Por último, si es la segunda carta elegida llamamos a la función checkForMatch que comprobará si las cartas elegidas con pareja. La función setTimeout añade un retardo de 500 milisegundos.
//flip your card
function flipCard() {
let cardId = this.getAttribute('data-id')
cardsChosen.push(cardArray[cardId].name)
cardsChosenId.push(cardId)
this.setAttribute('src', cardArray[cardId].img)
if (cardsChosen.length ===2) {
setTimeout(checkForMatch, 500)
}
}
Función para comprobar una pareja
Primero obtenemos una referencia de todas las cartas del tablero (cards), y para la primera y segunda carta (optionOneId y optionTwoId). Después evaluamos todas las posibilidades:
- la misma carta seleccionada dos veces (==)
- pareja de cartas encontrada (===)
- pareja de cartas no encontrada
En este caso, el operador == devuelve true cuando se compara el mismo objeto, en cambio, === devuelve true cuando los valores de dos objetos diferentes son iguales.
//check for matches
function checkForMatch() {
const cards = document.querySelectorAll('img')
const optionOneId = cardsChosenId[0]
const optionTwoId = cardsChosenId[1]
if(optionOneId == optionTwoId) {
cards[optionOneId].setAttribute('src', 'images/blank.png')
cards[optionTwoId].setAttribute('src', 'images/blank.png')
alert('You have clicked the same image!')
}
else if (cardsChosen[0] === cardsChosen[1]) {
alert('You found a match')
cards[optionOneId].setAttribute('src', 'images/white.png')
cards[optionTwoId].setAttribute('src', 'images/white.png')
cards[optionOneId].removeEventListener('click', flipCard)
cards[optionTwoId].removeEventListener('click', flipCard)
cardsWon.push(cardsChosen)
} else {
cards[optionOneId].setAttribute('src', 'images/blank.png')
cards[optionTwoId].setAttribute('src', 'images/blank.png')
alert('Sorry, try again')
}
cardsChosen = []
cardsChosenId = []
resultDisplay.textContent = cardsWon.length
if (cardsWon.length === cardArray.length/2) {
resultDisplay.textContent = 'Congratulations! You found them all!'
}
}
Llamada a la función createBoard
createBoard()
Programa completo
document.addEventListener('DOMContentLoaded', () => {
//card options
const cardArray = [
{
name: 'fries',
img: 'images/fries.png'
},
{
name: 'cheeseburger',
img: 'images/cheeseburger.png'
},
{
name: 'ice-cream',
img: 'images/ice-cream.png'
},
{
name: 'pizza',
img: 'images/pizza.png'
},
{
name: 'milkshake',
img: 'images/milkshake.png'
},
{
name: 'hotdog',
img: 'images/hotdog.png'
},
{
name: 'fries',
img: 'images/fries.png'
},
{
name: 'cheeseburger',
img: 'images/cheeseburger.png'
},
{
name: 'ice-cream',
img: 'images/ice-cream.png'
},
{
name: 'pizza',
img: 'images/pizza.png'
},
{
name: 'milkshake',
img: 'images/milkshake.png'
},
{
name: 'hotdog',
img: 'images/hotdog.png'
}
]
cardArray.sort(() => 0.5 - Math.random())
const grid = document.querySelector('.grid')
const resultDisplay = document.querySelector('#result')
let cardsChosen = []
let cardsChosenId = []
let cardsWon = []
//create your board
function createBoard() {
for (let i = 0; i < cardArray.length; i++) {
const card = document.createElement('img')
card.setAttribute('src', 'images/blank.png')
card.setAttribute('data-id', i)
card.addEventListener('click', flipCard)
grid.appendChild(card)
}
}
//check for matches
function checkForMatch() {
const cards = document.querySelectorAll('img')
const optionOneId = cardsChosenId[0]
const optionTwoId = cardsChosenId[1]
if(optionOneId == optionTwoId) {
cards[optionOneId].setAttribute('src', 'images/blank.png')
cards[optionTwoId].setAttribute('src', 'images/blank.png')
alert('You have clicked the same image!')
}
else if (cardsChosen[0] === cardsChosen[1]) {
alert('You found a match')
cards[optionOneId].setAttribute('src', 'images/white.png')
cards[optionTwoId].setAttribute('src', 'images/white.png')
cards[optionOneId].removeEventListener('click', flipCard)
cards[optionTwoId].removeEventListener('click', flipCard)
cardsWon.push(cardsChosen)
} else {
cards[optionOneId].setAttribute('src', 'images/blank.png')
cards[optionTwoId].setAttribute('src', 'images/blank.png')
alert('Sorry, try again')
}
cardsChosen = []
cardsChosenId = []
resultDisplay.textContent = cardsWon.length
if (cardsWon.length === cardArray.length/2) {
resultDisplay.textContent = 'Congratulations! You found them all!'
}
}
//flip your card
function flipCard() {
let cardId = this.getAttribute('data-id')
cardsChosen.push(cardArray[cardId].name)
cardsChosenId.push(cardId)
this.setAttribute('src', cardArray[cardId].img)
if (cardsChosen.length ===2) {
setTimeout(checkForMatch, 500)
}
}
createBoard()
})