JavaScript+HTML 实现贪吃蛇简陋版

有一天午睡突然突发奇想写个贪吃蛇玩一玩,一开始是想用c来写,然后弄一个8*8的点阵屏来玩的,但是又觉得太过于麻烦,所以就想着用最简单的方法来实现,所以就选择了JavaScript和HTML来实现,简述一下实现原理和提出代码

示例demo

snake-game
建议用手机打开,当然电脑也做了上下左右键盘控制,但是显示效果是为了手机显示适应的

效果图

效果图

实现原理

我觉得弄这个需要一点点的面相对象的思维就能简简单单的实现,首先我们需要有一个地图,所以就需要在这个地图上建立坐标系,不让我们的贪吃蛇抛出我们的坐标系,所以我就选择了二维数组来建立我们的坐标系,然后给每个坐标都设定一个值(我设定的就是x轴左边加y轴坐标的字符串),然后我们还需要一条贪吃蛇,和砖块,这里其实可以看成一部分,其实砖块就是我们坐标里面对应的值,而我们的贪吃蛇就是这个砖块的数组,所以我们可以理解成以下样子

地图:
一个二维数组
贪吃蛇
一个包含在地图里面的一维数组 ==> 多个砖块的拼接组成的一个数组
砖块
一个地图里面对应的准确的值

所以看到这里就很简单了,所谓的贪吃蛇其实就是在操作我们熟知的数组

上述的是我们游戏里面涉及到的元素,接下来我们讲讲我们涉及到的一些动作

蛇的行动范围

这个其实很简单,主要就是对蛇头做判断(数组第一个),只要蛇头不大于地图数组,游戏便可以继续下去

蛇的位移

其实蛇移动比较容易理解,例如 向下移动的时候y轴坐标+1,x轴坐标不动 其他方向同理,这样就能实现蛇的整体位移
示例
看图比较容易看懂,就是蛇头以后得元素需要向之前的移动

蛇的成长

示例

这里我们有使用数据结构中比较高级的插入方式,使用了我比较喜欢的渣渣方式,就是直接在数组的后面添加一个元素,实现蛇吃砖块长大的方式

砖块的随机生成
这里需要确保不会和我门蛇的数组位置冲突,需要做一些判断

蛇吃自己
这里只需要判断蛇里面没有重复的元素便可以了

视图渲染
每次蛇的移动完成以后都生成一个0和1组成的二维数组,遍历数组为HTML添加颜色就可以了

写在最后
其实实现起来远比我说明的这些要容易的多,毕竟我是一个喜欢讲废话的人,我个人觉得看了代码就知道这个东西确实是挺简单的

代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="user-scalable=0">
    <title>snake game</title>
    <style>
        * {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
        }

        #score {
            font-size: 300%;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        #handle {
            display: flex;
            flex-direction: column;
            overflow: hidden;
            font-size: 150%;
        }

        .game-row {
            display: flex;
            flex-direction: row;
        }

        .game-column {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: space-between;
            border: 1px #ce53d2 solid;
        }

        .game-column-snake {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: space-between;
            border: 1px #ce53d2 solid;
            background: black;
        }

        .game-column-block {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: space-between;
            border: 1px #ce53d2 solid;
            background: lightgreen;
        }

        .center {
            display: flex;
            align-items: center;
            justify-content: center;
        }
    </style>
</head>
<body id="body" style="display: flex;flex-direction: column">
<div id="score">分数</div>
<div id="game"></div>
<div id="handle">
    <div class="center" style="height: 30%;" "handle('up')">上</div>
    <div style="display: flex;flex-direction: row;height: 60%;">
        <div class="center" "handle('left')">左</div>
        <div class="center" "handle('start')">重新开始</div>
        <div class="center" "handle('right')">右</div>
    </div>
    <div class="center" style="height: 30%;" "handle('down')">
        下
    </div>
