1
\$\begingroup\$

I'm learning web development with JavaScript, HTML, and CSS and have just created my first application, a Pig Game. The app works well, however, I think my CSS is a bit over complicated and that the media query I wrote for responsiveness could be greatly improved.

Game rules:
Player 1 starts first. Each player take turns to roll a single dice as many times as they wish, adding all roll results to a running total. However if the player rolls a 1, they lose their gained score. Press the hold button to stop rolling the dice. First player to 100 points wins!

HTML:

<body>
<!-- Game Title  -->
<div class="container">
  <div class="game-title">
    <h1>PIG GAME</h1>
  </div>
  <div class="game-info-btns">
    <button type="button" class="new-game">🔁 NEW GAME</button>
    <button type="button" class="how-btn">?</button>
  </div>

  <!--  How to Play Modal -->
  <div class="how-to-play hidden">
    <p>
      Player 1 starts first. Each player take turns to roll a single dice as
      many times as they wish, adding all roll results to a running total.
      However if the player rolls a 1, they lose their gained score. Press
      the hold button to stop rolling the dice. First player to 100 points
      wins!
    </p>
    <button class="close-how">Ok</button>
  </div>
  <div class="how-overlay hidden"></div>
  <!-- Main Game Window -->
  <div class="game-window">
    <!-- Player 1 -->
    <div class="p1-overlay overlay-active"></div>
    <div class="player1">
      <h1 class="player1-message">PLAYER 1</h1>
      <div class="score-wrapper">
        <span class="p1-score">0</span>
      </div>
      <div class="current">
        <p>CURRENT</p>
        <p><span class="p1-current-hold">0</span></p>
      </div>
      <div class="game-btn">
        <button type="button" class="p1-roll">🎲 ROLL DICE</button>
        <button type="button" class="p1-hold">📥 HOLD</button>
      </div>
    </div>
    <div class="dice hidden">
      <img src="images/dice1.png" id="diceImg" alt="dice" />
    </div>
    <!-- Player 2 -->
    <div class="p2-overlay show-me"></div>
    <div class="player2">
      <h1 class="player2-message">PLAYER 2</h1>
      <div class="score-wrapper">
        <span class="p2-score">0</span>
      </div>
      <div class="current">
        <p>CURRENT</p>
        <p><span class="p2-current-hold">0</span></p>
      </div>
      <div class="game-btn">
        <button type="button" class="p2-roll">🎲 ROLL DICE</button>
        <button type="button" class="p2-hold">📥 HOLD</button>
      </div>
    </div>
  </div>
</div>
<script src="script.js"></script>

CSS:

    html {
  height: 100vh;
  background: linear-gradient(to top left, #174e86, #97e4f4);
  background-attachment: fixed;
}
body {
  margin: 0;
}
/* Game Info */

.container {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: min-content min-content 1fr;
  align-content: center;
  justify-items: center;
}
.game-title {
  grid-column: 1 / 2;
  grid-row: 1 / 2;
  position: relative;
  text-align: center;
  margin: 0;
}
.game-title h1 {
  font-family: 'Montserrat', sans-serif;
  color: #eee;
  font-size: 2.5rem;
  text-align: center;
}
.game-info-btns {
  grid-column: 1/2;
  grid-row: 2/3;
  margin-left: 44rem;
  margin-bottom: 1.5rem;
  display: flex;
}
.how-btn {
  margin-left: 1rem;
  font-size: 1rem;
  font-weight: 700;
  border-color: #eee;
  background-color: rgba(191, 184, 191, 0.68);
  color: #eee;
  cursor: pointer;
}

.new-game {
  font-family: 'Montserrat', sans-serif;
  width: 8rem;
  padding: 0.5rem;
  border-radius: 1.5rem;
  border-color: #fff;
  box-shadow: 0 0 0.7rem rgba(0, 0, 0, 0.5);
  background: #eee;
  cursor: pointer;
}

/* How to Play Modal */
.how-to-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  height: 10rem;
  width: 28rem;
  background-color: #eee;
  padding: 2rem;
  box-shadow: 0 0 0.7rem rgba(0, 0, 0, 0.5);
  border-radius: 2rem;
  border-color: #d3d3d3;
  z-index: 4;
}

