程序員帶娃神器:自制貪吃蛇網頁游戲教程

2024-12-18 11:38 更新

這個中秋可是悲催,別人放假,我還得在家辦公寫項目,帶娃的時間都沒有,這不,娃要纏著陪她玩積木游戲,哎,心中有事,陪娃都陪不好,咋整,靈機一動,先搞個小游戲讓娃耍個把小時,畢竟孩子長時間對著電腦不好,寫個貪吃蛇吧,能玩很久。

先看一下簡單的界面是這樣的:

貪吃蛇網頁游戲程序界面1

貪吃蛇網頁游戲程序界面2

貪吃蛇網頁游戲程序界面2

網頁游戲,比較簡單,一個頁面就搞定了,代碼是這樣的,直接生成一個 html 就能玩了。

創(chuàng)建一個簡單的貪吃蛇網頁游戲,使用 HTML、CSS 和 JavaScript 三件套,簡單高效。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Snake Game</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #333;
            margin: 0;
        }


        canvas {
            border: 1px solid #fff;
            background-color: #000;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="400" height="400"></canvas>


    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');


        const gridSize = 20;
        const tileCount = canvas.width / gridSize;
        let snake = [{ x: 10, y: 10 }];
        let food = { x: 5, y: 5 };
        let direction = { x: 0, y: 0 };
        let nextDirection = { x: 0, y: 0 };
        let speed = 200;


        function gameLoop() {
            // Update snake direction
            direction = nextDirection;


            // Move snake
            const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };
            snake.unshift(head);


            // Check for food collision
            if (head.x === food.x && head.y === food.y) {
                placeFood();
            } else {
                snake.pop();
            }


            // Check for wall collision
            if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount) {
                gameOver();
                return;
            }


            // Check for self collision
            for (let i = 1; i < snake.length; i++) {
                if (snake[i].x === head.x && snake[i].y === head.y) {
                    gameOver();
                    return;
                }
            }


            drawGame();
        }


        function drawGame() {
            // Clear canvas
            ctx.fillStyle = 'black';
            ctx.fillRect(0, 0, canvas.width, canvas.height);


            // Draw snake
            ctx.fillStyle = 'lime';
            snake.forEach(part => {
                ctx.fillRect(part.x * gridSize, part.y * gridSize, gridSize, gridSize);
            });


            // Draw food
            ctx.fillStyle = 'red';
            ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize, gridSize);
        }


        function placeFood() {
            food.x = Math.floor(Math.random() * tileCount);
            food.y = Math.floor(Math.random() * tileCount);


            // Make sure food doesn't appear on the snake
            for (let i = 0; i < snake.length; i++) {
                if (snake[i].x === food.x && snake[i].y === food.y) {
                    placeFood();
                }
            }
        }


        function changeDirection(event) {
            switch (event.keyCode) {
                case 37: // Left arrow
                    if (direction.x === 0) {
                        nextDirection = { x: -1, y: 0 };
                    }
                    break;
                case 38: // Up arrow
                    if (direction.y === 0) {
                        nextDirection = { x: 0, y: -1 };
                    }
                    break;
                case 39: // Right arrow
                    if (direction.x === 0) {
                        nextDirection = { x: 1, y: 0 };
                    }
                    break;
                case 40: // Down arrow
                    if (direction.y === 0) {
                        nextDirection = { x: 0, y: 1 };
                    }
                    break;
            }
        }


        function gameOver() {
            alert('Game Over!');
            snake = [{ x: 10, y: 10 }];
            direction = { x: 0, y: 0 };
            nextDirection = { x: 0, y: 0 };
            placeFood();
        }


        document.addEventListener('keydown', changeDirection);
        setInterval(gameLoop, speed);
        placeFood();
    </script>
</body>
</html>

前端三件套:

HTML:包含一個 <canvas> 元素,貪吃蛇游戲將會在這個畫布上渲染。

CSS:簡單地設置了畫布的外觀。

JavaScript:游戲邏輯,包括:

  • gameLoop 函數:負責蛇的移動、碰撞檢測、食物生成等。
  • drawGame 函數:繪制蛇和食物。
  • placeFood 函數:隨機放置食物在畫布上。
  • changeDirection 函數:監(jiān)聽鍵盤事件,改變蛇的移動方向。
  • gameOver 函數:處理游戲結束的邏輯。

下面再詳細解釋一下這個小游戲的實現邏輯:

這個貪吃蛇游戲使用 HTML、CSS 和 JavaScript 編寫,代碼實現的邏輯和流程如下:

1. HTML 部分

<canvas id="gameCanvas" width="400" height="400"></canvas>

  • 使用 <canvas> 元素作為游戲畫布,游戲會在這個區(qū)域繪制蛇、食物等內容。
  • 設置 id="gameCanvas" 以便在 JavaScript 中通過 document.getElementById 獲取它。
  • widthheight 屬性定義了畫布的尺寸為 400x400 像素。

2. CSS 部分

body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: #333;
    margin: 0;
}


canvas {
    border: 1px solid #fff;
    background-color: #000;
}

  • 使用 CSS 將畫布居中,背景設為黑色。
  • 設置畫布的邊框和背景顏色,增強視覺效果。

3. JavaScript 部分

JavaScript 部分包含了游戲的核心邏輯,包括蛇的移動、食物的生成、碰撞檢測、繪制和用戶輸入的處理。

3.1. 初始化變量

const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');


