You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

卡牌配对游戏开发问题:错误匹配卡牌无法自动翻转

卡牌配对游戏匹配逻辑与翻转问题排查

我正在开发一款简单的卡牌配对游戏,规则为:

  • 选中两张不同卡牌时,卡牌会翻转回去并消耗一次步数
  • 选中两张相同卡牌时,卡牌保持翻转状态,同时消耗步数并获得1分

目前不确定代码是否能正确识别卡牌是否匹配,且卡牌翻转效果与预期不符,曾参考类似游戏教程构建本游戏。以下是我的代码:

// Set global variables
const cards = document.getElementsByClassName('card');
let movesDisplay = document.querySelector('.move-counter');
let toggledCardsArray = [];
let move = 0;
let winCount = 0;
const restart = document.getElementById('restart');

const imagesLinkArray = [
    { id: 1, image: './assets/talisman1.png', newAlt: 'talisman1' },
    { id: 2, image: './assets/talisman2.png', newAlt: 'talisman2' },
    { id: 3, image: './assets/talisman3.png', newAlt: 'talisman3' },
    { id: 4, image: './assets/talisman4.png', newAlt: 'talisman4' },
    { id: 5, image: './assets/talisman5.png', newAlt: 'talisman5' },
    { id: 6, image: './assets/talisman6.png', newAlt: 'talisman6' },
    { id: 7, image: './assets/talisman1.png', newAlt: 'talisman1' },
    { id: 8, image: './assets/talisman2.png', newAlt: 'talisman2' },
    { id: 9, image: './assets/talisman3.png', newAlt: 'talisman3' },
    { id: 10, image: './assets/talisman4.png', newAlt: 'talisman4' },
    { id: 11, image: './assets/talisman5.png', newAlt: 'talisman5' },
    { id: 12, image: './assets/talisman6.png', newAlt: 'talisman6' }
];

// Function to restart the game
const restartGame = () => {
    const toggledCards = document.querySelectorAll('.card.toggled');
    toggledCards.forEach((card) => {
        card.classList.remove('toggled');
    });

    // Shuffle the imagesLinkArray
    imagesLinkArray.sort(() => Math.random() - 0.5);

    // Reset game state
    toggledCardsArray = [];
    move = 0;
    winCount = 0;
    movesDisplay.innerText = `Turn(s): ${move}`;

    // Update card images
    const allImagesSrc = document.querySelectorAll('.card-img');
    allImagesSrc.forEach((el, index) => {
        el.src = imagesLinkArray[index].image;
        el.alt = imagesLinkArray[index].newAlt;
        el.id = imagesLinkArray[index].id;
    });
};

// Add event listener to restart button
restart.addEventListener('click', restartGame);

// Function to handle card clicks
for (let i = 0; i < cards.length; i++) {
    cards[i].addEventListener('click', function () {
        // If the card is already flipped or two cards are already in the array, return
        if (this.classList.contains('toggled') || toggledCardsArray.length === 2) return;

        // Add 'toggled' class and add to toggledCardsArray
        this.classList.add('toggled');
        toggledCardsArray.push(this);

        // Check if two cards are flipped
        if (toggledCardsArray.length === 2) {
            let firstCardSrc = toggledCardsArray[0].querySelector('.card-img')?.src;
            let secondCardSrc = toggledCardsArray[1].querySelector('.card-img')?.src;

            // If cards match
            if (firstCardSrc === secondCardSrc) {
                winCount++;
                toggledCardsArray = []; // Clear the array for the next pair
            } else {
                // If cards do not match, flip them back after a delay
                setTimeout(() => {
                    toggledCardsArray.forEach((card) => {
                        card.classList.remove('toggled');
                    });
                    toggledCardsArray = []; // Reset the array
                }, 500);
            }

            // Increment move count and update display
            move++;
            movesDisplay.innerText = `Turn(s): ${move}`;

            // Check if the player has won
            if (winCount === 6) {
                setTimeout(() => {
                    alert(`Congratulations!!! You won the game in ${move} moves.`);
                }, 300);
            }
        }
    });
}

问题修复与优化建议

  1. 卡牌匹配判断逻辑修正
    当前使用src属性判断匹配存在风险:浏览器会将相对路径转换为绝对路径,可能导致原本应该匹配的卡牌因为路径格式不一致判断失败。建议改用alt属性(或自定义data-*属性)做匹配判断,修改后的代码如下:
// 替换原匹配判断部分
let firstCardAlt = toggledCardsArray[0].querySelector('.card-img').alt;
let secondCardAlt = toggledCardsArray[1].querySelector('.card-img').alt;

if (firstCardAlt === secondCardAlt) {
    winCount++;
    toggledCardsArray = [];
} else {
    // 原翻转逻辑不变
}
  1. 防止重复点击的状态锁
    在处理配对的延迟期间,用户可能快速点击第三张卡牌导致逻辑混乱,新增全局状态锁控制点击:
// 新增全局变量
let isProcessing = false;

// 修改点击事件开头的判断条件
if (this.classList.contains('toggled') || toggledCardsArray.length === 2 || isProcessing) return;

// 处理两张卡牌时设置锁
if (toggledCardsArray.length === 2) {
    isProcessing = true;
    // ... 匹配判断逻辑

    // 匹配成功后释放锁
    if (firstCardAlt === secondCardAlt) {
        winCount++;
        toggledCardsArray = [];
        isProcessing = false;
    } else {
        setTimeout(() => {
            toggledCardsArray.forEach((card) => {
                card.classList.remove('toggled');
            });
            toggledCardsArray = [];
            isProcessing = false; // 延迟后释放锁
        }, 500);
    }
}
  1. 洗牌算法优化
    原sort(() => Math.random() - 0.5)的洗牌方式不均匀,替换为Fisher-Yates洗牌算法:
// 新增洗牌函数
function shuffleArray(array) {
    for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
    return array;
}

// 在restartGame中替换原洗牌逻辑
shuffleArray(imagesLinkArray);
  1. 语法错误修复
    原代码的点击事件循环末尾缺少闭合的});和},已在代码块中补充完整,确保代码能正常运行。

内容的提问来源于stack exchange,提问作者Waskar Paulino

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 22:40:09