网页版贪食蛇【基于HTML+CSS+JavaScript】实现

最终效果

在这里插入图片描述
如果需要功能更完善、代码更简洁以及bug更少的代码,可以到我的小程序 航筱北同学上搜索查看。里面还有很多实战项目和面试话术。
在这里插入图片描述

HTML代码

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

<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="css/style.css">
    <title>贪食蛇</title>
</head>

<body>
    <div id="map" style="background: url('./images/map7.jpg');"></div>
    <div class="prompt">
        <div class="introduction">
            贪食蛇游戏 <br>LiuLei<br><br>1.通过 ↑ ↓ ← → 方向键控制蛇头的移动方向;
            <br>2.蛇头碰到边界时游戏结束;<br>3.蛇头碰到蛇身时游戏结束;
            <br>4.蛇头不能原路返回,即蛇头方向向左时,按右键无效,蛇头方向向下时,按上键无效。
            <br>5.对蛇头和蛇身进行了美化,蛇头由纯色小方块改成了蛇头图片,而且随着蛇头的移动方向改变,蛇头的朝向也会发生相应的改变。
            <br>6.对食物进行美化,由纯色小方块改成了苹果图片。
            <br>7.对地图进行美化,由纯色背景改成了图片背景。
            <br>8.增加了游戏得分的计数,并实时显示到屏幕。
        </div>
        <div id="score">
            得分:<span id="score_value">0</span>
        </div>
    </div>
    <script src="./js/index.js"></script>
    
</body>

</html>

CSS

#map{
    width: 800px;
    height: 600px;
    background-color: lightgray;
    position: relative;
}
.introduction{
    position: absolute;
    left: 830px;
    top: 0;
    width: 400px;
    height: 280px;
    color: rgb(75, 71, 71);
    font-size: 14px;
    background-color: rgb(233, 224, 226);
    box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
    
}

#score{
    position: absolute;
    left: 10px;
    top: 10px;
    color: red;
    font-size: 25px;
    font-weight: bold;
    font-family: '微软雅黑';
}

JavaScript代码

//如果需要部署到服务器上,需要将代码复制到用js压缩工具将js压缩,例如js在线压缩
//压缩后注释全部删除、空白和换行也会删除,甚至变量名会变短,以使得js文件体积更小,
//(到时候可读性会变差,但是部署到服务器上js体积小访问传输更快)

/*-----------------tools.js----------------- */
//注意自调用函数的问题,*****应该在自调用函数前面加一个分号********,表明上一个语句的结束,防止自调用函数被上一条语句结合而报错
//自调用函数传入window的目的,是为了让变量名可以被压缩
//在老版本的浏览器中,undefined可以被重新赋值
;(function (window, undefined) {
    var Tools = {
        getRandom: function (min, max) {
            return Math.floor(Math.random() * (max - min + 1)) + min;
        }
    }
    //暴露Tools给window
    window.Tools = Tools;
})(window, undefined)

/*-----------------food.js----------------- */
//所有的js文件中书写代码,都是全局作用域
//可以用自调用函数,开启一个新的作用域,避免全局作用域带来的命名冲突问题
;(function (window, undefined) {
    var position = 'absolute';
    //记录上次创建的食物,为删除做准备
    var elements = [];
    function Food(options) {
        options = options || {};
        this.x = options.x || 0;
        this.y = options.y || 0;
        this.width = options.width || 20;
        this.height = options.height || 20;
        //this.color = options.color || "yellow";
    }
    //渲染
    Food.prototype.render = function (map) {
        //删除之前创建的食物
        remove();
        //随机设置x和y的值
        this.x = Tools.getRandom(0, map.offsetWidth / this.width - 1) * this.width;
        this.y = Tools.getRandom(0, map.offsetHeight / this.height - 1) * this.height;

        //动态创建,页面上显示的食物
        var img = document.createElement('img');
        img.src = './images/food4.png';
       // var div = document.createElement('div');
        map.appendChild(img);
        elements.push(img);
        //设置食物的样式
        img.style.position = position;
        img.style.left = this.x + 'px';
        img.style.top = this.y + 'px';
        img.style.width = this.width + 'px';
        img.style.height = this.height + 'px';
        //img.style.backgroundColor = this.color;

    }
    function remove() {
        for (var i = elements.length - 1; i >= 0; i--) {
            //删除div
            elements[i].parentNode.removeChild(elements[i]);
            //删除数组中的元素
            //删除数组元素
            //第一个参数,从哪个位置开始删除
            //第二个参数,删除几个元素
            elements.splice(i, 1);
        }
    }
    //把Food构造函数,让外部可以访问
    window.Food = Food;
})(window, undefined)

