Skip to main content
0

มาลองสร้าง Snake Game ด้วย JavaScript กันเถอะ

สารจากนักเขียน

สวัสดีครับเพื่อน ๆ ทุกคนช่วงนี้หลายคนก็คงอ่านหนังสือเตรียมสอบกันอยู่หรือบางคนก็สอบไปแล้ว ก็อยากพักผ่อนเล่นเกม อะไรที่มันเพลิน ๆ ง่าย ๆ กันบ้างในวันนี้ก็จะพามาสร้างเกมงูกันจ้า🐍

เขียนโดย
Chairawit Iamkhajornchai
Internship @ borntoDev

บทความนี้ตีพิมพ์ และ เผยแพร่เมื่อ 29 สิงหาคม 2566

เริ่มต้นด้วยการสร้าง SnakeGame.html ขึ้นมาก่อนเลยนะครับ

ให้เพื่อน ๆ พิมพ์ doc จะได้โครง HTML ขึ้นมาแล้วก็ Styles ก็ใช้ตามกันก่อนได้เลยนะครับหรือถ้าใครอยากปรับแต่งอะไรก็ปรับเอาได้ตามสะดวกเลย โดยจะแบ่งเป็น font, body, details, control นะครับ

!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8" />
    <title>Snake Game</title>
    <style>
      @import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500;600;700&display=swap");
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
        font-family: "Open Sans", sans-serif;
      }
      body {
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: 100vh;
        background: #e3f2fd;
      }
      .wrapper {
        width: 65vmin;
        height: 70vmin;
        display: flex;
        overflow: hidden;
        flex-direction: column;
        justify-content: center;
        border-radius: 5px;
        background: #191f22;
        box-shadow: 0 20px 40px rgba(52, 87, 220, 0.2);
      }
      .game-details {
        color: #b8c6dc;
        font-weight: 500;
        font-size: 1.2rem;
        padding: 20px 27px;
        display: flex;
        justify-content: space-between;
      }
      .play-board {
        height: 100%;
        width: 100%;
        display: grid;
        background: #212837;
        grid-template: repeat(30, 1fr) / repeat(30, 1fr);
      }
      .play-board .food {
        background: #ff003d;
      }
      .play-board .head {
        background: #75ff60;
      }
      .controls {
        display: none;
        justify-content: space-between;
      }
      .controls i {
        padding: 25px 0;
        text-align: center;
        font-size: 1.3rem;
        color: #b8c6dc;
        width: calc(100% / 4);
        cursor: pointer;
        border-right: 1px solid #171b26;
      }
      @media screen and (max-width: 800px) {
        .wrapper {
          width: 90vmin;
          height: 115vmin;
        }
        .game-details {
          font-size: 1rem;
          padding: 15px 27px;
        }
        .controls {
          display: flex;
        }
        .controls i {
          padding: 15px 0;
          font-size: 1rem;
        }
      }
</style>

จากนั้นก็ตามมาด้วย body ภายใน HTML ซึ่งก็จะมีการเก็บ game-details, Score, High-Score และบอร์ดสำหรับใช้เล่นเอาไว้โดยเราจะตั้งให้ Controller ควบคุมด้วยลูกศรนะครับ

<meta name="viewport" content="width=device-width, initial-scale=1.0" />
  </head>
  <body>
    <div class="wrapper">
      <div class="game-details">
        <span class="score">Score: 0</span>
        <span class="high-score">High Score: 0</span>
      </div>
      <div class="play-board"></div>
      <div class="controls">
        <i data-key="ArrowLeft" class="fa-solid fa-arrow-left-long"></i>
        <i data-key="ArrowUp" class="fa-solid fa-arrow-up-long"></i>
        <i data-key="ArrowRight" class="fa-solid fa-arrow-right-long"></i>
        <i data-key="ArrowDown" class="fa-solid fa-arrow-down-long"></i>
      </div>
    </div>

ต่อไปจะเป็นส่วนหลักก็คือ Script มาดูไปพร้อม ๆ กันเลยนะครับ

<script>
      const playBoard = document.querySelector(".play-board");
      const scoreElement = document.querySelector(".score");
      const highScoreElement = document.querySelector(".high-score");
      const controls = document.querySelectorAll(".controls i");
      let gameOver = false;
      let foodX, foodY;
      let snakeX = 5,
        snakeY = 5;
      let velocityX = 0,
        velocityY = 0;
      let snakeBody = [];
      let setIntervalId;
      let score = 0;
      // Getting high score from the local storage
      let highScore = localStorage.getItem("high-score") || 0;
      highScoreElement.innerText = `High Score: ${highScore}`;

