页面

2011年9月23日星期五

2011年8月10日星期三

关于javascript的function内存优化基础(微博篇)

首先需要理解javascript中的function不仅代表函数,也代表一个构造函数,当作为构造函数时它创建出了一个对象,并且复制出了一份函数的副本。。。�……

2011年8月7日星期日

从WOW插件开发看WOW的数据架构

    做网页游戏客户端这么长时间,一直在寻求更好的客户端信息架构方案。客户端管理着大量的游戏数据,如角色的各种属性数据、血值、经验等,背包物品数据,商店物品数据,好友数据,地图数据,NPC数据,任务数据,宠物数据等等。同时客户端还需要大量的面板来显示这些信息,并且数据的改变要能及时的更新的面板上。
    这样就需要一套合理的架构来清晰明白的定义各模块的分工,同时还要照顾到多人协作完成这部分工作时,每人能独立的处理自己的数据(包括数据和面板),而与其它数据尽量解耦。
    曾经采用过的一些方案中,大致思路是:每个面板即是独立显示也是独立的数据容器,每次打开的时候向服务端请求所需要数据,采用http请求,响应数据直接在模块内处理,若对数据有操作从而影响到系统中的其它数据,抛事件到父级,再由父级调度去通知关联的面板。这种作法好处是前期人员分工很明确,互不干涉,但缺点也很明显,过多冗余的事件会在项目的中后期导致数据很混乱。
    前一段时间接触魔兽世界,想弥补一下当时在学校时的缺憾,也就毫无疑问地接触到了魔曾的插件,于是乎第一念头,魔兽是怎么处理这种数据与面板之间的关系的,稍微谷歌之,就发现几个不错的网站 http://wowprogramming.com  http://www.wowwiki.com,并下载WOW官方WoW_Interface,很快可以看到WOW Client与插件间的数据交互是基于事件,Client会在每一个状态改变的时候都抛出相应的事件,http://wowprogramming.com/docs/events可以看到其所有的事件,而插件需要某些数据只需要调用client提供的API即可获得所需要数据 http://wowprogramming.com/docs/api这里有所有的API。当然还有些细节需要再深入WoW_Interface去了解下。
    这样看来,大部分游戏UI数据的处理方式是大同小异(甚至WoW_Interface里的xml布局文件的写法都与mxml文件的写法相像),只是WOW把WoW Client作为最大的父级,而所有的插件基于父级是相互独立的,只与父级间有event 与 api的交互。
    那对于透明的WoW Client,我们就需要思考它保存数据的方式,是缓存了很多的数据在客户端呢还是每次都向服务端去请求数据,这个再找资料了解下WoW的私服应该就可以清楚,下次再来探讨,另外Client对api和event的封装手法也应该思考一下。

2011年8月3日星期三

游戏模块开发注意点(微博篇)

    记得以前在开发《热血三国II》时的一个教训,当时负责了一个城内建筑的模块,向外提供几个接口,其中包括一个addBuilding()的方法,做完后自我感觉良好,信心百倍的把模块扔到了主系统中去运行,结果游戏一启动的瞬间,卡得不成样子。跟踪了一下运行情况,结果发现在游戏启动的时候系统会直接扔一个buildingList,然后在一个循环中执行addBuilding()方法来让城内模块处理添加建筑的请求,而模块开发的时候没有预估到这种情况,每次addBuilding()就会处理一坨逻辑,最终导致问题的出现。
    事后很快解决了这个问题,也从中学习到一点:
        你永远不会预测到外部环境是怎么使用模块的,所以对于暴露的接口,模块内部一定要任何情况都能维持一个正常的生态。
    

2011年8月2日星期二

页游上线项目注意点

这是一个需要持续完善的博文:

一、项目的模块划分及模块的配置文件是必须的。因为在上线后,项目会做各种更新,而每次更新之后最好的作法是是让客户端仅更新受到影响的小模块。开发期也比较适合这种方法,因为随着现在游戏品质需求越来越高,导致工程文件也越来越大,每做一次10分钟的修改就需要编译20分钟,这样的情况是每个开发者都不能忍受的。

2011年4月26日星期二

关于flex module机制里的一个BUG

    近期要使用flex module机制对项目进行优化,但在刚划分模块后遇到一个诡异的问题,加载来的module怎么都无法显示到舞台上,百思不得其解,故晚上抽时间看了下module相关的源代码吗,终于发现问题所在。先直接说问题,再讲解一下module机制吧。
    原因就出在ModuleInfoProxy里对info的几个事件进行了弱引用的侦听器,所以事件就没有在ModuleInfoProxy中捕获到,所以也就没有再传到我们的应用层了,现行处理办法:一定要做ModuleEvent.PROGRESS事件侦听,这样就可以保证ModuleInfoProxy中的moduleEventHandler侦听器函数一直没有失效。

