-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
618 additions
and
2 deletions.
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
133 changes: 133 additions & 0 deletions
133
src/pages/advent-calendar-2024/components/games/candy.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
.candy-crush { | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
flex-direction: row; | ||
gap: 20px; /* Espacio entre las columnas */ | ||
} | ||
|
||
.left-column { | ||
flex: 1; /* Ocupa 1/3 del espacio */ | ||
padding: 20px; | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
text-align: left; | ||
gap: 10px; | ||
} | ||
|
||
.right-column { | ||
flex: 2; /* Ocupa 2/3 del espacio */ | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: flex-start; | ||
align-items: center; | ||
padding: 20px; | ||
} | ||
|
||
.grid { | ||
height: 560px; | ||
width: 560px; | ||
display: flex; | ||
flex-wrap: wrap; | ||
justify-content: center; /* Centra el contenido dentro de la grilla */ | ||
align-items: center; | ||
} | ||
|
||
/* Clase para bloquear la cuadrícula */ | ||
.grid.locked { | ||
pointer-events: none; | ||
opacity: 0.5; | ||
} | ||
|
||
.grid.locked::before { | ||
content: "Game Over"; | ||
position: relative; | ||
top: 50%; | ||
left: 50%; | ||
transform: translate(-50%, -50%); | ||
font-size: 2rem; | ||
color: white; | ||
background-color: rgba(0, 0, 0); | ||
padding: 10px; | ||
border-radius: 5px; | ||
} | ||
|
||
|
||
/* Estilos y animaciones */ | ||
.grid div { | ||
height: 70px; | ||
width: 70px; | ||
transition: transform 0.3s ease-in-out; | ||
} | ||
|
||
.dragging { | ||
opacity: 0.4; | ||
transform: scale(0.5); | ||
} | ||
|
||
.invalid-move { | ||
animation: shake 0.3s ease; | ||
} | ||
|
||
/* Animación para intercambiar posiciones */ | ||
@keyframes swap { | ||
0% { | ||
transform: translate(0, 0); | ||
} | ||
100% { | ||
transform: translate(100%, 100%); /* Ejemplo de cómo mover de un lugar a otro */ | ||
} | ||
} | ||
|
||
@keyframes shake { | ||
0%, 100% { transform: translateX(0); } | ||
25% { transform: translateX(-5px); } | ||
50% { transform: translateX(5px); } | ||
75% { transform: translateX(-5px); } | ||
} | ||
|
||
.square.shake { | ||
animation: shake 0.5s ease-in-out; | ||
} | ||
|
||
|
||
.drop { | ||
animation: drop 0.3s cubic-bezier(0.4, 0, 1, 1); | ||
} | ||
|
||
@keyframes drop { | ||
0% { transform: translateY(-100%); } | ||
100% { transform: translateY(0); } | ||
} | ||
|
||
@keyframes disappear { | ||
0% { transform: scale(1); opacity: 1; } | ||
100% { transform: scale(0); opacity: 0; } | ||
} | ||
|
||
.disappear { | ||
animation: disappear 0.8s ease forwards; | ||
} | ||
|
||
/* Animación para filas o columnas de 3 o 4 elementos */ | ||
@keyframes clearRowOrColumn { | ||
0% { | ||
opacity: 1; | ||
transform: scale(1); | ||
} | ||
50% { | ||
opacity: 0.5; | ||
transform: scale(1.2); | ||
} | ||
100% { | ||
opacity: 0; | ||
transform: scale(0.5); | ||
} | ||
} | ||
|
||
/* Clase para aplicar la animación */ | ||
.clear-animation { | ||
animation: clearRowOrColumn 0.5s ease-out forwards; | ||
} | ||
|
217 changes: 217 additions & 0 deletions
217
src/pages/advent-calendar-2024/components/games/candy.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,217 @@ | ||
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 './candy.css'; | ||
|
||
const CandyCrush = () => { | ||
const width = 8; | ||
const candyColors = [movistar, tu, vivo, blau, telefonica, o2]; | ||
const maxMoves = 10; | ||
|
||
const [squares, setSquares] = useState([]); | ||
const [score, setScore] = useState(0); | ||
const [movesRemaining, setMovesRemaining] = useState(maxMoves); | ||
const [draggingIndex, setDraggingIndex] = useState(null); | ||
const [invalidMove, setInvalidMove] = useState(null); // Estado para identificar si un movimiento es inválido | ||
|
||
useEffect(() => { | ||
if (movesRemaining === 0) { | ||
document.querySelector('.grid').classList.add('locked'); // Bloquea la cuadrícula | ||
} | ||
}, [movesRemaining]); | ||
|
||
useEffect(() => { | ||
createBoard(); | ||
}, []); | ||
|
||
useEffect(() => { | ||
const intervalId = setInterval(() => { | ||
moveDown(); | ||
checkMatches(); | ||
}, 100); | ||
|
||
return () => clearInterval(intervalId); // Limpiar el intervalo al desmontar | ||
}, [squares]); | ||
|
||
function createBoard() { | ||
const initialSquares = []; | ||
for (let i = 0; i < width * width; i++) { | ||
const randomColor = Math.floor(Math.random() * candyColors.length); | ||
initialSquares.push(candyColors[randomColor]); | ||
} | ||
setSquares(initialSquares); | ||
} | ||
|
||
function moveDown() { | ||
let newSquares = [...squares]; | ||
for (let i = width * (width - 1) - 1; i >= 0; i--) { | ||
if (newSquares[i + width] === undefined || newSquares[i + width] === '') { | ||
newSquares[i + width] = newSquares[i]; | ||
newSquares[i] = ''; | ||
} | ||
} | ||
for (let i = 0; i < width; i++) { | ||
if (newSquares[i] === '') { | ||
const randomColor = Math.floor(Math.random() * candyColors.length); | ||
newSquares[i] = candyColors[randomColor]; | ||
} | ||
} | ||
setSquares(newSquares); | ||
} | ||
|
||
function animateAndClear(squaresToClear) { | ||
let newSquares = [...squares]; | ||
squaresToClear.forEach(index => { | ||
newSquares[index] = ''; | ||
}); | ||
setSquares(newSquares); | ||
} | ||
|
||
function checkMatches() { | ||
checkRowForFour(); | ||
checkColumnForFour(); | ||
checkRowForThree(); | ||
checkColumnForThree(); | ||
} | ||
|
||
function checkRowForFour() { | ||
for (let i = 0; i < 63; i++) { | ||
if (i % width > width - 4) continue; | ||
const rowOfFour = [i, i + 1, i + 2, i + 3]; | ||
const decidedColor = squares[i]; | ||
const isBlank = decidedColor === ''; | ||
|
||
if (rowOfFour.every(index => squares[index] === decidedColor) && !isBlank) { | ||
setScore(prevScore => prevScore + 4); | ||
animateAndClear(rowOfFour); | ||
} | ||
} | ||
} | ||
|
||
function checkColumnForFour() { | ||
for (let i = 0; i < 47; i++) { | ||
const columnOfFour = [i, i + width, i + width * 2, i + width * 3]; | ||
const decidedColor = squares[i]; | ||
const isBlank = decidedColor === ''; | ||
|
||
if (columnOfFour.every(index => squares[index] === decidedColor) && !isBlank) { | ||
setScore(prevScore => prevScore + 4); | ||
animateAndClear(columnOfFour); | ||
} | ||
} | ||
} | ||
|
||
function checkRowForThree() { | ||
for (let i = 0; i < 64; i++) { | ||
if (i % width > width - 3) continue; | ||
const rowOfThree = [i, i + 1, i + 2]; | ||
const decidedColor = squares[i]; | ||
const isBlank = decidedColor === ''; | ||
|
||
if (rowOfThree.every(index => squares[index] === decidedColor) && !isBlank) { | ||
setScore(prevScore => prevScore + 3); | ||
animateAndClear(rowOfThree); | ||
} | ||
} | ||
} | ||
|
||
function checkColumnForThree() { | ||
for (let i = 0; i < 48; i++) { | ||
const columnOfThree = [i, i + width, i + width * 2]; | ||
const decidedColor = squares[i]; | ||
const isBlank = decidedColor === ''; | ||
|
||
if (columnOfThree.every(index => squares[index] === decidedColor) && !isBlank) { | ||
setScore(prevScore => prevScore + 3); | ||
animateAndClear(columnOfThree); | ||
} | ||
} | ||
} | ||
|
||
const handleDragStart = (e, index) => { | ||
if (movesRemaining === 0) return; // Bloquea el drag si no hay movimientos restantes | ||
setDraggingIndex(index); | ||
e.dataTransfer.setData('draggedIndex', index); | ||
}; | ||
|
||
// const handleDrop = (e, index) => { | ||
// if (movesRemaining === 0) return; // Bloquea el drop si no hay movimientos restantes | ||
// const draggedIndex = e.dataTransfer.getData('draggedIndex'); | ||
|
||
// let newSquares = [...squares]; | ||
// let temp = newSquares[index]; | ||
// newSquares[index] = newSquares[draggedIndex]; | ||
// newSquares[draggedIndex] = temp; | ||
|
||
// setSquares(newSquares); | ||
// setMovesRemaining(prev => prev - 1); | ||
// }; | ||
|
||
|
||
const handleDrop = (e, index) => { | ||
if (movesRemaining === 0) return; | ||
const draggedIndex = e.dataTransfer.getData('draggedIndex'); | ||
const isAdjacent = Math.abs(draggedIndex - index) === 1 || Math.abs(draggedIndex - index) === width; | ||
|
||
if (isAdjacent) { | ||
let newSquares = [...squares]; | ||
let temp = newSquares[index]; | ||
newSquares[index] = newSquares[draggedIndex]; | ||
newSquares[draggedIndex] = temp; | ||
setSquares(newSquares); | ||
setMovesRemaining(prev => prev - 1); | ||
setInvalidMove(null); // Reset el estado de movimiento inválido | ||
setDraggingIndex(null); | ||
} else { | ||
setInvalidMove(draggedIndex); // Activamos el movimiento inválido | ||
|
||
setDraggingIndex(null); // Limpiamos el estado de "draggingIndex" | ||
} | ||
}; | ||
|
||
const handleDragOver = (e) => { | ||
e.preventDefault(); | ||
}; | ||
|
||
return ( | ||
<div className="candy-crush"> | ||
<div className="left-column"> | ||
<Text10>Candy Crush</Text10> | ||
<p>Instructions: Try to match Telefonica brands of the same type in a row or column of 3!</p> | ||
<p id="score">Score: {score}</p> | ||
</div> | ||
<div className="right-column"> | ||
<div className="grid"> | ||
{squares.map((color, index) => ( | ||
<div | ||
key={index} | ||
id={index} | ||
className={`square ${draggingIndex === index ? 'dragging' : ''} ${invalidMove === index ? 'invalid-move' : ''}`} // Aplica shake a la imagen arrastrada si el movimiento es inválido | ||
style={{ backgroundImage: `url(${color})` }} | ||
draggable | ||
onDragStart={(e) => handleDragStart(e, index)} | ||
onDragOver={handleDragOver} | ||
onDrop={(e) => handleDrop(e, index)} | ||
></div> | ||
))} | ||
</div> | ||
<p id="timer">{movesRemaining} moves</p> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default CandyCrush; | ||
|
||
|
||
|
Oops, something went wrong.