ส่วนนี้จะประกาศสิ่งที่จะใช้หลักคือ playBoard, scoreElement, highScoreElement, Control และ ตัวตรวจเช็ค GameOver` โดยตั้งต้นเป็น false ไปก่อนและ `food` ซึ่งจะแสดงตำแหน่งตามแกน X,Y ตามมาด้วย Snake ที่แสดงตำแหน่งตามแกน X,Y เหมือนกันเลย

จากนั้นก็จะมีการเก็บขนาด Snake ไว้กับ Score และ High Score นั่นเอง

const updateFoodPosition = () => {
        // Passing a random 1 - 30 value as food position
        foodX = Math.floor(Math.random() * 30) + 1;
        foodY = Math.floor(Math.random() * 30) + 1;
      };
      const handleGameOver = () => {
        // Clearing the timer and reloading the page on game over
        clearInterval(setIntervalId);
        alert("Game Over! Press OK to restart...");
        location.reload();
      };
      const changeDirection = (e) => {
        // Changing velocity value based on key press
        if (e.key === "ArrowUp" && velocityY != 1) {
          velocityX = 0;
          velocityY = -1;
        } else if (e.key === "ArrowDown" && velocityY != -1) {
          velocityX = 0;
          velocityY = 1;
        } else if (e.key === "ArrowLeft" && velocityX != 1) {
          velocityX = -1;
          velocityY = 0;
        } else if (e.key === "ArrowRight" && velocityX != -1) {
          velocityX = 1;
          velocityY = 0;
        }
      };
// Calling changeDirection on each key click and passing key dataset value as an object
      controls.forEach((button) =>
        button.addEventListener("click", () =>
          changeDirection({ key: button.dataset.key })
        )
      );

เริ่มกันด้วย 3 ฟังก์ชันก่อนคือ updateFoodPosition() ตามชื่อเลยก็จะสุ่มตำแหน่งของอาหารไปเรื่อย ๆ เมื่องูกินไปแล้วและ handleGameOver() ไว้ตรวจสอบเมื่องูชน ขอบจอ และการควบคุมความเร็วของงู ด้วย changeDirection() โดยเราก็จะใช้ forEach ทำเป็น Loop เอาไว้เพราะผู้เล่นจะต้องกดปุ่มเพื่อเปลี่ยนทิศทางอยู่ตลอด

const initGame = () => {
        if (gameOver) return handleGameOver();
        let html = `<div class="food" style="grid-area: ${foodY} / ${foodX}"></div>`;
        // Checking if the snake hit the food
        if (snakeX === foodX && snakeY === foodY) {
          updateFoodPosition();
          snakeBody.push([foodY, foodX]); // Pushing food position to snake body array
          score++; // increment score by 1
          highScore = score >= highScore ? score : highScore;
          localStorage.setItem("high-score", highScore);
          scoreElement.innerText = `Score: ${score}`;
          highScoreElement.innerText = `High Score: ${highScore}`;
        }
        // Updating the snake's head position based on the current velocity
        snakeX += velocityX;
        snakeY += velocityY;

ต่อมาจะเป็น initGame() ที่ใช้สำหรับเริ่มเกมก็จะตั้งเงื่อนไขเอาไว้และเมื่อ งูกินอาหารก็จะเพิ่มคะแนนและขนาดงูด้วย และมีการ Update ตำแหน่งของงูอยู่ตลอดเพื่อให้ผู้เล่นสามารถควบคุมได้อิสระ ถ้าหากคะแนนเป็นสถิติสูงสุดใหม่ก็จะมีการ Record เก็บเอาไว้

// Shifting forward the values of the elements in the snake body by one
        for (let i = snakeBody.length - 1; i > 0; i--) {
          snakeBody[i] = snakeBody[i - 1];
        }
        snakeBody[0] = [snakeX, snakeY]; // Setting first element of snake body to current snake position
        // Checking if the snake's head is out of wall, if so setting gameOver to true
        if (snakeX <= 0 || snakeX > 30 || snakeY <= 0 || snakeY > 30) {
          return (gameOver = true);
        }
        for (let i = 0; i < snakeBody.length; i++) {
          // Adding a div for each part of the snake's body
          html += `<div class="head" style="grid-area: ${snakeBody[i][1]} / ${snakeBody[i][0]}"></div>`;
          // Checking if the snake head hit the body, if so set gameOver to true
          if (
            i !== 0 &&
            snakeBody[0][1] === snakeBody[i][1] &&
            snakeBody[0][0] === snakeBody[i][0]
          ) {
            gameOver = true;
          }
        }
        playBoard.innerHTML = html;
        // Change background color and snake color based on score
        if (score > 5) {
          document.body.style.backgroundColor = getRandomColor();
          document.querySelectorAll(".head").forEach((part) => {
            part.style.background = getRandomColor();
          });
        }
     };
     const getRandomColor = () => {
       const letters = "0123456789ABCDEF";
       let color = "#";
       for (let i = 0; i < 6; i++) {
         color += letters[Math.floor(Math.random() * 16)];
       }
       return color;
     };
     
     updateFoodPosition();
     setIntervalId = setInterval(initGame, 100);
     document.addEventListener("keyup", changeDirection);
   </script>
  </body>
</html>

ในส่วนนี้ก็จะเป็นการเพิ่มขนาดของงูเมื่อมีการกินอาหารเข้าไปและก็มีการตรวจเงื่อนไขด้วยว่างูชนกำแพงหรือ

ถ้าชน = เกมจบ และนอกจากกำแพงถ้าชนกับตัวเองก็จบเกมเหมือนกันนะ

และก็มีการเพิ่ม Events เข้าไปด้วยก็คือถ้าคะแนนเรามากกว่า 5 ขึ้นไปก็จะทำการสุ่มเปลี่ยนสีพื้นหลังและสีงูด้วยและมีการใช้งานสุ่มสีด้วย getRandomColor() ถ้าเพื่อน ๆ มาถึงขั้นตอนนี้แล้วก็จะเหลือแค่การ `Run ทดสอบ`เท่านั้นแล้ว

ลอง Run เพื่อตรวจดูผลลัพธ์กันเลย🎮

หน้าตาเกมก็จะประมาณนี้

ทดสอบลองกินอาหารดูคะแนนก็จะขึ้นตาม Function ที่เขียนไว้เลย

และเมื่อตายก็จะมี Alert แจ้งเตือนขึ้นมาว่าให้กด “OK” เพื่อเล่นใหม่ได้

ลองเช็คดูว่าถ้าคะแนนเกิน 5 แล้ว Event ที่เราสร้างไว้จะเกิดขึ้นหรือไม่ ซึ่งผลลัพธ์ก็คือ

จะได้ตามนี้เลย สีงู จะเปลี่ยนไปกับพื้นหลังที่มีการเปลี่ยนแปลงอยู่ตลอด หรือถ้าใครไม่ชอบก็ลองไปปรับแก้ไขกันดูได้เลยนะ และถ้าเพื่อน ๆ สังเกตกันจะพบว่า High Score คือ 16 ซึ่งระหว่างทำผมก็ได้ลอง Test ทดสอบไปหลายรอบเลยมันก็จะมีการเก็บ Record ที่ดีที่สุดไว้ตามที่เราเขียนไปนั่นแหละ

เพียงเท่านี้เราก็จะได้ Snake Game มาเล่นกันแล้ว เรียกได้ว่า เล่นได้เพลิน ๆ เลยนะ เบาสมองดี เห็นแล้วคิดถึงวันวานตอนแอบเอาโทรศัพท์พ่อแม่ มาเล่นเกมงูแบบนี้ในมือถือเลย ฮ่า ๆ มีใครเป็นบ้างไหมครับ😂👌

สุดท้ายนี้ถ้าเพื่อน ๆ ชื่นชอบบทความนี้และคิดว่าเป็นประโยชน์ก็อย่าลืมกด ❤ ให้กัน เพื่อที่จะได้ไม่พลาดความรู้ใหม่ ๆ ที่ส่งตรงถึงที่ให้กันแบบฟรี ๆ ไปเลย และในครั้งหน้าจะเป็นเรื่องอะไรอีกอย่าลืมติดตามกันไว้ ในตอนนี้ผมก็ต้องขอตัวลาไปก่อนละค้าบ แปรนนนน🐘…
.

ขอบคุณที่เข้ามาอ่านกันนะครับ🙏

.

🦖 borntoDev – สร้างการเรียนรู้ที่ดี สำหรับสายไอทีในทุกวัน

ระบบฝึกทักษะ การเขียนโปรแกรม

ที่พร้อมตรวจผลงานคุณ 24 ชั่วโมง

  • โจทย์ปัญหากว่า 200 ข้อ ที่รอท้าทายคุณอยู่
  • รองรับ 9 ภาษาโปรแกรมหลัก ไม่ว่าจะ Java, Python, C ก็เขียนได้
  • ใช้งานได้ฟรี ! ครบ 20 ข้อขึ้นไป รับ Certificate ไปเลย !!
เข้าใช้งานระบบ DevLab ฟรี !เรียนรู้เพิ่มเติม

เรียนรู้ไอที “อัพสกิลเขียนโปรแกรม” จากตัวจริง
ปั้นให้คุณเป็น คนสายไอทีระดับมืออาชีพ

7

แนะนำสำหรับคุณ

Close Menu

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

ตั้งค่าความเป็นส่วนตัว

คุณสามารถเลือกการตั้งค่าคุกกี้โดยเปิด/ปิด คุกกี้ในแต่ละประเภทได้ตามความต้องการ ยกเว้น คุกกี้ที่จำเป็น

ยอมรับทั้งหมด
จัดการความเป็นส่วนตัว
  • คุกกี้ที่จำเป็น
    เปิดใช้งานตลอด

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

  • คุกกี้สำหรับการติดตามทางการตลาด

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

บันทึกการตั้งค่า