เกมจับคู่ (Matching Game)

ผู้เขียนบทความ : นายธันยบูรณ์ โต๊ะน้อย (167404130066)

คณะวิศวกรรมศาสตร์ : สาขาวิศวกรรมไฟฟ้า

วิชา : 04000104 การโปรแกรมคอมพิวเตอร์ ภาคการศึกษาปี่ที่ 1/2567

1. ความเป็นมา

ในยุคดิจิทัลที่ผู้คนเข้าถึงเทคโนโลยีและอินเทอร์เน็ตได้ง่าย การพัฒนาเกมออนไลน์กลายเป็นแนวทางที่นิยมสำหรับการเรียนรู้และการพักผ่อนอย่างมีความสุข โดยเฉพาะเกมที่ช่วยเสริมสร้างทักษะการคิดวิเคราะห์และการจำ เช่น เกมจับคู่ภาพ ซึ่งเป็นเกมที่ไม่เพียงแต่ให้ความสนุกสนาน แต่ยังมีประโยชน์ต่อสมองและการพัฒนาทักษะต่าง ๆ การพัฒนาเกมนี้จึงมีความสำคัญในการสนับสนุนการเรียนรู้และการพัฒนาตนเองผ่านการเล่นเกม

2. วัตถุประสงค์

  • พัฒนาเกมจับคู่ภาพ: สร้างเกมที่สามารถเล่นได้ง่าย มีความน่าสนใจ และส่งเสริมทักษะการจำของผู้เล่น
  • ส่งเสริมการเรียนรู้ด้านเทคโนโลยี: มอบโอกาสให้ผู้เรียนได้เรียนรู้เกี่ยวกับ HTML, CSS และ JavaScript ผ่านการพัฒนาเกม
  • ศึกษาและทดลองระบบการจับคู่: เข้าใจหลักการทำงานของเกมจับคู่ที่ประกอบไปด้วยการจัดการกับสถานะและการตรวจสอบการจับคู่
  • เพิ่มพูนความสนุกสนานในการเรียนรู้: ทำให้การเรียนรู้เป็นเรื่องสนุกและไม่น่าเบื่อสำหรับผู้เรียนทุกช่วงวัย

3. ขอบเขต

โครงงานนี้มุ่งเน้นไปที่การพัฒนาเกมจับคู่ภาพบนแพลตฟอร์มเว็บ โดยใช้ภาษา HTML, CSS และ JavaScript เป็นหลัก รวมถึงการออกแบบประสบการณ์ผู้ใช้ (UX) เพื่อให้เหมาะสมกับผู้เล่น นอกจากนี้ยังมีการออกแบบให้เกมนี้สามารถเล่นได้ทั้งในคอมพิวเตอร์และอุปกรณ์เคลื่อนที่ โดยจะไม่รวมถึงการพัฒนาแอพพลิเคชันบนแพลตฟอร์มอื่น ๆ หรือเกมที่ซับซ้อนมาก โดยใช้เวลาในการสร้างและพัฒนาโปรแกรมเกม1สัปดาห์

4. ประโยชน์ที่คาดว่าจะได้รับ

  • พัฒนาทักษะการจำ: เกมนี้จะช่วยให้ผู้เล่นพัฒนาทักษะการจำภาพได้ดียิ่งขึ้น ผ่านการจำคู่การ์ดที่คล้ายกัน
  • ความสนุกสนาน: ผู้เล่นจะได้รับความสนุกจากการเล่นเกม และการมีส่วนร่วมในการแข่งขันกับตนเองหรือผู้อื่น
  • ความรู้ทางเทคโนโลยี: ผู้เรียนจะได้เรียนรู้การเขียนโค้ดและการออกแบบเว็บไซต์ ซึ่งเป็นทักษะที่มีค่าในยุคปัจจุบัน
  • การสร้างสัมพันธ์: เกมนี้สามารถเล่นร่วมกับเพื่อนหรือครอบครัว ช่วยสร้างสัมพันธ์ระหว่างกัน

