详解贪吃蛇 - 步骤五:添加事件、移动控制

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>贪吃蛇</title>
    <style>
        *{margin: 0; padding: 0;}
        .canvas{width: 400px; height: 400px; position: absolute;}
    </style>
</head>
<body>


<div class="canvas"></div>


<script>
    //绘制画布
    var zbxArr = [];
    var frag = document.createDocumentFragment();
    for(var i=0; i<20; i++){
        var oneArr = [];
        for(var j=0; j<20; j++){
            var div = document.createElement('div');
            div.style.position = 'absolute';
            div.style.left = j*20+'px';
            div.style.top = i*20+'px';
            div.style.width = '20px';
            div.style.height = '20px';
            div.style.background = 'black';
            frag.appendChild(div);
            oneArr.push(div);
        }
        zbxArr.push(oneArr);
    }
    document.querySelector('.canvas').appendChild(frag);


    //绘制指定位置色块方法
    function drawOneSquare(location,color) {
        for(var i=0; i<zbxArr.length; i++) {
            for(var j=0; j<zbxArr[i].length; j++) {
                var left = zbxArr[i][j].style.left;
                var top = zbxArr[i][j].style.top;
                if((parseInt(left.substring(0,left.length-2))==(location%20*20)) && (parseInt(top.substring(0,top.length-2))==(Math.floor(location/20)*20))){
                    zbxArr[i][j].style.background = color;
                }
            }
        }
    }
    // 蛇身
    var snakeBodyArr = [42,41];
    // nextLocation变量当做是一个临时容器,来存放我们的按键结果。
    var nextLocation;
    // 食物赋值
    var foodNum = 43;
    var fangxiang = 1;




    /*
        第五节课 1内容:
        到这里我们已经完成了贪吃蛇游戏的基本设置。
        还差最后一步我们就能够完成这个游戏
        那就是所有游戏的共同之处:交互


        贪吃蛇是一款传统的游戏,因此我们采用上下左右四个方向按钮来控制蛇的移动。
        那么在添加键盘事件之前,我们必须知道的事情是上下左右按键编码是多少:
        上:38    下:40    左:37    右:39
        乍一下的看来对于上下左右的控制没什么帮助,但是仔细分析就会得到一个惊人的结论:
        蛇左移一个格子:nextLocation = snakeBodyArr[0]+(-1)
        蛇上移一个格子:nextLocation = snakeBodyArr[0]+(-20)
        蛇右移一个格子:nextLocation = snakeBodyArr[0]+(1)
        蛇下移一个格子:nextLocation = snakeBodyArr[0]+(20)
          例如: 字符下标为42,
        所以我创建代表方向的数组【-1,-20,1,20】
        用(按键编码-37)得到0,1,2,3四个下标就能从数组中分别获取不同的方向
    */
    // 用户按下一个键盘按键时产生的事件
    document.οnkeydοwn=function(e){
        // 获取控制键的键码值
        var keyCode = (e||event).keyCode;
        var chaValue = keyCode-37;
        var touchArr = [-1,-20,1,20];
        
            // 第五节课 2内容:
            // 当我们按下一个按键的时候,的确能够从数组中获取到一个相应的方向。
            // 但是并不是所有的按键都能够被执行!
            // 所以在这里当用户按下方向键以外的某个按键时,我们要做出处理


            // 因为每一次间隔调用后nextLocation都会被重新赋值
            // 所以我们将nextLocation变量当做是一个临时容器,来存放我们的按键结果。
            // 通过一个简单的||或运算,避免了无效按键
        nextLocation = touchArr[chaValue]||fangxiang;
        // 例如:按了上键,字符编码为38,
            // 所以38-37为1,在touchArr数组中下标为1的是-20,
    // 此时,页面上蛇头就会减20px,造成了一种向上走的演示。
        /*// 使左上右下37,38,39,40四个按键,
使他们固定在nextLocation;固定在一个数组里,就避免了无效按键,
也就是说只有按了数组里的按键或等于fangxiang,页面才会发生作用




            第五节课 2内容·续:
            可能有人会问,为什么不直接将得到的结果赋值给fangxiang变量?
            这样不就能在按下按键之后,就能直接改变蛇的运行方向了么?


            诚然,不过正如我刚才所说的:
                并不是所有的按键都能够被执行!
            如果当蛇向右移动的时候,按下了左键。那么很显然这个方向赋值就是无效的。
            因此我们还要排除无效的方向按键


    至于如何判断:
        和当前蛇运行的方向相反的按键即为无效按键!
            而蛇运行的反向我们是能够获取的:
                snakeBodyArr[1]-snakeBodyArr[0]
        
    如果蛇身第二个元素减去第一个元素的值与下个一按键相等
        if(snakeBodyArr[1]-snakeBodyArr[0] == nextLocation){
            //方向则保持fangxiang变量值不变
            fangxiang = fangxiang;
        }else{
            //如果是其他方向按键,就改变fangxiang变量。
            fangxiang = nextLocation;
        }
    };




    //游戏执行
                定时器
    var timer = setInterval(function(){
        //添加蛇头下一个出现的位置
        向蛇身添加一个元素()
        snakeBodyArr.unshift(nextLocation=snakeBodyArr[0]+fangxiang);
        //结束判断
            判断蛇身是否碰到了自身,或者碰壁。
    如果碰到,则游戏结束。
        if(snakeBodyArr.indexOf(nextLocation,1)>0 ||
    下一次按键的值小于0则【上】为负。不存在画布中,则表示碰壁
                nextLocation<0 ||
    下一次按键的值大于400则【下】超出。不存在画布中,则表示碰壁
                nextLocation>400 ||
    下一次按键的值对20取余不等于0与按下【右】方向按键后39-37=2;
        2在数组var touchArr = [-1,-20,1,20];中为1,则不可取
                nextLocation%20==0&&fangxiang==1 ||
    下一次按键的值对20取余不等于20与按下【左】方向按键后37-37=0;
        0在数组var touchArr = [-1,-20,1,20];中为-1,则不可取;
                nextLocation%20==20&&fangxiang==-1
        ) {
            clearInterval(timer);
            return alert("GAME OVER");
        }
ps:以上判断条件满足任何一个都代表游戏结束,没有则继续向下执行
       


        //绘制蛇身
        drawOneSquare(nextLocation,'cyan');
        //增加判断
        if(nextLocation==foodNum){
            //创建食物
            do{先执行随机数食物
                foodNum=Math.floor(Math.random()*400);
            }
        判断食物是否在蛇身内,如果存在,则重新再绘制一个食物
            while(snakeBodyArr.indexOf(foodNum)>=0);
            //就继续执行,获取到目标色块位置后,绘制一个新的食物
            drawOneSquare(foodNum,"Yellow");
        }else {
            //蛇尾离开
            同时删除蛇身最后一个元素,返回显示黑色,
            从而变相的构成蛇身向前移动,蛇尾离开的样式
            drawOneSquare(snakeBodyArr.pop(), "Black");
        }
    },200);


</script>


</body>
</html>
  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王十一x

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值