我创建了一个记忆游戏,你尝试匹配成对的牌。它在第一个游戏中正常运行,但之后如果我点击一张卡就会自动匹配。我花了很多时间在这个bug上,一直在努力弄明白。任何建议将不胜感激。谢谢!
let symbol = [
"diamond",
"paper-plane-o",
"anchor",
"bolt",
"cube",
"leaf",
"bomb",
"bicycle",
];
let symbols = [...symbol, ...symbol];
const deck = document.querySelector(".deck");
const cards = deck.getElementsByTagName("li");
const stars = document.querySelector(".stars");
const restart = document.querySelector(".restart");
const timer = document.querySelector(".timer");
let starRating = 3;
let seconds = 0;
let opened = [];
let moves = 0;
let matches = 0;
const totalMatches = symbols.length / 2;
let counter;
function startGame() {
// Remove cards from previous game if any
while (deck.firstChild) {
deck.removeChild(deck.firstChild);
}
// Shuffle symbols
let shuffleDeck = shuffle(symbols);
// Reset Stats Function call
resetStats();
// Loop through symbols and add cards to deck w/ icons
for (let i = 0; i < shuffleDeck.length; i++) {
let card = document.createElement("li");
card.className = "card";
let icon = document.createElement("i");
icon.className = "fa fa-" + shuffleDeck[i];
card.appendChild(icon);
deck.appendChild(card);
}
cardListener();
resetTimer(counter);
seconds = 0;
startTimer();
}
function shuffle(array) {
var 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;
}
// Function for star ratings
function starRater(moves) {
starRating = 3;
if (moves >= 12 && moves < 18) {
document.querySelector("#star_1").className = "fa fa-star-o";
starRating = 2;
} else if (moves >= 18 && moves < 25) {
document.querySelector("#star_2").className = "fa fa-star-o";
starRating = 1;
} else if (moves >= 25) {
document.querySelector("#star_3").className = "fa fa-star-o";
starRating = 0;
}
}
// Function to reset stats
function resetStats() {
// Start all moves and card-matches at a default value of 0
matches = 0;
moves = 0;
document.querySelector(".moves").innerText = moves;
// Replace any stars lost in previous games and give starRating default value of 3
starRating = 3;
document.querySelector("#star_1").className = "fa fa-star";
document.querySelector("#star_2").className = "fa fa-star";
document.querySelector("#star_3").className = "fa fa-star";
}
// Create function to add event listener to deck and delegate events to all cards
const cardListener = function() {
deck.addEventListener("click", function(e) {
let card = e.target;
// Makes sure that target can only be a card
if (card.tagName != "LI") return;
// If card has class name show or match return true
if (
card.className === "card open show" ||
card.className === "card match"
) {
return true;
}
// If card is true then push into opened array
if (card) {
card.className = "card open show animated flipInY";
opened.push(card);
}
// Conditional that if opened has two items in array then run conditional to see if they match
if (opened.length > 1) {
// If the items match then iterate through the cards in deck and change class names to card match
if (card.firstChild.className === opened[0].firstChild.className) {
setTimeout(function() {
for (let x = 0; x < cards.length; x++) {
if (cards[x].className === "card open show animated flipInY") {
cards[x].className = "card match animated pulse";
}
}
}, 1000);
matches++;
// If the items do not match iterate through the cards and change class names back to just card add a delay so the user can see the second card they click on for a moment
} else {
setTimeout(function() {
for (let x = 0; x < cards.length; x++) {
if (cards[x].className === "card open show animated flipInY") {
cards[x].className = "card animated flipInX";
setTimeout(function(){
cards[x].className = "card";
}, 200);
};
}
}, 1000);
};
moves++;
document.querySelector(".moves").innerText = moves;
starRater(moves);
opened = [];
}
// Conditional to check to see if it's the end of the game
if (totalMatches === matches) {
endGame(moves, starRating);
}
});
};
// Reset Game Logic
restart.addEventListener("click", function() {
swal({
title: "Do you want to restart the game?",
text: "The clock is ticking!",
buttons: ["Nope!", "Restart!"],
dangerMode: true
}).then(function(isConfirm) {
if (isConfirm) {
startGame();
}
});
});
// Function to start timer
function startTimer() {
counter = setInterval(function() {
timer.innerText = seconds;
seconds += 1;
}, 1000);
}
// Function to reset timer
function resetTimer(counter) {
if (counter) {
clearInterval(counter);
}
}
// // Function to reset cards
// function resetCards(){
//
// }
// End game function
function endGame(moves, starRating) {
swal({
icon: "success",
title: "You did it!!",
text:
"It took " +
moves +
" moves and you got a " +
starRating +
" Star Rating in " +
seconds +
" seconds.\n Party on Garth. Do you want to play again?",
buttons: ["Nope!", "Play Again!"]
}).then(function(isConfirm) {
if (isConfirm) {
startGame();
}
});
resetTimer(counter);
}
// Initialize game
startGame();
html {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
body {
background: #ffffff url("../img/geometry2.png"); /* Background pattern from Subtle Patterns */
font-family: "Coda", cursive;
}
.container {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
h1 {
font-family: "Open Sans", sans-serif;
font-weight: 300;
}
/*
* Styles for the deck of cards
*/
.deck {
width: 660px;
min-height: 680px;
background: linear-gradient(160deg, #02ccba 0%, #aa7ecd 100%);
padding: 32px;
border-radius: 10px;
box-shadow: 12px 15px 20px 0 rgba(46, 61, 73, 0.5);
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
margin: 0 0 3em;
}
.deck .card {
height: 125px;
width: 125px;
background: #2e3d49;
font-size: 0;
color: #ffffff;
border-radius: 8px;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 5px 2px 20px 0 rgba(46, 61, 73, 0.5);
}
.deck .card.open {
transform: rotateY(0);
background: #02b3e4;
cursor: default;
}
.deck .card.show {
font-size: 33px;
}
.deck .card.match {
cursor: default;
background: #02ccba;
font-size: 33px;
}
/*
* Styles for the Score Panel
*/
.score-panel {
text-align: left;
width: 345px;
margin-bottom: 10px;
}
.score-panel .stars {
margin: 0;
padding: 0;
display: inline-block;
margin: 0 5px 0 0;
}
.score-panel .stars li {
list-style: none;
display: inline-block;
}
.score-panel .restart {
float: right;
cursor: pointer;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Matching Game</title>
<meta name="description" content="">
<link rel="stylesheet prefetch" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css">
<link rel="stylesheet prefetch" href="https://fonts.googleapis.com/css?family=Coda">
<link rel="stylesheet" href="css/app.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css@3.5.2/animate.min.css">
</head>
<body>
<div class="container">
<header>
<h1>Matching Game</h1>
</header>
<section class="score-panel">
<ul class="stars">
<li><i id="star_1" class="fa fa-star star-items"></i></li>
<li><i id="star_2" class="fa fa-star star-items"></i></li>
<li><i id="star_3" class="fa fa-star star-items"></i></li>
</ul>
<span class="moves">0</span> Moves - Time: <span class="timer">0</span>s
<div class="restart">
<i class="fa fa-repeat"></i>
</div>
</section>
<ul class="deck"></ul>
</div>
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
<script src="js/app.js"></script>
</body>
</html>
答案 0 :(得分:0)
我在测试之后意识到我忘了从套牌中删除事件监听器。因此,当我调用函数添加监听器时,它会添加一个新的事件监听器,导致匹配发生,因为被点击的单卡被推入阵列两次。