LOADING

JavaScript之贪吃的滑稽

这玩意光修bug都花了三小时 :kano-2d-19: 最终还是做出来了

效果(WASD操控)

代码

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>贪吃蛇</title>
    <link rel="stylesheet" href="./css/style.css">
    <style>
        body {
            padding: 0;
            margin: 0;
            overflow: hidden;
        }

        .map {
            position: relative;
            background-color: #313131;
            width: 100vw;
            height: 100vh;
        }

        .map .snake,
        .map .food {
            position: absolute;
            z-index: 1;
            display: block;
            width: 20px;
            height: 20px;
            background-color: red;
            border-radius: 50%;
            overflow: hidden;
            transition: all 1s;
        }

        #start {
            z-index: 10000;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            width: 140px;
            height: 40px;
            background-color: #00AEEC;
            border: none;
            border-radius: 20px;
            color: #eee;
            position: absolute;
        }

        #start:active {
            background-color: #00a1ec;
        }

        .snake:nth-child(2) {
            z-index: 111;
            transform: scale(1.5);
            background-image: url(data:image/png;base64,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);
            background-size: contain;
        }

        .sad {
            background-image: url(data:image/png;base64,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) !important;
        }

        .map .food {
            left: 30px;
            transform: translate(50%, 50%);
            background-image: url(data:image/png;base64,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);
            background-size: contain;
        }
    </style>
</head>

