原生js实现贪吃蛇小游戏 +背景音乐(包含对象、构造函数、this等知识点)+超详细注释

●锻炼逻辑思维
●加强对象、构造函数、this等知识点的应用
●html5中音乐播放器的应用
在这里插入图片描述

<!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>贪吃蛇</title>
    <style>
        *{
            padding: 0;
            margin: 0;
        }
        .wrapper .score{
            width: 600px;
            height:400px;
            box-sizing: border-box;
            padding-left: 240px;
            position: absolute;
            top: 100px;
            right: -30px;
            background:url('img/startP.jpg') no-repeat;
            background-size: 100% 100%;
            line-height: 400px;
            font-size: 50px;
            color: red;
        }
        .wrapper .box {
            width: 600px;
            height: 600px;
            border: 1px solid #ccc;
            background: url('img/bg.png') no-repeat;
            background-size: 100% 100%;
            margin-left: 50px;
            position: relative;
        }
        .wrapper .box .start {
            position: absolute;
            width: 200px;
            height: 100px;
            background: url('img/start.png') no-repeat;
            background-size: 100% 100%;
            right: -220px;
            top: 55%;        
            cursor: pointer;
            text-align: center;
            line-height: 100px;
            font-size: 20px;
            color:  #333;
            font-weight: 400;
        }
        .wrapper .box .pause{
            position: absolute;
            width: 200px;
            height: 100px;
            background: url('img/pause.png') no-repeat;
            background-size: 100% 100%;
            right: -220px;
            top: 50%;
            margin-top: -100px;
            cursor: pointer;
            text-align: center;
            line-height: 100px;
            font-size: 20px;
            color:  #333;
            font-weight: 400;
        }
        .snake {
            position: absolute;
            top:0;
            left: 0;
            width: 30px;
            height: 30px;
        }
       .over{
           width: 300px;
           height: 300px;
           position: absolute;
           top: -301px;
           left: 50%;
           margin-left: -150px;
           background: url('img/timg.jpg');
           background-size: 100% 100%;
           /* display: none; */
       }
    </style>
</head>
<body>
    <div class="wrapper">
        <div class="score" id="_score">0</div>
        <div class="box" id="_box">
            <span class="start" id="_start">开始</span>
            <span class="pause" id="_pause">暂停</span>
            <div class="over" id="_over"></div>
        </div>
    </div>   
    <audio src="music.mp3"   preload="auto" loop="true" id="music"></audio>
    <!-- <embed src="music.mp3"  type="" hidden="true"> -->