5. ความรู้ที่คาดว่าจะได้รับ

  • การเขียน HTML และ CSS: เรียนรู้โครงสร้างพื้นฐานของหน้าเว็บและการตกแต่งโดยใช้ CSS
  • การเขียน JavaScript: เข้าใจการเขียนโค้ดที่ใช้ในการควบคุมการทำงานของเกม การจัดการสถานะ และการตอบสนองต่อการกระทำของผู้ใช้
  • หลักการออกแบบเกม: เรียนรู้เกี่ยวกับการออกแบบเกมที่ดึงดูดผู้เล่นและการทำให้เกมมีความท้าทาย
  • การทำงานกับ DOM: เข้าใจการทำงานของ Document Object Model ในการควบคุมและปรับเปลี่ยนเนื้อหาในเว็บเพจ

6. ผลการดำเนินการ

ในขั้นตอนการพัฒนา เกมจับคู่ภาพถูกสร้างขึ้นมาให้มีฟังก์ชันการทำงานที่สมบูรณ์แบบ ผู้เล่นสามารถพลิกการ์ดได้ กำหนดการจับคู่ และนับคะแนนได้อย่างมีประสิทธิภาพ การทดสอบเกมมีผลลัพธ์ที่ดี ผู้เล่นส่วนใหญ่แสดงความพึงพอใจในความเรียบง่ายและการเล่นที่สนุกสนาน

  • 6.1 ตัวอย่างโค้ดที่ใช้ในการสร้างเกม
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Memory Matching Game - Hard Mode</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="title-container">
        <h1>เกมจับคู่ - จับยังไงก็โสดอยู่ดี</h1>
    </div>
    
    <img src="https://media.tenor.com/P5iiJiI_1tMAAAAi/please-begging.gif" alt="Please" id="begging-gif">

    <div id="stats">
        <p>Moves: <span id="moves">0</span></p>
        <p>Time: <span id="timer">0:00</span></p>
        <p>Level: <span id="level">1</span></p>
    </div>

    <div id="game-board"></div>
    <button id="restart-button">เริ่มเกมใหม่</button>
    <p id="next-level-message" style="color: green;"></p>
    
    <script src="script.js"></script>
</body>
</html>
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: 'Arial', sans-serif;
    background-image: url('https://images.pexels.com/photos/1213447/pexels-photo-1213447.jpeg');
    background-size: cover;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100vh;
    color: white;
}

h1 {
    margin-bottom: 20px;
    background: linear-gradient(to right, #ff6f00, #ffcc00, #99ff00, #00ccff, #0066ff, #6600cc, #cc00ff);
    -webkit-background-clip: text;
    color: transparent;
    font-weight: bold;
    font-size: 3.5rem;
    text-shadow: 2px 2px 8px rgba(0, 0, 0, 0.5);
    letter-spacing: 2px;
    border-radius: 10px;
    padding: 10px;
    background-color: rgba(255, 255, 255, 0.1);
    animation: bounce 1s infinite;
}

#game-board {
    display: grid;
    grid-template-columns: repeat(6, 80px);
    grid-template-rows: repeat(6, 80px);
    gap: 10px;
}

.card {
    width: 80px;
    height: 80px;
    background-color: silver;
    border-radius: 10px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 30px;
    color: white;
    cursor: pointer;
    transition: transform 0.3s ease, background-color 0.3s ease, box-shadow 0.3s ease;
    position: relative;
    overflow: hidden;
    box-shadow: 0 4px 15px rgba(255, 255, 255, 0.5);
}

.card.flipped {
    background: linear-gradient(145deg, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.5));
    color: #2c3e50;
    box-shadow: 0 4px 25px rgba(255, 255, 255, 0.7);
}

#restart-button {
    margin-top: 20px;
    padding: 10px 20px;
    background-color: green;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
}

#restart-button:hover {
    background-color: red;
    transform: scale(1.1);
    transition: transform 0.3s ease;
}
const cardValues = [
    '🌮', '🍕', '🍔', '🍟', '🍦', '🍩', '🍪', '🍰', '🥗', '🍝', '🍣', '🌭',
    '🍜', '🍙', '🥙', '🍚', '🍉', '🍓', '🍇', '🍒', '🍍', '🍌', '🍎', '🍑'
];

let firstCard = null;
let secondCard = null;
let lockBoard = false;
let matchedPairs = 0;
let moves = 0;
let timerInterval = null;
let timeElapsed = 0;
let level = 1;
let currentCardSet = [];
const displayTime = 5;

function shuffle(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;
}

