Skip to content

Commit

Permalink
Added Memory Cards
Browse files Browse the repository at this point in the history
  • Loading branch information
marinitx committed Oct 31, 2024
1 parent f876a1b commit b873681
Show file tree
Hide file tree
Showing 16 changed files with 376 additions and 16 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-helmet": "^6.1.0",
"react-router-dom": "^6.6.2",
"react-router-dom": "^6.27.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
Expand Down
5 changes: 5 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import WrappedFinale from "./pages/wrapped2023/finale";
import Skin2Json from "./pages/skin2Json";
import SkinTool from "./pages/skin-tool";
import ProgressView from "./pages/advent-calendar-2024/pages/progress-view";
import GamesView from "./pages/advent-calendar-2024/pages/games-view";

export const SchemeContext = createContext();

Expand Down Expand Up @@ -75,6 +76,10 @@ const App = () => {
path: `/advent-calendar-2024/progress-view`,
element: <ProgressView />,
},
{
path: `/advent-calendar-2024/games-view`,
element: <GamesView />,
},
{
path: `/skin2json`,
element: <Skin2Json />,
Expand Down
5 changes: 5 additions & 0 deletions src/img/games/blau.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/img/games/movistar.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/img/games/o2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions src/img/games/sound-mute.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions src/img/games/sound-on.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions src/img/games/telefonica.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/img/games/tu.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/img/games/vivo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
128 changes: 128 additions & 0 deletions src/pages/advent-calendar-2024/components/games/memory.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@

.memory-game {
text-align: center;
justify-content: center;
align-items: center;
flex-direction: row;
display: flex;
max-width: 100%;
height: 100vh;
}

.card-grid {
padding-top: 20px;
display: grid;
grid-template-columns: repeat(4, 1fr);
max-width: fit-content;
margin: 0 auto;
gap: 15px;
}

.card.disabled {
pointer-events: none;
opacity: 0.5;
}

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

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

.card-back,
.card-front {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
}

.card-front {
backface-visibility: hidden;
}

.card {
width: 100px;
height: 100px;
position: relative;
transform-style: preserve-3d;
transition: transform 0.6s;
cursor: pointer;
border-radius: 8px;
background-color: white;
border: 1px solid black;
font-size: 30px;
display: flex;
align-items: center;
justify-content: center;
}

.card.flipped {
transform: rotateY(180deg);
cursor: default;
}

/* Cara frontal de la carta (cuando está oculta) */
.card::before {
content: "";
position: absolute;
width: 100%;
height: 100%;
background-color: white;
color: white;
font-size: 30px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
backface-visibility: hidden;
}

.card img {
width: 70%;
height: 70%;
border-radius: 8px;
backface-visibility: hidden;
transform: rotateY(180deg);
}

.left-column {
flex: 1;
padding: 20px;
display: flex;
flex-direction: column;
justify-content: flex-start;
text-align: left;
gap: 10px;
}

.right-column {
flex: 2; /* Ocupa más espacio que la columna izquierda */
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}

.card-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 15px; /* Espacio entre cartas */
margin-bottom: 20px; /* Espacio entre el grid y el timer */
width: 100%;
}

#timer {
font-size: 20px;
margin-top: 10px;
}

#score {
font-size: 20px;
}
141 changes: 141 additions & 0 deletions src/pages/advent-calendar-2024/components/games/memory.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import {
Text10,
Text4,
Text3,
Text9
} from "@telefonica/mistica";
import React, { useState, useEffect } from 'react';
import blau from '../../../../img/games/blau.svg';
import movistar from '../../../../img/games/movistar.svg';
import o2 from '../../../../img/games/o2.svg';
import telefonica from '../../../../img/games/telefonica.svg';
import tu from '../../../../img/games/tu.svg';
import vivo from '../../../../img/games/vivo.svg';
import './memory.css';