</div>
</body>
<script>
    var w = 0,//页面的宽度
        h = 0,//页面的高度
        block = '00',//砖块
        snake = [],//蛇
        map = [], //实际坐标系
        xy = [],//渲染坐标系
        hanld = 'right', //走动方向
        mapSize = 10, //地图大小
        score = 0,//游戏积分
        level = 500,//游戏等级,默认是800毫秒走一次
        endflag = false,
        runStatus = 0;//自动运行标记
    main();

    /**
     * 主方法
     */
    function main() {
        initShow();
        initMap();
        genSnake();
        genBlock();
        gen01();
        next();
    }

    /**
     * 初始化页面信息
     */
    function initShow() {
        //获取body的高度和宽度
        var dom = document.getElementById("body");
        w = dom.offsetWidth, h = dom.offsetHeight;
        var h_w = h - w;
        //自适应分数显示区域的高度
        var score = document.getElementById('score');
        score.style.height = parseInt(h_w) * 0.2 + 'px';
        //自适应操作示区域的高度
        var handle = document.getElementById('handle');
        handle.style.height = parseInt(h_w) * 0.8 + 'px';
        //自适应游戏区域的高度和宽度
        var game = document.getElementById('game');
        game.style.width = parseInt(w) + 'px';
        game.style.height = parseInt(w) + 'px';
    }

    /**
     *初始化地图
     */
    function initMap() {
        for (var x = 0; x < mapSize; x++) {
            map[x] = [];
            for (var y = 0; y < mapSize; y++) {
                map[x][y] = splitStr(y, x);
            }
        }
    }

    /**
     * 生成随机数
     * @param filter 需要过滤掉的数字
     * @returns {number}
     */
    function rand(filter) {
        var rand = parseInt(Math.random() * 10);
        if (rand == filter) {
            rand(filter);
        }
        return rand;
    }

    /**
     * 将坐标系转换成0/1的数组
     */
    function gen01() {
        var overflag = false;
        for (var i = 0; i < mapSize; i++) {
            xy[i] = [];
            for (var j = 0; j < mapSize; j++) {
                xy[i][j] = 0;
                for (var s = 0; s < snake.length; s++) {
                    if (snake[s] == map[i][j]) {
                        xy[i][j] = 1;
                        break;
                    }
                }
                if (block == map[i][j]) {
                    xy[i][j] = 2;
                }
                if (snake[0] == map[i][j]) {
                    overflag = true;
                }
            }
        }
        if (!overflag) {
            //游戏结束
            showover();
        } else {
            if (!endflag) {
                //生成进制以后就将数据渲染到HTML中去
                show(xy);
            }
        }
    }

    /**
     * 生成小蛇
     */
    function genSnake() {
        snake.push(splitStr(rand(), rand()));
    }

    /**
     * 生成随机砖块
     */
    function genBlock() {
        block = splitStr(rand(), rand());
        //确保生成砖块不会生成到和蛇一样的,否则就重新生成
        for (var i in snake) {
            if (block == snake[i]) {
                genBlock();
            }
        }
    }

    /**
     * 蛇向下一步移动
     */
    function next() {
        clearTimeout(runStatus);
        changeSnakeHead();
        eatself();
        eatblock();
        gen01();
        runStatus = setTimeout(function () {
            next();
        }, level);
    }


    /**
     * 判断蛇是否吃自己
     */
    function eatself() {
        for (var s = 0; s < snake.length; s++) {
            if (s > 0 && snake[s] == snake[0]) {
                showover();
                break
            }
        }
    }

    /**
     * 修改蛇的身体
     */
    function changeSnakeHead() {
        var tempa = snake[0];
        for (var i = 0; i < snake.length; i++) {
            var a = snake[i][0], b = snake[i][1];
            if (i == 0) {
                switch (hanld) {
                    case 'up':
                        snake[i] = splitStr(a, parseInt(b) - 1);
                        break;
                    case 'down':
                        snake[i] = splitStr(a, parseInt(b) + 1);
                        break;
                    case 'left':
                        snake[i] = splitStr(parseInt(a) - 1, b);
                        break;
                    case 'right':
                        snake[i] = splitStr(parseInt(a) + 1, b);
                        break;
                }
            } else {
                var tempb = tempa;
                tempa = snake[i];
                snake[i] = tempb;
            }
        }
    }

    /**
     * 吃砖块
     */
    function eatblock() {
        if (snake[0] == block) {
            var tail = snake[snake.length - 1], temp = [], a = tail[0], b = tail[1];
            switch (hanld) {
                case 'up':
                    temp = splitStr(a, parseInt(b) + 1);
                    break;
                case 'down':
                    temp = splitStr(a, parseInt(b) - 1);
                    break;
                case 'left':
                    temp = splitStr(parseInt(a) + 1, b);
                    break;
                case 'right':
                    temp = splitStr(parseInt(a) - 1, b);
                    break;
            }
            snake.push(temp);
            addscore();
            genBlock();
        }
    }

    /**
     *  修改蛇的身体结构
     * @param x
     * @param y
     */
    function splitStr(x, y) {
        return x + '' + y;
    }


    /**
     * 键盘按下事件绑定
     */
    document.onkeydown = function (e) {
        var e = window.event || e;
        switch (e.keyCode) {
            case 37: //左
                hanld = hanld != 'left' && hanld != 'right' ? 'left' : hanld;
                break;
            case 38: //上
                hanld = hanld != 'up' && hanld != 'down' ? 'up' : hanld;
                break;
            case 39:  //右
                hanld = hanld != 'left' && hanld != 'right' ? 'right' : hanld;
                break;
            case 40:  //下
                hanld = hanld != 'up' && hanld != 'down' ? 'down' : hanld;
                break;
        }
    }

    /**
     * 按键事件处理
     */
    function handle(e) {
        if (e == 'start') {
            if (endflag) {
                //只有输掉游戏才能重新开始游戏
                window.location.reload();
            }
        } else {
            if ((hanld == 'left' || hanld == 'right')) {
                if (e == 'up' || e == 'down') {
                    hanld = e;
                }
            } else {
                if (e == 'left' || e == 'right') {
                    hanld = e;
                }
            }
        }
    }

    /**
     * 添加游戏积分,目前的积分就是蛇的长度
     */
    function addscore() {
        var score = parseInt(snake.length) - 1;
        //根据游戏得分修改游戏等级,一共分五个等级,
        if (score > 20) {
            level = 250;
        } else if (score > 15) {
            level = 300;
        } else if (score > 10) {
            level = 350;
        } else if (score > 5) {
            level = 400;
        } else if (score > 1) {
            level = 450;
        } else {
            level = level;
        }
        document.getElementById('score').innerHTML = '分数:' + score;
    }

    /**
     * 将数据渲染在页面上去
     * @param xy
     */
    function show(xy) {
        var html = '',
            height = parseInt(w) / mapSize;
        for (var i = 0; i < mapSize; i++) {
            html += '<div class="game-row" style="height:' + height + 'px;">'
            for (var j = 0; j < mapSize; j++) {
                if (xy[i][j] == 1) {
                    html += '<div class="game-column-snake"></div>';
                } else if (xy[i][j] == 2) {
                    html += '<div class="game-column-block"></div>';
                } else {
                    html += '<div class="game-column"></div>';
                }

            }
            html += '</div>';
        }
        document.getElementById('game').innerHTML = html;
    }

    /**
     * 游戏结束
     */
    function showover() {
        document.getElementById('game').innerHTML = '<h1 align="center" style="font-size: 500%;color:red;">game over!</h1>';
        endflag = true;
    }


</script>
</html>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值