.how-to-play p {
  font-family: 'Montserrat', sans-serif;
  font-weight: 500;
  color: #000000;
}

.how-to-play button {
  font-family: 'Montserrat', sans-serif;
  color: #000000;
  float: right;
  background-color: rgba(236, 232, 236, 0.68);
  cursor: pointer;
}

.how-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(3px);
  z-index: 3;
}

/* Main Game */
.game-window {
  grid-row: 3 / 4;
  position: relative;
  align-self: auto;
  width: 55rem;
  border-radius: 0.5rem;
  background-color: #e8749a;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr;
  align-items: center;
  font-family: 'Montserrat', sans-serif;
  color: #eee;
  margin-bottom: 2rem;
}

.player1 {
  grid-column: 1 / 2;
  grid-row: 1 / 2;
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  align-items: center;
  margin: 3rem 0;
}

.score-wrapper {
  font-size: 3rem;
}
.p1-overlay {
  grid-column: 1 / 2;
  grid-row: 1 / 2;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  border-top-left-radius: 0.5rem;
  border-bottom-left-radius: 0.5rem;
  z-index: 1;
}
.player2 {
  grid-column: 2 / 3;
  grid-row: 1 / 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 3rem 0;
}

.p2-overlay {
  grid-column: 2 / 3;
  grid-row: 1 / 2;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  border-top-right-radius: 0.5rem;
  border-bottom-right-radius: 0.5rem;
  z-index: 1;
}
.current {
  background-color: #d12e64;
  text-align: center;
  font-size: 1.5rem;
  width: 15rem;
  border-radius: 2rem;
  margin-bottom: 2rem;
  margin-top: 2rem;
}
.current span {
  font-size: 2rem;
}

.game-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.game-btn button {
  font-family: 'Montserrat', sans-serif;
  padding: 0.5rem;
  width: 10rem;
  border-radius: 1rem;
  box-shadow: 0 0 0.7rem rgba(0, 0, 0, 0.5);
  border-color: rgba(224, 218, 218, 0.5);
  background-color: rgba(191, 184, 184, 0.5);
  color: #eee;
  cursor: pointer;
}

.p1-roll,
.p2-roll {
  margin-bottom: 1rem;
}

.dice {
  position: absolute;
  top: 25%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 5rem;
  height: 5rem;
  z-index: 2;
}

.dice img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Hidden Class for Reuse */
.hidden {
  display: none;
}

.overlay-active {
  visibility: hidden;
  opacity: 0;
  transition: all 0.4s ease-in;
}
.overlay-unactive {
  visibility: visible;
  opacity: 1;
}

/* Media Query */

@media (max-width: 971px) {
  .container {
    position: relative;
  }
  .game-info-btns {
    margin-left: 57%;
  }
  .new-game {
    width: fit-content;
    font-size: 0.8rem;
    padding: 0.4rem;
  }

  .game-window {
    display: grid;
    grid-template-columns: 1fr;
    grid-template-rows: 1fr 1fr;
    grid-gap: 2rem;
    width: 75%;
    margin: 3rem 2rem;
  }

  .player1 {
    grid-column: 1 / 1;
    grid-row: 1 / 2;
  }

  .p1-overlay {
    grid-column: 1 / 1;
    grid-row: 1 / 2;
    border-top-right-radius: 0.5rem;
    border-bottom-left-radius: 0rem;
  }

  .player2 {
    grid-column: 1 / 1;
    grid-row: 2 / 3;
  }

  .p2-overlay {
    grid-column: 1 / 1;
    grid-row: 2 / 3;
    border-top-right-radius: 0rem;
    border-bottom-left-radius: 0.5rem;
  }

  .dice {
    position: absolute;
    top: 51.5%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 4rem;
    height: 4rem;
    z-index: 2;
  }
}
@media (max-width: 770px) {
  .container {
    position: relative;
  }
  .game-info-btns {
    margin-left: 52%;
  }

  .dice {
    width: 3rem;
    height: 3rem;
  }
}

