HTML5 2D游戏引擎研发系列 第五章

HTML5 2D游戏引擎研发系列 第五章 <Canvas技术篇-画布技术-纹理集复杂动画>
作者:HTML5游戏开发者社区-白泽

转载请注明出处:http://html5gamedev.org/

目录

 

上一章节我们介绍了如何基于切片的动画,实际上那很难满足我的大部分动画的需求,而且必须要求宽度和高度是已知的,这样会浪费很多空白区域而且极其的不方便,我们很多情况下是需要播放下面的这几种动画的.

kuloniaofashi

看到了吗,这些丰富的动画实际上每一帧的尺寸都不一样,没有人愿意知道他们的宽度是多少,然后像上一章节一样去一个一个数,所以现在,我们需要工具去导出这种动画,如果你电脑上没有,可以下一个FLASH CS6,你只需要对动画右键>生成Sprite表,就会看到这样一个画面.

QQ截图20130917235500

它会自动计算你有多少重复的帧和消除空白区域,现在你只需要点击导出,你就会在你选择的位置看到一个png图片和一个XML配置表。

QQ截图20130917235642

当然,我考虑了你可能还没来得及下这个软件,所以你可以用我的图片和XML,图片查看原图保存吧,

donghua

XML地址 :http://jfy19771224.sinaapp.com/course/demo_3/donghua.xml

现在,如果都准备好了,你可以打开这个XML,它看来是这样的格式.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-16"?>
<TextureAtlas imagePath="donghua.png">
    <!-- Created with Adobe Flash CS6 version 12.0.0.481 -->
    <SubTexture name="fashi0000" x="206" y="340" width="47" height="93" frameX="-19" frameY="-5" frameWidth="70" frameHeight="103"/>
    <SubTexture name="fashi0001" x="154" y="340" width="51" height="94" frameX="-18" frameY="-1" frameWidth="70" frameHeight="103"/>
    <SubTexture name="fashi0002" x="1" y="405" width="54" height="95" frameX="-16" frameY="0" frameWidth="70" frameHeight="103"/>
    <SubTexture name="fashi0003" x="1" y="405" width="54" height="95" frameX="-16" frameY="0" frameWidth="70" frameHeight="103"/>
    <SubTexture name="fashi0004" x="56" y="405" width="65" height="76" frameX="0" frameY="-27" frameWidth="70" frameHeight="103"/>
    <SubTexture name="fashi0005" x="122" y="435" width="59" height="75" frameX="0" frameY="-28" frameWidth="70" frameHeight="103"/>
    <SubTexture name="fashi0006" x="182" y="435" width="59" height="73" frameX="0" frameY="-30" frameWidth="70" frameHeight="103"/>
    <SubTexture name="fashi0007" x="182" y="435" width="59" height="73" frameX="0" frameY="-30" frameWidth="70" frameHeight="103"/>
    <SubTexture name="fashi0008" x="182" y="435" width="59" height="73" frameX="0" frameY="-30" frameWidth="70" frameHeight="103"/>
    <SubTexture name="niao0000" x="1" y="140" width="75" height="149" frameX="-19" frameY="0" frameWidth="121" frameHeight="149"/>
    <SubTexture name="niao0001" x="104" y="112" width="84" height="137" frameX="-31" frameY="-4" frameWidth="121" frameHeight="149"/>
    <SubTexture name="niao0002" x="104" y="1" width="108" height="110" frameX="-13" frameY="-17" frameWidth="121" frameHeight="149"/>
    <SubTexture name="niao0003" x="189" y="112" width="63" height="117" frameX="-7" frameY="-32" frameWidth="121" frameHeight="149"/>
    <SubTexture name="niao0004" x="1" y="290" width="60" height="114" frameX="-10" frameY="-31" frameWidth="121" frameHeight="149"/>
    <SubTexture name="niao0005" x="189" y="230" width="64" height="109" frameX="-4" frameY="-32" frameWidth="121" frameHeight="149"/>
    <SubTexture name="niao0006" x="77" y="250" width="76" height="105" frameX="0" frameY="-39" frameWidth="121" frameHeight="149"/>
    <SubTexture name="niao0007" x="1" y="1" width="102" height="138" frameX="-13" frameY="-8" frameWidth="121" frameHeight="149"/>
