Starling外部资源管理

编程入门 行业动态 更新时间:2024-10-10 11:23:45

Starling外部<a href=https://www.elefans.com/category/jswz/34/1755980.html style=资源管理"/>

Starling外部资源管理

对于所有程序员来说,外部资源管理意味着你只需要关心你的程序逻辑即可,对于外部的美工动画你可以不用过多的考虑。也正式因为一些不规范的动画或者美工素材导致一些程序员对此有很大的抵触心里。我也曾经见过一些制作的非常混乱的动画内容,导致在程序配合的时候无从下手,这种情况是极为糟糕的。相对于沟通成本来说,你可能更加倾向于位图。现在有了GPU,你也可以强制的在项目中使用位图资源,而放弃混乱不堪的矢量图内容。

     当然,如果是多人开发的话,也需要注意程序员之间的配合,使用统一的接口,统一访问各种资源。否则你的项目可能会陷入进退两难的境地。对于程序规范这方面,本文不深入设计,大家有兴趣可以去搜索一些代码规范一类的文章。

     资源的外部管理另外一个好处就是方便你的国际化,当然,如果你想发展海外市场,你的游戏或者应用还需要考虑到一些当地的法律和风俗习惯,比如在天朝你不可能去制作色情游戏,在一些中东地区国家你需要注意宗教问题。这些都会牵制着你的游戏是否能够得到当地网民的追捧程度。

      在Starling中,我们可以使用系统默认为我们提供的一些sprite sheet技术来方便的制作位图序列动画。当然,你可以编写自己的数据解析逻辑来方便的控制你的可视化内容。在这篇文章中,我将继续编写我的“打飞机”游戏,其中关于界面的部分,我都会抽离成为外部可配置的文件,这样不仅仅方便你游戏中所有UI的调整,同时也方便后期的国际化移植。

      首先,我们来看一看在Starlig中如何使用sprite sheet。你需要的是已经制作好的素材和一个能够生成sprite sheet配置数据的软件,这里笔者使用的是TexturePacker。值得称赞的是,这款软件拥有Mac和Windows两个版本。你可以根据你的需要来进行下载,在试用期过了之后你需要付费并且激活。下面这幅图片是我所生成的图片和配置文件(这里的素材不是最终完整版)。

生成的XML配置文件:

