Skip to content

Commit

Permalink
Version 2.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
HassaniDev committed Oct 10, 2024
1 parent 7d4b86f commit db082b4
Show file tree
Hide file tree
Showing 8 changed files with 392 additions and 75 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ This project is structured using the MVC (Model-View-Controller) architecture, w

## 🎮 Demo

You can play the game live [here](#). _(This link isn't available yet)_
You can play the game live [here](https://dice-game-hassanidev.netlify.app/)

## 📂 Installation

Expand Down Expand Up @@ -63,6 +63,11 @@ If you prefer to play the game without sound, please feel free to mute your brow
- 🎮 Implement single-player mode.
- 📱 Improve mobile responsiveness.
- 🎵 Add background soft music to enhance focus, with an option for the player to disable or mute the music.
- 🌑 **Dark Theme**: Currently, the game only supports a light theme. A dark theme option will be implemented in future updates for better user customization.

## ⚠️ Important Note

This game uses fonts from Google Fonts, which require an active internet connection. Please ensure that your Wi-Fi or internet connection is turned on for the fonts to load correctly and for the best experience.

## 🏅 Credits

Expand Down
15 changes: 11 additions & 4 deletions src/CSS/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -228,21 +228,28 @@ main {
display: none;
}

/* When player--winner class is absent */
.winner {
display: none;
}

.player--winner .winner {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
display: block;
position: absolute;
bottom: 8.5rem;
font-size: 3.2rem;
font-family: inherit;
color: var(--white);
z-index: 10;
}

.player--winner .current-winner {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

.player--winner .icon {
font-size: 5rem;
}
Expand Down
4 changes: 2 additions & 2 deletions src/JS/config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'use strict';

// exporting a default constant
const WINNING_SCORE = 100;
// 🏆 Exporting the default constant for the winning score
const WINNING_SCORE = 100; // 🎯 First player to reach 100 wins!
export default WINNING_SCORE;
101 changes: 92 additions & 9 deletions src/JS/controller.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,110 @@
'use strict';

// IMPORTING EXTERNAL FILES
// 📂 IMPORTING EXTERNAL FILES
import modal from './modal.js';
import * as view from './view.js';
import { newGame, holdScore, rollDice } from './helper.js';
import {
btnSound,
switchPlayer,
clear,
winner,
restartGame,
} from './helper.js';
import WINNING_SCORE from './config.js';

// EVENTS
// 🎮 FUNCTIONALITY

// 1️⃣ New game
export const newGame = () => {
// 🔊 Play sound for new game
btnSound(view.newGameBtn, 0.3);

// 🔄 Reset and restart the game
restartGame();
};

// 2️⃣ Roll Dice
export const rollDice = () => {
if (modal.state.play) {
// 🎲 Play roll dice sound
btnSound(view.rollDiceBtn, 0.4);

// 🎲 Generate random dice value (1-6)
const dice = Math.floor(Math.random() * 6) + 1; // 1 - 6
view.diceEl.src = `./Images/dice-${dice}.png`;

// 🛑 If dice === 1, switch player
if (dice === 1) switchPlayer();
else {
// 🔢 Update current player score
modal.state.currentScore += dice;
modal.updateCurrentScore(modal.state.currentScore);

document.querySelector(
`#current--${modal.state.currentPlayer}`
).textContent = modal.state.currentScore;
}
}
};

// 3️⃣ Hold score
export const holdScore = () => {
if (modal.state.play) {
// 💼 Play hold score sound
btnSound(view.holdScoreBtn, 1);

// ➕ Update total score

// METHOD 1 ⛳ --> Easy way
// modal.state.totalScore[modal.state.currentPlayer] += Number(
// document.querySelector(`#current--${modal.state.currentPlayer}`).textContent
// );

// METHOD 2 ⛳
modal.state.totalScore[modal.state.currentPlayer] +=
modal.state.currentScore;
modal.updateTotalScore(
modal.state.currentPlayer, // 1️⃣
modal.state.totalScore[modal.state.currentPlayer] // Update player's total score
);

document.querySelector(`#score--${modal.state.currentPlayer}`).textContent =
modal.state.totalScore[modal.state.currentPlayer];

// 🧹 Clear current score
clear();

// 🏆 Check if the current player won
if (modal.state.totalScore[modal.state.currentPlayer] >= WINNING_SCORE) {
// 🎲 Hide the dice
view.diceEl.classList.add('hidden');

// 🏅 Player wins
winner();

// 🚫 End the game (disable buttons)
modal.updatePlayState(false); // play = false
} else {
// 🔄 Switch player
switchPlayer();
}
}
};

// 📅 EVENTS

// METHOD 1 ☝️
// Controller object
// 🎮 Controller object
const controller = {
// Initialize function that sets up event listeners
// 🛠️ Initialize function that sets up event listeners
init: function () {
view.btnRoll.addEventListener('click', rollDice);
view.btnHold.addEventListener('click', holdScore);
view.btnNew.addEventListener('click', newGame);
},
};

// Initialize the controller when the page loads
// 🌐 Initialize the controller when the page loads
document.addEventListener('DOMContentLoaded', () => {
controller.init();
});
Expand All @@ -31,7 +116,5 @@ document.addEventListener('DOMContentLoaded', () => {
// view.btnNew.addEventListener('click', newGame);
// };

// // Initialize the controller when the page loads
// // 🌐 Initialize the controller when the page loads
// document.addEventListener('DOMContentLoaded', init);

// console.log(modal.state.currentPlayer);
125 changes: 105 additions & 20 deletions src/JS/helper.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,117 @@
'use strict';

// Imports
// 📂 Imports
import modal from './modal.js';
import * as view from './view.js';

// HELPER FUNCTIONS
const btnSound = (btn, volume) => {
btn.volume = volume; // Set the volume (between 0.0 and 1.0) 0 is 0%, 1 is 100%
btn.play(); // Play the sound
// 🛠️ HELPER FUNCTIONS
export const btnSound = (btn, volume) => {
btn.volume = volume; // 🎚️ Set the volume (between 0.0 and 1.0) 0 is 0%, 1 is 100%
btn.play(); // ▶️ Play the sound
};

const switchPlayer = () => {};
const clear = () => {};
export const switchPlayer = () => {
// 1. 🧹 Clear and reset the current score
clear();

// Functionality
// 1. New game
export const newGame = () => {
// 1. Sound
btnSound(view.newGameBtn, 0.3);
// 2. 🔄 Update current player
modal.state.currentPlayer = modal.state.currentPlayer === 0 ? 1 : 0; // Switch between player 0 and 1
modal.updateCurrentPlayer(modal.state.currentPlayer);

// 3. ✨ Remove active class from all players
document.querySelectorAll('.player').forEach((Element) => {
Element.classList.remove('player--active'); // 🟢 Remove active state
});

// 4. 🚦 Add active class to the current player
document
.querySelector(`#current--${modal.state.currentPlayer}`)
.parentElement.parentElement.classList.toggle('player--active');
};

// 2. Roll Dice
export const rollDice = () => {
// 1. Sound
btnSound(view.rollDiceBtn, 0.4);
export const clear = () => {
// 🧽 Clear and reset the current score
modal.updateCurrentScore(0); // Reset score to 0
document.querySelector(
`#current--${modal.state.currentPlayer}`
).textContent = 0;
};

export const winner = function () {
// 1. 🎯 Remove active class
document.querySelectorAll('.player').forEach((Element) => {
Element.classList.remove('player--active'); // Remove active class
});

// 2. 🏆 Add winner class to the current player
document
.querySelector(`#current--${modal.state.currentPlayer}`)
.parentElement.parentElement.classList.toggle('player--winner');

// 3. ✨ Show sparkles for 11.8s
// METHOD 1 ☝️
// view.sparkles.style.display = 'block'; // Show the image immediately

// METHOD 2 ✌️
setTimeout(() => (view.sparkles.style.display = 'block'), 300); // Delay sparkles for 300ms

// 🕰️ Hide the sparkles after 7 seconds
setTimeout(function () {
view.sparkles.style.display = 'none';
}, 7000);

// 4. 🏅 Show winning points
document.querySelector(`.winner--${modal.state.currentPlayer}`).innerHTML =
''; // Clear container
document
.querySelector(`.winner--${modal.state.currentPlayer}`)
.insertAdjacentHTML(
'beforeend',
view.winPoints(modal.state.totalScore[modal.state.currentPlayer])
);

// 5. 🔊 Play winning sound
view.winnerSound.play();
view.winnerSound.volume = 0.1; // Set the volume to 10%
};

// 3. Hold score
export const holdScore = () => {
// 1. Sound
btnSound(view.holdScoreBtn, 1);
export const restartGame = function () {
// 1. 🟢 Set play state back to true
modal.updatePlayState(true);

// 2. 🎲 Display the dice again (reset to 5)
view.diceEl.src = `./Images/dice-${5}.png`;
view.diceEl.classList.remove('hidden');

// 3. 🎮 Set current player to player 0
modal.updateCurrentPlayer(0);

// 4. 🧼 Remove active & winner classes from all players
document.querySelectorAll('.player').forEach((Element) => {
Element.classList.remove('player--active'); // Remove active class
Element.classList.remove('player--winner'); // Remove winner class
});

// 5. 🏅 Add active class to player 0
document
.querySelector(`#current--${modal.state.currentPlayer}`)
.parentElement.parentElement.classList.add('player--active');

// 6. ✨ Hide sparkles
view.sparkles.style.display = 'none';

// 7. 🧹 Clear current score
clear();

// 8. 🔄 Reset total score for both players
modal.updateTotalScore(0, 0);
modal.updateTotalScore(1, 0);

// Update the displayed score
modal.state.totalScore.forEach((Element, i) => {
document.querySelector(`#score--${i}`).textContent =
modal.state.totalScore[Element];
});

// 9. ✨ Clear winner message
};
Loading

0 comments on commit db082b4

Please sign in to comment.