canvas雷霆战机

作者: 马大哈tt | 来源:发表于2018-01-03 21:24 被阅读0次

    这个游戏大家肯定都玩过,今天分享一个用canvas写的一个小demo。
    效果图:


    QQ20180103-204422-HD.gif

    一、首先要做的肯定是图片预加载

    var imgArr = {
                "bg":"img/background.png",
                "herofly":"img/herofly.png",
                "bullet1":"img/bullet1.png",
                "bullet2":"img/bullet2.png",
                "enemy1":"img/enemy1.png",
                "enemy2":"img/enemy2.png",
                "enemy3":"img/enemy3.png",
                "prop":"img/prop.png"
            }
            var imgLength = 0;
            for(var i in imgArr){
                imgLength++;
            }
            var num = 0;
            var loadArr = {};
            for(let i in imgArr){
                var img = new Image();
                img.src = imgArr[i];
                img.onload = function(){
                    loadArr[i] = this;
                    num++;
                    if(num>=imgLength){
                        main(loadArr);
                    }
                }
            }
    

    二、分析游戏中都几个对象

    对象一:主机;
    对象二:敌机;
    对象三:奖励;
    每个对象都有move移动,draw绘画,isClear是否清除的方法
    以子弹为例:其余对象的构造函数类似

    // 子弹构造函数
                function Bullet(x,y,power,obj,speed){
                    this.x = x;
                    this.y = y;
                    this.power = power;
                    this.obj = obj;
                    this.w = obj.width;
                    this.h = obj.height;
                    this.speed = speed;
                }
                Bullet.prototype.draw = function(){
                    context.drawImage(this.obj,0,0,this.w,this.h,this.x,this.y,this.w,this.h);
                    // 子弹与敌机的碰撞检测
                    for(var j = 0 ; j < enemy.length;j++){
                        if((this.x<enemy[j].x+enemy[j].w && this.x+this.w>enemy[j].x) && (this.y<enemy[j].y+enemy[j].h && this.y+this.h>enemy[j].y)){   
                            enemy[j].blood -= 25;
                            if(enemy[j].i == 5){
                                music2.src = "audio/enemy1_down.mp3";
                            }else if(enemy[j].i == 6){
                                music2.src = "audio/enemy2_down.mp3";
                            }else{
                                music2.src = "audio/enemy3_down.mp3";
                            }   
                            this.y = -10;   
                        }   
                    }   
                }
                Bullet.prototype.move = function(){
                    this.y -= this.speed;   
                }
                Bullet.prototype.isClear = function(){
                    if(this.y<0){
                        return true;
                    }else{
                        return false;
                    }
                }
    

    三、定义几个数组存放实例化的子弹,敌机,奖励

    方便后面做碰撞判断

    // 存放子弹的容器
                var bullet = [];
                var num = 0;
                var bgY = 0;
                // 存放敌机的容器
                var enemy = [];
                var enemyBlood = 100;
                // 存放奖励的容器
                var award = [];
                // 子弹的颗数
                var bulletNum = loadArr.bullet1;
                var bulletX = 30;
                // 敌机与主机碰撞的开关
                var isCarld = true;
    

    四、动画函数

    创建一个act函数做动画,函数里实例化子弹,敌机,以及做各种碰撞检测,这里注意:碰撞检测不要全部在act方法里判断,可以在构造函数的draw方法里判断,优化性能,使游戏画面流畅。

    1. 背景图滚动
                    bgY--;
                    context.drawImage(loadArr.bg,0,0+bgY,canvas.width,canvas.height);
                    context.drawImage(loadArr.bg,0,canvas.height+bgY,canvas.width,canvas.height);
                    if(Math.abs(bgY) >= canvas.height){
                        bgY = 0;
                    }
    
    1. 绘画主机和实例化敌机,奖励,Rand()是一个封装好取随机数的函数,使用随机数出现的概率来决定不同敌机和不同奖励出现的概率。
    // 画主机
                    newHero.draw();
                    newHero.move();
                    // 实例化敌机和奖励
                    if(num%50 == 0){
                        var randNum = Rand(0,34);
    //                  console.log(randNum);
                        if(randNum>=0 && randNum<20){
                            // 随机位置
                            var randX = Rand(0,canvas.width-loadArr.enemy1.width/5);
                            // 敌机的血量
                            var blood = enemyBlood -20;
                            var newEnemy = new Enemy(randX,-loadArr.enemy1.height,blood,20,loadArr.enemy1,1.5,5);
                            enemy.push(newEnemy);
                        }else if(randNum >= 20 && randNum <28){
                            var randX = Rand(0,canvas.width-loadArr.enemy2.width/6);
                            var blood = enemyBlood -50;
                            var newEnemy = new Enemy(randX,-loadArr.enemy2.height,blood,35,loadArr.enemy2,1,6);
                            enemy.push(newEnemy);
                        }else if(randNum >= 28 && randNum <30){
                            var blood = enemyBlood;
                            var randX = Rand(0,canvas.width-loadArr.enemy3.width/10);
                            var newEnemy = new Enemy(randX,-loadArr.enemy3.height,blood,50,loadArr.enemy3,0.5,10);
                            enemy.push(newEnemy);
    //                      console.log(newEnemy.x,newEnemy.y);
                        }else if(randNum >= 30 && randNum <31){
                            // 奖励1
                            var randX = Rand(0,canvas.width-loadArr.prop.width/3);
                            var newRaward = new Award(randX,-loadArr.prop.height,loadArr.prop,1,0);
                            console.log(newRaward);
                            award.push(newRaward);
                        }else if(randNum >= 31 && randNum <33){
                            // 奖励2
                            var randX = Rand(0,canvas.width-loadArr.prop.width/3);
                            var newRaward = new Award(randX,-loadArr.prop.height,loadArr.prop,1,1);
                            console.log(newRaward);
                            award.push(newRaward);
                        }else{
                            // 奖励3
                            var randX = Rand(0,canvas.width-loadArr.prop.width/3);
                            var newRaward = new Award(randX,-loadArr.prop.height,loadArr.prop,1,2);
                            console.log(newRaward);
                            award.push(newRaward);
                        }
                    }
    
    1. 敌机与主机的碰撞检测
      这里使用的事普通碰撞,大家有兴趣可以换成像素碰撞。
      遍历敌机enemy数组,使用isCarld控制只碰撞一次,主机血量减少。血量为0时主机爆炸游戏结束。
    for(var i = 0 ; i < enemy.length ; i++){
                        enemy[i].draw();
                        enemy[i].move();
                        // 敌机与主机的碰撞检测
                        if((newHero.x< enemy[i].x+enemy[i].w && newHero.x+newHero.w>enemy[i].x) && (newHero.y< enemy[i].y+enemy[i].h && newHero.y+newHero.h>enemy[i].y)){
                            if(isCarld){
                                isCarld = false;
                                newHero.blood -= enemy[i].power;    
                                if(newHero.blood < 0){
                                    newHero.blood = 0;
                                }
                                bloodNum.innerHTML = "血量:"+ newHero.blood;
                                bloodPress.style.width = 200*newHero.blood/100 + "px";
                            }
                            enemy[i].isF = true;
                            console.log(newHero.blood);
    //                      music2.src = "audio/enemy2_out.mp3";
                        }
                        if(enemy[i].isF && enemy[i].y >= canvas.height){
                            isCarld = true;
                        }
                        if(enemy[i].isClear()){
                            enemy.splice(i,1);
                        }
    //                  console.log(enemy.length);
                    }
    

    像子弹和敌机的碰撞还有主机和奖励的碰撞代码大同小异,就是其中逻辑不同,这里就不一一展示了。

    1. 游戏结束
      使用requestAnimationFrame做动画,使用cancelAnimationFrame(Timer);来停止动画。
    var Timer = window.requestAnimationFrame(act);
                    if(newHero.index >= newHero.i-1){
                        console.log("dfsf");
                        music1.src = "audio/game_over.mp3";
                        music1.loop = "";
                        music2.remove();
                        cancelAnimationFrame(Timer);
                        // 游戏结束
                        btn.style.display = "block";
                        context.beginPath();
                        context.fillStyle = "grey";
                        context.fillRect(0,150,canvas.width,200);
                        context.beginPath();
                        context.textBaseline = "middle";
                        context.textAlign = "center";
                        context.font = "40px Arial";
                        context.fillStyle = "red";
                        context.fillText("gameover",canvas.width/2,275);
                    }
    

    游戏结束的页面图:


    C09F4603-BE58-4C6C-A1DB-25050CF7B32F.png

    相关文章

      网友评论

        本文标题:canvas雷霆战机

        本文链接:https://www.haomeiwen.com/subject/pwyknxtx.html