</body>
</html>
<script>    
    var box = document.getElementById('_box');
    var start = document.getElementById('_start');
    var pause = document.getElementById('_pause');
    var over = document.getElementById('_over');
    var music = document.getElementById('music');
    // 每个小方块的宽度
    var squareWidth = 30;
    // 存放蛇;
    var snakeArr = [];
    //存放食物对象的数组
    var foods = [];
    // 设置定时器
    var timer = null;
    // 设置定时器时间
    var speed;
    // 分数
    var score = 0;
    // 每次只能一个方向改变
    var block = true;
    // 蛇头蛇身对象
    var snakeType = {
        head : {value: 0,url:"img/head.png"},
        body : {value: 1,url:'img/body.png'},
    }
    // 记录运动的方向,及蛇头旋转的角度
    var toward = {
        up: {rotate : 270,x:0,y:-squareWidth },
        right:{rotate: 0,x:squareWidth,y:0},
        down:{rotate: 90,x:0,y:squareWidth},
        left:{rotate:180,x:-squareWidth,y:0}
    }
    // 记录当前的运动方向
    var nowToward = toward.right;// 默认为右
    // 食物集合
    var foodSet = [
        // 苹果
        {
            name: 'apple',
            value: 2,
            url:'img/pingguo.png',
            maxNum: 2,
            // 蛇吃到食物后的方法
            action: function(){
                //蛇吃到食物后创建一个蛇头 并且产生的蛇身就在所吃食物的位置
                var snakebody = createSquare(this.row,this.col,snakeType.head);
                // 重新渲染之前的蛇头小方块,使之变为蛇身
                renderSquare(snakeArr[0],snakeType.body);
                // 将产生的蛇头方块添加在最前面
                snakeArr.unshift(snakebody);
                // 吃到食物后移除
                box.removeChild(this.foodSquare);
                // foods数组里面也将其删除(splice删除指定位置的对象)
                foods.splice(foods.indexOf(this),1);
                // 分数加10
                score += 10;
            },
            maxCtrl: function () {
            return this.maxNum;
        }
        },
        // 菠萝
        {
            name: 'pineapple',
            value: 3,
            url:'img/菠萝.png',
            maxNum: 2,
            // 蛇吃到食物后的方法
            action: function(){
                //蛇吃到食物后创建一个蛇头 并且产生的蛇身就在所吃食物的位置
                var snakebody = createSquare(this.row,this.col,snakeType.head);
                // 重新渲染之前的蛇头小方块,使之变为蛇身
                renderSquare(snakeArr[0],snakeType.body);
                // 将产生的蛇头方块添加在最前面
                snakeArr.unshift(snakebody);
                // 吃到食物后移除
                box.removeChild(this.foodSquare);
                // foods数组里面也将其删除(splice删除指定位置的对象)
                foods.splice(foods.indexOf(this),1);
                // 分数加10
                score += 10;
            } ,
            maxCtrl: function () {
            return this.maxNum;
        }
        },
        // 草莓
        {
            name: 'strawberry',
            value: 4,
            url:'img/caomei.png',
            maxNum: 2,
            // 蛇吃到食物后的方法
            action: function(){
                //蛇吃到食物后创建一个蛇头 并且产生的蛇身就在所吃食物的位置
                var snakebody = createSquare(this.row,this.col,snakeType.head);
                // 重新渲染之前的蛇头小方块,使之变为蛇身
                renderSquare(snakeArr[0],snakeType.body);
                // 将产生的蛇头方块添加在最前面
                snakeArr.unshift(snakebody);
                // 吃到食物后移除
                box.removeChild(this.foodSquare);
                // foods数组里面也将其删除(splice删除指定位置的对象)
                foods.splice(foods.indexOf(this),1);
                // 分数加10
                score += 10;
            },
            maxCtrl: function () {
            return this.maxNum;
        }
        },
        // 炸弹
        {
            name: 'bomb',
            value: 5,
            url:'img/bomb.png',
            maxNum: 2,
            // 蛇吃到食物后的方法
            action: function(){
                 gameOver();
                 return;
            },
            maxCtrl: function () {
            return Math.floor(score / 80) + 2;
        }
        }

    ]
    function Food(row,col,foodtype){
        this.foodtype = foodtype;
        this.row = row;
        this.col = col;
        this.url = foodtype.url;
        this.action = foodtype.action;
        this.foodSquare = null;
        // init()创建一个食物小方块
        this.init = function(){
        this.foodSquare = createSquare(this.row,this.col,this.foodtype);
        }
    }
    function generatefood() {
        for(var  i = 0;i < foodSet.length;i++)
        {
            // filter()方法把传入的函数作用于每个元素,
            // item表示foods数组里面某一对象,filter()返回的是一个数组
            var nowLen = foods.filter(function(item){
                if(item.foodtype.value == foodSet[i].value)
                {
                    return item;
                }
            }).length;
            if(nowLen < foodSet[i].maxNum)// 每个食物产生的个数不能大于它的maxNum;
            {
                var row ,col;
                do{
                    // 随机的行与列
                    row = Math.floor(Math.random()*20);
                    col = Math.floor(Math.random()*20);
                }while(existFood(row,col));// 如果已经存在则重新产生行与列
                // 产生一个食物对象
                var food = new Food(row,col,foodSet[i]);
                food.init();
                foods.push(food);// 将这个对象放入数组中
            }
        }
    }
    function existFood(row,col){
        for(var  i = 0; i < foods.length;i++)
        {
            if(foods[i].row == row && foods[i].col == col)
            {
                return true;
            }
            return false;
        }
    }
    init();
    // 初始化
    function init(){
        // 初始化蛇
        var head =  createSquare(0,3,snakeType.head);
        var body1 =  createSquare(0,2,snakeType.body);
        var body2 =  createSquare(0,1,snakeType.body);
        var body3 =  createSquare(0,0,snakeType.body);
        // 存入数组
        snakeArr.push(head,body1,body2,body3);
        //运动
      
    }
    // 创建蛇 
    function createSquare(row,col,squareType) {
        var span = document.createElement('span');
        span.classList.add('snake');
        // 确定位置
        span.style.top = row * squareWidth + 'px';
        span.style.left = col * squareWidth + 'px';
        // 渲染
        renderSquare(span,squareType);
        box.appendChild(span);
        return span;
    }
    // 渲染蛇头蛇身
    function renderSquare(span,snakeType){
        span.value = snakeType.value;
        span.style.backgroundImage = 'url('+snakeType.url+')';

    }
    // 蛇运动
    start.onclick = function(){
        run();   
        music.play();
    }
     // 键盘操作
     document.onkeydown = function(event){
        var event = event || window.event;
        var code = event.keyCode;
        changeTowrad(code);
    }
    pause.onclick = function(){
        clearTimeout(timer);
        music.pause();
       
    }
    function run(){
        speed =  400 -(Math.min( Math.floor(score / 50)*50,300));// 最小不小于100
        clearTimeout(timer);
        timer =  setTimeout(function(){
            // 检查碰撞
            var flag = checkCrash();
            if(flag.result == -1)
            {
                gameOver();
                return;
            }
            else if(flag.result == 1)
            {
                flag.target.action();
                block = true;
                document.getElementById('_score').innerHTML = score;
            }
            else{
                // move
                move();
                //产生食物
                 generatefood();
                // 移动一次将锁打开
                block = true ;
            }
            for (var i = 0; i < foodSet.length; i++) {
            foodSet[i].maxNum = foodSet[i].maxCtrl();
             };
            if(timer != null)
            {
                run();
            }
           
       },speed);
     
    }
    // 蛇移动
    function move(){
        // 将头变成蛇身
        renderSquare(snakeArr[0],snakeType.body);
        // 将最后一个变为蛇头
        var last = snakeArr.pop()// 移除数组最后一个;
        last.style.left = snakeArr[0].offsetLeft +  nowToward.x  +'px';
        last.style.top = snakeArr[0].offsetTop + nowToward.y + 'px';
        // 让蛇头旋转
        last.style.transform = "rotate(" + nowToward.rotate + "deg)";
        snakeArr.unshift(last);// 放在最前面
        // 将蛇身变为蛇头
        renderSquare(snakeArr[0],snakeType.head);    
    }
    function changeTowrad(code){
        if(!block)
        {
            return;
        }
        // 按下一次键盘后将锁关闭,等移动一次后再开启,保证每次只能按一个键
        block = false;    
        if(code == 40 && (nowToward.x & toward.down.x)==0 && (nowToward.y & toward.down.y)== 0)
        {
            nowToward = toward.down;
        }
        else if(code == 38 && (nowToward.x & toward.up.x)==0 && (nowToward.y & toward.up.y)== 0)
        {
            nowToward = toward.up;
        }
        else if(code == 37 && (nowToward.x & toward.left.x)==0 && (nowToward.y & toward.left.y)== 0)
        {
            nowToward = toward.left;
        }
        else if(code == 39 && (nowToward.x & toward.right.x)==0 && (nowToward.y & toward.right.y)== 0)
        {
            nowToward = toward.right;
        }
     }
    function checkCrash(){
        //碰到边界
        if(snakeArr[0].offsetLeft +nowToward.x  >= box.clientWidth || 
        snakeArr[0].offsetLeft <= 0)
        {
            return {result: -1,target:null};
        } 
        else if(snakeArr[0].offsetTop + nowToward.y >= box.clientHeight ||
        snakeArr[0].offsetTop + nowToward.y < 0)
        {
            return {result: -1,target:null};
        }
      
        // 碰到自己的身体
        else{
            for(var i = 3; i < snakeArr.length - 1; i++)
            {
                if(snakeArr[0].offsetLeft + nowToward.x == snakeArr[i].offsetLeft &&
                snakeArr[0].offsetTop + nowToward.y == snakeArr[i].offsetTop)
                {
                    return {result: -1,target: null};
                }
            }
             // 碰到道具
        for( var i = 0;i < foods.length;i++)
        {
            if(snakeArr[0].offsetLeft + nowToward.x == foods[i].foodSquare.offsetLeft &&
            snakeArr[0].offsetTop + nowToward.y == foods[i].foodSquare.offsetTop)
            {
                return {result: 1,target: foods[i]};
            }
        }
        }
       
        return 0;
    }
    function gameOver(){
        clearTimeout(timer);
        timer = null;
        // alert('游戏结束');
        var leader = over.offsetTop;
        var target = box.offsetHeight / 2 - over.offsetHeight /2;
        over.timer = setInterval(function(){
            leader = leader + (target - leader ) /10;
            over.style.top = leader + 'px';
        },8)
        over.style.display = 'block';
        music.pause();
        return;
    }
   
</script>
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值