const initialCards = [
blau, blau,
movistar, movistar,
o2, o2,
telefonica, telefonica,
tu, tu,
vivo, vivo
];
const MemoryGame = () => {
const timeLimit = 60; // Tiempo en segundos
const [cards, setCards] = useState([]);
const [flippedCards, setFlippedCards] = useState([]);
const [matchedPairs, setMatchedPairs] = useState(0);
const [score, setScore] = useState(0);
const [timerStarted, setTimerStarted] = useState(false);
const [timeRemaining, setTimeRemaining] = useState(timeLimit);
const [gameEnded, setGameEnded] = useState(false); // Para controlar cuando terminas
const [revealedCards, setRevealedCards] = useState([]); // Cartas que han sido reveladas y son una pareja

// Función para barajar las cartas
const shuffle = (array) => {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
};

// Efecto para iniciar el juego
useEffect(() => {
setCards(shuffle([...initialCards]));
}, []);

// Efecto para manejar el temporizador
useEffect(() => {
if (timerStarted && timeRemaining > 0 && !gameEnded) {
const timerId = setInterval(() => {
setTimeRemaining((prevTime) => prevTime - 1);
}, 1000);
return () => clearInterval(timerId);
} else if (timeRemaining === 0 && !gameEnded) {
setGameEnded(true);
}
}, [timerStarted, timeRemaining, gameEnded]);


const startTimer = () => {
setTimerStarted(true);
};

const flipCard = (index) => {
if (gameEnded || revealedCards.includes(index)) return; // Evitar interacciones si el juego ha terminado o si la carta ya ha sido revelada

if (flippedCards.length === 0 && !timerStarted) {
startTimer(); // Inicia el temporizador al girar la primera carta
}

if (flippedCards.length < 2) {
const newFlippedCards = [...flippedCards, index];
setFlippedCards(newFlippedCards);

if (newFlippedCards.length === 2) {
setTimeout(() => checkForMatch(newFlippedCards), 500);
}
}
};

const checkForMatch = (newFlippedCards) => {
const [firstCardIndex, secondCardIndex] = newFlippedCards;

if (cards[firstCardIndex] === cards[secondCardIndex]) {
setMatchedPairs(prev => prev + 1);
const scoreToAdd = Math.max(0, timeRemaining);
setScore(prev => prev + scoreToAdd); // Sumar tiempo restante a la puntuación

// Añadir índices de cartas reveladas a la lista de cartas reveladas
setRevealedCards(prev => [...prev, firstCardIndex, secondCardIndex]);
setFlippedCards([]); // Reiniciar cartas volteadas
} else {
setTimeout(() => {
setFlippedCards([]); // Reiniciar cartas volteadas si no hay coincidencia
}, 500);
}

// Verificar si se han encontrado todos los pares
if (matchedPairs + 1 === cards.length / 2) {
setGameEnded(true); // Terminar el juego si se encuentran todos los pares
}
};

return (
<div className="memory-game">
<div className="left-column">
<Text10>Memory Cards</Text10>
<Text4>Instructions</Text4>
<Text3>Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</Text3>
<Text9 id="score">Score: {score}</Text9>
{gameEnded && <p>Congratsss! Your final score is: {score}</p>}
</div>
<div className="right-column">
<div className="card-grid">
{cards.map((imageUrl, index) => (
<div
key={index}
className={`card ${flippedCards.includes(index) || revealedCards.includes(index) ? "flipped" : ""} ${gameEnded ? "disabled" : ""}`}
onClick={() => flipCard(index)}
>
{(flippedCards.includes(index) || revealedCards.includes(index)) ? (
<img src={imageUrl} alt="Card" style={{ display: "block" }} />
) : (
<div className="card-back"></div>
)}
</div>
))}
</div>
<p id="timer">{timeRemaining} s</p>
</div>
</div>
);
};

export default MemoryGame;
Empty file.
Loading

0 comments on commit b873681

Please sign in to comment.