JS实现贪吃蛇

JS实现贪吃蛇

1.结构

创建一个盒子box作为蛇的身体,当前盒子中只有一个子元素,代表此时蛇的长度为1.
在创建一个盒子food作为贪吃蛇的食物。

 <div id="box">
        <div></div>
 </div>
 <div id="food"></div>

2.CSS

设置蛇和食物的样式,这里注意蛇和食物都是绝对定位。

<style>
    *{
        padding: 0px;
        margin: 0px;
    }
    #box div{
        width: 30px;
        height: 30px;
        box-sizing: border-box;
        background: green;
        border: 1px solid black;
        position: absolute;
    }
    #food{
        width: 30px;
        height: 30px;
        background: brown;
        position: absolute;
    }
    </style>

3.脚本

获取蛇的身体和每一个子元素
var box = document.getElementById("box");
var boxs = document.getElementById("box").children;
定义蛇头的位置
 var snackX = 0;
 var snackY = 0;
获取屏幕宽度和高度,以此来设定墙的边界,以限制蛇的移动范围。
 var cw = document.documentElement.clientWidth;
 var ch = document.documentElement.clientHeight;
 var minsnackX = 0;
 var maxsnackX = Math.floor(cw / boxs[0].offsetWidth)*boxs[0].offsetWidth;
 var minsnackY = 0;
 var maxsnackY = Math.floor(ch / boxs[0].offsetHeight)*boxs[0].offsetHeight;
定义初始的移动方向。
  var turn = "right";
获取食物元素,并设置食物的位置座标。
 var foodele = document.getElementById("food");
    var foodX,foodY;
蛇的初始化
  for(var i = 0; i <6 ; i++){
        box.appendChild(boxs[0].cloneNode(true));
    }
刷新食物
 function food(){
 	//此处的座标要先获取页面最大支持的蛇身体的块数,然后在块数中随机,然后乘以块数的大小,
 	//因为蛇的移动每一步都是固定的,想要判定食物和蛇头重合就必须座标是整块的倍数。
   	 foodX = parseInt( Math.random()*Math.floor(cw / boxs[0].offsetWidth))*boxs[0].offsetWidth;
     foodY = parseInt( Math.random()*Math.floor(ch / boxs[0].offsetHeight))*boxs[0].offsetHeight;
        //判定当食物的产生位置和蛇的任何一个位置重合时就重新生成食物。
        for(var i = 0;i<boxs.length;i++){
            if(foodX + "px" === boxs[i].style.left && foodY + "px" === boxs[i].style.top){
                food();
            }
        }
        foodele.style.left = foodX + "px";
        foodele.style.top = foodY + "px";
 }
调用food()方法 生成第一个食物
   food();
设置定时器 每次执行一次蛇的运行方法
   var timer = setInterval(function(){
        snackMOve();
    },150)
封装一个蛇的运动方法
  //移动和判定边界
    function snackMOve(){
    //此处为判定方向 根据判定的方向,向改方向前进一个方块
        switch(turn){
            case "right":snackX +=30;break;
            case "left":snackX -=30;break;
            case "bottom":snackY +=30;break;
            case "top":snackY -=30;break;
        }
        //如果蛇越过了墙就从另一端出现
        if(snackX > maxsnackX){
            snackX = 0;
        }
        if(snackX < minsnackX){
            snackX = maxsnackX;
        }
        if(snackY > maxsnackY){
            snackY = 0;
        } 
        if(snackY < minsnackY){
            snackY = maxsnackY;
        }
        //从最后一个开始,每个元素跟随上一个元素的位置
        for(var i = boxs.length-1; i >0 ; i--){
            boxs[i].style.left = boxs[i-1].style.left;
            boxs[i].style.top =  boxs[i-1].style.top ;
        }
        //第一个也就是蛇头的位置,永远是根据方向获取的位置
        boxs[0].style.left = snackX + "px";
        boxs[0].style.top =  snackY + "px" ;


        //判定吃到食物 就长大和刷新
        //当蛇头位置移动之后与食物重合 那么刷新食物,并且在蛇的身体中插入一个克隆的元素,相当于长度+1
        if(snackX  === foodX && snackY  === foodY){
            food();
            box.appendChild(boxs[0].cloneNode(true));
        }else{
        //判定撞死 
        //当蛇头与身体中的任何一个元素重合,那么判定结束游戏,停止定时器
            for(var i = 1;i<boxs.length;i++){
                if(snackX + "px" === boxs[i].style.left && snackY + "px" === boxs[i].style.top){
                    clearInterval(timer);
                    alert("失败");
                }
            }
        }
    }

