0% found this document useful (0 votes)
12 views

Memory game

The document outlines the steps to create a real-time Memory Game (Memorama) using Node.js with Express and WebSockets for the backend, and HTML, CSS, and JavaScript for the frontend. It includes instructions for setting up the project, creating the backend server, designing the frontend, and implementing game logic. Additionally, it highlights features such as multiplayer functionality, live score updates, and suggests challenges for further enhancements.

Uploaded by

roman.delangel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views

Memory game

The document outlines the steps to create a real-time Memory Game (Memorama) using Node.js with Express and WebSockets for the backend, and HTML, CSS, and JavaScript for the frontend. It includes instructions for setting up the project, creating the backend server, designing the frontend, and implementing game logic. Additionally, it highlights features such as multiplayer functionality, live score updates, and suggests challenges for further enhancements.

Uploaded by

roman.delangel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

🚀WebSockets

Real-time Memory Game (Memorama) with


and Express
In this exercise, you will build a real-time Memory Game (Memorama) where multiple players can
compete to find matching cards first. The game will be developed using Node.js (Express +
WebSockets) for the backend and HTML, CSS, and JavaScript for the frontend.

🛠1️⃣ Step 1: Setup the Project


Initialize a new Node.js project
Run the following command in your project folder:
npm init -y

2️⃣ Install required dependencies


npm install express ws

3️⃣ Create the following files in your project directory:


/memory-game
│── server.js (Backend server with WebSockets)
│── /public
│ ├── index.html (Frontend UI)
│ ├── styles.css (CSS styling)
│ ├── script.js (Game logic)
│ ├── /img (Folder for images)
│ │ ├── img1.png
│ │ ├── img2.png
│ │ ├── img3.png
│ │ ├── img4.png
│ │ ├── img5.png
│ │ ├── img6.png
│ │ ├── img7.png
│ │ ├── img8.png
│ ├── /sounds (Folder for sounds)
│ │ ├── correct.mp3
│ │ ├── wrong.mp3

📌 Step 2: Create the Backend (server.js)



This will:


Serve the static frontend files.


Handle WebSocket connections.
Broadcast game updates in real-time.

const express = require('express');


const http = require('http');
const WebSocket = require('ws');
const path = require('path');

const app = express();


const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

app.use(express.static(path.join(__dirname, 'public')));

let players = {};


let flippedCards = [];
let matchedPairs = 0;

// Lista de imágenes (coloca las imágenes en la carpeta /public/img/)


let images = [
'img/img1.jpg', 'img/img1.jpg', 'img/img2.png', 'img/img2.png',
'img/img3.png', 'img/img3.png', 'img/img4.png', 'img/img4.png',
'img/img5.png', 'img/img5.png', 'img/img6.png', 'img/img6.png',
'img/img7.png', 'img/img7.png', 'img/img8.png', 'img/img8.png'
];

images = shuffle(images);

function shuffle(array) {
return array.sort(() => Math.random() - 0.5);
}

wss.on('connection', function connection(ws) {


let playerId = `Player-${Math.floor(Math.random() * 1000)}`;
players[playerId] = { ws, score: 0 };

ws.send(JSON.stringify({ type: 'init', playerId, images }));

ws.on('message', function incoming(message) {


const data = JSON.parse(message);

if (data.type === 'flip') {


if (flippedCards.length < 2) {
flippedCards.push({ index: data.index, playerId });
broadcast({ type: 'flip', index: data.index, image:
images[data.index] });

if (flippedCards.length === 2) {
setTimeout(checkMatch, 1000);
}
}
}
});

ws.on('close', () => {
delete players[playerId];
});
});

function checkMatch() {
if (flippedCards[0].index !== flippedCards[1].index &&
images[flippedCards[0].index] === images[flippedCards[1].index]) {

players[flippedCards[0].playerId].score += 1;
broadcast({
type: 'match',
playerId: flippedCards[0].playerId,
score: players[flippedCards[0].playerId].score,
indexes: [flippedCards[0].index, flippedCards[1].index]
});

matchedPairs++;
if (matchedPairs === images.length / 2) {
broadcast({ type: 'gameOver' });
}
} else {
broadcast({ type: 'unflip', indexes: [flippedCards[0].index,
flippedCards[1].index] });
}

flippedCards = [];
}

function broadcast(data) {
wss.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(data));
}
});
}

server.listen(8080, () => {
console.log('Server running on http://localhost:8080');
});

🎨 Step 3: Create the Frontend (public/index.html)



This will:


Display the memory game grid.


