程序員帶娃神器:自制貪吃蛇網(wǎng)頁游戲教程

2024-12-18 11:38 更新

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

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

貪吃蛇網(wǎng)頁游戲程序界面1

貪吃蛇網(wǎng)頁游戲程序界面2

貪吃蛇網(wǎng)頁游戲程序界面2

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

創(chuàng)建一個(gè)簡單的貪吃蛇網(wǎ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:包含一個(gè) <canvas> 元素,貪吃蛇游戲?qū)?huì)在這個(gè)畫布上渲染。

CSS:簡單地設(shè)置了畫布的外觀。

JavaScript:游戲邏輯,包括:

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

下面再詳細(xì)解釋一下這個(gè)小游戲的實(shí)現(xiàn)邏輯:

這個(gè)貪吃蛇游戲使用 HTML、CSS 和 JavaScript 編寫,代碼實(shí)現(xiàn)的邏輯和流程如下:

1. HTML 部分

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

  • 使用 <canvas> 元素作為游戲畫布,游戲會(huì)在這個(gè)區(qū)域繪制蛇、食物等內(nèi)容。
  • 設(shè)置 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 將畫布居中,背景設(shè)為黑色。
  • 設(shè)置畫布的邊框和背景顏色,增強(qiáng)視覺效果。

3. JavaScript 部分

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

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:網(wǎng)格大小,每個(gè)網(wǎng)格 20x20 像素。
  • tileCount:計(jì)算畫布中網(wǎng)格的數(shù)量,canvas.width / gridSize(這里為 20x20 個(gè)網(wǎng)格)。
  • snake:蛇的初始位置,初始為一個(gè)對象數(shù)組,蛇頭位置在 {x: 10, y: 10}。
  • food:食物的初始位置 {x: 5, y: 5}。
  • directionnextDirection:蛇的當(dāng)前移動(dòng)方向和下一個(gè)移動(dòng)方向。
  • 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)函數(shù),使用 setInterval 在一定時(shí)間間隔內(nèi)重復(fù)調(diào)用,實(shí)現(xiàn)游戲的實(shí)時(shí)更新。
  • 移動(dòng)方向更新:更新蛇的移動(dòng)方向。
  • 移動(dòng)蛇:創(chuàng)建蛇頭的新位置,根據(jù)方向調(diào)整 xy 坐標(biāo),將新頭部添加到 snake 數(shù)組的開頭。
  • 檢查食物碰撞:如果蛇頭和食物位置相同,調(diào)用 placeFood 生成新的食物位置;否則,移除蛇尾(snake.pop()),維持蛇的長度。
  • 檢測碰撞
    • 墻壁碰撞:如果蛇頭的位置超出畫布范圍,調(diào)用 gameOver 函數(shù)結(jié)束游戲。
    • 自身碰撞:如果蛇頭與身體的任何部分重疊,調(diào)用 gameOver 函數(shù)結(jié)束游戲。
  • 繪制游戲:調(diào)用 drawGame 函數(shù)更新畫布。

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 函數(shù)負(fù)責(zé)繪制游戲的每一幀。
  • 清空畫布:用黑色填充整個(gè)畫布,清除之前的繪制內(nèi)容。
  • 繪制蛇:遍歷 snake 數(shù)組,在蛇每個(gè)部分的位置上繪制一個(gè)綠色矩形。
  • 繪制食物:在 food 的位置繪制一個(gè)紅色矩形。

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 隨機(jī)在畫布上放置食物。
  • 防止食物出現(xiàn)在蛇身上:如果生成的食物位置在蛇身上,則遞歸調(diào)用 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 函數(shù)監(jiān)聽鍵盤事件,更新蛇的移動(dòng)方向。
  • 確保蛇不能直接反方向移動(dòng):例如,蛇正在向右移動(dòng)時(shí),不能直接按左鍵,否則會(huì)導(dǎo)致游戲結(jié)束。

3.6. 游戲結(jié)束

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

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

3.7. 啟動(dòng)游戲

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

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

最后小結(jié)一下

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

好了,現(xiàn)在可以靜靜的寫項(xiàng)目了,專心致志,效率翻倍。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號