Game | Memory

by Kofod

HTML

<div class="memoryContainer">

	<!-- START/GAME OVER/VICTORY SCREENS -->
	<!-- All these screens have a title and a subtitle. You want to keep your sentences on one line or the animation will be a little weird. You can prevent this by adding a <br> when you need something on the next line. Also, all the text will automatically center vertically, so you don't have to worry about that.. -->
	
	<!-- Start Screen -->
	<div class="overlay-text visible">
		start
		<span class="overlay-text-small">
			Can you find all the card sets?<br><br>
			
			Click to start.
		</span>
	</div>
	
	<!-- Game Over Screen -->
	<div id="game-over-text" class="overlay-text">
		game over
		<span class="overlay-text-small">
			You didn't get it this time<br><br>

			Click to start over.
		</span>
	</div>
	
	<!-- Victory Screen -->
	<div id="victory-text" class="overlay-text">
		Victory
		<span class="overlay-text-small">
			F: Styl1shXmasC0at <br><br>M: pantsmakegoodgifts<br><br>

			Click to start over.
		</span>
	</div>
	
	<!-- GAME CONTAINER -->
	<div class="gameContainer">
		<div class="game-info-container">
			<div class="game-info">
				Time <span id="time-remaining"></span>
			</div>
			<div class="game-info">
				Flips <span id="flips">0</span>
			</div>
		</div>

		<!-- CARDS -->
		<!-- Here is where all your memory cards are. You can copy the 'Card Pair' section and paste that as many times as you want. By default 8 card pairs (16 cards total) will fit into the layout, but in the CSS you can change things so more or less cards will fit. It's up to you! -->
		
		<!-- Card Pair -->
		<div class="card">
			<div class="card-back card-face">
				<!-- Back of all the cards, you can use any image you want. Keep in mind you want to pick/make an image with the size of your cards (which is specified in the CSS at '.card'. -->
				<img class="back-image" src="https://i.imgur.com/1s67aNU.png">
			</div>
			<div class="card-front card-face">
				<!-- The front of your card, you want the two...

CSS

* {
	box-sizing: border-box;
}

.memoryContainer {
	position: relative;
	overflow: hidden;
	/* Background for the layout */
	background: url(https://i.imgur.com/jot08mi.png);
	/* Width and height of the layout */
	width: 688px;
	height: 500px;
}

.game-info-container {
	grid-column: 1 / -1;
	display: flex;
	justify-content: space-between;
}

.game-info {
	/* Font, colour and size of the text of 'Time' and 'Flips' */
	font-family: 'Arial', sans-serif;
	color: #000;
	font-size: 30px;
}

.gameContainer {
	display: grid;
	/* The '4' is how many cards will be in the same row, you can change this number to anything you want. If you change the card size below, you might want to change this number as well. */
	grid-template-columns: repeat(4, auto);
	grid-gap: 10px;
	margin: 50px;
	justify-content: center;
	perspective: 500px;
}

.card {
	position: relative;
	/* Width and height of the memory cards */
	height: 80px;
	width: 125px;
}

.card:hover {
	cursor: pointer;
}

.card-face {
	position: absolute;
	width: 100%;
	height: 100%;
	display: flex;
	justify-content: center;
	align-items: center;
	overflow: hidden;
	border-radius: 12px;
	transition: transform 500ms ease-in-out;
	backface-visibility: hidden;
	-webkit-transform-style: preserve-3d;
}

.card-back {
	/* Background colour of the back of the cards */
	background: #93BEC4;
}

.card-back:hover {
	/* Background colour of the back of the cards on hover */
	background: #5B8D94;
}

.card-front {
	/* Background colour of the front of the cards */
	background-color: #C5E4E8;
	transform: rotateY(180deg);
	-webkit-backface-visibility: hidden;
	-webkit-transform-style: preserve-3d;
}

.card-front:hover {
	/* Currently nothing, but you can put CSS for front of the cards on hover here */
}

.card-value {
	transition: transform 100ms ease-in-out;
	transform: scale(1);
}

.card-front:hover .card-value {
	transform: scale(1.05);
}

.back-image {
	align-self: flex-start;
	opacity: 1;
	transition: transform 100ms...

JavaScript

// Change this to the time you want people to have for the memory game.
var countdownTime = '75';

// You don't have to change anything here.
class Memory {
	constructor(totalTime, cards) {
		this.cardsArray = cards;
		this.totalTime = totalTime;
		this.timeRemaining = totalTime;
		this.timer = document.getElementById('time-remaining')
		this.ticker = document.getElementById('flips');
	}

	startGame() {
		this.totalClicks = 0;
		this.timeRemaining = this.totalTime;
		this.cardToCheck = null;
		this.matchedCards = [];
		this.busy = true;
		setTimeout(() => {
			this.shuffleCards(this.cardsArray);
			this.countdown = this.startCountdown();
			this.busy = false;
		}, 500);
		this.hideCards();
		this.timer.innerText = this.timeRemaining;
		this.ticker.innerText = this.totalClicks;
	}
	startCountdown() {
		return setInterval(() => {
			this.timeRemaining--;
			this.timer.innerText = this.timeRemaining;
			if(this.timeRemaining === 0)
				this.gameOver();
		}, 1000);
	}
	gameOver() {
		clearInterval(this.countdown);
		document.getElementById('game-over-text').classList.add('visible');
	}
	victory() {
		clearInterval(this.countdown);
		document.getElementById('victory-text').classList.add('visible');
	}
	hideCards() {
		this.cardsArray.forEach(card => {
			card.classList.remove('visible');
			card.classList.remove('matched');
		});
	}
	flipCard(card) {
		if(this.canFlipCard(card)) {
			this.totalClicks++;
			this.ticker.innerText = this.totalClicks;
			card.classList.add('visible');
			if(this.cardToCheck) {
				this.checkForCardMatch(card);
			} else {
				this.cardToCheck = card;
			}
		}
	}
	checkForCardMatch(card) {
		if(this.getCardType(card) === this.getCardType(this.cardToCheck))
			this.cardMatch(card, this.cardToCheck);
		else 
			this.cardMismatch(card, this.cardToCheck);
			this.cardToCheck = null;
		}
		cardMatch(card1, card2)...