Group D Team SSpim(Copy 1368)
✨ VISAL SUWANARAT
<div class="container"> <style> * { margin: 0; padding: 0; } *, *::before, *::after { box-sizing: inherit; } html { box-sizing: border-box; } body { font-family: "Open Sans", sans-serif; /*one Em roughly ten pixels (16 x 62.5% = 10)*/ font-size: 62.5%; letter-spacing: 1.5px; margin: 0; text-align: center; } .container { display: flex; justify-content: center; align-items: center; flex-direction: column; margin-top: 0.5em; } .win{ margin-top: -20px; } ul>li { list-style: none; } .card,.btn { border-radius: 1em; border: none; color: #fff; box-shadow: 5px 2px 20px 0 rgba(46, 61, 73, 0.5); padding: 0.8em; cursor: pointer; } /*---------------------------------- Header ------------------------------------*/ h1 { font-size: 3em; font-weight: 400; margin-top: 20px; } h2 { font-size: 2.5em; font-weight: 600; margin-top: 5px; } h3 { font-weight: 400; } /*---------------------------------- Section - Score Panel ------------------------------------*/ .score-panel { font-size: 1.4em; padding: 1em 0 2em; } .star-rating>li { display: inline-block; color: #ea1; padding: 0.6em; margin:-5px; } .moves-counter { padding: 0.5em; } .reset-btn { background: #bbb; border-radius: 10em; color: #f55; margin: 20px; padding: 1em; } .timer-container { background: #aaa; border-radius: 10em; font-size: 15px; color: #f55; margin: 0.5em; padding: 1em; margin-top: -50px; } .timer { font-size: .5em; } /*---------------------------------- Section - Modal ------------------------------------*/ /* Help with the modal from https://www.w3schools.com/howto/howto_css_modals.asp */ /* Modal (background) */ .modal { /*Hidden by default */ font-family: "Open Sans", sans-serif; display: none; position: fixed; z-index: 99; left: 0; top: 0; width: 100%; height: 100%; /* Fallback color */ background-color: rgb(46, 61, 73); /* With opacity */ background-color: rgba(46, 61, 73, 0.6); } /* Modal Content/Box */ .modal-content { display: flex; flex-direction: column; justify-content: center; align-items: center; background-color: #fff; /* 5% from the top and centered */ margin: 5% auto; border: 0.8em solid rgb(247,233,197); padding-right: 2em; width: 80%; boder-radius: 20%; } /* The Close Button */ .close { align-self: flex-end; color: rgb(145, 203, 202); font-size: 5em; } .close:hover, .close:focus { color: rgb(145, 203, 202); text-decoration: none; cursor: pointer; } /* Modal Image*/ .modal-img { display: inline-block; margin: 1em 0 1em; width: 20em; } p.stats { font-weight: 600; } p.stats:last-child { margin-bottom: 1em; } .win { font-size: 1em; } .play-again-btn { background: rgb(145, 203, 202); border-radius: 10em; font-size: 15px; color: #fff; margin-bottom: 1em; } /*---------------------------------- Deck of Cards ------------------------------------*/ /*Mobile first responsivness*/ .deck { background: linear-gradient(to bottom, #bbb, #eee); border-radius: 1.5em; display: flex; flex-wrap: wrap; justify-content: space-around; align-items: center; height: 35em; margin-bottom: 6em; margin-top: -25px; padding: 0.5em; width: 35em; } .deck, .card { box-shadow: 5px 2px 20px 0 rgba(46, 61, 73, 0.5); } .card { background-image:url("https://h.lnwfile.com/x5n327.jpg"); background-size: 300px 300px; border-radius: 0.5em; height: 7em; width: 7em; } /* To disable the color highlight if and img is clicked https://stackoverflow.com/questions/21107439/disable-or-change-firefoxs-element-image-highlight-color */ img { user-select: none; width: 6em; } .deck img { visibility: hidden; } .deck .card.flip { background: #fff; cursor: default; transform: rotateY(180deg); transition: transform 0.3s linear; pointer-events: none; } .flip img { background: #fff; visibility: visible; } .deck .card.match { background: rgb(145, 203, 202); visibility: visible; cursor: default; animation: pulse 1s; } .match img { background: rgb(145, 203, 202); } @keyframes pulse { 0% { transform: scale(1); } 80% { transform: scale(1.1); } 100% { transform: scale(1); } } @media screen and (min-width: 550px) { .deck { height: 50em; padding: 2em; width: 50em; } .card { height: 10em; width: 10em; } .deck img { width: 9em; } .modal-content h2 { font-size: 4em; } .play-again-btn { font-size: 1.8em; } } /*---------------------------------- Desktops ------------------------------------*/ @media screen and (min-width: 800px) { h1 { font-size: 6em; } p { font-size: 2.3em; } .deck { height: 70em; width: 70em; } .card { height: 15em; width: 15em; } .deck img { width: 13em; } .reset-btn { font-size: 0.8em; } .footer { font-size: 1.2em; } .modal-content h2 { font-size: 5em; } * Modal Image*/ .modal-img { width: 30em; } .play-again-btn { font-size: 2em; } .credit{ font-size: 20px; margin-right: -30em; margin-top: -50px; } .add{ color: #f55; } } </style> <header class="header"> <h1>Idol Memory</h1> <h2>Team sspim</h2> </header> <section class="score-panel"> <h3>Score Panel</h3> <ul id="star-rating" class="star-rating"> <li class="star"><i class="fa fa-star"></i></li> <li class="star"><i class="fa fa-star"></i></li> <li class="star"><i class="fa fa-star"></i></li> </ul> <span class="moves-counter">0</span> Moves <div class="reset"> <button class="btn reset-btn">Reset <i class="fa fa-repeat"></i></button> </div> </section> <section class="win-game-modal"> <div id="modal" class="modal"> <!-- Modal content --> <div class="modal-content"> <span class="close">×</span> <h2 class="win">You win!!</h2> <br></br> <button class="btn play-again-btn">Play Again?</button> </div> </div> </section> <ul class="deck"></ul> <div class="timer-container"> <span class="timer"><i class="fa fa-hourglass-start"> </i> Timer: 00:00</span> </div> <h1 class="credit"> <a href="https://youtube.com/watch?v=Y4lOwOOK7yE&feature=share" class="add">@credit</a> </h1> <script> // Array of Deck of Card Images const deckCards = ["https://github.com/Sarawutgame/multmedia/blob/main/img/doyoung.jpg?raw=true", "https://github.com/Sarawutgame/multmedia/blob/main/img/inyeop.jpg?raw=true", "https://github.com/Sarawutgame/multmedia/blob/main/img/jackson.jpg?raw=true", "https://github.com/Sarawutgame/multmedia/blob/main/img/jaehyun.jpg?raw=true", "https://github.com/Sarawutgame/multmedia/blob/main/img/lai%20kuanlin.jpg?raw=true", "https://ih1.redbubble.net/image.400013424.8386/st,small,507x507-pad,600x600,f8f8f8.u1.jpg", "https://github.com/YakSudNamKlureRongBan/How-s-your-day-going-/blob/main/img/S__2760713.jpg?raw=true", "https://github.com/Sarawutgame/multmedia/blob/main/img/taeyeong.jpg?raw=true", "https://github.com/Sarawutgame/multmedia/blob/main/img/doyoung.jpg?raw=true", "https://github.com/Sarawutgame/multmedia/blob/main/img/inyeop.jpg?raw=true", "https://github.com/Sarawutgame/multmedia/blob/main/img/jackson.jpg?raw=true", "https://github.com/Sarawutgame/multmedia/blob/main/img/jaehyun.jpg?raw=true", "https://github.com/Sarawutgame/multmedia/blob/main/img/lai%20kuanlin.jpg?raw=true", "https://ih1.redbubble.net/image.400013424.8386/st,small,507x507-pad,600x600,f8f8f8.u1.jpg", "https://github.com/YakSudNamKlureRongBan/How-s-your-day-going-/blob/main/img/S__2760713.jpg?raw=true", "https://github.com/Sarawutgame/multmedia/blob/main/img/taeyeong.jpg?raw=true"]; // Global Arrays // Access the <ul> with class of .deck const deck = document.querySelector(".deck"); // Create an empty array to store the opened cards let opened = []; // Create an empty array to store the matched cards let matched = []; // Access the modal const modal = document.getElementById("modal"); // Access the reset button const reset = document.querySelector(".reset-btn"); // Access the play again button const playAgain = document.querySelector(".play-again-btn"); // Select the class moves-counter and change it's HTML const movesCount = document.querySelector(".moves-counter"); // Create variable for moves counter, start the count at zero let moves = 0; // Access the <ul> element for the star rating section and then the <li> elements within it const star = document.getElementById("star-rating").querySelectorAll(".star"); // Variable to keep track of how many stars are left let starCount = 3; // Get the span tag for the timer. const timeCounter = document.querySelector(".timer"); // To use this variable to stop the time started in timer let time; // Create variables for time count, start all at zero let minutes = 0; let seconds = 0; // For use in the click card event listener let timeStart = false; // Shuffle function from http://stackoverflow.com/a/2450976 function shuffle(array) { let currentIndex = array.length, temporaryValue, randomIndex; while (currentIndex !== 0) { randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; } /* TODO: Start Game: Shuffle the deck, create <li> tags and <img> tags and append to the deck <ul> with the new shuffled content */ function startGame() { // Invoke shuffle function and store in variable const shuffledDeck = shuffle(deckCards); // Iterate over deck of cards array for (let i = 0; i < shuffledDeck.length; i++) { // Create the <li> tags const liTag = document.createElement('LI'); // Give <li> class of card liTag.classList.add('card'); // Create the <img> tags const addImage = document.createElement("IMG"); // Append <img> to <li> liTag.appendChild(addImage); // Set the img src path with the shuffled deck addImage.setAttribute("src", deckCards[i]); // Add an alt tag to the image addImage.setAttribute("alt", "image of vault boy from fallout"); // Update the new <li> to the deck <ul> deck.appendChild(liTag); } } startGame(); /* Remove all child nodes from the deck <li> tags and <img> tags. To be called in set everything function only */ function removeCard() { // As long as <ul> deck has a child node, remove it while (deck.hasChildNodes()) { deck.removeChild(deck.firstChild); } } /* Update the timer in the HTML for minutes and seconds This timer() function is invoked in the event listener on the first card click Used: https://www.w3schools.com/js/js_timing.asp */ function timer() { // Update the count every 1 second time = setInterval(function() { seconds++; if (seconds === 60) { minutes++; seconds = 0; } // Update the timer in HTML with the time it takes the user to play the game timeCounter.innerHTML = "<i class='fa fa-hourglass-start'></i>" + " Timer: " + minutes + " Mins " + seconds + " Secs"; }, 1000); } /* Stop the timer once the user has matched all 16 cards, total of 8 pairs Used: https://www.w3schools.com/js/js_timing.asp */ function stopTime() { clearInterval(time); } /* Reset all global variables and the content of HTML elements timer, stars, moves, and the moves and timer inner HTML */ function resetEverything() { // Stop time, reset the minutes and seconds update the time inner HTML stopTime(); timeStart = false; seconds = 0; minutes = 0; timeCounter.innerHTML = "<i class='fa fa-hourglass-start'></i>" + " Timer: 00:00"; // Reset star count and the add the class back to show stars again star[1].firstElementChild.classList.add("fa-star"); star[2].firstElementChild.classList.add("fa-star"); starCount = 3; // Reset moves count and reset its inner HTML moves = 0; movesCount.innerHTML = 0; // Clear both arrays that hold the opened and matched cards matched = []; opened = []; // Clear the deck removeCard(); // Create a new deck startGame(); } /* Increment the moves counter. To be called at each comparison for every two cards compared add one to the count */ function movesCounter() { // Update the html for the moves counter movesCount.innerHTML++; // Keep track of the number of moves for every pair checked moves++; } /* Update the star rating. Depending on the number of moves the user completes the game, the stars will decrease with the more moves the user takes. */ function starRating() { if (moves === 14) { // First element child is the <i> within the <li> star[2].firstElementChild.classList.remove("fa-star"); starCount--; } if (moves === 18) { star[1].firstElementChild.classList.remove("fa-star"); starCount--; } } /* Compare two cards to see if they match or not */ function compareTwo() { // When there are 2 cards in the opened array if (opened.length === 2) { // Disable any further mouse clicks on other cards document.body.style.pointerEvents = "none"; } // Compare the two images src if (opened.length === 2 && opened[0].src === opened[1].src) { // If matched call match() match(); // console.log("It's a Match!"); } else if (opened.length === 2 && opened[0].src != opened[1].src) { // If No match call noMatch() noMatch(); // console.log("NO Match!"); } } /* If the two cards match, keep the cards open and apply class of match */ function match() { /* Access the two cards in opened array and add the class of match to the imgages parent: the <li> tag */ setTimeout(function() { opened[0].parentElement.classList.add("match"); opened[1].parentElement.classList.add("match"); // Push the matched cards to the matched array matched.push(...opened); // Allow for further mouse clicks on cards document.body.style.pointerEvents = "auto"; // Check to see if the game has been won with all 8 pairs winGame(); // Clear the opened array opened = []; }, 600); // Call movesCounter to increment by one movesCounter(); starRating(); } /* If the two cards do not match, remove the cards from the opened array and flip the cards back over by removing the flip class. */ function noMatch() { /* After 700 miliseconds the two cards open will have the class of flip removed from the images parent element <li>*/ setTimeout(function() { // Remove class flip on images parent element opened[0].parentElement.classList.remove("flip"); opened[1].parentElement.classList.remove("flip"); // Allow further mouse clicks on cards document.body.style.pointerEvents = "auto"; // Remove the cards from opened array opened = []; }, 700); // Call movesCounter to increment by one movesCounter(); starRating(); } /* Get stats on the time, how many moves, and star rating for the end game and update the modal with these stats */ function AddStats() { // Access the modal content div const stats = document.querySelector(".modal-content"); // Create three different paragraphs for (let i = 1; i <= 3; i++) { // Create a new Paragraph const statsElement = document.createElement("p"); // Add a class to the new Paragraph statsElement.classList.add("stats"); // Add the new created <p> tag to the modal content stats.appendChild(statsElement); } // Select all p tags with the class of stats and update the content let p = stats.querySelectorAll("p.stats"); // Set the new <p> to have the content of stats (time, moves and star rating) p[0].innerHTML = "Time to complete: " + minutes + " Minutes and " + seconds + " Seconds"; p[1].innerHTML = "Moves Taken: " + moves; p[2].innerHTML = "Your Star Rating is: " + starCount + " out of 3"; } /* Display the modal on winning the game Help with the modal from: https://www.w3schools.com/howto/howto_css_modals.asp */ function displayModal() { // Access the modal <span> element (x) that closes the modal const modalClose = document.getElementsByClassName("close")[0]; // When the game is won set modal to display block to show it modal.style.display = "block"; // When the user clicks on <span> (x), close the modal modalClose.onclick = function() { modal.style.display = "none"; }; // When the user clicks anywhere outside of the modal, close it window.onclick = function(event) { if (event.target == modal) { modal.style.display = "none"; } }; } /* Check the length of the matched array and if there are 8 pairs 16 cards all together then the game is won. Stop the timer update the modal with stats and show the modal */ function winGame() { if (matched.length === 16) { stopTime(); AddStats(); displayModal(); } } /*---------------------------------- Main Event Listener ------------------------------------*/ /* Event Listener if a card <li> is clicked call flipCard() */ deck.addEventListener("click", function(evt) { if (evt.target.nodeName === "LI") { // To console if I was clicking the correct element console.log(evt.target.nodeName + " Was clicked"); // Start the timer after the first click of one card // Executes the timer() function if (timeStart === false) { timeStart = true; timer(); } // Call flipCard() function flipCard(); } //Flip the card and display cards img function flipCard() { // When <li> is clicked add the class .flip to show img evt.target.classList.add("flip"); // Call addToOpened() function addToOpened(); } //Add the fliped cards to the empty array of opened function addToOpened() { /* If the opened array has zero or one other img push another img into the array so we can compare these two to be matched */ if (opened.length === 0 || opened.length === 1) { // Push that img to opened array opened.push(evt.target.firstElementChild); } // Call compareTwo() function compareTwo(); } }); //Event Listener /*---------------------------------- Restart Buttons ------------------------------------*/ /* Event Listener to listen for a click on the reset button, once clicked call resetEverything() */ reset.addEventListener('click', resetEverything); /* Event Listener to listen for a click on the play again button, once clicked call resetEverything() */ playAgain.addEventListener('click', function() { modal.style.display = "none"; resetEverything(); }); </script>