function createBoard() {
    matchedPairs = 0;
    moves = 0;
    timeElapsed = 0;
    document.getElementById('moves').textContent = moves;
    document.getElementById('timer').textContent = formatTime(timeElapsed);
    document.getElementById('level').textContent = level;
    clearInterval(timerInterval);
    timerInterval = setInterval(updateTimer, 1000);

    const gameBoard = document.getElementById('game-board');
    gameBoard.innerHTML = '';

    let cardPairs = Math.min(level + 1, 10);
    let cardCount = cardPairs * 2;

    currentCardSet = shuffle(cardValues.slice(0, cardPairs).concat(cardValues.slice(0, cardPairs)));

    const gridSize = Math.ceil(Math.sqrt(cardCount));
    gameBoard.style.gridTemplateColumns = `repeat(${gridSize}, 80px)`;
    gameBoard.style.gridTemplateRows = `repeat(${gridSize}, 80px)`;

    currentCardSet.forEach((value) => {
        const card = document.createElement('div');
        card.classList.add('card');
        card.dataset.value = value;
        card.addEventListener('click', flipCard);
        gameBoard.appendChild(card);
    });

    setTimeout(() => {
        document.querySelectorAll('.card').forEach(card => {
            card.classList.remove('flipped');
            card.textContent = '';
        });
    }, displayTime * 1000);
}

function flipCard() {
    if (lockBoard || this.classList.contains('flipped')) return;

    this.classList.add('flipped');
    this.textContent = this.dataset.value;

    if (!firstCard) {
        firstCard = this;
        return;
    }

    secondCard = this;
    lockBoard = true;
    checkForMatch();
}

function checkForMatch() {
    moves++;
    document.getElementById('moves').textContent = moves;

    if (firstCard.dataset.value === secondCard.dataset.value) {
        disableCards();
        matchedPairs++;
        if (matchedPairs === currentCardSet.length / 2) {
            setTimeout(() => {
                clearInterval(timerInterval);
                showCelebrationMessage();
                document.getElementById('next-level-message').textContent = 'กด Spacebar เพื่อไปยังเลเวลถัดไป!';
                level++;
            }, 500);
        }
    } else {
        unflipCards();     
    }
}

function disableCards() {
    firstCard.removeEventListener('click', flipCard);
    secondCard.removeEventListener('click', flipCard);
    firstCard.classList.add('matched');
    secondCard.classList.add('matched');
    resetBoard();
}

function unflipCards() {
    firstCard.classList.add('incorrect');
    secondCard.classList.add('incorrect');

    setTimeout(() => {
        firstCard.classList.remove('flipped', 'incorrect');
        secondCard.classList.remove('flipped', 'incorrect');
        firstCard.textContent = '';
        secondCard.textContent = '';
        resetBoard();
    }, 1000);
}

function resetBoard() {
    [firstCard, secondCard, lockBoard] = [null, null, false];
}

