基于JS的贪吃蛇-附源码

前言

万年无更,突然想起来还有这个,分享一下

功能说明

仿照以前game boy的贪吃蛇游戏
先选择速度及地图大小,点击[play]开始
[上][下][左][右]控制移动.[Space]暂停
吃掉食物得分,碰撞身体及地图边缘则结束

在这里插入图片描述

页面主要包含两个对象

1.配置及分数显示区域
2.地图(含贪吃蛇主体+食物对象)

设计上比较关键的几个方法,在代码中有简单注释

1.地图生成及贪吃蛇对象初始化,速度控制等
2.贪吃蛇控制方法
3.食物生成算法
4.设计贪吃蛇队列,计算长度及位置
5.积分计算
6.碰撞方法(吃食物or碰撞自身or碰撞地图边缘)

详细代码

<html>
<style>

    select {
        width: 120px;
    }

    #table td {
        width: 10px;
        height: 10px;
        /*margin: 1px;*/
        background: #f7fff3;
    }

    #table td.snakeBody {
        background: #000000;
    }

    #table td.food {
        background: #ff0000;
    }

    #info td {
        color: white;
        background: #000000;
    }


</style>
<body id="body">
<table id="info">
    <tr>
        <td>
            <label>LEVEL:</label>
        </td>
        <td>
            <select id="level">
                <option value="1">1</option>
                <option value="2">2</option>
                <option value="3">3</option>
                <option value="4">4</option>
                <option value="5">5</option>
                <option value="6">6</option>
            </select>
        </td>
    </tr>
    <tr>
        <td>
            <label>Field:</label>
        </td>
        <td>
            <select id="field">
                <option value="20_20">min(20*20)</option>
                <option value="50_50">normal(50*50)</option>
                <option value="80_80">max(80*80)</option>
            </select>
        </td>
    </tr>
    <tr>
        <td>
            <label>Source:</label>
        </td>
        <td>
            <p id="source">0</p>
        </td>
    </tr>
    <tr>
        <td colspan="2" style="text-align:center">
            <button onclick="refresh()" style="width: 120px;">Play</button>
        </td>
    </tr>
