HTML5学习+javascript学习:打飞机游戏Service层Control层+源码

   2023-02-08 学习力0
核心提示:2.Service层如前所述,Service层是Control层与Model层之间桥接的一层,它拥有所有要在屏幕上显示的实体(除了背景)的引用 我们知道,当游戏运行时,随时都可能发生碰撞,随时都可能发生飞行物的消失。而我们要想判定飞行物的状态,就必须把所有的飞行物都遍

2.Service层

如前所述,Service层是Control层与Model层之间桥接的一层,它拥有所有要在屏幕上显示的实体(除了背景)的引用

 

我们知道,当游戏运行时,随时都可能发生碰撞,随时都可能发生飞行物的消失。而我们要想判定飞行物的状态,就必须把所有的飞行物都遍历一遍方可,那么我们要把所有的没消失的飞行物都放在一起。但是如果这些飞行物放在一起都放在control层里,control层会显得很庞大,又要处理飞机的销毁,又要给返回图片。然后如果我们想通过服务器根据条件获得新的飞机,我们是不是又要在control层中添加事件,添加代码。那control层会显得很乱。所以,保险起见,我们在control层和model层之间桥接了一个service层,它就只负责处理飞行物销毁和子弹发射等已有的事件,提供一些可供control层访问的接口(事件其实就是方法),并把图像返回到control层去,将来如果我们从服务器得到更多的飞机要来,那就把这些飞机给传到control层,然后由control层来调用service的接口就好啦。也就是把control层分成两部分,一部分处理业务,一部分处理显示。

我们已经介绍了Model层,我们知道model层的方法是由service来调用的,Model层的所有方法(除了访问其私有变量的方法外)均会返回一个array,而调用方法返回的这个array是如何被service抓取又是如何被service处理的呢?我们又如何来设计这个service层呢?

首先要有一个飞行物的数组来存放所有的飞行物,同时要有一个数组来缓存事件,另外一个数组来缓存图片。然后要有一个接口的方法update,之后要有一个draw方法来返回给control层更新图像的图片和坐标,还要有一些事件来处理Model返回的事件,其流程为:

update:1.遍历model,先判断model是否有可能发生碰撞,如果有(即碰撞体积有重合的部分),那么就调用model的碰撞方法,将返回的结果缓存到注册表中,然后调用draw方法(因为有可能新增飞行物,飞行物消失等改变飞行物数组的事件出现因此不可以一并处理,设想这样:如果一个飞行物已经消失了,还调用它的移动方法是没有意义的 )2.遍历model调用它们的移动方法,更新它们的坐标,将返回的内容缓存到注册表中(因为如果出了边界也有可能出现消失,发射炮弹也有可能新增飞行物)。

 

draw:将注册表的事件逐个取出,执行,并返回一个图像的数组

下面给出service的代码

service.js

 