view source print ?
01<?xml version="1.0" encoding="UTF-8"?>
02<!-- Created with TexturePacker >
03<!-- $TexturePacker:SmartUpdate:a9479bcf80444cacbc2cb7cb2411210b$ -->
04<TextureAtlas imagePath="config_ui.png">
05    <SubTexture name="0_num" x="1008" y="42" width="12" height="18" frameX="-10" frameY="-5" frameWidth="30" frameHeight="30"/>
06    <SubTexture name="1_num" x="1016" y="82" width="6" height="16" frameX="-12" frameY="-6" frameWidth="30" frameHeight="30"/>
07    <SubTexture name="1_panel" x="933" y="263" width="60" height="126" frameX="-55" frameY="-84" frameWidth="200" frameHeight="300"/>
08    <SubTexture name="2_num" x="1008" y="62" width="12" height="18" frameX="-10" frameY="-4" frameWidth="30" frameHeight="30"/>
09    <SubTexture name="2_panel" x="806" y="425" width="92" height="126" frameX="-52" frameY="-84" frameWidth="200" frameHeight="300"/>
10    <SubTexture name="3_num" x="1002" y="138" width="10" height="18" frameX="-10" frameY="-5" frameWidth="30" frameHeight="30"/>
11    <SubTexture name="3_panel" x="900" y="485" width="90" height="126" frameX="-52" frameY="-84" frameWidth="200" frameHeight="300"/>
12    <SubTexture name="4_num" x="1002" y="102" width="12" height="16" frameX="-10" frameY="-6" frameWidth="30" frameHeight="30"/>
13    <SubTexture name="5_num" x="1002" y="158" width="10" height="18" frameX="-11" frameY="-5" frameWidth="30" frameHeight="30"/>
14    <SubTexture name="6_num" x="1008" y="2" width="14" height="18" frameX="-8" frameY="-5" frameWidth="30" frameHeight="30"/>
15    <SubTexture name="7_num" x="1002" y="120" width="12" height="16" frameX="-10" frameY="-6" frameWidth="30" frameHeight="30"/>
16    <SubTexture name="8_num" x="1002" y="82" width="12" height="18" frameX="-10" frameY="-5" frameWidth="30" frameHeight="30"/>
17    <SubTexture name="9_num" x="1008" y="22" width="14" height="18" frameX="-8" frameY="-5" frameWidth="30" frameHeight="30"/>
18    <SubTexture name="aircraft_enemy_0" x="933" y="194" width="67" height="67"/>
19    <SubTexture name="aircraft_enemy_1" x="806" y="194" width="125" height="125"/>
20    <SubTexture name="aircraft_enemy_2" x="911" y="391" width="93" height="92"/>
21    <SubTexture name="aircraft_player" x="806" y="321" width="103" height="102"/>
22    <SubTexture name="and_btn" x="858" y="594" width="39" height="39"/>
23    <SubTexture name="back_btn" x="653" y="727" width="247" height="60" frameX="-5" frameY="-5" frameWidth="257" frameHeight="72"/>
24    <SubTexture name="blood" x="806" y="553" width="50" height="50"/>
25    <SubTexture name="blood_line" x="806" y="2" width="200" height="30"/>
26    <SubTexture name="blood_line_context" x="806" y="34" width="200" height="30"/>
27    <SubTexture name="change_missile" x="899" y="613" width="50" height="50"/>
28    <SubTexture name="get_skill" x="951" y="613" width="50" height="50"/>
29    <SubTexture name="go_panel" x="806" y="66" width="194" height="126" frameX="-4" frameY="-82" frameWidth="200" frameHeight="300"/>
30    <SubTexture name="help_back_ground" x="404" y="2" width="400" height="600"/>
31    <SubTexture name="help_game_btn" x="404" y="666" width="247" height="60" frameX="-5" frameY="-5" frameWidth="257" frameHeight="72"/>
32    <SubTexture name="invincible" x="653" y="604" width="50" height="50"/>
33    <SubTexture name="setting_back_ground" x="2" y="604" width="400" height="600"/>
34    <SubTexture name="setting_game_btn" x="653" y="665" width="247" height="60" frameX="-5" frameY="-5" frameWidth="257" frameHeight="72"/>
35    <SubTexture name="start_game_back_ground" x="2" y="2" width="400" height="600"/>
36    <SubTexture name="start_game_btn" x="404" y="604" width="247" height="60" frameX="-5" frameY="-5" frameWidth="257" frameHeight="72"/>
37    <SubTexture name="sub_btn" x="858" y="553" width="39" height="39"/>
38</TextureAtlas>

      好了,到此位置,UI素材部分已经准备妥当,你需要在程序中编写你的代码来获取这些资源。那么在Starling中图片素材资源最终都会被处理为贴图资源,也就是Texture对象。但不幸的是starling.textures.Texture类只能处理一张位图图片,不能够处理sprite sheet类型的素材,此时你就需要使用到starling.textures.TextureAtlas这个类来进行制作,具体代码如下:

view source print ?
1var textures:Texture = Texture.fromBitmapData( PublicData.texturesBitmapData );
2            PublicData.UI_TEXTURES_ATLAS = new TextureAtlas( textures, PublicData.texturesXML );
3            textures = null;

通过这样的操作后,你可以使用类似于下面的语句来方便的获取单独的贴图资源。

view source print ?
1PublicData.UI_TEXTURES_ATLAS.getTexture("background");

注意,这里的"background"字符串来自于XML配置表中SubTexture节点的name属性。

      通过这种方法,我们对现在的所有资源进行统一管理,并且能够很好的进行内存控制。当然,我不建议你将所有的资源全部放到一张图片中,你需要根据你的项目需要进行有效的分配管理。

      下面则是使用Starling来制作位图字体。对于制作webgame的同学来说,在网页中使用个性化字体是非常纠结的事情,尤其中中文字体,我们不可能将一个30M+的字体文件打包到swf文件中让用户加载,对于国内的网速来说是非常不乐观的。使用问题字体你会有效的缓解这方面的压力。当然,对于中文还是无能为力。下面的图片是笔者用GlyphDesigner这款软件来制作的,不幸的是这方面的软件我目前找到了三款MAC系统的,而且质量都不错,对于windows平台还没有发现比较好的软件。图片和配置文件如下:

XML配置文件:

