纯原生JavaScript 实现贪吃蛇案例 思路以及源码 直接使用

426 阅读2分钟

简单实现贪吃蛇小游戏效果图

文章底部有案例中的背景图

image.png image.png

这是简单的html结构和样式部分

    <!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>

    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .map {
            width: 1000px;
            height: 600px;
            border: 5px solid #333;
            margin: 50px auto;
            position: relative;
            background-image: url(./imgs/bg.png);
            background-repeat: repeat;
            background-size: 20px 20px;
        }

        .map>div {
            width: 20px;
            height: 20px;
            position: absolute;
            background-size: 20px 20px;
            background-repeat: no-repeat;
        }

        .map>.food {
            background-image: url(./imgs/food.png);
        }

        .map>.head {
            background-image: url(./imgs/head.png);
        }

        .map>.body {
            background-image: url(./imgs/body.png);
        }
        button{
            width: 150px;
            text-align: center;
            height: 50px;
            font-size: 30px; 
        }
    </style>

</head>

<body>


    <button id="btn1">开始</button>
    <button id="btn2">暂停</button>
    <button id="btn3">重新开始</button>

    <div class="map" id="map"></div>
    
//我们在html 底部 书写的一部分 js
    <script type="module">

        // 导入js2
        import Game from './贪吃蛇2.js'
        const g = new Game('#map')
    
    // 三个按钮的点击事件  
        document.querySelector('#btn1').onclick = function(){
            g.start()
        }
        document.querySelector('#btn2').onclick = function(){
            g.pause()
        }
        document.querySelector('#btn3').onclick = function(){
            g.reload()
        }

        //当按下方向键盘的时候 控制蛇的移动方向
        
        document.onkeydown = function(e){
        // 事件委托的方式 拿到键盘上的上下左右的code 编码
            if(e.keyCode == 37){
                //left
                g.setDes('left')
            }else if(e.keyCode == 38){
                //top
                g.setDes('top')
            }else if(e.keyCode == 39){
                //right
                g.setDes('right')
            }else if(e.keyCode == 40){
                // bottom
                g.setDes('bottom')
            }
        }
    </script>

</body>

</html>



单独的./贪吃蛇.js' js文件

export default class food{
    constructor(ele){
        //获取到地图范围
        this.map = document.querySelector(ele)
        //新建一个食物的div
        this.Food = document.createElement('div')
        //新建一个头部的div
        this.Head = document.createElement('div')
        //新建一个身体的div
        this.Body = document.createElement('div')
        //给食物DIV 添加一个类名
        this.Food.classList.add('food')

        // 将新建的食物div插入到地图中
        this.map.appendChild(this.Food)

        //记录食物的坐标
        this.x = 0
        this.y = 0
        // 调用改变食物位置的方法
        this.changeFood()

    }
    // 原型内容部分
    changeFood(){
        //0 拿到地图的高度和宽度
        const w = parseInt(window.getComputedStyle(this.map).width)
        const h = parseInt(window.getComputedStyle(this.map).height)
        // 1.1计算每行多少个小格子
        // 1.2计算每列多少个小格子
        const row = w / 20
        const col = h / 20
        // 2求食物在第几个格子上
        // const posX = (Math.floor(Math.random()*(row-1))+1)*20
        const posX = Math.floor(Math.random()*row)*20
        const posY = Math.floor(Math.random()*col)*20
        // 3求出随机数后 赋值给坐标
        this.x = posX
        this.y = posY
        // 4修改食物的坐标
        this.Food.style.left = this.x + "px"
        this.Food.style.top = this.y + "px"
    }
}

单独的./贪吃蛇.js1' js文件

export default class Snake{
    constructor(ele){
        //1 拿到范围地图
        this.map = document.querySelector(ele)
        // 2方向
        this.des = 'right'
        // 数组来存储一条蛇
        this.Snake = []
        // 4. 创建一条蛇
        this.makeSnake();
        this.isDie()

    }
    addSnake(){
        // 1. 当前 this.snake 为空数组, 此时只需要创建一节蛇头即可
        // 2. 当前 this.snake 数组已经有值了, 除了要创建一节蛇头意外, 还要把原本的蛇头更改蛇身
        // 0 拿到数组的第一项定位蛇头
        const head = this.Snake[0]
        //首次判断 是否 为空数组
        // 不为空 有内容 将之更改为蛇身
        if(head !== undefined){
            head.className = 'body'
        }
        //3 创建蛇头
        const oHaed = document.createElement('div')
        // 添加类名 
        oHaed.className = 'head'
        // 再地图页面生成蛇头
        this.map.appendChild(oHaed)
        //并且插入在数组的开头
        this.Snake.unshift(oHaed) 
        //4 调整蛇头的走位
        const pos = {
            x : 0,
            y : 0,
        }
        if(head !== undefined){
             /**
             *  如果当前方向是 向 右, left += 20    top 不变
             *                  左, left -= 20  top 不变
             *                  下, left 不变   top += 20
             *                  上, left 不变   top -= 20
             */
            // 先获取蛇头原本的偏移量
            pos.x = head.offsetLeft
            pos.y = head.offsetTop

            switch(this.des){
                case "right":  pos.x += 20; break;
                case "left":  pos.x -= 20; break;
                case "bottom": pos.y += 20; break;
                case "top": pos.y -= 20; break;
            }
        }
        oHaed.style.left = pos.x + "px";
        oHaed.style.top = pos.y + "px";
    }

    makeSnake(){
        // 调用五次 生成长度为 5 一条的蛇
        for (let i = 0; i < 10; i++) {
            this.addSnake();
        }

    }
    //走一步
    move(){
        // 删除末尾的元素
        // 删除对应的dom 节点
        // 新增一个蛇头 
        const body = this.Snake.pop()
        body.remove()
        this.addSnake()
    }

    // 判断食物重叠
    isEat(footX,footY){
        //定义第一项为蛇头
        const head = this.Snake[0]
        if(head.offsetLeft == footX && head.offsetTop == footY){
            return true
        }
        return false
    }

    //判断是失败 条件 超界
    isDie(){
        const head =this.Snake[0]
        if(
            head.offsetLeft < 0 |
            head.offsetTop < 0 |
            head.offsetLeft > this.map.clientWidth |
            head.offsetTop  > this.map.clientHeight 

        ){
            return true
        }
        return false
    }

}

单独的./贪吃蛇.js2' js文件

必须在贪吃蛇js2中 按顺序先导入 这如下两个js

import food from './贪吃蛇.js'

import Snake from './贪吃蛇1.js'


export default class Game{
    constructor(ele){
        this.food = new food(ele)
        this.Snake = new Snake(ele)
        this.timer = 0
        this.sum = 0
        this.level = 1
    }
    //开始游戏
    start(){
        // let newTime = 1800 - this.leve * 100;
        this.timer = setInterval(()=>{
            this.Snake.move()

            // this.up()
            // 判断是否吃到了食物
            if(this.Snake.isEat(this.food.x,this.food.y)){
                this.food.changeFood()
                this.Snake.addSnake()
                this.sum ++
            }
            // 判断蛇头是否超界
            if(this.Snake.isDie()){
                clearInterval(this.timer)
                alert('小菜鸟!还敢继续挑战吗?')
            }
        },100)
    }
    //暂停游戏
    pause(){
        clearInterval(this.timer)
    }
    //重新开始
    reload(){
        window.location.reload()
    }
    //修改蛇的方向
    setDes(type){
        this.Snake.des = type
    }
   
}

案例中的背景图 

背景

bg.png

蛇的身体

body.png

蛇的食物

food.png

蛇的头部

head.png