js小游戏贪吃蛇

介绍一个由本人制作的贪吃蛇小游戏。这个游戏采用了前端BootStrap框架和jQuery框架,因此移动端和电脑端都能兼容。虽然界面比较简陋,但是基本功能比较齐全,如果有bug欢迎各位能给我提出来,希望大家能喜欢这个小游戏!


项目结构:


虽然是个动态web项目,但我是用纯前端技术完成的,只是使用的工具是eclipse而已,大家大可放心运行在自己的浏览器上。

运行效果

注意,历史最高分我采用了webstorage,所以可以做到数据持久化,但有的浏览器可能不支持,我也没有继续深究下去。音效功能尚未实现,有兴趣的读者可以实现一下。

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<link href="css/bootstrap.min.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="bootstrap.min.js"></script>
<script type="text/javascript" src="my.js"></script>
<style type="text/css">
    #tab{
        background-color:black;
        margin: 0;
    }   
    .glyphicon{
        font-size:150%;
    }
   
</style>


</head>
<body >
<div class="container-fluid">
    <!--标题面板行-->
    <div class="row bg-primary">
        <div class="col-xs-12">
            <h1 class="text-center">贪吃蛇</h1>
        </div>
    </div>
    
    <!--记录面板行-->
    <div class="row bg-info">
        <!--历史记录行-->
        <div class="row">
            <div class="col-xs-6">
                <span class="h1">历史记录</span>    
            </div>
            <div class="col-xs-4 col-xs-offset-2">
                <span id="his-score" class="h1">00</span>   
            </div>
        </div>
         
        <!--本次得分行-->  
        <div class="row">
            <div class="col-xs-6">
                <span class="h1">本次得分</span>    
            </div>
            <div class="col-xs-4 col-xs-offset-2">
                <span id="cur-score" class="h1">00</span>   
            </div>
        </div>
    </div>

<!--游戏面板行-->
    <div class="row">
        <!--22行20列-->
        <table id="tab" class="table table-bordered">
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
            
            
        </table>
        
    </div>
    
    <!--功能面板行-->
    <div class="row bg-info">
        <!--功能按钮列-->
        <div class="col-xs-8 row">
            <div class="col-xs-2">
                <button id="start-game" class="btn btn-primary">重新开始</button>
                <button id="pause" class="btn btn-danger"><span class="glyphicon glyphicon-pause"></span></button>
            </div>
            
            <div class="col-xs-2 col-xs-offset-4">
                <button class="btn btn-info">
                <span>音效&nbsp;</span><span class="glyphicon glyphicon-volume-up"></span>
                </button>
                <div class="btn-group dropup">
                    <button class="btn btn-success" data-toggle="dropdown">
                    <span id="speed-span">中</span><span class="caret"></span>
                    </button>
                    <ul id="speed-menu" class="dropdown-menu" style="min-width:50px">
                        <li class="text-center">快</li>
                        <li class="text-center">中</li>
                        <li class="text-center">慢</li>
                    
                    </ul>
                
                
                </div>
            </div>
        </div>
        <!--方向按钮列-->
        <div class="col-xs-4">
            <!--向上按钮,独占一行-->
            <div class="row">
                <div class="col-xs-4 col-xs-offset-4">
                    <button id="up" type="button" class="btn">
                        <span class="glyphicon glyphicon-triangle-top"></span>
                    </button> 
                </div>
            </div>
            <!--向左和向右按钮,占一行-->
            <div class="row">
                <div class="col-xs-2">
                    <button id="left" type="button" class="btn">
                        <span class="glyphicon glyphicon-triangle-left"></span>
                    </button> 
                </div>
                <div class="col-xs-2 col-xs-offset-5">
                    <button id="right" type="button" class="btn">
                        <span class="glyphicon glyphicon-triangle-right"></span>
                    </button> 
                </div>
            </div>
            
            <!--向下按钮,独占一行-->
            <div class="row">
                <div class="col-xs-4 col-xs-offset-4">
                    <button id="down" type="button" class="btn">
                        <span class="glyphicon glyphicon-triangle-bottom"></span>
                    </button> 
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

my.js