</TextureAtlas>

仔细看看,这个XML对应了我们PNG的2个动画,分别为niao和fashi,然后看到后面的序号了吗?0001这也就是我们动画的帧编号,再往后面看看,哇,这不是我们上一章使用过的属性吗,裁切XY,裁切宽度和高度,而后面的4个参数则是我们本章的动画关键,帧偏移信息和动画最大宽度和高度,其实看到这里,后面的逻辑就很简单了,我们只需要把XML解析出来,然后让我们的动画系统根据这些参数切片就好了.现在,我们可能需要2个数据结构来存储他们,把下面的代码添加到DisplayerObject.js中,一个结构动画信息,它用于存储动画的名称和帧的序列,也就是一个数组.

1
2
3
4
5
6
7
8
9
10
11
12
13
//动画信息
function QuadData()
{
    /**
    * 动画名称
    */
    this.name="";
  
    /**
    * 动画片段
    */
    this.quadFrameLst;
};

下一个就是具体每帧动画的切片信息.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//帧信息
function QuadFrame()
{
    /**
    * 帧名称
    */
    this.name="";
  
    /**
    * 帧X坐标
    */
    this.x = 0;
  
    /**
    * 帧Y坐标
    */
    this.y = 0;
  
    /**
    * 帧宽度
    */
    this.width = 0;
  
    /**
    * 帧高度
    */
    this.height = 0;
  
    /**
    * 帧X偏移坐标
    */
    this.frameX = 0;
  
    /**
    * 帧Y偏移坐标
    */
    this.frameY = 0;
  
    /**
    * 帧最大宽度
    */
    this.frameWidth = 0;
  
    /**
    * 帧最大高度
    */
    this.frameHeight = 0;
};