Show the player's score.
Connect to the WebSocket server.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Real-time Memory Game</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Real-time Memory Game</h1>
<h2 id="playerId"></h2>
<h3>Score: <span id="score">0</span></h3>
<div id="gameBoard"></div>
<script src="script.js"></script>
</body>
</html>
🎨 Step 4: Add Styling (public/styles.css)

This will:


Style the game board.
Make it visually appealing.
body {
font-family: Arial, sans-serif;
text-align: center;
margin: 0;
padding: 0;
overflow: hidden;
background: linear-gradient(45deg, #ff0080, #ff8c00, #40e0d0, #0080ff);
background-size: 300% 300%;
animation: backgroundMove 6s infinite alternate;
}

@keyframes backgroundMove {
0% { background-position: 0% 50%; }
100% { background-position: 100% 50%; }
}

#gameBoard {
display: grid;
grid-template-columns: repeat(4, 120px);
grid-gap: 10px;
justify-content: center;
margin-top: 50px;
}

.card {
width: 120px;
height: 120px;
perspective: 1000px;
cursor: pointer;
}

.card-inner {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
transition: transform 0.6s;
}

.card.flipped .card-inner {
transform: rotateY(180deg);
}

.card-front,
.card-back {
width: 100%;
height: 100%;
position: absolute;
backface-visibility: hidden;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.card-front {
background: #ffffff;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
font-weight: bold;
color: #333;
}

.card-back {
background-size: cover;
background-position: center;
transform: rotateY(180deg);
}

🔥 Step 5: Game Logic (public/script.js)



This will:


Handle card clicks.


Send data to the server via WebSockets.
Update the UI in real-time.

const socket = new WebSocket('ws://localhost:8080');


let playerId;
let score = 0;
let gameBoard = document.getElementById('gameBoard');
let scoreDisplay = document.getElementById('score');
let flippedCards = {};

// Cargar sonidos
const correctSound = new Audio('sounds/correct.mp3');
const wrongSound = new Audio('sounds/wrong.mp3');

socket.onmessage = function(event) {
let data = JSON.parse(event.data);

if (data.type === 'init') {


playerId = data.playerId;
document.getElementById('playerId').innerText = playerId;
createBoard(data.images);
} else if (data.type === 'flip') {
flipCard(data.index, data.image);
} else if (data.type === 'unflip') {
setTimeout(() => {
unflipCards(data.indexes);
wrongSound.play(); // Sonido de fallo
}, 1000);
} else if (data.type === 'match') {
if (data.playerId === playerId) {
score = data.score;
scoreDisplay.innerText = score;
}
setTimeout(() => {
removeMatchedCards(data.indexes);
correctSound.play(); // Sonido de acierto
}, 1000);
} else if (data.type === 'gameOver') {
alert('¡Juego terminado! Recarga para jugar otra vez.');
}
};

function createBoard(images) {
gameBoard.innerHTML = '';
images.forEach((_, index) => {
let card = document.createElement('div');
card.classList.add('card');
card.dataset.index = index;

let cardInner = document.createElement('div');


cardInner.classList.add('card-inner');

let cardFront = document.createElement('div');


cardFront.classList.add('card-front');
cardFront.innerText = '?';

let cardBack = document.createElement('div');


cardBack.classList.add('card-back');
cardBack.style.backgroundImage = "url('" + images[index] + "')";

cardInner.appendChild(cardFront);
cardInner.appendChild(cardBack);
card.appendChild(cardInner);

card.addEventListener('click', () => sendFlip(index));


gameBoard.appendChild(card);
});
}

function sendFlip(index) {
if (!flippedCards[index]) {
socket.send(JSON.stringify({ type: 'flip', index }));
}
}

function flipCard(index, image) {


let card = document.querySelector(`[data-index="${index}"]`);
card.classList.add('flipped');
flippedCards[index] = true;
}

function unflipCards(indexes) {
indexes.forEach(index => {
let card = document.querySelector(`[data-index="${index}"]`);
card.classList.remove('flipped');
delete flippedCards[index];
});
}

function removeMatchedCards(indexes) {
indexes.forEach(index => {
let card = document.querySelector(`[data-index="${index}"]`);
setTimeout(() => card.remove(), 500);
});
}

✅1️⃣ Step 6: Run the Game


Start the server
node server.js

2️⃣ Open the game in multiple browsers


Go to:
http://localhost:8080

Try playing on two different tabs to see the real-time interactions!

🎯✅ Game Features

Multiplayer in real-time (Players see each other's flips).


Players compete to find pairs first.


Scores update live.
Basic WebSockets integration with Node.js & Express.

🚀 CHALLENGE
🔹 ⏳
You need to compete the game by adding:

🔹 👭
A timer

🔹 🎨
Take Turns

🔹 🔢
More animations
Individual Scores

🤖You can use AI to complete the challenges

You might also like