</table>
</body>
<html>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>


    /**
     * 指定背景和初始化操作
     * @param w  宽(格字数)
     * @param h  高(格字数)
     * @param level  级别(格字数)
     * @constructor
     */
    function Field(w, h, level) {
        //清除所有
        $("#table").remove();
        //默认宽20格
        this.width = w ? w : 20;
        //默认高20格
        this.height = h ? h : 20;
        //级别
        this.level = level ? level : 1;
        //贪吃蛇队列
        this.snakeQueue;
        //当前行进方向
        this.aspect = "right";
        //下一个行进方向
        this.nextAspect = "right";
        //蛇头坐标
        this.snakeHead = {"x": 3, "y": 1};


        //显示
        this.show = function () {
            //创建活动区域table
            $("#body").append("<table id='table' style='border: #0C0C0C solid 1px'></table>");
            var table = $("#table");
            for (var i = 1; i <= this.height; i++) {
                $(table).append("<tr id='tr_" + i + "'></tr>");
                var tr = $("#tr_" + i);
                for (var j = 1; j <= this.width; j++) {
                    $(tr).append("<td id='tr_" + i + "td_" + j + "' x='" + j + "' y='" + i + "'></td>");
                    $("#tr_" + i + "td_" + j);
                }
                $(table).append(tr);
            }
            //初始化蛇
            this.initSnake();
            //初始化第一个食物
            this.food();
        };

        //初始化蛇
        this.initSnake = function () {
            this.snakeQueue = new SnakeQueue(null);
            this.snakeQueue.push({"x": 1, "y": 1});
            this.snakeQueue.push({"x": 2, "y": 1});
            this.snakeQueue.push({"x": 3, "y": 1});
        };

        //判断移动后的坐标是否合法
        this.check = function (position) {
            var x = parseInt(position.x);
            var y = parseInt(position.y);
            //超出了边界
            if (x < 1 || y < 1 || x > this.width || y > this.height) {
                return false;
            }
            //碰撞了身体
            if ($("#tr_" + y + "td_" + x).hasClass("snakeBody")) {
                return false;
            }
            return true;
        };


        this.move = function (aspect) {
            //暂停判断
            if(stop) return;
            //判断方向和原方向相反,则按原方向前进
            if ((aspect == "up" && this.aspect == "down") ||
                (aspect == "down" && this.aspect == "up") ||
                (aspect == "left" && this.aspect == "right") ||
                (aspect == "right" && this.aspect == "left")) {
                //撤销下一方向,按原方向前进
                this.nextAspect = this.aspect;
                aspect=this.aspect;
            }
            //蛇头坐标
            var x = parseInt(f.snakeHead.x);
            var y = parseInt(f.snakeHead.y);
            //新坐标
            var position;
            switch (aspect) {
                case "up":
                    position = {"x": x, "y": y - 1};
                    break;
                case "down":
                    position = {"x": x, "y": y + 1};
                    break;
                case "right":
                    position = {"x": x + 1, "y": y};
                    break;
                case "left":
                    position = {"x": x - 1, "y": y};
                    break;
            }
            //校验新坐标是否合法
            if (!this.check(position)) {
                over = true;
                alert("YOU DIE!");
                return;
            }
            //更新方向
            this.aspect = aspect;
            //更新头坐标
            this.snakeHead = position;
            //将新的坐标加入队列
            this.snakeQueue.push(position);
            //如果吃到食物,则长度+1,重新刷新食物节点
            if($("td.food").attr("id")=="tr_"+position.y+"td_"+position.x){
                $("td.food").removeClass("food");
                this.food();
                //得分+1
                var source = parseInt($("#source")[0].innerText);
                $("#source")[0].innerText=source+1;
            }else{
                //如果没有吃到食物,则需要从队列中减掉一个
                this.snakeQueue.pop();
            }
        };

        //刷新食物
        this.food=function(){
            //获取剩余空白节点
            var emptyTd = $("#table td:not(.snakeBody)");
            // 获取一个范围内的随机数
            var random = parseInt(1 + (emptyTd.length) * (Math.random()));
            //食物
            var foodTd = emptyTd[random];
            $(foodTd).addClass("food");
        };

        this.stop=function () {
            stop=!stop;
        }

    }


    /**
     * 定义贪吃蛇队列
     * @param {[Int]} size [队列大小]
     */
    function SnakeQueue(size) {
        var list = [];

        //向队列中添加数据
        this.push = function (data) {
            if (data == null) {
                return false;
            }
            //如果传递了size参数就设置了队列的大小
            if (size != null && !isNaN(size)) {
                if (list.length == size) {
                    this.pop();
                }
            }
            list.unshift(data);
            //新加入的节点,增加标志位和颜色
            $("#tr_" + data.y + "td_" + data.x).addClass("snakeBody");
            return true;
        };

        //从队列中取出数据
        this.pop = function () {
            var data = list.pop();
            //移除节点的标志位和颜色
            $("#tr_" + data.y + "td_" + data.x).removeClass("snakeBody");
            return data;
        };

        //返回队列的大小
        this.size = function () {
            return list.length;
        };

        //返回队列的内容
        this.queue = function () {
            return list;
        }
    }


    /**
     * 初始化
     */
    function refresh() {
        over = false;
        stop = false;
        //获取活动区域大小
        var area = $("#field").val().split("_");
        var w = parseInt(area[0]);
        var h = parseInt(area[1]);
        //获取速度级别
        var level = parseInt($("#level").val());
        //重置区域
        f = new Field(w, h, level);
        f.show();
        //重置计时器
        clearInterval(timer);
        timer = window.setInterval("if(!over&&!stop) f.move(f.nextAspect);", 1000/f.level);
        //指定焦点
        $("#table").focus();
    }


    //定义活动区域
    var f;
    //定义计时器
    var timer;
    //结束标志
    var over = false;
    //暂停标志
    var stop=false;

    //定时器,游戏未结束的情况下,每0.5s向下移动方块
    var timer;
    //键盘监听
    document.onkeydown = function (e) {
        if (over) return;
        var e = window.event ? window.event : e;
        switch (e.keyCode) {
            case 38: //up
                f.nextAspect ="up";//延时转向
                //f.move("up");//立即转向
                break;
            case 40: //down
                f.nextAspect ="down";//延时转向
                //f.move("down");//立即转向
                break;
            case 37: //left
                f.nextAspect ="left";//延时转向
                //f.move("left");//立即转向
                break;
            case 39: //right
                f.nextAspect ="right";//延时转向
                //f.move("right");//立即转向
                break;
            case 32: //空格键暂停,开始
                f.stop();
                break;
        }
    }
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值