/*
*后台控制层类,完成model层和view层的控制和数据传递服务,它通过不停地调用自己的私有数组的特有方法,收集这些方法返回的
*事件,放到注册表中,最后一并处理:调注册表中的事件,事件会更新自己的私有数组内容,并将欲传递给view层显示的图片信息缓存。
*/
var service=function(){
    var registry=[];//存放注册时间的列表,是model层返回的内容
    var bulletNum=0;//只是暂时存储子弹的数目。
    var flies=[];//飞行物的列表,私有数组,遍历访问其方法,返回的事件就存储在registry中
    var images=[];//用于缓存显示图片的数组:{img,x,y}
    var is_array = function(value) {//判断值是否为数组
                    return value &&
                typeof value === 'object' &&
                value.constructor === Array;

        }

    
    
    function registEvent(regist){//注册事件,参数为事件数组/事件对象
    if(regist) {
        // 如果是数组,则调用concat方法把方法名和参数推进注册表中
        if(is_array(regist)){
        
        registry=registry.concat(regist);
        
        }
        else{
        //如果这个方法名和数组返回了不可以识别的值,则什么都不做否则用push方法压入注册表。
        if(typeof regist!=='undefined'){
        registry.push(regist);
        }
        }
        
    }
    }
    function peng(fly1,fly2){//碰撞判断
        //sqr1,sqr2表示碰撞体的左上角坐标和右下角坐标。即,从图片的中心开始,上下左右均为碰撞边长的1/2
        var sqr1={
        x1:fly1.x()+fly1.width()/2-fly1.cflctSqr()/2,
        x2:fly1.x()+fly1.cflctSqr()/2+fly1.width()/2,
        y1:fly1.y()+fly1.height()/2-fly1.cflctSqr()/2,
        y2:fly1.y()+fly1.cflctSqr()/2+fly1.height()/2
        };
        var sqr2={
        x1:fly2.x()+fly2.width()/2-fly2.cflctSqr()/2,
        x2:fly2.x()+fly2.cflctSqr()/2+fly2.width()/2,
        y1:fly2.y()+fly2.height()/2-fly2.cflctSqr()/2,
        y2:fly2.y()+fly1.cflctSqr()+fly2.height()/2
        };
        var x1=sqr1.x1<sqr2.x1?sqr1.x1:sqr2.x1;
        var x2=sqr1.x2>sqr2.x2?sqr1.x2:sqr2.x2;
        var y1=sqr1.y1>sqr2.y1?sqr1.y1:sqr2.y1;
        var y2=sqr1.y2<sqr2.y2?sqr1.y2:sqr2.y2;
        var sqr=fly1.cflctSqr()+fly2.cflctSqr();//是碰撞边长之和
        if((x2-x1)<sqr&&(y1-y2)<sqr){//如果最右边的横坐标减去最左边的横坐标小于两个飞行物碰撞边长之和,而且纵坐标也如此,那么碰撞成立。
        //if((typeof fly1.isbullet !== 'undefined' && typeof fly2.isbullet==='undefined')||(typeof fly2.isbullet !== 'undefined' && typeof fly1.isbullet==='undefined')){
        //var ale="sqr1:x1:"+sqr1.x1+"y1:"+sqr1.y1+"x2:"+sqr1.x2+"y2:"+sqr1.y2+"\n";
        //ale+="fly1:"+"x:"+fly1.x()+"y:"+fly1.y()+"width:"+fly1.width();
        //alert(ale);
        //}
        return true;
        }
        
        return false;
    }
    return {//上面的都是私有方法和变量,下面是返回值。
        total:function(){//求出飞行物的总数,在添加新的飞行物时会用到这个函数。
            return flies.length;
        },
        spliceflies:function(ndex){//删除一个对应序列号的飞行物,并更新飞行物数组中被改变下表的元素的序号。
                flies.splice(ndex,1);
                var i;
            for(i=ndex;i<flies.length;i++)
            {
                flies[i].setIndex(i);//从删除的那个起,数组元素的序列号均与数组下标保持一致
            }
        },
        conflict:function(){//判断是否有碰撞的必要,并检测是否碰撞成功
        var length=flies.length;//飞行物的个数
        var i=0;//遍历被碰者
        var j=0;//遍历碰撞发起者确保飞行物中所有的元素均两两配过对

        if(length>=2){//小于2不会发生碰撞
        for(i=0;i<length;i+=1){
        for(j=i+1;j<length;j+=1){//自己也不会跟自己碰撞,自己之前的已经判定过了。
            if(flies[i].target() !== flies[j].target()){//如果目标不同,就是敌人,就有‘血拼’或者拼血的必要
                if(peng(flies[i],flies[j])){//判断它们是否确实会发生碰撞
                    var regist=flies[i].onConflict(flies[j]);//调用飞行物的碰撞方法。
                    registEvent(regist);//把碰撞方法的返回事件压入注册表中
                    
            //    var q;
            //if(regist){
            //for(q=0;q<regist.length;q++){
            //    alert(regist[q].func+"  "+regist[q].params[0]+"  "+regist[q].params[1]);
            //}}
                    
                    
                }
                
            }
        }
        }
        
    }
    },
        update:function(){//更新,先看是否会发生碰撞,如果碰撞,让碰撞应该消失的消失,然后再更新仍存在于flies中的元素的位置。
        
        //registry= getSameNameAndInitParams(registry,'disapear','func');
        images.length=0;//图像清空
        this.conflict();//碰撞判断
        this.draw();//把注册表中的事件逐个取出,看是否需要更新flies数组(包括添加,删除)
        var length=flies.length;
        var i=0;
        for(i=0;i<length;i++){//然后根据每个飞行物的移动方法不同,分别改变各个飞行物的坐标
            var regist=flies[i].onMove();
            registEvent(regist);//注册移动后的事件,主要是把图片压到缓存区去。
            
        }
        },
        disapear:function(){//消失事件,碰撞成功导致飞行物损毁,就调用这个事件
            var len=arguments.length;
            var i;
            for(i=0;i<len;i+=1){
            //alert("splice");
            //flies.splice(arguments[i],1);
            this.spliceflies(arguments[i]);//把应该消失的飞行物从飞行物数组中移除。
            }
            //alert(flies.length);
        },
        explore:function(img,x,y){//爆炸,所有飞行物通过碰撞消失之前都会爆炸
            //alert("explore");
            this.drawimg(img,x,y);
        },
        drawimg:function(img,x,y){//把飞行物的图片压入缓存
            images.push({img:arguments[0],x:arguments[1],y:arguments[2]});
            
        },
        draw:function(){//就是把注册表中的事件一个个取出然后执行,最后返回缓存区的图像。
            
            //var q;
            //for(q=0;q<registry.length;q++){
            //    var s;
            //    if(registry[q].func !== 'drawimg'){
            //    for(s=0;s<registry[q].params.length;s+=1){alert(registry[q].func+"  "+registry[q].params[s]);
        //    }
        //}}
            var handle=registry.pop();
            
            while(typeof handle !== 'undefined'){
                
                var fuc=handle.func;
                
                    //alert(fuc);
                //if(fuc=='disapear'){
                //alert(flies.length);
                //}
                fuc=this[fuc];
                fuc.apply(this,handle.params);//第一个参数:上下文,第二个参数:传入函数的参数
                handle=registry.pop();
            }
            
            return images;
        },
        shoot:function(spec){//事件:射击,飞行物数组中压入选手的炮弹,这个选手的炮弹
            bullet=playerbullet(spec);
            bullet.setIndex(this.total());
            flies.push(bullet);
            bulletNum+=1;
        },
        reduceBulet:function(){//就是改变bulletNum这个变量的值。
            bulletNum-=1;
            //alert(bulletNum);
        },
        newfly:function(flier){//新飞行物
            //alert(flier.index());
            flier.setIndex(this.total());
            flies.push(flier);
        },
        newplane:function(){//这个以及下面的几个方法都是可有可无的,只是作为例子来看。
            var plane={
                x:Math.random()*CANVAS_WIDTH,
                y:Math.random()*CANVAS_HEIGHT,
                hp:10,
                index:flies.length,
                exploreImg:getImg("img/blasts3.png"),
                img:getImg("img/dplayerplane.png"),
                target:0,
                conflictSquare:20,
                speedX:5,
                speedY:5,
                movex:-1,
                movey:-1
                };
            var pl=fly(plane);
            flies.push(pl);
                
        },
        newenemy:function(){
            var plane={
                x:Math.random()*CANVAS_WIDTH,
                y:Math.random()*CANVAS_HEIGHT,
                hp:1,
                index:flies.length,
                exploreImg:getImg("img/blasts3.png"),
                img:getImg("img/amay.png"),
                target:1,
                conflictSquare:7,//碰撞体积
                speedX:5,
                speedY:5,
                movex:1,
                movey:-1
                };
            var pl=fly(plane);
            flies.push(pl);
        },
        newbullets:function(){
            var plane={
                x:Math.random()*CANVAS_WIDTH,
                y:Math.random()*CANVAS_HEIGHT,
                hp:1,
                index:flies.length,
                exploreImg:getImg("img/bossbullet2.png"),
                img:getImg("img/bossbullet3.png"),
                target:1,
                conflictSquare:2,//碰撞体积
                speedX:5,
                speedY:-5,
                movex:1,
                movey:-1
                };
            var pl=bullets(plane);
            
            
            flies.push(pl);
        }    
    };
};
service.js
 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • HTML中将背景颜色渐变 html设置背景颜色渐变
    通过使用 css3 渐变可以让背景两个或多个指定的颜色之间显示平稳的过渡,由于用到css3所以需要考虑下浏览器兼容问题,例如:从左到右的线性渐变,且带有透明度的样式:#grad {background: -webkit-linear-gradient(left,rgba(255,0,0,0),rgba(255,0,0,1)); /*
    03-08
  • html5 Canvas 如何自适应屏幕大小
    但是这样创建出的画布不能随着浏览器窗口大小的改变而动态的改变画布的大小。而这一点往往又非常重要, 因为我们会经常改变浏览器窗口大小,不会一直保持某个固定的大小。 html代码 canvas width="300" height="300" id="myCanvas"/canvas设置样式 * {
    03-08
  • Vue中出现Do not use built-in or reserved HTML elements as component id:footer等等vue warn问题
    Vue中出现Do not use built-in or reserved HTM
    错误示图:原因:是因为在本地项目对应文件的script中,属性name出现了错误的命名方式,导致浏览器控制台报错!  诸如: name: header 、  、 name: menu , 等等都属于错误的命名方式等 错误代码命名如下:解决办法:办法1: 如果我们采用正确命名
    03-08
  • HTML在网页中插入音频视频简单的滚动效果
    HTML在网页中插入音频视频简单的滚动效果
    每次上网,打开网页后大家都会看到在网页的标签栏会有个属于他们官网的logo,现在学了HTML了,怎么不会制作这个小logo呢,其实很简单,也不需要死记硬背,每当这行代码出现的时候能知道这是什么意思就ok1 link rel="shortcuticon" type="image/x-icon" href="
    03-08
  • HTML的video标签,不能下载视频代码
    !-- 在线视频不能下载代码 --!DOCTYPE html html headscript src="../Demo/demo/book/JQuery/jQuery v2.2.0.js"/script/headbody div style="text-align:center;"video src="../images/PreviewVideo.mp4" width="820"controls="controls&
    03-08
  • ThinkPHP报错 The requested URL /admin/index/login.html was not found on this server.
    ThinkPHP报错 The requested URL /admin/index/
           解决方案在入口文件夹public下查看.htaccess是否存在。不存在则新建,存在的话,那内容替换为下面这串代码 就可以解决Not Fund#IfModule mod_rewrite.c#Options +FollowSymlinks -Multiviews#RewriteEngine On##RewriteCond %{REQUEST_FILENAME
    03-08
  • HTML特殊字符、列表、表格总结 html特殊符号对
            HTML实体字符  在HTML中一些特殊的字符需要用特殊的方式才能显示出来,比如小于号、版权等,  在课堂上老师教了我们一个有点意思的:空格,在教材上字符实体是“nbsp”通过老师  的演示我们发现不同的浏览器他所显示的效果不同,有的比
    03-08
  • 【JavaScript】使用document.write输出覆盖HTML
    您只能在 HTML 输出中使用 document.write。如果您在文档加载后使用该方法,会覆盖整个文档。分析HTML输出流是指当前数据形式是HTML格式的数据,这部分数据正在被导出、传输或显示,所以称为“流”。通俗的来说就是HTML文档的加载过程,如果遇到document.writ
    03-08
  • ASP.Net MVC 控制@Html.DisplayFor日期显示格式
    在做一個舊表的查詢頁時,遇到一個問題:字段在db里存儲的是DATETIME,但保存的值只有日期,沒有時間數據,比如2018/2/26 0:00:00,顯示出來比較難看,當然也可以做一個ViewModel,在字段上添加Attribute定義來更改名稱和顯示名稱,如下:[Display(Name = "建
    03-08
  • html 基础代码
    title淄博汉企/title/headbody bgcolor="#00CC66" topmargin="200" leftmargin="200" bottommargin="200"a name="top"/a今天br /天气nbsp;nbsp;nbsp;nbsp;nbsp;不错br /font color="#CC0000"格式控制标签br /b 文字加粗方式1\bbr /str
    03-08
点击排行