现在定义好了2个结构体然后是读取XML信息和解析.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
this.AnimationXML=function()
{
    this.quadFrameList;
    this.quadDataList;
    this.loadComplete =null;
    loadTarget=this;
    this.createXMLHttpRequest=function(){
     if (window.ActiveXObject){
      xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
     }else if (window.XMLHttpRequest){
      xmlHttp = new XMLHttpRequest("Msxml2.XMLHTTP.3.0");
     };
    };
  
    //发请请求
    this.doSearch=function(url){
     this.createXMLHttpRequest();
     xmlHttp.onreadystatechange = this.handleStateChange;
     xmlHttp.open("GET",url,"true");
     xmlHttp.send(null);
    };
  
    //处理响应
    this.handleStateChange=function(){
     if (xmlHttp.readyState == 4){
      if (xmlHttp.status == 200){
       loadTarget.parseResults();
      };
     };
    };
  
    //取得URL
    this.createURL=function(text){
        this.doSearch(text);
    };
  
    //加载完毕回调侦听器
    this.addEventListener=function(fun)
    {
        this.loadComplete = fun;
    };
    /**
     * 删除侦听器
     * @param   event
     */
    this.removeEventListener=function(event)
    {
        switch(event)
        {
            case EVENT_COMPLETE:
                this.loadComplete = null;
                break;
        };
    };
    this.parseResults=function(){
        var results = xmlHttp.responseXML;
        var textureAtlas = results.getElementsByTagName("SubTexture");
        this.quadDataList=[];
        this.quadFrameList=[];
  
         for (var i = 0; i< textureAtlas.length; i++){
              subTexture =  textureAtlas[i];
              if(name!=subTexture.getAttribute("name").substr(0,subTexture.getAttribute("name").length-4))
              {
  
                this.quadFrameList=[];
                var quadData=new QuadData();
                quadData.name=subTexture.getAttribute("name").substr(0,subTexture.getAttribute("name").length-4);
                quadData.quadFrameLst=this.quadFrameList;
                this.quadDataList.push(quadData);
              };
  
              var cacheframeWidth;
              var cacheframeHeight;
              var cacheWidth;
              var cacheHeight
              var quadFrame=new QuadFrame();
              quadFrame.name=subTexture.getAttribute("name");
              var replace=subTexture.getAttribute("x");
              if(replace!=null)
              {
                quadFrame.x=replace;
              };
  
              replace=subTexture.getAttribute("y");
              if(replace!=null)
              {
                quadFrame.y=replace;
              };
  
              replace=subTexture.getAttribute("width");
              if(replace!=null)
              {
                  quadFrame.width=replace;
                  cacheWidth=replace;
              };
  
              replace=subTexture.getAttribute("height");
              if(replace!=null)
              {
                  quadFrame.height=replace;
                  cacheHeight=replace;
              };
  
              replace=subTexture.getAttribute("frameX");
              if(replace!=null)
              {
                quadFrame.frameX=subTexture.getAttribute("frameX");
              }else
              {
                  quadFrame.frameX=0;
              }
  
              replace=subTexture.getAttribute("frameY");
              if(replace!=null)
              {
                quadFrame.frameY=replace;
              }else
              {
                  quadFrame.frameY=0;
              }
  
              replace=subTexture.getAttribute("frameWidth");
              if(replace!=null)
              {
                quadFrame.frameWidth=replace;
                cacheframeWidth=replace;
              }else{
  
                  if(cacheframeWidth!=null)
                  {
                      quadFrame.frameWidth=cacheframeWidth;
                  }else
                  {
                      quadFrame.frameWidth=cacheWidth;
                  }
              }
  
              replace=subTexture.getAttribute("frameHeight");
              if(replace!=null)
              {
                 quadFrame.frameHeight=replace;
                 cacheframeHeight=replace;
              }else
              {
                  if(cacheframeHeight!=null)
                  {
                      quadFrame.frameHeight=cacheframeHeight;
                  }else
                  {
                      quadFrame.frameHeight=cacheHeight;
                  }
  
              }
  
              this.quadFrameList.push(quadFrame);
              name=subTexture.getAttribute("name").substr(0,subTexture.getAttribute("name").length-4);
         }
  
         if(this.loadComplete!=null){
            this.loadComplete(this);
         };
    };
};

然后回到Main.js定义一个需要读取的XML队列.

1
var xmlAddress=["donghua.xml"];

和已经处理完毕的数据队列.

1
var xmlStart=[];

最后是开始读取资源.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var xmlid=0;
this.loadXml=function()
{
    var load=new AnimationXML();
    this.initer=function(e) 
    {   
        xmlStart.push(load);
        xmlid++;
  
        if(xmlid<xmlAddress.length)
        {
  
            loadXml();
        }
        if(xmlid==xmlAddress.length)
        {
            init();
            alert("XML加载完毕"+xmlStart.length);
        }
    }
    load.addEventListener(EVENT_COMPLETE,this.initer);
    load.createURL(xmlAddress[xmlid]);
}

还记得我们上一章节的读取图片的队列加载器吗?现在我们需要整合一下,可以选择先加载图片还是XML,整合后的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//需要加载的图像资源
var imageAddress=["donghua.png","map.png"];
  
//需要加载的XML对象池
var xmlAddress=["donghua.xml"];
  
//已经加载好的图像资源池
var imageStart=[];
//XML已经加载好的对象池
var xmlStart=[];
  
//当前加载资源的ID
var imageId=0;
  
//XML加载ID
var xmlid=0;
  
//加载回调函数
this.loadImag=function()
{
    var imageObj=new Image();
    imageObj.src=imageAddress[imageId];
    imageObj.onload=function(){
        if(imageObj.complete==true){
            imageStart.push(imageObj);
            imageId++;
            if(imageId<imageAddress.length)
            {
                loadImag();
            }
            if(imageId==imageAddress.length)
            {
                loadXml();
            }
  
        }
    }
}
  
