<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【CSON原創(chuàng)】HTML5游戲框架cnGameJS開(kāi)發(fā)實(shí)錄(動(dòng)畫(huà)篇)

      返回目錄 

       在游戲中,游戲角色的動(dòng)畫(huà)效果是一個(gè)游戲必不可少的一部分。這節(jié)我們以構(gòu)造超級(jí)馬里奧的角色為例,講解cnGameJS里動(dòng)畫(huà)的實(shí)現(xiàn)。

      1.原理:

        一個(gè)動(dòng)畫(huà)如果要實(shí)現(xiàn)一連串動(dòng)作,我們可以把每個(gè)動(dòng)作的快照保留起來(lái),并放在一個(gè)大圖上面,然后每次幀更新的時(shí)候,就在每個(gè)動(dòng)作的快照之間循環(huán)顯示,最終得出一個(gè)動(dòng)畫(huà)。因此我們首先要準(zhǔn)備一個(gè)類似下面的這種圖片:

        看到不?把每個(gè)動(dòng)作放在圖片的不同位置上,之后就可以通過(guò)改變顯示位置實(shí)現(xiàn)動(dòng)畫(huà)效果了。

        當(dāng)cnGameJS調(diào)用start方法開(kāi)始游戲后,將會(huì)調(diào)用傳入的gameObj的initialize方法進(jìn)行初始化,并且生成一個(gè)游戲循環(huán),循環(huán)里每次調(diào)用gameObj的update和draw方法。(詳見(jiàn)(HTML5游戲框架cnGameJS開(kāi)發(fā)實(shí)錄(資源加載篇)和 HTML5游戲框架cnGameJS開(kāi)發(fā)實(shí)錄(游戲循環(huán)篇)))因此我們可以把動(dòng)畫(huà)的初始化放在gameObj的initialize中,update和draw分別放在gameObj的update和draw中,實(shí)現(xiàn)動(dòng)畫(huà)播放。

      效果:

       


      代碼:

      <body>
      <canvas id="gameCanvas">請(qǐng)使用支持canvas的瀏覽器查看</canvas>
      </body>
      <script src="https://files.cnblogs.com/Cson/cnGame_v1.0.js"></script>
      <script>
      var Src="http://pic002.cnblogs.com/images/2012/273330/2012021312050269.png";
      /* 初始化 */
      cnGame.init(
      'gameCanvas',{width:50,height:60});
      var gameObj={
      initialize:
      function(){
      this.marie=cnGame.SpriteSheet("marie",Src,{frameSize:[50,60],width:150,height:60,loop:true});
      },
      update:
      function(){
      this.marie.update();
      },
      draw:
      function(){
      this.marie.draw();
      }

      }
      cnGame.loader.start([Src],gameObj);
      </script>
       
      2.實(shí)現(xiàn)
        正如上面看到的,我們只需要用很少的代碼量,就可以實(shí)現(xiàn)一個(gè)幀動(dòng)畫(huà)的播放,接下來(lái)將介紹cnGameJS里的幀動(dòng)畫(huà)是怎樣封裝的。
        大家很容易可以發(fā)現(xiàn),cnGameJS都遵循一個(gè)特定的模式,把對(duì)象的階段分為三個(gè):initialize(初始化),update(幀更新)和draw(繪制)。這樣我們可以很方便地把不同功能的代碼寫在對(duì)應(yīng)的階段內(nèi)。spriteSheet幀動(dòng)畫(huà)也不例外,同樣按照這種模式來(lái)寫。
       
        初始化:用戶對(duì)一些必要的信息進(jìn)行設(shè)定。
          spriteSheet.prototype={
      /**
      *初始化
      *
      */
      init:function(id,src,options){

      /**
      *默認(rèn)對(duì)象
      *
      */
      var defaultObj={
      x:0,
      y:0,
      width:120,
      height:40,
      frameSize:[40,40],
      frameDuration:100,
      direction:"right", //從左到右
      beginX:0,
      beginY:0,
      loop:false,
      bounce:false
      };
      options=options||{};
      options=cg.core.extend(defaultObj,options);
      this.id=id; //spriteSheet的id
      this.src=src; //圖片地址
      this.x=options.x; //動(dòng)畫(huà)X位置
      this.y=options.y; //動(dòng)畫(huà)Y位置
      this.width=options.width; //圖片的寬度
      this.height=options.height; //圖片的高度
      this.image=cg.loader.loadedImgs[this.src]; //圖片對(duì)象
      this.frameSize=options.frameSize; //每幀尺寸
      this.frameDuration=options.frameDuration; //每幀持續(xù)時(shí)間
      this.direction=options.direction; //讀取幀的方向(從做到右或從上到下)
      this.currentIndex=0; //目前幀索引
      this.beginX=options.beginX; //截取圖片的起始位置X
      this.beginY=options.beginY; //截圖圖片的起始位置Y
      this.loop=options.loop; //是否循環(huán)播放
      this.bounce=options.bounce; //是否往返播放
      this.onFinsh=options.onFinsh; //播放完畢后的回調(diào)函數(shù)
      this.frames=caculateFrames(options); //幀信息集合
      this.now=new Date().getTime(); //當(dāng)前時(shí)間
      this.last=new Date().getTime(); //上一幀開(kāi)始時(shí)間
      },
        
        上面的參數(shù)比較多,都是一些對(duì)幀動(dòng)畫(huà)屬性的預(yù)設(shè)置。需要注意的是我們調(diào)用了私有方法caculateFrames來(lái)計(jì)算每個(gè)幀的信息,并保存到frames內(nèi),為幀繪制做準(zhǔn)備。
       
        幀更新:
        在每一幀的更新過(guò)程中,我們首先獲取當(dāng)前時(shí)間作為幀的開(kāi)始時(shí)間,并且和上一次幀的開(kāi)始時(shí)間相減,就得出上一次幀的用時(shí)。如果用時(shí)超過(guò)之前設(shè)置的每幀的用時(shí),則可以進(jìn)行幀更新。然后判斷是否循環(huán)或者往返播放動(dòng)畫(huà),按情況更新對(duì)應(yīng)的幀索引。在最終確定幀的索引后,就可以從frames數(shù)組中獲取該幀的信息,并返回。
              /**
      *更新幀
      *
      */
      update:function(){

      this.now=new Date().getTime();
      var frames=this.frames;
      if((this.now-this.last)>this.frameDuration){//如果間隔大于幀間間隔,則update
      var currentIndex=this.currentIndex;
      var length=this.frames.length;
      this.last=this.now;

      if(currentIndex>=length-1){
      if(this.loop){ //循環(huán)
      return frames[this.currentIndex=0];
      }
      else if(!this.bounce){//沒(méi)有循環(huán)并且沒(méi)有往返滾動(dòng),則停止在最后一幀
      this.onFinsh&&this.onFinsh();
      this.onFinsh=undefined;
      return frames[currentIndex];
      }
      }
      if((this.bounce)&&((currentIndex>=length-1&&path>0)||(currentIndex<=0&&path<0))){ //往返
      path*=(-1);
      }
      this.currentIndex+=path;

      }
      return frames[this.currentIndex];
      },

        幀繪制:

        在幀更新后,已經(jīng)獲取到當(dāng)前幀的索引,因此draw方法就可以從保存所有幀信息的frames獲取到當(dāng)前幀的信息(包括圖像截取的起始位置等),從而在指定位置截取大圖片,并畫(huà)出該圖片區(qū)域的圖像:

              /**
      *在特定位置繪制該幀
      *
      */
      draw:function(){

      var currentFrame=this.getCurrentFrame();
      var width=this.frameSize[0];
      var height=this.frameSize[1];
      cg.context.drawImage(this.image,currentFrame.x,currentFrame.y,width,height,this.x,this.y,width,height);
      }

       

      最后,還提供跳到特定幀等方法。


      動(dòng)畫(huà)模塊所有源碼:

          /**
      *包含多幀圖像的大圖片
      *
      */
      spriteSheet=function(id,src,options){
      if(!(this instanceof arguments.callee)){
      return new arguments.callee(id,src,options);
      }
      this.init(id,src,options);
      }
      spriteSheet.prototype={
      /**
      *初始化
      *
      */
      init:function(id,src,options){

      /**
      *默認(rèn)對(duì)象
      *
      */
      var defaultObj={
      x:0,
      y:0,
      width:120,
      height:40,
      frameSize:[40,40],
      frameDuration:100,
      direction:"right", //從左到右
      beginX:0,
      beginY:0,
      loop:false,
      bounce:false
      };
      options=options||{};
      options=cg.core.extend(defaultObj,options);
      this.id=id; //spriteSheet的id
      this.src=src; //圖片地址
      this.x=options.x; //動(dòng)畫(huà)X位置
      this.y=options.y; //動(dòng)畫(huà)Y位置
      this.width=options.width; //圖片的寬度
      this.height=options.height; //圖片的高度
      this.image=cg.loader.loadedImgs[this.src]; //圖片對(duì)象
      this.frameSize=options.frameSize; //每幀尺寸
      this.frameDuration=options.frameDuration; //每幀持續(xù)時(shí)間
      this.direction=options.direction; //讀取幀的方向(從做到右或從上到下)
      this.currentIndex=0; //目前幀索引
      this.beginX=options.beginX; //截取圖片的起始位置X
      this.beginY=options.beginY; //截圖圖片的起始位置Y
      this.loop=options.loop; //是否循環(huán)播放
      this.bounce=options.bounce; //是否往返播放
      this.onFinsh=options.onFinsh; //播放完畢后的回調(diào)函數(shù)
      this.frames=caculateFrames(options); //幀信息集合
      this.now=new Date().getTime(); //當(dāng)前時(shí)間
      this.last=new Date().getTime(); //上一幀開(kāi)始時(shí)間
      },
      /**
      *更新幀
      *
      */
      update:function(){

      this.now=new Date().getTime();
      var frames=this.frames;
      if((this.now-this.last)>this.frameDuration){//如果間隔大于幀間間隔,則update
      var currentIndex=this.currentIndex;
      var length=this.frames.length;
      this.last=this.now;

      if(currentIndex>=length-1){
      if(this.loop){ //循環(huán)
      return frames[this.currentIndex=0];
      }
      else if(!this.bounce){//沒(méi)有循環(huán)并且沒(méi)有往返滾動(dòng),則停止在最后一幀
      this.onFinsh&&this.onFinsh();
      this.onFinsh=undefined;
      return frames[currentIndex];
      }
      }
      if((this.bounce)&&((currentIndex>=length-1&&path>0)||(currentIndex<=0&&path<0))){ //往返
      path*=(-1);
      }
      this.currentIndex+=path;

      }
      return frames[this.currentIndex];
      },
      /**
      *跳到特定幀
      *
      */
      index:function(index){
      this.currentIndex=index;
      return this.frames[this.currentIndex];
      },
      /**
      *獲取現(xiàn)時(shí)幀
      *
      */
      getCurrentFrame:function(){
      return this.frames[this.currentIndex];
      },
      /**
      *在特定位置繪制該幀
      *
      */
      draw:function(){

      var currentFrame=this.getCurrentFrame();
      var width=this.frameSize[0];
      var height=this.frameSize[1];
      cg.context.drawImage(this.image,currentFrame.x,currentFrame.y,width,height,this.x,this.y,width,height);
      }

      }
      this.SpriteSheet=spriteSheet;

      });



       
        
       

      posted @ 2012-02-14 12:42  Cson  閱讀(5271)  評(píng)論(8)    收藏  舉報(bào)
      主站蜘蛛池模板: 亚洲精品无码日韩国产不卡av | 亚洲码和欧洲码一二三四| 精品人妻久久久久久888| 亚洲成人一区二区av| 最新亚洲av日韩av二区| 91中文字幕一区在线| 中文字幕亚洲精品人妻| 人妻系列无码专区69影院| 亚洲人成自拍网站在线观看| 人妻无码av中文系列久| 亚洲av无码片在线播放| 精品无码专区久久久水蜜桃| 久久精品国产亚洲成人av| 2021国产成人精品久久| 国产99视频精品免费视频36| 久久国产自偷自偷免费一区| 丰满少妇在线观看网站| 99精品人妻少妇一区| 国产网红女主播精品视频| 国产乱码日产乱码精品精| 国产日韩精品欧美一区喷水| 麻豆一区二区中文字幕| 日本一区二区不卡精品| 亚洲精品中文av在线| 欧美人与性动交ccoo| 亚洲欧洲久久激情久av| 国产精品老熟女露脸视频| 亚洲第一极品精品无码久久| 国产精品高清视亚洲乱码| 国产内射性高湖| 免费国产一级 片内射老| 久久香蕉国产亚洲av麻豆| 亚洲av永久无码天堂影院| 久在线精品视频线观看| 国产中文字幕精品在线| 艳妇乳肉豪妇荡乳av无码福利| 亚洲一级特黄大片一级特黄| 国产精品日日摸夜夜添夜夜添2021| 西乡县| 久久夜色噜噜噜亚洲av| 97欧美精品系列一区二区|