<body>
    <button id="start">开始游戏</button>
    <div class="map">

        <!-- <span class="snake"></span> -->
    </div>
    <script>
        //随机工具类
        var Tools = {
            getRandom: function(min, max) {
                //min和max都能取到
                return Math.floor(Math.random() * (Math.floor(max) - Math.ceil(min) + 1)) + min
            }

        };
    </script>
    <script>
        //独立作用域
        (() => {
            //记录上次创建的食物
            let elements = [];

            // 食物对象
            function Food(options) {
                //防止传参为空
                options = options || {};
                this.x = options.x || 0;
                this.y = options.y || 0;
                this.width = options.width || 40;
                this.height = options.height || 40;

                this.color = options.color || 'transparent';
            }
            //渲染食物
            Food.prototype.render = function(map) {
                //删除之前创建的食物
                remove();
                //随机设置食物位置
                this.x = Tools.getRandom(0, (map.offsetWidth / this.width - 1) * this.width);
                this.y = Tools.getRandom(0, (map.offsetHeight / this.height - 1) * this.height);

                //动态创建元素,我选择用span来显示食物
                let span = document.createElement('span');
                //设置样式s
                span.style.left = this.x + 'px';
                span.style.top = this.y + 'px';
                span.style.backgroundColor = this.color;
                span.classList.add('food');
                map.appendChild(span);

                //保存食物
                elements.push(span);
            };

            //删除食物
            function remove() {
                while (elements.length > 0) {
                    elements[elements.length - 1].parentNode.removeChild(elements[elements.length - 1]);
                    elements.splice(elements.length - 1, 1);
                }
            }
            //把构造函数添加到window对象下,外部就可以访问了
            window.Food = Food;
        })();
    </script>
    <script>
        //蛇对象
        (() => {
            //记录上次创建的蛇
            let elements = [];

            function Snake(options) {
                //防止传参为空
                options = options || {};
                //蛇节
                this.width = options.width || 20;
                this.height = options.height || 20;
                //蛇的移动方向
                this.direction = options.direction || 'right';
                //蛇身
                this.body = [{
                    x: 12,
                    y: 2,
                    color: 'transparent'
                }, {
                    x: 11,
                    y: 2,
                    color: `rgba(${Tools.getRandom(0,255)},${Tools.getRandom(0,255)},${Tools.getRandom(0,255)},1)`
                }, ];

            };
            //渲染
            Snake.prototype.render = function(map) {
                //删除之前创建的蛇
                remove();
                //渲染蛇节
                for (let i = 0, len = this.body.length; i < len; i++) {
                    //蛇节
                    let obj = this.body[i];

                    //创建元素
                    let span = document.createElement('span');
                    //设置样式
                    span.style.width = this.width + 'px';
                    span.style.height = this.height + 'px';
                    //obj.x * this.width 表示x个蛇节宽度这么多的距离
                    span.style.left = (obj.x * this.width) + 'px';
                    span.style.top = (obj.y * this.height) + 'px';
                    span.style.backgroundColor = obj.color;
                    span.classList.add('snake');
                    map.appendChild(span);
                    elements.push(span);
                }
            };
            //删除蛇方法
            function remove() {
                while (elements.length > 0) {
                    elements[elements.length - 1].parentNode.removeChild(elements[elements.length - 1]);
                    elements.splice(elements.length - 1, 1);
                }
            }
            //蛇移动
            Snake.prototype.move = function(food, map) {
                //控制蛇的身体移动(当前蛇节到上一个蛇节的位置)
                for (let 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;
                }
                //控制蛇头的移动
                //判断蛇移动的方向
                let head = this.body[0];

                switch (this.direction) {
                    case 'right':
                        head.x += 0.2;
                        break;
                    case 'left':
                        head.x -= 0.2;
                        break;
                    case 'up':
                        head.y -= 0.2;
                        break;
                    case 'down':
                        head.y += 0.2;
                        break;
                }
                //判断蛇头是否在食物的坐标范围内
                let snakeX = (head.x * (this.width))
                let snakeY = (head.y * (this.height));
                let leftPaddingIsTrue = ((snakeX >= food.x) && (snakeX <= (food.x + food.width))) && ((snakeY >= food.y) && (snakeY <= (food.y + food.height)))
                let rightPaddingIsTrue = ((snakeX + this.width / 2 >= food.x) && (snakeX + this.width / 2 <= (food.x + food.width))) && ((snakeY + this.height / 2 >= food.y) && (snakeY + this.height / 2 <= (food.y + food.height)))
                if (leftPaddingIsTrue || rightPaddingIsTrue) {
                    //蛇加一节
                    //复制蛇的最后一节
                    let lastNode = this.body[this.body.length - 1];
                    for (let i = 0; i < 10; i++) {
                        this.body.push({
                            x: lastNode.x,
                            y: lastNode.y,
                            color: `rgba(${Tools.getRandom(0,255)},${Tools.getRandom(0,255)},${Tools.getRandom(0,255)},.7)`
                        });
                    }

                    //随机在地图上增加食物
                    food.render(map);
                }

            }

            //把构造函数添加到window对象下,外部就可以访问了
            window.Snake = Snake;
        })();
    </script>
    <script>
        //主游戏对象
        (() => {
            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);
                runSnake();
                //开始游戏逻辑
                //让蛇动起来
                //通过键盘控制蛇移动的方向
                //当蛇遇到食物 做相应的处理
                //当蛇遇到边界游戏结束
            };
            //让蛇润起来
            function runSnake() {
                var timer = setInterval(function() {
                    //这里请注意this指向
                    that.snake.move(that.food, that.map);
                    that.snake.render(that.map);
                    //当蛇遇到边界游戏结束
                    //只需要判断蛇头的坐标即可
                    let headX = that.snake.body[0].x;
                    let headY = that.snake.body[0].y;
                    let maxX = Math.floor(that.map.offsetWidth / that.snake.width) - 0.5;
                    let maxY = Math.floor(that.map.offsetHeight / that.snake.height) - 0.5;
                    if (headX >= maxX || headY >= maxY) {
                        //设置异步,避免alert卡帧
                        setTimeout(() => {
                            // alert('你创到墙啦,游戏结束');
                            document.querySelector('.snake:nth-child(2)').classList.add('sad');
                            btn.style.display = 'block';
                        }, 100);
                        clearInterval(timer);
                    }
                    if (headX <= 0 || headY <= 0) {
                        setTimeout(() => {
                            // alert('你创到墙啦,游戏结束');
                            document.querySelector('.snake:nth-child(2)').classList.add('sad');
                            btn.style.display = 'block';
                        }, 100);
                        clearInterval(timer);
                    }
                    //判断是否吃到了自己
                    snakeBody = that.snake.body;
                    for (let i = 1; i < snakeBody.length; i++) {
                        if ((snakeBody[0].x == snakeBody[i].x) && (snakeBody[0].y == snakeBody[i].y)) {
                            setTimeout(() => {
                                // alert('你咬到自己啦,游戏结束');
                                document.querySelector('.snake:nth-child(2)').classList.add('sad');
                            }, 100);
                            //clearInterval(timer);
                            break;
                        }
                    }
                }, 10);
            }
            //蛇控制
            function keyControl() {
                document.addEventListener('keyup', function(e) {
                    switch (e.code) {
                        case 'KeyD':
                            //蛇不能180度掉头
                            if (that.snake.direction != 'left') {
                                that.snake.direction = 'right';
                            }
                            break;
                        case 'KeyA':
                            if (that.snake.direction != 'right') {
                                that.snake.direction = 'left';
                            }
                            break;
                        case 'KeyS':
                            if (that.snake.direction != 'up') {
                                that.snake.direction = 'down';
                            }
                            break;
                        case 'KeyW':
                            if (that.snake.direction != 'down') {
                                that.snake.direction = 'up';
                            }
                            break;
                    }
                }, false); //事件冒泡

            }
            keyControl();
            //当蛇遇到食物 做相应的处理
            window.Game = Game;
        })();
    </script>
    <script>
        var btn = document.querySelector('#start');
        btn.addEventListener('click', function() {
            this.style.display = 'none';
            var map = document.querySelector('.map');
            var game = new Game(map);
            game.start();
        })
    </script>
</body>

</html>

    发表回复

    电子邮件地址不会被公开。必填项已用 * 标注