this.loadXml=function()
{
    var load=new AnimationXML();
    this.initer=function(e)
    {
        xmlStart.push(load);
        xmlid++;
  
        if(xmlid<xmlAddress.length)
        {
            loadXml();
        }
        if(xmlid==xmlAddress.length)
        {
            init();
        }
    }
    load.addEventListener(this.initer);
    load.createURL(xmlAddress[xmlid]);
}
  
window.onload=function(){
    this.loadImag();
}
  
//定义场景管理器
var stage2d;
  
//初始化函数
function init () {
  
    //创建场景管理器
    stage2d=new Stage2D();
  
    //启用场景逻辑
   stage2d.init();
}

好像代码有点多了,但其实逻辑很简单,我们把加载好的数据存放在

1
xmlStart

可以通过id访问我们加载的第几个数据比如

1
xmlStart[id]

然后通过来访问数据里的帧信息

1
xmlStart[id].quadDataList

现在万事俱备,我们需要动画系统支持XML所以要在DisplayerObject.js中稍作改动,现在遇到了一个设计问题,我们之前有2种方式显示图片的某个区域,通过isPlay来控制是否手动个切片,现在又多了一个XML控制,现在我们需要把isPlay变成一个int类型,然后修改3个地方,来支持我们以后的扩展,其实我是有点恋旧情怀.来看看我们修改后的代码吧.

在MovieClip2D类的构造函数里加入第二个参数data,我们的动画数据就是通过第二参数传递进来的

1
function MovieClip2D(img,data)

然后是动画更新逻辑部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//动画更新逻辑
    this.upFrameData=function()
    {
        switch(this.isPlay)
        {
            case 1:
                this.mcY=this.frameHeadY*this.frameHeight;
                this.mcX=this.frameHeadX*this.frameWidth+this.currentFrame*this.frameWidth;
                this.currentFrame++;
                if(this.currentFrame>=this.totalFrames)
                {
                    this.currentFrame=0;
                }
                break;
            case 2:
                this.width=data[this.nameId].quadFrameLst[this.currentFrame].width;
                this.height=data[this.nameId].quadFrameLst[this.currentFrame].height
  
                this.mcX=data[this.nameId].quadFrameLst[this.currentFrame].x;
                this.mcY=data[this.nameId].quadFrameLst[this.currentFrame].y;
                this.frameX=data[this.nameId].quadFrameLst[this.currentFrame].frameX;
                this.frameY=data[this.nameId].quadFrameLst[this.currentFrame].frameY;
                this.frameWidth=data[this.nameId].quadFrameLst[this.currentFrame].frameWidth;
                this.frameHeight=data[this.nameId].quadFrameLst[this.currentFrame].frameHeight;
                this.totalFrames=data[this.nameId].quadFrameLst.length;
                this.currentFrame++;
                if(this.currentFrame>=this.totalFrames)
                {
                    this.currentFrame=0;
                }
                break;
        }
    }

之后在paint重绘函数中做如下修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//动画类的重绘函数
    this.paint=function()
    {
        if(this.visible)
        {
            this.upFrameData();
  
            //保存画布句柄状态
            context.save();
  
            //更改画布句柄的透明度,从这以后绘制的图像都会依据这个透明度
            context.globalAlpha=this.alpha;
  
            //设置画布句柄的位置,实际上是设置的图像的位置
            context.translate(this.x,this.y);
  
            //设置画布旋转角度实际上是设置了图像的角度,参数是弧度,所以我们必须把角度转换为弧度
            context.rotate(this.rotation*Math.PI/180);
  
            //设置画布句柄的比例,实际上是设置了图像的比例
            context.scale(this.scaleX,this.scaleY);
  
            switch(this.isPlay)
            {
                case 1:
                    context.drawImage(img,this.mcX,this.mcY,this.frameWidth,this.frameHeight,-this.frameWidth/2,-this.frameHeight/2,this.frameWidth,this.frameHeight);
                    break;
                case 2:
                    //增加了帧信息的偏移量,和最后一段的动画实际宽度和高度
                    context.drawImage(img,this.mcX,this.mcY,this.width,this.height,
                        -(this.frameX)-this.frameWidth/2,
                        -(this.frameY)-this.frameHeight/2
                        ,this.width,this.height);
                    break
                default :
                    context.drawImage(img,this.mcX,this.mcY,this.frameWidth,this.frameHeight,-this.frameWidth/2,-this.frameHeight/2,this.frameWidth,this.frameHeight);
                    break;
            }
  
            //最后返回画布句柄的状态,因为画布句柄是唯一的,它的状态也是唯一的,当我们使用之后方便其他地方使用所以
            //需要返回上一次保存的状态,就好像什么事情都没有发生过
            context.restore();
        }
    }