/*-----------------snake.js----------------- */
//自调用函数,开启一个新的局部作用域,防止命名冲突
;(function (window, undefined){
    var position = 'absolute';
    //记录之前创建的蛇
    var elements = [];
    function Snake (options){
        options = options || {};
        //蛇节的大小
        this.width = options.width || 20;
        this.height = options.height || 20;
        this.score = 0; // 游戏得分
        //蛇的移动方向
        this.direction = options.direction || 'right';
        //蛇头旋转角度
        this.angle = {
            left: {
                rotate: 180 // 蛇头旋转角度
            },
            right: {
                rotate: 0
            },
            top: {
                rotate: -90
            },
            bottom: {
                rotate: 90
            }
        }
        //蛇的身体(第一个元素是蛇头)
        this.body = [
            {x: 3, y: 2, color: 'red'},
            {x: 2, y: 2, color: '#9CCC65'},
            {x: 1, y: 2, color: '#9CCC65'}
        ];
        
    }
    Snake.prototype.render = function (map) {
        //删除之前创建的蛇
        remove();
        //把每一个蛇节渲染到地图上
        for (var i = 0, len = this.body.length; i < len; i++) {
            if (i == 0) {
                //把蛇头渲染到地图
                var objecthead = this.body[0];
                var snakeHead = document.createElement('img');
                snakeHead.src = './images/head.jpg';
                map.appendChild(snakeHead);
                //记录当前蛇头
                elements.push(snakeHead);
                //设置样式
                snakeHead.style.position = position;
                snakeHead.style.width = this.width + 'px';
                snakeHead.style.height = this.height + 'px';
                snakeHead.style.left = objecthead.x * this.width + 'px';
                snakeHead.style.top = objecthead.y * this.height + 'px';
                snakeHead.style.transform = 'rotate(' + this.angle.rotate + 'deg)';
                continue;
            }
            //蛇节
            var object = this.body [i];
            //
            var div = document.createElement('div');
            map.appendChild(div);
            //记录当前蛇
            elements.push(div);
            //设置样式
            div.style.position = position;
            div.style.width = this.width + 'px';
            div.style.height = this.height + 'px';
            div.style.left = object.x * this.width + 'px';
            div.style.top = object.y * this.height + 'px';
            div.style.backgroundColor = object.color;
            div.style.borderRadius = '10px';
        }
    }
    //私有的成员
    function remove (){
        for (var i = elements.length - 1; i >= 0; i--){
            //删除div
            elements[i].parentNode.removeChild(elements[i]);
            //删除数组中的元素
            elements.splice(i, 1);
        }
    }
    //控制蛇移动的方法
    Snake.prototype.move = function (food, map){
        //控制蛇的身体移动,当前蛇节到上一个蛇节的位置
        for (var i = this.body.length - 1; i > 0; i--){
            this.body[i].x = this.body[i-1].x;
            this.body[i].y = this.body[i-1].y;
        }
        //控制蛇头的移动
        //判断蛇头的方向
        var head = this.body[0];
        switch (this.direction){
            case 'right':
                head.x += 1;               
                break;
            case 'left':
                head.x -= 1;                
                break;
            case 'top':
                head.y -= 1;               
                break;
            case 'bottom':
                head.y += 1;          
                break;
        }
        //2.4判断蛇头是否和食物的坐标重合
        var headX = head.x * this.width;
        var headY = head.y * this.height;
        if (headX === food.x && headY === food.y){
            //让蛇增加一节
            //获取蛇的最后一节
            var last = this.body[this.body.length - 1];
            this.body.push({
                x: last.x,
                y: last.y,
                color: last.color
            });
            //在地图上随机重新生成食物
            food.render(map);
            //分数加1
            this.score += 1;
            document.getElementById('score_value').innerHTML = this.score;
        }
    }
    //暴露构造函数给外部
    window.Snake = Snake;
})(window, undefined)

