HTML
<!-- STARTING SCREEN -->
<header class="main-header">
<div class="container">
<h1>
<span>Rock,</span>
<span>Paper,</span>
<span>Scissors</span>
</h1>
<p class="intro">An Epic battle of Human Vs. Computer</p>
</div>
<div class="starter-screens">
<!-- START -->
<div class="starter-screen start">
<div class="medium-container">
<button class="start button">Start</button>
</div>
</div>
<!-- HOW MANY ROUNDS -->
<div class="starter-screen choose-rounds">
<div class="medium-container">
<h2>How many rounds would you like to play?</h2>
<ul>
<li class="button" data-rounds="3" role="button"><span>3</span></li>
<li class="button" data-rounds="5" role="button"><span>5</span></li>
<li class="button" data-rounds="9" role="button"><span>9</span></li>
<li class="button" data-rounds="15" role="button"><span>15</span></li>
</ul>
</div>
</div>
<div class="starter-screen choose-character">
<div class="medium-container">
<h2>Choose your character</h2>
<ul>
<li role="button" class="character1" data-character="character1"><span>Fluff fluff</span></li>
<li role="button" class="character2" data-character="character2"><span>Squidgy</span></li>
<li role="button" class="character3" data-character="character3"><span>Timmy</span></li>
</ul>
</div>
</div>
<!-- CHARACTERS -->
<div class="starter-screen choose-rival">
<div class="medium-container">
<h2>Choose your rival:</h2>
<ul>
<li role="button" class="robot1" data-character="robot1"><span>Eugene</span></li>
<li role="button" class="robot2" data-character="robot2"><span>Ada</span></li>
<li role="button" class="robot3" data-character="robot3"><span>Turing</span></li>
</ul>
</div>
</div>
</div>
</header>
<main>
<div class="container container-collapse">
<div class="play-area">
<!-- PLAYER & COMPUTER ICON -->
<div class="players">
<div class="player-info">
<div class="player-character"></div>
<p>Score: <span class="player-score">0</span></p>
</div>
<span>Vs.</span>
<div class="player-info">
<div class="computer-character"></div>
<p>Score: <span class="computer-score">0</span></p>
</div>
</div>
<!-- ROUND -->
<div class="round-wrap">
<p>Round: <span class="round">1</span>/<span class="best-of"></span></p>
</div>
<!-- PLAY ARENA -->
<div class="arena">
<div class="player-chip">
<h3>Your choice</h3>
<span class="player-choice"></span>
<div class="player-choice-icon"></div>
</div>
<div class="computer-chip">
<h3>Computer choice</h3>
<span class="computer-choice"></span>
<div class="computer-choice-icon"></div>
</div>
<!-- CHOOSE WEAPON -->
<div class="weapon">
<div class="weapon-inner">
<h3>Choose your weapon</h3>
<ul>
<li class="rock" role="button" data-weapon="rock"><span>Rock</span></li>
<li class="paper" role="button" data-weapon="paper"><span>Paper</span></li>
<li class="scissors" role="button" data-weapon="scissors"><span>Scissors</span></li>
</ul>
</div>
</div>
<!-- ROUND RESULTS -->
<div class="result">
<div class="result-inner">
<h3 class="winner"></h3>
<button class="play-again button">Play again</button>
</div>
</div>
</div>
</div>
</div>
</main>
<!-- END SCREEN -->
<section class="end-screen">
<div class="medium-container">
<div class="end-result"></div>
<div class="rounds-end-screen">
<h3>Would you like a rematch? How many rounds do you want to play?</h3>
<ul>
<li class="button rounds-3" data-rounds="3" role="button"><span>3</span></li>
<li class="button rounds-5" data-rounds="5" role="button"><span>5</span></li>
<li class="button rounds-9" data-rounds="9" role="button"><span>9</span></li>
<li class="button rounds-15" data-rounds="15" role="button"><span>15</span></li>
</ul>
</div>
<button class="reset button">Rematch</button>
</div>
</section>
SCSS
/*==========================================
VARIABLES
==========================================*/
/* WIDTHS */
$max-width: 1400px;
$med-width: 900px;
/* BREAKPOINTS */
$screenS: 600px;
$screenM: 800px;
$screenL: 1200px;
$ml: 1000px;
$border-radius-width: 900px;
/* FONTS */
$rock: 'Luckiest Guy', cursive;
$paper: 'Open Sans Condensed', sans-serif;
$scissors: 'Mr Dafoe', cursive;
$body-font: $paper;
/* COLOURS */
$dark-grey: #333;
$white: #f9f9f9;
$duck-blue: #78d1dc;
$purple: #eee1fe;
$yellow: #f9edc5;
$pink: #ffcbe2;
$green: #ade9dd;
/* COLOR ASSIGNMENTS */
$body-bg: $duck-blue;
$header-bg: $dark-grey;
$border: $duck-blue;
$border-dark: $dark-grey;
$arena-bg: $dark-grey;
$button: $dark-grey;
$footer: $dark-grey;
/* TIMINGS */
$cubic: cubic-bezier(0.46,-0.41,0.3,1.52);
$transition: 0.4s ease-out all;
$cubic-transition: 1s $cubic all;
/*==========================================
BREAKPOINTS
==========================================*/
@mixin bp($point){
// "less than XS" mobile only (saves having to zero out properties on larger breakpoints)
@if $point == lt-xs {
@media only screen and (max-width: $screenXS) {
@content;
}
}
@else if $point == lt-s {
@media only screen and (max-width: $screenS) {
@content;
}
}
@else if $point == lt-m {
@media only screen and (max-width: $screenM) {
@content;
}
}
@else if $point == lt-l {
@media only screen and (max-width: $screenL) {
@content;
}
}
// Extra small devices (smart-phones from 480px)
@else if $point == xs {
@media only screen and (min-width: $screenXS) {
@content;
}
}
// Small devices (tablets, 768px and up)
@else if $point == s {
@media only screen and (min-width: $screenS) {
@content;
}
}
@else if $point == s-m {
@media only screen and (min-width: $screenS) and (max-width: $screenM) {
@content;
}
}
@else if $point == m {
// Medium devices (desktops, 992px and up)
@media only screen and (min-width: $screenM) {
@content;
}
}
@else if $point == m-l {
// Medium to Large only
@media only screen and (min-width: $screenM) and (max-width: $screenL) {
@content;
}
}
@else if $point == l {
// Large devices (large desktops, 1200px and up)
@media only screen and (min-width: $screenL) {
@content;
}
}
@else if $point == xl {
// Large devices (large desktops, 1350px and up)
@media only screen and (min-width: $screenXL) {
@content;
}
}
@else if $point == landscape {
@media only screen and (orientation:landscape) {
@content;
}
}
@else if $point == portrait {
@media only screen and (orientation:portrait) {
@content;
}
}
@else {
@media only screen and (min-width: $point) {
@content;
}
}
}
@mixin hide-text(){
font-size:0;
color: transparent;
text-shadow: none;
background-color: transparent;
border: 0;
}
/*==========================================
ANIMATIONS
==========================================*/
@keyframes fade-in-left {
0% {
transform: translateX(-100%);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
@keyframes fade-in-down {
0% {
transform: translateY(-100%);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
@keyframes fade-out-right {
0% {
opacity: 1;
}
100% {
opacity: 0;
transform: translateX(100%);
}
}
@keyframes fade-out-left {
0% {
opacity: 1;
}
100% {
opacity: 0;
transform: translateX(-100%);
}
}
@keyframes headersize {
0% {
height: 100vh;
}
100% {
height: 3rem;
}
}
@keyframes scale-text {
100% {
font-size: 2rem;
}
}
@keyframes bg {
0% {
background-position: bottom -20rem center;
}
100% {
background-position: bottom -0.5rem center;
}
}
/*==========================================
LAYOUT
==========================================*/
.container {
padding: 0 2rem;
max-width: $med-width;
margin: 0 auto;
width: 100%;
&.container-collapse {
padding: 0;
@include bp(m) {
padding: 0.2rem;
}
}
}
.medium-container {
@extend .container;
max-width: $med-width;
}
/*==========================================
GENERAL
==========================================*/
.character {
display: inline-block;
margin: 0.5rem;
border-radius: 100%;
background-color: white;
border: 5px solid $border;
background-repeat: no-repeat;
}
.button {
padding: 10px 20px;
border: none;
padding: 10px 40px;
border: none;
background-color: $button;
color: $white;
font-size: 2rem;
cursor: pointer;
position: relative;
z-index: 1;
transition: $transition;
overflow: hidden;
border-radius: 5px;
&.active {
background-color: $duck-blue;
color: $dark-grey;
@include bp(m) {
&:hover {
color: $dark-grey;
&:before,
&:after {
background-color: $duck-blue;
}
}
}
}
&:before,
&:after {
content: "";
position: absolute;
z-index: -1;
width: 51%;
height: 100%;
top: 0;
background-color: $white;
transition: $transition;
}
&:before {
left: -100%;
}
&:after {
right: -100%;
}
@include bp(m) {
&:hover {
color: $dark-grey;
transition: $transition;
&:before,
&:after {
transition: $transition;
}
&:before {
left: 0;
}
&:after {
right: 0;
}
}
}
}
/*==========================================
BACKGROUNDS
==========================================*/
.tie {
background-color: $yellow;
}
.win {
background-color: $green;
}
.lose {
background-color: $pink;
}
.rock {
background-image: url('http://hannahch.com/images/rock.svg');
}
.paper {
background-image: url('http://hannahch.com/images/paper.svg');
}
.scissors {
background-image: url('http://hannahch.com/images/scissors.svg');
}
.character1 {
background-image: url('http://hannahch.com/images/character1.svg');
}
.character2 {
background-image: url('http://hannahch.com/images/character2.svg');
}
.character3 {
background-image: url('http://hannahch.com/images/character3.svg');
}
.robot1 {
background-image: url('http://hannahch.com/images/robot1.svg');
}
.robot2 {
background-image: url('http://hannahch.com/images/robot2.svg');
}
.robot3 {
background-image: url('http://hannahch.com/images/robot3.svg');
}
/*==========================================
GENERAL
==========================================*/
html {
font-size: 62.5%;
min-width: 300px;
}
body {
background-color: $body-bg;
color: white;
font-family: $body-font;
font-size: 2rem;
overflow: hidden;
&.game-started {
overflow-x: hidden;
overflow-y: auto;
}
}
main {
padding-top: 7rem;
padding-bottom: 1rem;
}
h2 {
font-size: 2.5rem;
margin-bottom: 4rem;
}
h3 {
margin-bottom: 3rem;
}
/*==========================================
HEADER
==========================================*/
.main-header {
z-index: 10;
padding: 10px 0;
position: fixed;
width: 100vw;
height: 100vh;
background-color: $header-bg;
display: flex;
flex-wrap: wrap;
align-items: center;
border-bottom: 1px solid white;
h1 {
padding: 30px 0;
span {
display: inline-block;
margin-right: 10px;
font-size: 3rem;
animation: fade-in-left 0.5s $cubic both 0.5s;
.game-started & {
animation: scale-text 1s $cubic both 0.2s;
}
@include bp(s) {
font-size: 6rem;
}
&:first-child {
font-family: $rock;
}
&:nth-child(2) {
animation-delay: 0.7s;
font-family: $paper;
.game-started & {
animation-delay: 0.2s;
}
}
&:last-child {
animation-delay: 0.9s;
font-family: $scissors;
.game-started & {
animation-delay: 0.2s;
}
}
}
}
.game-started & {
animation: headersize 0.5s ease-out both 0.5s;
h1 {
padding: 0;
}
}
}
.intro {
animation: fade-in-left 0.2s ease-out both 1.3s;
margin-bottom: 3rem;
.game-started & {
animation: fade-out-right 0.5s both 1;
}
}
/*==========================================
STARTER SCREENS
==========================================*/
.starter-screens {
height: 430px;
position: relative;
width: 100%;
.button {
background-color: $purple;
color: $dark-grey;
margin-bottom: 10px;
}
.game-started & {
animation: fade-out-right 0.5s both 0.2s;
}
}
.starter-screen {
width: 100%;
text-align: center;
transform: translateX(-150%);
transition: $transition;
&.animate-in {
animation: fade-in-left 1s $cubic both;
}
ul {
@include bp(m) {
display: flex;
justify-content: space-between;
}
}
li {
font-family: $scissors;
font-size: 3rem;
@include bp(m) {
font-size: 5rem;
}
}
}
.start {
animation: fade-in-left 1s $cubic both 1.4s;
text-align: left;
}
.choose-character,
.choose-rival {
li {
@extend .character;
cursor: pointer;
transition: $transition;
width: 10rem;
height: 10rem;
@include bp(m) {
width: 15rem;
height: 15rem;
&:hover {
border-color: $white;
background-color: $duck-blue;
transition: $transition;
}
}
}
span {
@include hide-text();
}
}
.player-character,
.computer-character {
@extend .character;
width: 7rem;
height: 7rem;
border-color: $border-dark;
@include bp(m) {
width: 10rem;
height: 10rem;
}
}
.player-character,
.computer-character,
.choose-character li,
.choose-rival li,
.player-character li,
.computer-character li {
background-position: center;
background-size: 70%;
}
/*==========================================
ARENA/PLAY
==========================================*/
.arena {
width: 100%;
height: 36rem;
background-color: $arena-bg;
overflow: hidden;
position: relative;
h3 {
text-align: center;
width: 100%;
}
@include bp($border-radius-width) {
border-radius: 0 0 1rem 1rem;
}
}
.weapon,
.result {
z-index: 3;
width: 100%;
height: 100%;
position: absolute;
left: 0;
display: flex;
flex-wrap: wrap;
align-items: center;
text-align: center;
color: $dark-grey;
justify-content: center;
transition: $cubic-transition;
}
.result {
top: -100%;
.weapon-chosen & {
top: 0;
transition: 1s $cubic all 3s;
}
h3 {
font-size: 3rem;
}
}
.weapon {
bottom: 0;
background-color: $purple;
transition-delay: 0.2s;
.weapon-inner {
width: 100%;
}
.weapon-chosen & {
bottom: -100%;
}
h3 {
font-size: 2.5rem;
margin-bottom: 4rem;
}
ul {
width: 100%;
display: flex;
justify-content: space-between;
}
li {
@extend .character;
width: 24vw;
height: 24vw;
max-width: 200px;
max-height: 200px;
cursor: pointer;
transition: $transition;
margin: 1rem;
background-size: 70%;
.game-started & {
animation: bg 0.3s ease-out both 1s;
&:nth-child(2) {
animation-delay: 1.2s
}
&:nth-child(3) {
animation-delay: 1.4s
}
}
@include bp(m) {
margin: 0 4rem;
&:hover {
background-color: $duck-blue;
border-color: $white;
transition: $transition;
}
}
}
span {
@include hide-text();
}
}
.computer-chip,
.player-chip {
position: absolute;
width: 100%;
text-align: center;
h3 {
margin-bottom: 2rem;
@include bp(m) {
font-size: 2.5rem;
}
}
span {
@include hide-text();
}
@include bp(m) {
width: 50%;
transform: translateY(-50%);
}
}
.computer-chip {
right: -100%;
transition: $cubic-transition;
bottom: 2rem;
@include bp(m) {
top: 50%;
bottom: auto;
}
.weapon-chosen & {
right: 0;
transition: 0.8s $cubic all 1.5s;
}
}
.player-chip {
left: -100%;
transition: $cubic-transition;
top: 2rem;
@include bp(m) {
top: 50%;
}
.weapon-chosen & {
left: 0;
transition: 0.8s $cubic all 0.6s;
}
}
.computer-choice-icon,
.player-choice-icon {
@extend .character;
width: 10rem;
height: 10rem;
display: inline-block;
background-position: bottom -0.5rem center;
background-size: 60%;
@include bp(l) {
width: 20rem;
height: 20rem;
}
}
/*==========================================
PLAYERS
==========================================*/
.players {
margin-bottom: 3rem;
display: flex;
justify-content: space-between;
align-items: center;
color: $dark-grey;
span {
font-size: 2rem;
color: $dark-grey;
}
}
.player-info {
text-align: center;
padding: 0 20px;
}
.round-wrap {
padding: 20px;
border-bottom: 1px solid $white;
background-color: $dark-grey;
@include bp($border-radius-width) {
border-radius: 1rem 1rem 0 0;
}
}
/*==========================================
END SCREEN
==========================================*/
.end-screen {
position: fixed;
right: -100%;
top: 0;
width: 100%;
height: 100%;
transition: $cubic-transition;
display: flex;
align-items: center;
z-index: 20;
text-align: center;
color: $dark-grey;
h2 {
margin-bottom: 1rem;
font-size: 5rem;
}
h3 {
margin-bottom: 2.5rem;
}
p {
margin-bottom: 3rem;
font-size: 2rem;
}
.end-game & {
right: 0;
transition: 1s $cubic all 5s;
}
}
.rounds-end-screen {
margin-bottom: 5rem;
ul {
@include bp(m) {
display: flex;
justify-content: space-around;
}
}
li {
margin-bottom: 1rem;
}
}
JAVASCRIPT
var gameModule = (function () {
$(function() {
// General variables
var playerChoice,
computerChoice,
winner,
round = 1,
playerScore = 0,
computerScore = 0,
bestOf,
overallResultClass,
overallResultText,
character,
choices = ['rock', 'paper', "scissors"];
// Text Variables
var playerWinsText = "You win the round!",
computerWinsText = "Computer wins the round!",
tieText = "It's a Tie!",
overallPlayerWinText = "<h2>Well Done!</h2> <p>You won against the computer.</p>",
overallComputerWinText = "<h2>You Lose...</h2> <p>The computer has defeated you</p>",
overallTieText = "<h2>It's a draw!</h2> <p>Good effort.</p>";
// Set Characters
function setCharacter(div, className) {
character = $(div).data('character');
$(className).addClass(character);
}
function nextScreen(div) {
div.parents('.starter-screen').hide().next().addClass('animate-in');
}
// Decides on whether the computer is playing rock, paper or scissors
function computerDecision() {
var randomChoice = Math.floor(Math.random() * choices.length);
return choices[randomChoice];
}
// Plays the game
function playGame(playerChoice) {
computerChoice = computerDecision();
round++;
// Set Choices
$('.player-choice-icon').attr('class', 'player-choice-icon ' + playerChoice);
$('.computer-choice-icon').attr('class', 'computer-choice-icon ' + computerChoice);
winner = decideWinner(playerChoice, computerChoice);
// Set the values on the screen
setValues(playerChoice, computerChoice, winner);
}
// Sets all the values on the board
function setValues(playerChoice, computerChoice, winnerText) {
$('.player-choice').text(playerChoice); // If the player has chosen rock, paper or scissors
$('.computer-choice').text(computerChoice); // If the computer has chosen rock, paper or scissors
$('.winner').text(winnerText); // Who won the round
// If the game has been reset set the score immediately
if(round !== 1) {
// Set the values once the animation has finished
setTimeout(function(){
setScore();
}, 4000);
} else {
// Set the values immediately
setScore();
$('.round').text(round);
}
}
// Set the scores
function setScore() {
$('.player-score').text(playerScore); // The running score for the player
$('.computer-score').text(computerScore); // The running score for the computer
}
// Decide who wins based on the player & computer choice
function decideWinner(playerChoice, computerChoice) {
var resultClass;
// Who wins, What text is shown & What class is applied to the result screen
if (playerChoice === computerChoice) {
// If there is a tie
winner = tieText;
resultClass = "tie";
} else if (playerChoice === "rock") {
// If the player chooses "Rock"
switch (computerChoice) {
case "scissors":
winner = playerWinsText;
playerScore++;
resultClass = "win";
break;
case "paper":
winner = computerWinsText;
computerScore++;
resultClass = "lose";
break;
}
} else if (playerChoice === "paper") {
// If the player chooses "Paper"
switch (computerChoice) {
case "rock":
winner = playerWinsText;
playerScore++;
resultClass = "win";
break;
case "scissors":
winner = computerWinsText;
computerScore++;
resultClass = "lose";
break;
}
} else {
// If the player chooses "Scissors"
switch (computerChoice) {
case "rock":
winner = computerWinsText;
computerScore++;
resultClass = "lose";
break;
case "paper":
winner = playerWinsText;
playerScore++;
resultClass = "win";
break;
}
}
// Set the class of the result screen
$('.result').attr('class', 'result ' + resultClass);
return winner;
}
// Set all variables to their base values
function resetGame () {
playerChoice = "";
computerChoice = "";
winner = "";
round = 1;
playerScore = 0;
computerScore = 0;
setValues();
$('body').removeClass('end-game weapon-chosen');
$('.play-again').show();
}
// Decide on who is the winner of the whole game
function overallWinner() {
if (playerScore > computerScore) {
// Player wins
overallResultText = overallPlayerWinText;
overallResultClass = "win";
} else if (playerScore < computerScore) {
// Computer wins
overallResultText = overallComputerWinText;
overallResultClass = "lose";
} else {
// Tie
overallResultText = overallTieText;
overallResultClass = "tie";
}
$('.end-result').html(overallResultText);
$('.end-screen').attr('class', 'end-screen ' + overallResultClass);
}
// Show the end screen and final result
function endGame() {
$('body').addClass('end-game');
$('.play-again').hide();
overallWinner();
}
// Set the total number of rounds
function setBestOf(selectedRounds) {
var endScreenRounds;
bestOf = selectedRounds.data('rounds');
$('.best-of').text(bestOf);
// Set the active class on the number of rounds on the end screen
endScreenRounds = ".rounds-" + bestOf;
$(endScreenRounds).addClass('active').siblings().removeClass('active');
}
// Start
$('.start').on('click', function(e) {
e.preventDefault();
nextScreen($(this));
});
// Set what character is chosen and start the game
$('.choose-rounds li').on('click', function(e) {
e.preventDefault();
setBestOf($(this));
nextScreen($(this));
});
// Set what character is chosen and start the game
$('.choose-character li').on('click', function(e) {
e.preventDefault();
setCharacter($(this), '.player-character');
nextScreen($(this));
});
// Set what character is chosen and start the game
$('.choose-rival li').on('click', function(e) {
e.preventDefault();
setCharacter($(this), '.computer-character');
$('body').addClass('game-started');
});
// Play the game
$('.weapon li').on('click', function(e) {
e.preventDefault();
playerChoice = $(this).data('weapon');
$('body').addClass('weapon-chosen');
playGame(playerChoice);
if (round > bestOf) {
endGame();
}
});
// Play the next round
$('.play-again').on('click', function(e) {
e.preventDefault();
$('body').removeClass('weapon-chosen');
$('.round').text(round); // How many rounds there have been
});
// Reset the game from the beginning
$('.reset').on('click', function(e) {
e.preventDefault();
resetGame();
});
// Reset the game from the beginning
$('.rounds-end-screen li').on('click', function(e) {
e.preventDefault();
setBestOf($(this));
});
});
}());