JavaScript+HTML 实现贪吃蛇简陋版

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

示例demo

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

效果图

效果图

实现原理

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

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

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

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

蛇的行动范围

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

蛇的位移

其实蛇移动比较容易理解,例如 向下移动的时候y轴坐标+1,x轴坐标不动 其他方向同理,这样就能实现蛇的整体位移


示例

看图比较容易看懂,就是蛇头以后得元素需要向之前的移动

蛇的成长

image.png

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

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

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

视图渲染
每次蛇的移动完成以后都生成一个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%;" onclick="handle('up')">上</div>
    <div style="display: flex;flex-direction: row;height: 60%;">
        <div class="center" onclick="handle('left')">左</div>
        <div class="center" onclick="handle('start')">重新开始</div>
        <div class="center" onclick="handle('right')">右</div>
    </div>
    <div class="center" style="height: 30%;" onclick="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>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • #史上最详细的C语言贪吃蛇教程 #前言 在有用C写贪吃蛇的一个想法之后,上网查了几个教程,觉得不是很能看懂。恩。。...
    iimT阅读 33,150评论 19 30
  • 每一个平凡的人都曾有过“功成名就”的梦想。一些人仅仅只是做梦,梦醒了还是该干啥干啥;另一些人梦醒了,又接着做...
    烽火煤阅读 141评论 0 0
  • 天气一下子就热了,感觉很是不能适应。其实明明已经过了数不尽个夏天,但是一下子的炎热袭来还是感觉像以前没过过夏天一样...
    清风伏笔阅读 325评论 2 1
  • 最怕你碌碌无为,还劝自己平凡可贵。 又开始准备考试,无形之中给了自己不小压力。本来想着可以投机取巧,却发现怀抱着不...
    周诗汶阅读 478评论 0 0