Magazine | March - Memory

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">
		April Fools' Memory
		<span class="overlay-text-small">
			So uhm... yeah have fun!<br><br>
			
			Click to start.
		</span>
	</div>
	
	<!-- Game Over Screen -->
	<div id="game-over-text" class="overlay-text">
		April Fools!
		<span class="overlay-text-small">
			Hehehehe. Okay maybe next time you'll solve it.<br><br>

			Click to start over.
		</span>
	</div>
	
	<!-- Victory Screen -->
	<div id="victory-text" class="overlayText">
		You made it!
		<span class="overlay-text-small">
			But...<br><br>
			
			Female (LE 125 claims): IsThisaRealFemCode<br>

			Male (LE 25 claims): AreuSureThisIsaMaleCode<br><br>

			Refresh the page 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"...

CSS

* {
	box-sizing: border-box;
}

.memoryContainer {
	position: relative;
	overflow: hidden;
	/* Background for the layout */
	background: url(https://i.imgur.com/Gtj4E9X.jpg);
	/* 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: #dff3c1;
	box-shadow: 3px 3px rgba(0, 0, 0, 0.2);
}

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

.card-front {
	/* Background colour of the front of the cards */
	background: #dff3c1;
	box-shadow: 3px 3px rgba(0, 0, 0, 0.2);
	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,
.cardValue {
	position: absolute;
	transition: transform 100ms ease-in-out;
	transform: scale(1);
}

.card-front:hover .card-value,
.card-front:hover...

JavaScript

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

// 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)...