function formatTime(seconds) {
    const minutes = Math.floor(seconds / 60);
    const sec = seconds % 60;
    return `${minutes}:${sec

6.2 อธิบายโค้ดแต่ละส่วนโดยรวม

โครงสร้าง HTML

  • doctype และ html: เริ่มต้นด้วยการระบุชนิดเอกสาร (HTML5) และเปิดแท็ก <html> ที่กำหนดภาษาเป็นภาษาอังกฤษ (lang="en").
  • head:
    • <meta>: กำหนดการเข้ารหัสตัวอักษรเป็น UTF-8 และการปรับขนาดของมุมมองสำหรับอุปกรณ์เคลื่อนที่.
    • <title>: กำหนดชื่อของหน้าเว็บเป็น “Memory Matching Game – Hard Mode”.
    • <link>: เชื่อมโยงไฟล์ CSS สำหรับการจัดรูปแบบ.
  • body:
    • title-container: แสดงชื่อเกมด้วย <h1>.
    • begging-gif: แสดง GIF ที่สื่อถึงการขอความช่วยเหลือ.
    • stats: แสดงข้อมูลสถิติเกี่ยวกับการเคลื่อนไหว เวลา และระดับ.
    • game-board: พื้นที่สำหรับแสดงการ์ดเกม.
    • restart-button: ปุ่มสำหรับเริ่มเกมใหม่.
    • next-level-message: ข้อความที่จะแสดงเมื่อผู้เล่นสามารถไปยังระดับถัดไปได้.

CSS สำหรับการจัดรูปแบบ

  • global styles: ตั้งค่า box-sizing, margin, และ padding สำหรับทุกๆ องค์ประกอบในเอกสาร.
  • body: ตั้งค่าพื้นหลังและจัดวางองค์ประกอบให้อยู่กลางจอ.
  • animations:
    • @keyframes move: สร้างการเคลื่อนไหว (ยืด-หด) สำหรับชื่อเกม.
    • @keyframes bounce, @keyframes slide: ใช้สำหรับสร้างการเคลื่อนไหวให้กับการ์ด.
  • card styles: ตั้งค่าลักษณะของการ์ด เช่น ขนาด สีพื้นหลัง เอฟเฟกต์เมื่อถูกพลิกหรือจับคู่สำเร็จ.
  • #restart-button: ตั้งค่าลักษณะสำหรับปุ่มเริ่มใหม่ เช่น สีพื้นหลัง การโค้งมุม และเอฟเฟกต์เมื่อ hover.

JavaScript สำหรับตรรกะของเกม

  • ตัวแปรเริ่มต้น:
    • cardValues: อาร์เรย์ที่เก็บค่าอีโมจิสำหรับการ์ด.
    • ตัวแปรสำหรับจัดการการพลิกการ์ด, การจับคู่, การนับการเคลื่อนไหว, เวลา, และระดับ.
  • ฟังก์ชันหลัก:
    • shuffle(array): สุ่มเรียงลำดับการ์ด.
    • createBoard(): สร้างบอร์ดเกม โดยขึ้นอยู่กับระดับที่กำหนด.
    • flipCard(): พลิกการ์ดที่ถูกคลิก.
    • checkForMatch(): ตรวจสอบว่าการ์ดสองใบที่พลิกมีค่าเหมือนกันหรือไม่.
    • disableCards(): ปิดการคลิกการ์ดที่จับคู่สำเร็จ.
    • unflipCards(): พลิกการ์ดกลับเมื่อไม่จับคู่.
    • resetBoard(): รีเซ็ตตัวแปรเพื่อเริ่มการพลิกการ์ดใหม่.
    • formatTime(seconds): ฟังก์ชันสำหรับแสดงเวลาที่ผ่านไปในรูปแบบที่อ่านง่าย.
    • updateTimer(): อัปเดตเวลาในทุก ๆ วินาที.
  • การจัดการเหตุการณ์:
    • มีการติดตั้ง event listeners สำหรับปุ่มเริ่มใหม่ และปุ่ม Spacebar เพื่อลงไปยังระดับถัดไป.
  • การแสดงข้อความเฉลิมฉลอง: ฟังก์ชัน showCelebrationMessage() สำหรับแสดงข้อความเมื่อผู้เล่นชนะระดับ.
  • การเปลี่ยนสีพื้นหลัง: ฟังก์ชัน changeBackground() เปลี่ยนสีพื้นหลังตามระดับ.

7. การทดลอง สรุปผล ข้อเสนอแนะ

จากการทดลองเล่นเกมนี้ พบว่าผู้เล่นส่วนใหญ่มีความพึงพอใจในความง่ายในการเข้าใจเกมและความสนุกที่ได้รับ โดยผู้เล่นสามารถเข้าใจวิธีการเล่นได้ในเวลาที่สั้น และได้พัฒนาทักษะการจำได้อย่างเห็นได้ชัด อย่างไรก็ตาม ควรมีการเพิ่มความหลากหลายของการ์ดเพื่อให้ผู้เล่นมีความท้าทายมากขึ้น นอกจากนี้ยังมีความคิดในการพัฒนาเวอร์ชันที่มีระดับความยากหลากหลายเพื่อรองรับผู้เล่นที่มีทักษะต่างกัน

7.1 ตัวอย่างเกมจริง

หน้าเริ่มเกม
กรณีเล่นจนผ่านด่าน
กรณีที่เลือกผิดภาพ

8. อ้างอิง

GeeksforGeeks. (n.d.). CSS Tutorial. Retrieved from geeksforgeeks.org

W3Schools. (n.d.). HTML Tutorial. Retrieved from w3schools.com

Mozilla Developer Network. (n.d.). JavaScript Guide. Retrieved from developer.mozilla.org

You may also like...

ใส่ความเห็น

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น ช่องข้อมูลจำเป็นถูกทำเครื่องหมาย *