view source print ?
01<font>
02    <info face="mebius" size="32" bold="0" italic="0" chasrset="" unicode="0" stretchH="100" smooth="1" aa="1" padding="0,0,0,0" spacing="2,2"/>
03    <common lineHeight="36" base="29" scaleW="128" scaleH="64" pages="1" packed="0"/>
04    <pages>
05        <page id="0" file="number text.png"/>
06    </pages>
07    <chars count="11">
08        <char id="57" x="2" y="3" width="20" height="28" xoffset="1" yoffset="4" xadvance="18" page="0" chnl="0" letter="9"/>
09        <char id="56" x="24" y="3" width="20" height="28" xoffset="1" yoffset="4" xadvance="18" page="0" chnl="0" letter="8"/>
10        <char id="54" x="46" y="3" width="20" height="28" xoffset="1" yoffset="4" xadvance="18" page="0" chnl="0" letter="6"/>
11        <char id="48" x="68" y="3" width="19" height="28" xoffset="1" yoffset="4" xadvance="18" page="0" chnl="0" letter="0"/>
12        <char id="51" x="89" y="3" width="19" height="28" xoffset="1" yoffset="4" xadvance="18" page="0" chnl="0" letter="3"/>
13        <char id="52" x="2" y="33" width="20" height="27" xoffset="0" yoffset="5" xadvance="18" page="0" chnl="0" letter="4"/>
14        <char id="53" x="24" y="33" width="20" height="27" xoffset="1" yoffset="5" xadvance="18" page="0" chnl="0" letter="5"/>
15        <char id="50" x="46" y="33" width="20" height="27" xoffset="1" yoffset="5" xadvance="18" page="0" chnl="0" letter="2"/>
16        <char id="55" x="68" y="33" width="20" height="27" xoffset="2" yoffset="5" xadvance="18" page="0" chnl="0" letter="7"/>
17        <char id="49" x="90" y="33" width="13" height="27" xoffset="3" yoffset="5" xadvance="18" page="0" chnl="0" letter="1"/>
18        <char id="32" x="105" y="33" width="0" height="0" xoffset="9" yoffset="49" xadvance="9" page="0" chnl="0" letter=" "/>
19    </chars>
20    <kernings count="1">
21        <kerning first="49" second="49" amount="-2"/>
22    </kernings>
23</font

      下面我们将使用Starling为我们提供的位图字体类来实现文图文本。

view source print ?
1private function drawBitmapFont():void
2        {
3            var fontTexture:Texture = Texture.fromBitmapData( PublicData.numbertexturesBitmapData );
4            PublicData.BitmapFontToNumber = new BitmapFont(fontTexture, PublicData.numberXML);
5            TextField.registerBitmapFont( PublicData.BitmapFontToNumber );
6        }

      在后面编写程序的时候,当你实例化一个TextField的时候只需要设置字体为mebius即可。这里你需要注意一个问题,你定义的字体名称千万不能可系统以后或者市面上已有的字体名称想冲突,否则在用户的及其中显示为系统字体样式。

      最后我来介绍一个我自己编写的UI描述格式,这个格式非常的简单,我们只需要在面板中定义资源的id标签和位置即可。配置文件格式如下:

view source print ?
01<root>
02    <scene name="start">
03        <element type="image" name="startbg" texturesname="start_game_back_ground" x="0" y="0" />
04        <element type="button" name="start_btn" texturesname="start_game_btn" x="0" y="300" />
05        <element type="button" name="setting_btn" texturesname="setting_game_btn" x="0" y="390" />
06        <element type="button" name="help_btn" texturesname="help_game_btn" x="0" y="480" />
07    </scene>
08    <scene name="setting">
09        <element type="image" name="setting_bg" texturesname="setting_back_ground" x="0" y="0" />
10        <element type="button" name="soundsub_btn" texturesname="sub_btn" x="50" y="100" />
11        <element type="numtext" name="Volumetext" texturesname="" x="100" y="100" />
12        <element type="button" name="soundand_btn" texturesname="and_btn" x="200" y="100" />
13        <element type="button" name="quality_level_sub_btn" texturesname="sub_btn" x="50" y="200" />
14        <element type="numtext" name="qualityleveltext" texturesname="" x="100" y="200" />
15        <element type="button" name="quality_level_and_btn" texturesname="and_btn" x="200" y="200" />
16        <element type="button" name="back_btn" texturesname="back_btn" x="0" y="300" />
17    </scene>
18    <scene name="help">
19        <element type="image" name="helpbg" texturesname="help_back_ground" x="0" y="0" />
20        <element type="button" name="back_btn" texturesname="back_btn" x="0" y="300" />
21    </scene>
22</root>

      这个描述文件中scene标签标识一个场景,里面的element标识一个UI空间,其中type用来分辨UI空间类型。请注意,这仅仅是一个前期模型的简单版本,并非最终版本。最后的数据格式会更加复杂,解析模块如下:

view source print ?
001package ashan.res
002{
003    import ashan.data.PublicData;
004      
005    import starling.display.DisplayObject;
006    import starling.display.DisplayObjectContainer;
007    import starling.display.Image;
008    import starling.display.Sprite;
009    import starling.text.TextField;
010    import starling.text.BitmapFont;
011    import starling.utils.Color;
012  
013    public class SceneRead
014    {
015          
016        private var _mSceneV:Vector.<Sprite>;
017        private var _mSceneNameList:Vector.<String>;
018          
019        public function SceneRead()
020        {
021            init();
022        }
023          
024        private function init():void
025        {
026            this._mSceneV = new Vector.<Sprite>;
027            this._mSceneNameList = new Vector.<String>;
028        }
029          
030        public function getSceneByName(_name:String):Sprite
031        {
032            var _scene:Sprite;
033            var _isCreated:Boolean = false;
034              
035            var i:uint = 0;
036            var t:uint = this._mSceneNameList.length;
037            while( i < t )
038            {
039                if( this._mSceneNameList[i] == _name )
040                {
041                    _isCreated = true;
042                    break;
043                }
044                else
045                {
046                    _isCreated = false;
047                }
048                i++;
049            }
050              
051            if( !_isCreated )
052            {
053                this.drawScene( _name );
054            }
055              
056            _scene = this._mSceneV[i];
057            return _scene;
058        }
059          
060        private function drawScene(_name:String):void
061        {   
062            var _scene:Sprite = new Sprite();
063            var _xmlElement:XMLList = new XMLList( PublicData.sceneXML.scene.(@name == _name ) );
064            //
065            var i:uint = 0;
066            var t:uint = _xmlElement.element.length();
067            while( i < t )
068            {
069                var _element:DisplayObject = drawElement( new XMLList(_xmlElement.element[i]));
070                _scene.addChild( _element );
071                //
072                i++;
073            }
074              
075            this._mSceneV.push( _scene );
076            this._mSceneNameList.push( _name );
077        }
078          
079        private function drawElement(_xmllist:XMLList):DisplayObject
080        {
081            var _element:DisplayObject;
082            var type:String = _xmllist.@type;
083            var _texturesNameStr:String = _xmllist.@texturesname;
084            switch( type )
085            {
086                case "image":
087                    _element = new Image( PublicData.UI_TEXTURES_ATLAS.getTexture(_texturesNameStr) );
088                    break;
089                case "button":
090                    _element = new Image( PublicData.UI_TEXTURES_ATLAS.getTexture(_texturesNameStr) );
091                    break;
092                case "numtext":
093                    _element = new TextField(100,50,"0","mebius");
094                    ( _element as TextField ).fontName = "mebius";
095                    ( _element as TextField ).fontSize = BitmapFont.NATIVE_SIZE;
096                    ( _element as TextField ).color = Color.WHITE;
097                    break;
098            }
099            _element.x = uint( _xmllist.@x );
100            _element.y = uint( _xmllist.@y );
101            _element.name = _xmllist.@name;
102            //
103            return _element;
104        }
105    }
106}

       我们通过这个SceneRead类来将XML数据转化为对象,并且方便我们的代码管理。最终我们来看一下如何实例化操作一个场景,并且为这个场景中的UI添加逻辑(这部分代码也是demo模型,后期会更加复杂)。