蛇的运动方向

document.onkeydown = function(eve){
    var e = eve||event;
    var keyCode = e.keyCode||e.which;
    switch(keyCode){
        case 37:if(turn === "right"){break;}turn = "left";break;
        case 38:if(turn === "bottom"){break;}turn = "top";break;
        case 39:if(turn === "left"){break;}turn = "right";break;
        case 40:if(turn === "top"){break;}turn = "bottom";break;
    }        
}

全部代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
    *{
        padding: 0px;
        margin: 0px;
    }
    #box div{
        width: 30px;
        height: 30px;
        box-sizing: border-box;
        background: green;
        border: 1px solid black;
        position: absolute;
    }
    #food{
        width: 30px;
        height: 30px;
        background: brown;
        position: absolute;
    }
    </style>
</head>
<body>
    <div id="box">
        <div></div>
    </div>
    <div id="food"></div>
    <script>
        var box = document.getElementById("box");
        var boxs = document.getElementById("box").children;
        var snackX = 0;
        var snackY = 0;
        var cw = document.documentElement.clientWidth;
        var ch = document.documentElement.clientHeight;
        var minsnackX = 0;
        var maxsnackX = Math.floor(cw / boxs[0].offsetWidth)*boxs[0].offsetWidth;
        var minsnackY = 0;
        var maxsnackY = Math.floor(ch / boxs[0].offsetHeight)*boxs[0].offsetHeight;
        var turn = "right";
        var foodele = document.getElementById("food");
        var foodX,foodY;

        for(var i = 0; i <6 ; i++){
            box.appendChild(boxs[0].cloneNode(true));
        }


        //随机食物
        function food(){
            foodX = parseInt( Math.random()*Math.floor(cw / boxs[0].offsetWidth))*boxs[0].offsetWidth;
            foodY = parseInt( Math.random()*Math.floor(ch / boxs[0].offsetHeight))*boxs[0].offsetHeight;
            for(var i = 0;i<boxs.length;i++){
                if(foodX + "px" === boxs[i].style.left && foodY + "px" === boxs[i].style.top){
                    food();
                }
            }
            foodele.style.left = foodX + "px";
            foodele.style.top = foodY + "px";
        }
        food();

        //设置定时器 移动
        var timer = setInterval(function(){
            snackMOve();
        },150)


        //移动和判定边界
        function snackMOve(){
            switch(turn){
                case "right":snackX +=30;break;
                case "left":snackX -=30;break;
                case "bottom":snackY +=30;break;
                case "top":snackY -=30;break;
            }
            //根据边界归零
            if(snackX > maxsnackX){
                snackX = 0;
            }
            if(snackX < minsnackX){
                snackX = maxsnackX;
            }
            if(snackY > maxsnackY){
                snackY = 0;
            } 
            if(snackY < minsnackY){
                snackY = maxsnackY;
            }
            for(var i = boxs.length-1; i >0 ; i--){
                boxs[i].style.left = boxs[i-1].style.left;
                boxs[i].style.top =  boxs[i-1].style.top ;
            }
            boxs[0].style.left = snackX + "px";
            boxs[0].style.top =  snackY + "px" ;


            //判定吃到食物 就长大和刷新
            if(snackX  === foodX && snackY  === foodY){
                food();
                box.appendChild(boxs[0].cloneNode(true));
            }else{
            //判定撞死 暂停计时器 刷新
                for(var i = 1;i<boxs.length;i++){
                    // console.log(boxs[i].style.left);
                    if(snackX + "px" === boxs[i].style.left && snackY + "px" === boxs[i].style.top){
                        clearInterval(timer);
                        alert("失败");
                        // console.log(1)
                    }
                }
            }
        }



        //方向
        document.onkeydown = function(eve){
            var e = eve||event;
            var keyCode = e.keyCode||e.which;
            switch(keyCode){
                case 37:if(turn === "right"){break;}turn = "left";break;
                case 38:if(turn === "bottom"){break;}turn = "top";break;
                case 39:if(turn === "left"){break;}turn = "right";break;
                case 40:if(turn === "top"){break;}turn = "bottom";break;
            }        
        }
    </script>
</body>
</html>

总结

贪吃蛇的思路主要是有以下几个部分
1.食物的随机出现(不能随机在蛇身上)
2.定时器控制蛇的移动
3.墙的判定
4.蛇的运动逻辑
5.运动方向的判定
6.吃到食物的判定
7.蛇头与身体的判定(即游戏结束的判定)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章