@media (max-width: 660px) {
  .game-title h1 {
    font-size: 2rem;
  }
  .game-window {
    margin: 0rem;
  }
  .game-info-btns {
    margin-left: auto;
    margin-right: 1rem;
  }
  .how-to-play {
    width: 70%;
  }
}

@media (max-width: 500px) {
  .game-title h1 {
    font-size: 1.5rem;
  }
  .game-window {
    margin: 0rem;
  }

  .player1 h1,
  .player2 h1 {
    font-size: 1.5rem;
  }

  .player1 span,
  .player2 span {
    font-size: 1.5rem;
  }
  .game-btn button {
    font-size: 0.8rem;
    width: 8rem;
  }
  .current {
    width: 10rem;
    font-size: 0.8rem;
  }
  .current span {
    font-size: 1rem;
  }

  .game-info-btns {
    margin-bottom: 1rem;
  }

  .new-game {
    font-size: 0.5rem;
  }

  .how-btn {
    height: 100%;
    align-self: end;
    font-size: 0.8rem;
  }

  .how-to-play {
    height: fit-content;
  }
}

Javascript:

  'use strict';

// Set DOM elements

// How to Play elements
const howBtn = document.querySelector('.how-btn');
const howWindow = document.querySelector('.how-to-play');
const howOverlay = document.querySelector('.how-overlay');
const closeHowBtn = document.querySelector('.close-how');
const newGameBtn = document.querySelector('.new-game');

// Gameplay Elements

//Player One Elements
const playerOneMessage = document.querySelector('.player1-message');
const playerOneOverlay = document.querySelector('.p1-overlay');
const playerOneScore = document.querySelector('.p1-score');
const playerOneCurrent = document.querySelector('.p1-current-hold');
const playerOneRoll = document.querySelector('.p1-roll');
const playerOneHold = document.querySelector('.p1-hold');

// Player Two Elements
const playerTwoMessage = document.querySelector('.player2-message');
const playerTwoOverlay = document.querySelector('.p2-overlay');
const playerTwoScore = document.querySelector('.p2-score');
const playerTwoCurrent = document.querySelector('.p2-current-hold');
const playerTwoRoll = document.querySelector('.p2-roll');
const playerTwoHold = document.querySelector('.p2-hold');

// Dice Elements
const diceBox = document.querySelector('.dice');
const dice = document.getElementById('diceImg');
const diceArr = [
  'images/dice1.png',
  'images/dice2.png',
  'images/dice3.png',
  'images/dice4.png',
  'images/dice5.png',
  'images/dice6.png',
];

// State Variables
let diceRoll = 0;
let score;
let current = 0;

// How to Play Modal
howBtn.addEventListener('click', function () {
  removeHidden(howWindow);
  removeHidden(howOverlay);
});

howOverlay.addEventListener('click', function () {
  addHidden(howOverlay);
  addHidden(howWindow);
});

closeHowBtn.addEventListener('click', function () {
  addHidden(howOverlay);
  addHidden(howWindow);
});

// Gameplay Logic

// Player 1 Rolls
playerOneRoll.addEventListener('click', function () {
  removeHidden(diceBox);
  diceRoll = Math.trunc(Math.random() * 6) + 1;
  changeDiceImg(`images/dice${diceRoll}.png`);
  current += diceRoll;
  playerOneCurrent.textContent = current;
  if (diceRoll === 1) playerTwoTurn();
});

playerOneHold.addEventListener('click', function () {
  score = Number(playerOneScore.textContent) + current;
  playerOneScore.textContent = score;
  console.log(score);
  if (score >= 100) {
    playerOneMessage.textContent = 'PLAYER 1 WINS! 🥇';
    gameEnd();
  } else playerTwoTurn();
});

