Skip to content

Commit

Permalink
[Play] 2048 Game (reactplay#701)
Browse files Browse the repository at this point in the history
* Update the readme file

* Added the cells for the game board

* Added the game images

* Add the game components

* Add the styles

* Add the game sound

* Add the game logic

* Add the cover image

* Completed the game

* Added new images

* Updated the media queries

* Some minor changes

* Added the status to the Modal

* Format the file

* Added new function

* Added some state variables

* Extracted a logic into the function

* Update the modal logic with useEffect

* Updated the video music name

* Added unique classnames

* Added unique style names

* Created and Passed handler function as a prop

* Changed camelCase classnames to kebab-case

* Added p5 js script

Co-authored-by: Koustov <[email protected]>
Co-authored-by: Ammaar Aslam <[email protected]>
Co-authored-by: Sachin Chaurasiya <[email protected]>
  • Loading branch information
4 people committed Oct 29, 2022
1 parent a462652 commit 73192eb
Show file tree
Hide file tree
Showing 45 changed files with 1,319 additions and 0 deletions.
3 changes: 3 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.js%22%3E"></script>
</script>
<div id="root" class="app-container"></div>
<!--
This HTML file is a template.
Expand Down
11 changes: 11 additions & 0 deletions src/plays/2048/Game2048Components/Cell.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from "react";

function Cell(props) {
return (
<div className={`cell cell--${props.label}`}>
<span className="cell__label">{props.label}</span>
</div>
);
}

export default Cell;
39 changes: 39 additions & 0 deletions src/plays/2048/Game2048Components/Game.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { useState } from "react";
import Grid from "./Grid";
import TranformGrid from "../transformGrid";

function Game(props) {
const [grid, setGrid] = useState(grids)

function grids() {
let _grid = [
[null, null, null, null],
[null, null, null, null],
[null, null, null, null],
[null, null, null, null]
];

_grid = TranformGrid.addRandomCell(_grid);
_grid = TranformGrid.addRandomCell(_grid);

return _grid;
}

const handleGrid = (grid) => setGrid(grid)
return (
<div className="game_wrapper">
<Grid
grid={grid}
setGridState={handleGrid}
score={props.score}
setScore={props.setScore}
best={props.best}
setBest={props.setBest}
status={props.status}
setStatus={props.setStatus}
/>
</div>
);
}

export default Game;
22 changes: 22 additions & 0 deletions src/plays/2048/Game2048Components/GameHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react'
import Score from './Score'
import { FiRefreshCcw } from "react-icons/fi";

function GameHeader(props) {
return (
<div className="twenty-forty-eight-header">
<div className="twenty-forty-eight-header__row">
<h1 className="twenty-forty-eight-header__title">2048
</h1>
<Score score={props.score} best={props.best} />
</div>
<div className="twenty-forty-eight-header__row">
<button className="twenty-forty-eight-restart" onClick={props.resetGame}>
<FiRefreshCcw />
</button>
</div>
</div>
)
}

export default GameHeader
54 changes: 54 additions & 0 deletions src/plays/2048/Game2048Components/GameOverlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react'
import "../Game2048Styles/game-overlay.css"
import gameOver from "../GameAudio/gameOver.wav"
import gameWin from "../GameAudio/gameWin.wav"

function GameOverlay(props) {

const over = new Audio(gameOver)
const win = new Audio(gameWin)

const isStatusOver = props.status === "over"
const isStatusWon = props.status === "won"

{ isStatusOver ? over.play() : over.pause() } //Play game over sound effect
{ isStatusWon === "win" ? win.play() : win.pause() } //Play game win sound effect
return (
<>
<div
className={
isStatusOver
? "game-overlay game-overlay--over active"
: "game-overlay game-overlay--over"
}
>
<h1 className="game-overlay__message">Game Over!</h1>
<button className="game-overlay__try-again" onClick={props.tryAgain}>
Try Again
</button>
</div>
<div
className={
isStatusWon
? "game-overlay game-overlay--won active"
: "game-overlay game-overlay--won"
}
>
<h1 className="game-overlay__message">You win!</h1>
<button
className="game-overlay__keep-going"
onClick={() => {
props.setStatus("continue");
}}
>
Keep going
</button>
<button className="game-overlay__try-again" onClick={props.tryAgain}>
Try Again
</button>
</div>
</>
)
}

export default GameOverlay
64 changes: 64 additions & 0 deletions src/plays/2048/Game2048Components/Grid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { useEffect } from "react";
import Row from "./Row";
import TransformGrid from "../transformGrid";
import GameLogic from "../gameLogic";

function Grid(props) {

function handleKey(e) {
e.preventDefault();

if (props.status !== "running" && props.status !== "continue") return;
let result = {};

switch (e.key) {
case "ArrowUp":
result = GameLogic.addCell(TransformGrid.shiftUp(props.grid), props);
break;
case "ArrowRight":
result = GameLogic.addCell(
TransformGrid.shiftRight(props.grid),
props
);
break;
case "ArrowDown":
result = GameLogic.addCell(
TransformGrid.shiftDown(props.grid),
props
);
break;
case "ArrowLeft":
result = GameLogic.addCell(
TransformGrid.shiftLeft(props.grid),
props
);
break;
default:
}

if (props.status !== "continue" && GameLogic.has2048(result.transform)) {
props.setStatus("won");
}

if (GameLogic.hasNoMovesLeft(result.transform)) {
props.setStatus("over");
}
}
useEffect(() => {
window.addEventListener("keydown", handleKey);
return () => {
window.removeEventListener("keydown", handleKey);
};
}, [handleKey]);

return (
<div className="twenty-forty-eight-grid">
<Row row={props.grid[0]} />
<Row row={props.grid[1]} />
<Row row={props.grid[2]} />
<Row row={props.grid[3]} />
</div>
);
}

export default Grid;
42 changes: 42 additions & 0 deletions src/plays/2048/Game2048Components/Modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { useState, useEffect } from "react";
import { FaRegQuestionCircle } from 'react-icons/fa';
import "../Game2048Styles/Modal.css";

export default function Modal(props) {
const [modal, setModal] = useState(false);

const toggleModal = () => {
setModal(previous=>!previous);
};

useEffect(() => {
document.body.classList.add('twenty-forty-eight-active-modal')
}, [modal])

return (
<>
<button onClick={toggleModal} className={`${props.status === "over" ? "hide" : "twenty-forty-eight-btn-modal"}`}>
<FaRegQuestionCircle />
</button>

{modal && (
<div className="twenty-forty-eight-modal">
<div onClick={toggleModal} className="twenty-forty-eight-overlay"></div>
<div className="twenty-forty-eight-modal-content">
<h2 className="mb-4 font-extrabold">HOW TO PLAY</h2>
<p className="twenty-forty-eight-modal-para-one">
Use your arrow keys to move the tiles. When two tiles with the same number touch, they merge into one!
</p>
<br />
<p className="twenty-forty-eight-modal-para-two">
Join the numbers and get the <b>2048 tile!</b>to WIN.
</p>
<button className="twenty-forty-eight-close-modal font-extrabold text-red-500" onClick={toggleModal}>
CLOSE
</button>
</div>
</div>
)}
</>
);
}
15 changes: 15 additions & 0 deletions src/plays/2048/Game2048Components/Row.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react";
import Cell from "./Cell";

function GridRow(props) {
return (
<div className="twenty-forty-eight-row">
<Cell label={props.row[0]} />
<Cell label={props.row[1]} />
<Cell label={props.row[2]} />
<Cell label={props.row[3]} />
</div>
);
}

export default GridRow;
11 changes: 11 additions & 0 deletions src/plays/2048/Game2048Components/Score.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react'

function Score(props) {
return (
<>
<div className="score score--current">{props.score}</div>
<div className="score score--best">{props.best}</div>
</>
)
}
export default Score
15 changes: 15 additions & 0 deletions src/plays/2048/Game2048Components/VideoMusic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react'
import Video from "../GameAudio/VideoMusic.mp4"

function VideoMusic(props) {
return (
<>
<div className='invisible'>
<video width="20" height="40" controls autoPlay="autoplay" loop>
<source src={Video} type="video/mp4" />
</video>
</div>
</>
)
}
export default VideoMusic
87 changes: 87 additions & 0 deletions src/plays/2048/Game2048Styles/Modal.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
.twenty-forty-eight-active-modal {
overflow-y: hidden;
}

.twenty-forty-eight-btn-modal {
padding: 10px 20px;
font-size: 18px;
color: black;
font-size: 47px;
position: absolute;
top: 7rem;
}

.twenty-forty-eight-modal,
.twenty-forty-eight-overlay {
width: 100vw;
height: 100vh;
top: 0;
left: 0;
right: 0;
bottom: 0;
position: fixed;
}

.twenty-forty-eight-modal {
z-index: 1;
}

.twenty-forty-eight-overlay {
background: rgba(49, 49, 49, 0.8);
}

.hide {
visibility: hidden;
}

.twenty-forty-eight-modal-content {
position: absolute;
top: 40%;
left: 50%;
transform: translate(-50%, -50%);
line-height: 1.4;
background: #f1f1f1;
padding: 14px 28px;
border-radius: 3px;
max-width: 600px;
min-width: 300px;
text-align: center;
}

.twenty-forty-eight-close-modal {
position: absolute;
top: 10px;
right: 10px;
padding: 5px 7px;
}

@media(max-width: 593px) {
.twenty-forty-eight-btn-modal {
top: 6rem;
font-size: 23px;
}
}

@media(max-width: 494px) {
.twenty-forty-eight-btn-modal {
top: 16rem;
font-size: 23px;
left: -8px;
}
}

@media(max-width:424px) {
.twenty-forty-eight-btn-modal {
top: 27.1rem;
font-size: 23px;
left: 245px;
}
}

@media(max-width: 354px) {
.twenty-forty-eight-btn-modal {
top: 17rem;
font-size: 19px;
left: 0rem;
}
}
Loading

0 comments on commit 73192eb

Please sign in to comment.