var px;//蛇身x坐标数组
    var py;//蛇身y坐标数组
    var nt;//蛇身作一次运动后的新头坐标数组
    var ow;//蛇身作一次运动后的旧尾坐标数组
    var ot;//蛇身作一次运动后的旧头坐标数组
    var l;//蛇身长度
    var fx;//食物x坐标
    var fy;//食物y坐标
    var flag;//表示生成的随机食物是否与蛇身重复的标志
    var d;//表示当前蛇身运动方向
    var timer;//蛇身运动的定时器
    var flag1;//表示蛇头坐标是否和蛇身坐标出现重复的标志
    var score;//分数,吃一个食物加10分
    var hisScore;//历史最高分
    var speed;
    //返回一个随机数
    function getRandom(a){
    return Math.floor(Math.random()*a);
   
    }
    //生成与蛇身不重复的随机食物
    function getFood(){
   
    do{
        //获取食物坐标
        fx=getRandom(19);
            fy=getRandom(21);
            flag=0;//表示食物与蛇身不重复
            for(var i=0;i<l;i++){
            //逐一判断是否有重复
            
                if(px[i]==fx && py[i]==fy){
                flag=1;//表示食物与蛇身重复了
                break;
                }       


            }
        }while(flag==1);
   
    $("tr:eq("+fy+")>td:eq("+fx+")").css("background-color","red");
   
    }
    
    //判断蛇头是否撞墙或者撞自己
    function isDead(){
    flag1=0;
    //判断蛇头是否撞了自己
    for(var i=1;i<l;i++){
    if(px[0]==px[i] && py[0]==py[i]){
    flag1=1;//出现重复,表示蛇头撞到了蛇身
    break;
    }
    }
    //判断蛇头是否撞墙或撞了自己
    if(px[0]<0 || px[0]>19 || py[0]<0 || py[0]>21 || flag1==1){
    endGame();
    return true;
    }
   
   
    }
    //结束游戏
    function endGame(){
    //移除蛇身运动定时器
window.clearInterval(timer);
alert('游戏结束')
//消除已经死掉的蛇身
for(var i=0;i<l;i++){
        $("tr:eq("+py[i]+")>td:eq("+px[i]+")").css("background-color","black");
        }
//消除未吃掉的食物
    $("tr:eq("+fy+")>td:eq("+fx+")").css("background-color","black");
       
    


        //数据持久化

        if(score>parseInt(localStorage.getItem("key"))){
            window.localStorage.setItem("key",String(score));
        }        
        //一次游戏结束,初始化游戏
init();
    }
    //判断蛇头是否吃到食物
    function isEat(){
    if(px[0]==fx && py[0]==fy){
            //加分
            score+=10;
            $("#cur-score").text(score);
            //蛇身要加1
            l++;
            //蛇身长一节,思路是让已经被去掉的旧尾再回来
        $("tr:eq("+ow[1]+")>td:eq("+ow[0]+")").css("background-color","white");


            //蛇身x坐标数组添加新蛇尾x坐标
            px.push(ow[0]);
            //蛇身y坐标数组添加新蛇尾y坐标
            py.push(ow[1]);
          //表示吃到了食物,获取新的随机食物
    getFood();
    }
   
    }
    //蛇身作一次运动
    function runOnce(){
    //根据四种不同的运动方向获得新头坐标数组
    if(d=='left'){
    nt=[px[0]-1,py[0]];
    }else if(d=='right'){
    nt=[px[0]+1,py[0]];
    }else if(d=='up'){
    nt=[px[0],py[0]-1];
    }else{
    nt=[px[0],py[0]+1];
    }

//旧尾坐标数组
ow=[px[l-1],py[l-1]];
//旧头坐标数组
ot=[px[0],py[0]];
//刷新蛇身x坐标数组、y坐标数组

px.pop();
py.pop();
px.unshift(nt[0]);
py.unshift(nt[1]);

//去掉旧尾
    $("tr:eq("+ow[1]+")>td:eq("+ow[0]+")").css("background-color","black");
//如果蛇死了,就不要让后面的代码继续执行,否则会出bug
if(isDead()==true){

return;
}

//注意,要先去尾再显头,否则特殊情况下没效果


//显示新头
$("tr:eq("+py[0]+")>td:eq("+px[0]+")").css("background-color","green");
//旧头由绿变白
$("tr:eq("+ot[1]+")>td:eq("+ot[0]+")").css("background-color","white");
isEat();



   
    }
    //重新开始游戏
    function restart(){
    var a=window.confirm('确定开始新的游戏?');
        if(a==true){
        endGame();
        } 
    }
    
    //暂停游戏
    function pause(){
   
    if($("#pause>span").hasClass("glyphicon-pause")){
    //移除定时器
    window.clearInterval(timer);
    //改变图标
    $("#pause>span").removeClass("glyphicon-pause");
    $("#pause>span").addClass("glyphicon-play");
    //暂定状态下重新启用速度下拉菜单事件
    changeSpeed();
   
    }else{
    //重新上定时器
    timer=window.setInterval(function(){
        runOnce();
       
        }, speed);
    //改变图片
    $("#pause>span").removeClass("glyphicon-play");
    $("#pause>span").addClass("glyphicon-pause");
    //移除速度下单菜单事件
        $('#speed-menu>li').each(function(){
    $(this).unbind();
    });
    }
    }
    //蛇身运动
    function run(){
    //改变重新开始按钮绑定的事件
    $("#start-game").unbind();
    $("#start-game").bind("click",restart);
    //给暂停按钮绑定事件
    $("#pause").bind("click",pause);


    //移除速度下单菜单事件
    $('#speed-menu>li').each(function(){
$(this).unbind();
});
    timer=window.setInterval(function(){
    runOnce();
   
    }, speed);
   
   
    }
    
    //改变蛇身运动方向
    function changeFx(a){
    //将传过来的方向参数赋给d
    d=a;
    //根据具体的蛇身运动方向动态地给方向按钮绑定或解绑事件
    if(d=='left' || d=='right'){
        $("#left").unbind();
        $("#right").unbind();
        $("#up").bind("click",function(){changeFx('up')});
        $("#down").bind("click",function(){changeFx('down')});


    }else{
    $("#left").bind("click",function(){changeFx('left')});
        $("#right").bind("click",function(){changeFx('right')});
        $("#up").unbind();
        $("#down").unbind();
    }
   
    }
    //给速度下拉菜单注册事件
    function changeSpeed(){
   
$('#speed-menu>li:eq(0)').bind("click",function(){
speed=200;
$("#speed-span").text('快')
});
        $('#speed-menu>li:eq(1)').bind("click",function(){
speed=400;
$("#speed-span").text('中')


});
        $('#speed-menu>li:eq(2)').bind("click",function(){
        speed=600;
$("#speed-span").text('慢')



        });
    }
    
    //游戏初始化
    function init(){
    //初始化蛇身x坐标数组,索引为0即为蛇头x坐标
    px=[11,10,9,8];
    //初始化蛇身y坐标数组,索引为0即为蛇尾y坐标
    py=[10,10,10,10];
    //初始化蛇身长度
    l=4;
   
    //初始化蛇头
        $("tr:eq("+py[0]+")>td:eq("+px[0]+")").css("background-color","green");


    //初始化蛇身
    for(var i=1;i<l;i++){
        $("tr:eq("+py[i]+")>td:eq("+px[i]+")").css("background-color","white");
        }
    //初始化食物
    getFood();
    //初始化分数
    score=0;
        $("#cur-score").text("00");
        //从本地存储获取历史最高分
        hisScore=localStorage.getItem("key"); 
        if(hisScore!=null){
            $("#his-score").text(hisScore);
        }
        
        //初始化速度
        var s=$("#speed-span").text();
        if(s='快'){
        speed=200;
        }else if(s='中'){
        speed=400;
       
        }else{
        speed=600;        
        }
        
    //初始化蛇身运动方向
    d='right';
    //初始化向上和向下方向按钮
    $("#up").bind("click",function(){changeFx('up')});
    $("#down").bind("click",function(){changeFx('down')});
    //给开始游戏按钮绑定事件
    $("#start-game").unbind();
    $("#start-game").bind("click",run);
    //移除暂停按钮的事件
    $("#pause").unbind();
    //初始化暂停按钮图标
    $("#pause>span").removeClass("glyphicon-play");
$("#pause>span").addClass("glyphicon-pause");
    changeSpeed();

    }
    $(function(){
    //初始化游戏
    init();
   
    });   

猜你喜欢

转载自blog.csdn.net/xl_1803/article/details/79934435