Skip to main content
0

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

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

เขียนโดย
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 ฟรี !เรียนรู้เพิ่มเติม

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

BorntoDev

Author BorntoDev

BorntoDev Co., Ltd.

More posts by BorntoDev

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

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

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

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

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

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

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

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