// Player 2 Rolls
playerTwoRoll.addEventListener('click', function () {
  diceRoll = Math.trunc(Math.random() * 6) + 1;
  changeDiceImg(`images/dice${diceRoll}.png`);
  current += diceRoll;
  playerTwoCurrent.textContent = current;
  if (diceRoll === 1) playerOneTurn();
});

playerTwoHold.addEventListener('click', function () {
  score = Number(playerTwoScore.textContent) + current;
  playerTwoScore.textContent = score;
  if (score >= 100) {
    playerTwoMessage.textContent = 'PLAYER 2 WINS! 🥇';
    gameEnd();
  } else playerOneTurn();
});

// Reset values for New Game
newGameBtn.addEventListener('click', function () {
  playerOneCurrent.textContent = 0;
  playerOneScore.textContent = 0;
  playerTwoCurrent.textContent = 0;
  playerTwoScore.textContent = 0;

  playerOneRoll.disabled = false;
  playerOneHold.disabled = false;
  playerTwoRoll.disabled = false;
  playerTwoHold.disabled = false;

  playerOneMessage.textContent = 'PLAYER 1';
  playerTwoMessage.textContent = 'PLAYER 2';

  addHidden(diceBox);
  playerOneTurn();
});

// Reusable functions
function addHidden(element) {
  element.classList.add('hidden');
}

function removeHidden(element) {
  element.classList.remove('hidden');
}

function changeDiceImg(source) {
  dice.src = source;
}

function playerOneTurn() {
  playerOneOverlay.classList.add('overlay-active');
  playerOneOverlay.classList.remove('overlay-unactive');

  playerTwoOverlay.classList.remove('overlay-active');
  playerTwoOverlay.classList.add('overlay-unactive');
  current = 0;
  playerTwoCurrent.textContent = current;
}

function playerTwoTurn() {
  playerTwoOverlay.classList.add('overlay-active');
  playerTwoOverlay.classList.remove('overlay-unactive');

  playerOneOverlay.classList.remove('overlay-active');
  playerOneOverlay.classList.add('overlay-unactive');
  current = 0;
  playerOneCurrent.textContent = current;
}

function gameEnd() {
  current = 0;
  addHidden(diceBox);
  playerOneRoll.disabled = true;
  playerOneHold.disabled = true;
  playerOneCurrent.textContent = current;

  playerTwoRoll.disabled = true;
  playerTwoHold.disabled = true;
  playerTwoCurrent.textContent = current;
}

If anyone could review the overall quality of the code in all three files, that'd be greatly appreciated.

\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

In your JavaScript code you might want to try storing your variables in an object, like so:

const howBtn = document.querySelector('.how-btn');
const howWindow = document.querySelector('.how-to-play');
const howOverlay = document.querySelector('.how-overlay');
const closeHowBtn = document.querySelector('.close-how');
const newGameBtn = document.querySelector('.new-game');
``` ==
``` const howToElements = {
howBtn:document.querySelector('.how-btn'),
howWindow:document.querySelector('.how-to-play'), 
howOverlay:document.querySelector('.how-overlay'), 
closeHowBtn:document.querySelector('.close-how'),
newGameBtn = document.querySelector('.new-game')
};

You can then access these variables using howToElements.howBtn and similar methods.

This alone should greatly improve the readability of your code.

In your CSS code you have some repeating rules in your CSS; instead try to combine repeating rules into one.

I hope this helps.

\$\endgroup\$
2
  • \$\begingroup\$ The link to the article explaining the Comma Role in CSS is very helpful, nice! \$\endgroup\$
    – MadHatter
    Mar 17, 2022 at 6:10
  • 1
    \$\begingroup\$ Storing the variables is a great idea. The link was also very helpful, thank you! \$\endgroup\$
    – schan
    Mar 17, 2022 at 15:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.