const gridSize = 20;
const tileCount = canvas.width / gridSize;
let snake = [{ x: 10, y: 10 }];
let food = { x: 5, y: 5 };
let direction = { x: 0, y: 0 };
let nextDirection = { x: 0, y: 0 };
let speed = 200;

  • canvas:獲取畫布元素。
  • ctx:獲取畫布的 2D 渲染上下文,用于繪制圖形。
  • gridSize:網格大小,每個網格 20x20 像素。
  • tileCount:計算畫布中網格的數量,canvas.width / gridSize(這里為 20x20 個網格)。
  • snake:蛇的初始位置,初始為一個對象數組,蛇頭位置在 {x: 10, y: 10}
  • food:食物的初始位置 {x: 5, y: 5}。
  • directionnextDirection:蛇的當前移動方向和下一個移動方向。
  • speed:控制游戲循環(huán)的速度,單位是毫秒。

3.2. 游戲主循環(huán)

function gameLoop() {
    // Update snake direction
    direction = nextDirection;


    // Move snake
    const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };
    snake.unshift(head);


    // Check for food collision
    if (head.x === food.x && head.y === food.y) {
        placeFood();
    } else {
        snake.pop();
    }


    // Check for wall collision
    if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount) {
        gameOver();
        return;
    }


    // Check for self collision
    for (let i = 1; i < snake.length; i++) {
        if (snake[i].x === head.x && snake[i].y === head.y) {
            gameOver();
            return;
        }
    }


    drawGame();
}

  • gameLoop 是游戲的主循環(huán)函數,使用 setInterval 在一定時間間隔內重復調用,實現游戲的實時更新。
  • 移動方向更新:更新蛇的移動方向。
  • 移動蛇:創(chuàng)建蛇頭的新位置,根據方向調整 xy 坐標,將新頭部添加到 snake 數組的開頭。
  • 檢查食物碰撞:如果蛇頭和食物位置相同,調用 placeFood 生成新的食物位置;否則,移除蛇尾(snake.pop()),維持蛇的長度。
  • 檢測碰撞
    • 墻壁碰撞:如果蛇頭的位置超出畫布范圍,調用 gameOver 函數結束游戲。
    • 自身碰撞:如果蛇頭與身體的任何部分重疊,調用 gameOver 函數結束游戲。
  • 繪制游戲:調用 drawGame 函數更新畫布。

3.3. 繪制游戲

function drawGame() {
    // Clear canvas
    ctx.fillStyle = 'black';
    ctx.fillRect(0, 0, canvas.width, canvas.height);


    // Draw snake
    ctx.fillStyle = 'lime';
    snake.forEach(part => {
        ctx.fillRect(part.x * gridSize, part.y * gridSize, gridSize, gridSize);
    });


    // Draw food
    ctx.fillStyle = 'red';
    ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize, gridSize);
}

  • drawGame 函數負責繪制游戲的每一幀。
  • 清空畫布:用黑色填充整個畫布,清除之前的繪制內容。
  • 繪制蛇:遍歷 snake 數組,在蛇每個部分的位置上繪制一個綠色矩形。
  • 繪制食物:在 food 的位置繪制一個紅色矩形。

3.4. 生成新食物

function placeFood() {
    food.x = Math.floor(Math.random() * tileCount);
    food.y = Math.floor(Math.random() * tileCount);


    // Make sure food doesn't appear on the snake
    for (let i = 0; i < snake.length; i++) {
        if (snake[i].x === food.x && snake[i].y === food.y) {
            placeFood();
        }
    }
}

  • placeFood 隨機在畫布上放置食物。
  • 防止食物出現在蛇身上:如果生成的食物位置在蛇身上,則遞歸調用 placeFood 重新生成位置。

3.5. 處理方向改變

function changeDirection(event) {
    switch (event.keyCode) {
        case 37: // Left arrow
            if (direction.x === 0) {
                nextDirection = { x: -1, y: 0 };
            }
            break;
        case 38: // Up arrow
            if (direction.y === 0) {
                nextDirection = { x: 0, y: -1 };
            }
            break;
        case 39: // Right arrow
            if (direction.x === 0) {
                nextDirection = { x: 1, y: 0 };
            }
            break;
        case 40: // Down arrow
            if (direction.y === 0) {
                nextDirection = { x: 0, y: 1 };
            }
            break;
    }
}

  • changeDirection 函數監(jiān)聽鍵盤事件,更新蛇的移動方向。
  • 確保蛇不能直接反方向移動:例如,蛇正在向右移動時,不能直接按左鍵,否則會導致游戲結束。

3.6. 游戲結束

function gameOver() {
    alert('Game Over!');
    snake = [{ x: 10, y: 10 }];
    direction = { x: 0, y: 0 };
    nextDirection = { x: 0, y: 0 };
    placeFood();
}

  • gameOver 函數在蛇撞墻或自身時調用,顯示“游戲結束”信息,并重置游戲狀態(tài)。

3.7. 啟動游戲

document.addEventListener('keydown', changeDirection);
setInterval(gameLoop, speed);
placeFood();

  • 事件監(jiān)聽:監(jiān)聽鍵盤事件,調用 changeDirection 函數。
  • 啟動游戲循環(huán):使用 setInterval 定期調用 gameLoop,使游戲持續(xù)運行。
  • 初始食物生成:調用 placeFood 函數生成初始食物位置。

最后小結一下

  • 這個貪吃蛇游戲使用了 JavaScript 進行畫布繪制、碰撞檢測和用戶輸入處理。
  • 游戲循環(huán) (gameLoop) 不斷更新蛇的位置、檢查碰撞、繪制游戲元素,形成動畫效果。
  • 使用鍵盤事件來改變蛇的方向,實現玩家的控制。

好了,現在可以靜靜的寫項目了,專心致志,效率翻倍。

以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號