---------------------------------------------------
    那么在flex中是怎么处理Module的呢?

    首先要熟悉FlexModuleFactory,它和SystemManager同继承自MovieClip,都是用来引导主文档类的,同实现IFlexModuleFactory接口,前面大概介绍过SystemManager类,这里再简单的说一下,它们都至少有两帧,第一帧作为loading处理,主类在第二帧上,在第一帧的时候会处理诸如显示进度条、加载RSL等工作,在第一阶段工作完成且主类已经加载完成的情况下开始对主类做一些初始化处理,如注册一些框架单例等。(另外这些类里有很多的小技巧可以在平时借鉴,如update()管理STATE的变化,而update再由特定事件驱动)
    如果是Module,那么会在这一步向外抛出ready事件。
    再看flex是如何用ModuleManager管理Module的,首先对module的加载是交给ModuleInfo来处理的,用ModuleInfo来实现Load()并做各种事件侦听,而ModuleInfo又被ModuleInfoProxy所封装,向外提供更加简明的接口,封装的一个工作就是对ModuleInfo的几个事件进行转发,如下图:
这就是上面说的弱侦听器导致的问题。

因为module变量是loadModule方法里面的临时变量,因此一旦调用方法执行结束则module的生存周期结束,因此module肯定被标识为垃圾回收对象。又由于其是以弱引用方式加入监听器,所以事件不会再派发到需要回收的监听器上。


解决方案:module变量改变为类属性以延长了其生存周期


参考:http://hi.baidu.com/vim888/blog/item/1e9fcc3474cf99a1d1a2d35b.html

2011年4月9日星期六

关于flex框架启动的一些事(1)

flex编译器在编译flex工程时会创建出四个基本类:

//
_MyProject_mx_managers_SystemManager  extends mx.managers.SystemManager
SystemManager类为flash项目的文档类
这里flex编译器会为项目生成一个SystemManager的子类,在其中生成与项目相关的一些数据,如:
  create()方法中定义该项目的主类名称;
  info()方法中生成很多与项目相关的信息

//
MyProject extends spark.components.Application

Application为项目的主类
这里flex编译器会为项目生成一个Application的子类,在该类要完成做为容器的功能(mxmlcontent),还要完成整个项目的style功能:
  在set moduleFactory(factory:IFlexModuleFactory)方法(被加入显示列表前调用)中调用一个生成的MyProject_StylesInit()方法,在该方法中完成自定义css文件中所有样式的注册,如:
        selector = null;
        conditions = null;
        conditions = [];
        condition = new CSSCondition("class", "Button1");
        conditions.push(condition);
        selector = new CSSSelector("spark.components.Button", conditions, selector);
        // spark.components.Button.Button1
        style = styleManager.getStyleDeclaration("spark.components.Button.Button1");
        if (!style)
        {
            style = new CSSStyleDeclaration(selector, styleManager);
        }

        if (style.factory == null)
        {
            style.factory = function():void
            {
                this.backgroundImage = _embed_css____assets_ui_add_png_867674143;
            };
        }
//
_TestProject_FlexInit
[Mixin]类,被写入SystemManager::info()["minxins"]中,在SystemManager初始货完成加载Application之前(SystemManager::kickoff()中)调用静态的init方法

此类完成各种单例、效果、别名等的注册

//
_TestProject_Styles
[Mixin]类,被写入SystemManager::info()["minxins"]中,在SystemManager初始货完成加载Application之前(SystemManager::kickoff()中)调用静态的init方法

此类完成系统内置组件样式、皮肤的绑定,如:

        selector = null;
        conditions = null;
        conditions = null;
        selector = new CSSSelector("spark.components.Button", conditions, selector);
        mergedStyle = styleManager.getMergedStyleDeclaration("spark.components.Button");
        style = new CSSStyleDeclaration(selector, styleManager, mergedStyle == null);

        if (style.defaultFactory == null)
        {
            style.defaultFactory = function():void
            {
                this.skinClass = spark.skins.spark.ButtonSkin;
            };
        }


        if (mergedStyle != null &&
            (mergedStyle.defaultFactory == null ||
            ObjectUtil.compare(new style.defaultFactory(), new mergedStyle.defaultFactory())))
        {
            styleManager.setStyleDeclaration(style.mx_internal::selectorString, style, false);
        }


///////////////////////////////////

根据这些信息,可以思考如何优化flex工程的编译速度,及缩减项目swf的大小