好了,是时候加入新的切片代码了.现在我们是时候用到MovieClip2D类添加一些新成员.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//动画实际宽度
    this.width=0;
  
    //动画实际高度
    this.height=0;
  
    //帧偏移X信息
    this.frameX=0;
  
    //帧偏移Y信息
    this.frameY=0;
  
    //动画ID
    this.nameId=0;

 

我们保留了上一章节的动画系统,也兼容了这一章的复杂动画,现在让我们回到Main.js中的init初始化函数添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//初始化函数
function init () {
  
    //创建场景管理器
    stage2d=new Stage2D();
  
    //启用场景逻辑
    stage2d.init();
  
    var mc=new MovieClip2D(imageStart[0],xmlStart[0].quadDataList);
    mc.isPlay=2;
    mc.x=500;
    mc.y=500;
    stage2d.addChild(mc);
  
}

如果没有出任何问题的画,现在你可以测试页面,它应该是这个样子

QQ截图20130918220739

 

动画播放起来了,但是有个很严重的问题,动画的播放速度跟抽筋了一样,早在第一章节我们就介绍过动画的帧率一般是24帧和30,但是现在我们播放的速度是几乎为0延迟的播放,所以我们现在需要加入动画帧率的概念,现在我们先让我们在MovieClip2D里加入2个新的成员变量.

1
2
3
4
5
//动画播放速度
    this.animationSpeed=24;
  
    //用于计算过去的时间
    this.animationTime=0;

然后修改upFrameData更新函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//动画更新逻辑
    this.upFrameData=function()
    {
        switch(this.isPlay)
        {
            case 1:
                this.mcY=this.frameHeadY*this.frameHeight;
                this.mcX=this.frameHeadX*this.frameWidth+this.currentFrame*this.frameWidth;
  
                break;
            case 2:
                this.width=data[this.nameId].quadFrameLst[this.currentFrame].width;
                this.height=data[this.nameId].quadFrameLst[this.currentFrame].height
  
                this.mcX=data[this.nameId].quadFrameLst[this.currentFrame].x;
                this.mcY=data[this.nameId].quadFrameLst[this.currentFrame].y;
                this.frameX=data[this.nameId].quadFrameLst[this.currentFrame].frameX;
                this.frameY=data[this.nameId].quadFrameLst[this.currentFrame].frameY;
                this.frameWidth=data[this.nameId].quadFrameLst[this.currentFrame].frameWidth;
                this.frameHeight=data[this.nameId].quadFrameLst[this.currentFrame].frameHeight;
                this.totalFrames=data[this.nameId].quadFrameLst.length;
  
                break;
        }
        var date=new Date();
        if((date.getTime()-this.animationTime>=1000/this.animationSpeed))
        {
            this.animationTime=date.getTime();
            this.currentFrame++;
        }
        if(this.currentFrame>=this.totalFrames)
        {
            this.currentFrame=0;
        }
    }