/*-----------------game.js----------------- */
//可以用自调用函数,开启一个新的作用域,避免全局作用域带来的命名冲突问题
;(function (window, undefined) {
    var that; //记录游戏对象
    function Game(map) {
        this.food = new Food();
        this.snake = new Snake();
        this.map = map;
        that = this;
    }
    Game.prototype.start = function () {
        //把蛇和食物对象渲染到地图上
        this.food.render(this.map);
        this.snake.render(this.map);
        //测试蛇移动
        // this.snake.move();
        // this.snake.render(this.map);
        // this.snake.move();
        // this.snake.render(this.map);
        // this.snake.move();
        // this.snake.render(this.map);
        //开始游戏的逻辑
        //2.1让蛇移动起来
        runSnake();
        //2.2当蛇遇到边界,游戏结束
        //2.2通过键盘控制蛇移动的方向
        bindKey();
        //2.4当蛇遇到食物,做相应的处理
    }
    //通过键盘控制蛇的移动
    function bindKey() {
        // document.onkeydown = function () {}
        document.addEventListener('keydown', function (e) {
            // console.log(e.keyCode);
            //37 - left
            //39 - up
            //39 - right
            //40 - down
            switch (e.keyCode) {
                case 37:
                    if (this.snake.direction != 'right'){   // 不允许返回,向右的时候不能向左
                        this.snake.direction = 'left';
                        this.snake.angle.rotate = 180;
                    }
                    break;
                case 38:
                    if (this.snake.direction != 'bottom'){
                        this.snake.direction = 'top';
                        this.snake.angle.rotate = -90;
                    }
                    break;
                case 39:
                    if (this.snake.direction != 'left'){
                        this.snake.direction = 'right';
                        this.snake.angle.rotate = 0;
                    }  
                    break;
                case 40:
                    if (this.snake.direction != 'top'){
                        this.snake.direction = 'bottom';
                        this.snake.angle.rotate = 90;
                    }
                    break;
            }
        }.bind(that), false);
    }
    //私有的函数,让蛇移动
    function runSnake() {
        var timerId = setInterval(function () {
            //让蛇走一格
            //在定时器的function中,this是指向window对象
            //要获取游戏对象中的蛇属性
            this.snake.move(this.food, this.map);
            this.snake.render(this.map);
            //2.2当蛇遇到边界,游戏结束
            //获取蛇头的坐标
            var maxX = this.map.offsetWidth / this.snake.width;
            var maxY = this.map.offsetHeight / this.snake.height;
            var headX = this.snake.body[0].x;
            var headY = this.snake.body[0].y;
            if (headX < 0 || headX >= maxX || headY < 0 || headY >= maxY) {
                alert('撞到边界了!Game Over');
                clearInterval(timerId);
            }
            // 吃到自己死亡,从第五个开始与头判断,因为前四个永远撞不到
            for (var i = 4; i < this.snake.body.length; i++) {
                if (this.snake.body[0].x === this.snake.body[i].x && this.snake.body[0].y === this.snake.body[i].y) {
                    alert("咬到自己啦!Game Over");
                    clearInterval(timerId);   // 清除定时器
                }
            }
        }.bind (that), 150);
    }
    //暴露构造函数给外部
    window.Game = Game;
})(window, undefined);

/*-----------------main.js----------------- */
;(function (window, undefined) {
    var map = document.getElementById('map');
    var game = new Game(map);
    game.start();
})(window, undefined)

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值