view source print ?
001package ashan.scene
002{
003    import ashan.data.PublicData;
004    import ashan.events.SceneEvent;
005    import ashan.res.SceneRead;
006      
007    import flash.events.EventDispatcher;
008      
009    import starling.display.DisplayObject;
010    import starling.display.Sprite;
011    import starling.events.Touch;
012    import starling.events.TouchEvent;
013    import starling.events.TouchPhase;
014    import starling.text.TextField;
015      
016    public class SettingScene extends EventDispatcher
017    {
018        private var _scene:Sprite;
019        private var _mSceneRead:SceneRead;
020          
021        public function SettingScene(_sceneRead:SceneRead)
022        {
023            this._mSceneRead = _sceneRead;
024            init();
025        }
026          
027        private function init():void
028        {
029              
030            //
031            this._scene = this._mSceneRead.getSceneByName(PublicData.SETTING_SCENE_NAME);
032            this._scene.getChildByName("back_btn").addEventListener(TouchEvent.TOUCH,
033                                                                        back_btn_event);
034            this._scene.getChildByName("soundsub_btn").addEventListener(TouchEvent.TOUCH,
035                                                                        sub_volume);
036            this._scene.getChildByName("soundand_btn").addEventListener(TouchEvent.TOUCH,
037                                                                        and_volume);
038            this._scene.getChildByName("quality_level_sub_btn").addEventListener(TouchEvent.TOUCH,
039                                                                        sub_quality);
040            this._scene.getChildByName("quality_level_and_btn").addEventListener(TouchEvent.TOUCH,
041                                                                        and_quality);
042            //
043            var txt:TextField = this._scene.getChildByName("Volumetext") as TextField;
044            txt.text = PublicData.Volume.toString();
045            var qtxt:TextField = this._scene.getChildByName("qualityleveltext") as TextField;
046            qtxt.text = PublicData.QualityLevel.toString();
047        }
048          
049        private function sub_quality(evt:TouchEvent):void
050        {
051            var btn:DisplayObject = this._scene.getChildByName("quality_level_sub_btn");
052            var touch:Touch = evt.getTouch(btn, TouchPhase.BEGAN);
053            if (touch)
054            {
055                if( PublicData.QualityLevel != PublicData.QualityLevel_MIN )
056                {
057                    PublicData.QualityLevel--;
058                    var txt:TextField = this._scene.getChildByName("qualityleveltext") as TextField;
059                    txt.text = PublicData.QualityLevel.toString();
060                }
061            }
062        }
063          
064        private function and_quality(evt:TouchEvent):void
065        {
066            var btn:DisplayObject = this._scene.getChildByName("quality_level_and_btn");
067            var touch:Touch = evt.getTouch(btn, TouchPhase.BEGAN);
068            if (touch)
069            {
070                if( PublicData.QualityLevel != PublicData.QualityLevel_MAX )
071                {
072                    PublicData.QualityLevel++;
073                    var txt:TextField = this._scene.getChildByName("qualityleveltext") as TextField;
074                    txt.text = PublicData.QualityLevel.toString();
075                }
076            }
077        }
078          
079        private function sub_volume(evt:TouchEvent):void
080        {
081            var btn:DisplayObject = this._scene.getChildByName("soundsub_btn");
082            var touch:Touch = evt.getTouch(btn, TouchPhase.BEGAN);
083            if (touch)
084            {
085                if( PublicData.Volume != PublicData.Volume_MIN )
086                {
087                    PublicData.Volume--;
088                    var txt:TextField = this._scene.getChildByName("Volumetext") as TextField;
089                    txt.text = PublicData.Volume.toString();
090                }
091            }
092              
093        }
094          
095        private function and_volume(evt:TouchEvent):void
096        {
097            var btn:DisplayObject = this._scene.getChildByName("soundand_btn");
098            var touch:Touch = evt.getTouch(btn, TouchPhase.BEGAN);
099            if (touch)
100            {
101                if( PublicData.Volume != PublicData.Volume_MAX )
102                {
103                    PublicData.Volume++;
104                    var txt:TextField = this._scene.getChildByName("Volumetext") as TextField;
105                    txt.text = PublicData.Volume.toString();
106                }
107            }
108              
109        }
110          
111        private function back_btn_event(evt:TouchEvent):void
112        {
113            var btn:DisplayObject = this._scene.getChildByName("back_btn");
114            var touch:Touch = evt.getTouch(btn, TouchPhase.BEGAN);
115            if (touch)
116            {
117                var evts:SceneEvent = new SceneEvent( SceneEvent.BACK_START_SCENE_WINDOWS );
118                this.dispatchEvent( evts );
119            }
120        }
121          
122        public function get scene():Sprite
123        {
124            return _scene;
125        }
126          
127          
128    }
129}

更多推荐

Starling外部资源管理

本文发布于:2024-03-06 01:04:56,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1713948.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:资源管理   Starling

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!