看到了吗,我们只是把下一帧的循环逻辑放在了最后并且加上了一个限制,我们通过date.getTimer()来访问1970年到现在的毫秒数,然后让它和上一次记录的时间相减,这样就能求出动画运行的时间是多少了,如果大于1000/速度的时间就开始下一帧播放,我们希望用户输入的是帧率而不是毫秒 ,所以我们在底层除以了1000,现在试试新的动画系统吧,把帧率设置成24帧,漂亮的动画就这样出来了,最后,我们还有一些辅助功能需要完成,比如动画的播放和停止,跳转到某个帧并且播放和停止,切换动画等等,下面是代码片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//逻辑更新开关
    this.logicUpData=true;
  
    //跳转到某一帧并且播放
    this.gotoAndPlay=function(value)
    {
        this.currentFrame=value;
        this.logicUpData=true;
    }
  
    //跳转到某一帧并且停止
    this.gotoAndStop=function(value)
    {
        this.currentFrame=value;
        this.logicUpData=false;
    }
  
    //开始播放动画
    this.play=function()
    {
        this.logicUpData=true;
    }
  
    //停止播放动画
    this.stop=function()
    {
        this.logicUpData=false;
    }
  
    //查询名字
    this.queryName=function(name)
    {
        for(var i=0;i<data.length;i++)
        {
            if(data[i].name==name)
            {
                return i;
            };
        };
        return 0;
    };
  
    //设置场景,可以是数字或者名称
    this.scene=function(name)
    {
        if(isNaN(name))
        {
            this.nameId=this.queryName(name);
        }else
        {
            this.nameId=name;
        };
    };
  
    //动画更新逻辑
    this.upFrameData=function()
    {
        switch(this.isPlay)
        {
            case 1:
                this.mcY=this.frameHeadY*this.frameHeight;
                this.mcX=this.frameHeadX*this.frameWidth+this.currentFrame*this.frameWidth;
  
                break;
            case 2:
                this.width=data[this.nameId].quadFrameLst[this.currentFrame].width;
                this.height=data[this.nameId].quadFrameLst[this.currentFrame].height
  
                this.mcX=data[this.nameId].quadFrameLst[this.currentFrame].x;
                this.mcY=data[this.nameId].quadFrameLst[this.currentFrame].y;
                this.frameX=data[this.nameId].quadFrameLst[this.currentFrame].frameX;
                this.frameY=data[this.nameId].quadFrameLst[this.currentFrame].frameY;
                this.frameWidth=data[this.nameId].quadFrameLst[this.currentFrame].frameWidth;
                this.frameHeight=data[this.nameId].quadFrameLst[this.currentFrame].frameHeight;
                this.totalFrames=data[this.nameId].quadFrameLst.length;
  
                break;
        }
        if(this.logicUpData)
        {
            var date=new Date();
            if((date.getTime()-this.animationTime>=1000/this.animationSpeed))
            {
                this.animationTime=date.getTime();
                this.currentFrame++;
            }
            if(this.currentFrame>=this.totalFrames)
            {
                this.currentFrame=0;
            }
        }
    }

现在你可以回到Main.js去生成2个动画了.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//初始化函数
function init () {
  
    //创建场景管理器
    stage2d=new Stage2D();
  
    //启用场景逻辑
    stage2d.init();
  
    var mc=new MovieClip2D(imageStart[0],xmlStart[0].quadDataList);
    mc.isPlay=2;
    mc.x=100;
    mc.y=500;
    mc.scene("niao")
    stage2d.addChild(mc);
  
    var mc2=new MovieClip2D(imageStart[0],xmlStart[0].quadDataList);
    mc2.isPlay=2;
    mc2.x=500;
    mc2.y=500;
    mc2.scene(0)
    stage2d.addChild(mc2);
  
}

如果没有出问题的话,应该就出现下面的画面了

QQ截图20130918230100

哇,终于结束了,现在我们离游戏又进了一步了,总结一下,我们这一章节除了代码多还是代码多,其实知识点非常得少,基本的知识点都是上2章的内容,我们现在只不过是借助了工具和XML记录了切片信息而已,现在这个动画系统还不是很完善,你可以自己添加帧事件,帧标签,动画延迟(打击感强的游戏都会用到这个技术,比如当挥砍的动作触碰到怪物时可以让这个动画在一定时间段之类,等等,如果有兴趣欢迎来群里交流,最后我得想想下一章的内容了。

在线演示 源码下载

转载请注明:HTML5游戏开发者社区 » HTML5 2D游戏引擎研发系列 第五章

 

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值