Archive for the "AIR/RIA" Category

ItemRenderer在DataGrid中涉及问题解决

一、设若DataGrid中有个ComboBox的ItemRenderer,操作这个ComboBox,影响其它列的值变化。要使Flash的画面Redraw,需要将绑定到DataGrid上的ArrayCollection执行refresh().

二、涉及到需要通过绑定数据来更新显示多个DataGrid中的ItemRenderer,需要使用ArrayCollection而不是Array.

三、要理解Flex ItemRenderer生成及使用的机制,在Flex开发人员中心中有这么一段话,道出了ItemRenderer的真面目:假设您要显示 1,000 条记录。如果您认为列表控制会创建 1,000 个 itemRenderer, 您就错了。如果列表只显示 10 行, 它会创建约 12 个 itemRenderer-这些足以显示各个可见行, 多出的几个则用于缓冲和性能。列表最初显示行 1–10。当用户滚动这个列表时, 它现在可能显示行 3-12。但那 12 个 itemRenderer 仍在那里: 及时滚动列表后, 也不会新建任何 itemRenderer。

 

Flex新框架:FlexAip

Flex2007这位朋友问FlexAip的官网是什么?
非常抱歉,这是我的疏忽,其官网是:http://flexaip.org/
同时感谢大家的关注!
FlexAip是什么
1. FlexAIP试图为企业RIA应用的开发提供Flex程序的基础架构,或者说是提供一个微框架,来满足如下类型的应用:

  • 一个工程由多个子项目构成。
    • 例如:ERP工程由订单、采购、生产、销售、库存等若干子项目构成。
  • 该工程由一个主程序(Application)和若干子程序(Module)构成。
    • 例如:主程序实现菜单和Module容器的作用,每个Module都是一个画面,被主程序动态加载,运行在主程序中。
    • 主程序可以一次加载一个Module,也可以同时加载多个。
    • 主程序可以一次显示一个Module,也可以同时显示多个Module。
  • 把共用的画面独立成为对话框,在全项目中共用。
    • 例如商品检索对话框、社员检索对话框。
  • 团队(多人)并行开发。

2. 它实现如下功能:

  • 利用Flex事件机制,实现事件的一对一传播,或可控范围内的传播。
    • 例如:多个子画面都会调用相同的对话框,对话框只和调用它的子画面通过事件进行联系。事件不会扩散到第三者那里。
  • 把画面的共通机能抽象出来,交由第三方对象异步完成,通过事件机制进行相互通知。
    • Module的加载/卸载
    • 画面表示文字和提示信息的动态更新(国际化)
    • 事件派发
  • 数据在不同画面间的共享

3. 是开源代码,许可证类型为Apache License 2.0

FlexAIP是MVC框架吗

诸如Cairngorm、PureMVC是对Flex画面内部进行代码划分的框架。

FlexAIP是在画面之间建立联系的框架。

它们服务的对象不同,在使用FlexAIP框架的画面内部,可以进一步使用MVC理念进行规划。

但是,RIA中,Flex完成的是视图层(View)的功能。再对视图层进一步划分MVC并不是个好主意。

作者不建议把MVC引入Flex程序中。

FlexAip是用什么开发的

是使用FlexSDK4.0(FlashBuilder4)开发的。

*稍加修改,可以用于FlexSDK3.x。

FlexAIP适用场景适用于数据导向的企业RIA应用,例如ERP。

绝大多数的企业RIA应用是数据导向的。

其需求特点是机能多,各个机能相对独立,计算密集型机能多(数据计算、数据库操作等)。

其开发特点是团队(多人)并行渐进式开发。常伴有机能变更,机能增减等外部要求。

这些特点反映在RIA应用上,就变为对其结构的要求:

  • 程序单元的划分要保证其功能的相对独立性,使其能够独立开发,独立测试。
  • 程序单元要能够很方便地进行组合,完成系统整体功能。

FlexAIP关注的是如何划分程序单元,使其具备独立开发、测试的特点;同时能够保持和外界必要的联系。

FlexAIP试图站在系统结构的角度规划程序单元之间的关系。

FlexAIP的目的

  • 程序单元可被分发,交由团队(多人)并行开发。
  • 程序单元易于独立测试。
  • 程序单元易于集成。
  • 程序单元只需要开发和业务要求有关的内容,其他共通功能都交由FlexAIP框架完成。

 

Flash Game 英文教程

  • 1. Flash Game Development with Flex and Actionscript – Getting Started
  • 2. Flash Game Development with Flex and Actionscript – Double Buffer Rendering
  • 3. Flash Game Development with Flex and Actionscript – Embedding Resources and Adding Game Objects
  • 4. Flash Game Development with Flex and Actionscript – User Input and an Animated Background
  • 5. Flash Game Development with Flex and Actionscript – Adding Weapons
  • 6. Flash Game Development with Flex and Actionscript – Collision Detection
  • 7. Flash Game Development with Flex and Actionscript – Bitmap Animations
  • 8. Flash Game Development with Flex and Actionscript – Music and Sound FX
  • 9. Flash Game Development with Flex and Actionscript – Defining a Level
  • 10. Flash Game Development with Flex and Actionscript – Tiled Background Rendering
  • 先看看英文版的吧,有机会的话再翻译成中文!

     

    Flex 中限制 TextInput 的输入设置方法

    1. 限制某个字符的输入,用符号 ^ 跟上要限制的字符,可跟多个字符

    <!– 限制字符”~”的输入 –>

    <mx:TextInput id=”xxx”  restrict=”^~” />

    <!– 限制字符”ab”的输入 –>

    <mx:TextInput id=”xxx”  restrict=”^ab” />

    2. 设置只能输入某些字符,将允许输入的字符罗列出来即可,也可以用 – 组合表示字符范围

    <!– 只能输入abc –>

    <mx:TextInput id=”xxx”  restrict=”abc” />

    <!– 只能输入小写字母 –>

    <mx:TextInput id=”xxx”  restrict=”a-z” />

    <!– 只能输入小写字母、大写字母和数字 –>

    <mx:TextInput id=”xxx”  restrict=”a-zA-Z0-9″ />

    3. 组合使用

    <!– 只能输入数字和符号”.” –>

    <mx:TextInput id=”xxx”  restrict=”0-9.” />

    <!– 只能输入除ab之外的小写字母 –>

    <mx:TextInput id=”xxx”  restrict=”a-z^ab” />

     

    5月30日 第3次 FLASH开发者交流会火热报名中!

    

    经过紧张的筹办,第三次FLASH开发者交流会活动开始报名咯!请大家访问:www.swfsh.com

    在这次的活动中,我们邀请到AsWing开源UI框架的作者iiley同学跟大家介绍他在FLASH独立游戏开发方面的经验和感受。

    同时我们请来积木网的主程谢敏同学,谢敏采用FLEX框架一手开发了积木网网上电脑,谢敏将为我们带来FLEX框架的完整的开发经验谈(超多干货!!)。

    在1月活动中,向大家介绍FLASH播放器性能优化经验的主持人谈熠同学将在这次的活动中给我们介绍如何在FLASH中运用元编程方法来提高代码效率和优化开发过程。

    “开心宠物”和“升职记”的主程唐翎同学将告诉大家一种全新的FLASH程序的UI设计方式,使你的程序能够超灵活地支持皮肤设定

    ……

    还有很多新鲜有益的主题,我们将不断地更新在网站上,请关注:www.swfsh.com

     

    基于Flash展现的互动虚拟城市解决方案的设计与实现

    发一篇肖刚清华大学工硕毕业论文,初看了一下,写的还不错!暂时只看了前面,其使用技术框架为 Flash + WebService + Socket.

    喜欢的话就下载下来看吧:基于Flash展现的互动虚拟城市解决方案的设计与实现 (136)

     

    Flex开发中可能出现内存泄漏的地方

    收集了不少的会导致内存泄露的情况:
    事件监听:
    对父级对象加了监听函数,会造成内存泄露,例:
    override protected function mouseDownHandler(…):void {
    systemManager.addEventListener(“mouseUp”, mouseUpHandler);
    ……
    }
    解决:
    在销毁对象的时候,remove掉这些监听,虽然弱引用也可以避免这些问题,但自己掌控感觉更好。
    但以下几种情况不会造成内存泄露:
    弱引用:someObject.addEventListener(MouseClick.CLICK, handlerFunction, false, 0, true);
    对自己的引用:this.addEventListener(MouseClick.CLICK, handlerFunction);
    子对象的引用:
    private var childObject:UIComponent = new UIComponent;
    addChild(childObject);
    childObject.addEventListener(MouseEvent.CLICK, clickHandler);
    总之…有addEventListener,就removeEventListener一下吧,要为自己做的事负责~哈哈
    清除引用
    remove掉子对象后并不会删除该对象,他还保留在内存中,应该将引用设置为null
    removeChildren(obj);
    obj = null;
    静态成员
    Class (或MXML)中有:
    public static var _eventService : MyService=new MyService();
    解决:在dispose时,需要设置:
    _eventService =null;
    module (未解决)
    moduleLoader unloadModule后
    ModuleInfo 并不会被GC.
    Garbage Collection in a MultiCore Modular Pipes Application
    这篇文章介绍了一种GC策略,感觉对于ModuleInfo 的GC无效。
    (未尝试、未遇到)
    CSS样式
    module 中如果使用了shell的CSS定义或是<mx:Style> 这样的定义,那么这个module将不能GC.
    弹出的窗口应该是同样的结果.
    解决方法,使用动态CSS文件
    module init中
    StyleManager.loadStyleDeclarations(“css/myStyle.swf”);
    module dispose中
    StyleManager.unloadStyleDeclarations(“css/myStyle.swf”);
    TextInput/Textarea(未解决)
    如果module中有window使用了TextInput/Textarea控件,不点击没有问题,只要点上去,那么很遗憾了,module和所在窗体将不能被GC.
    这个BUG非常严重,目前还没有解决方法。
    memory leak when using TextInput and TextArea when click the keyboard 这里面附加的解决方法无效。
    通过profiler分析,应该和Focusmanager有关,只有一点击就不会释放。
    CursorManager.setCursor
    使用了
    cursorID = CursorManager.setCursor(iconClosed);
    dispose时要
    CursorManager.removeCursor(cursorID);
    Bitmap
    如果使用Bitmap,结束时需要调用其dispose方法,否则内存消耗巨大。
    另外,BitmapData是可以共享使用的,多个Bitmap可以使用同一BitmapData,节省不少内存。
    var bmp:Bitmap  =new Bitmap();
    ……..
    if (bmp.bitmapData!=null) {
    bmp.bitmapData.dispose();
    }
    Image
    包含了Image对象时,在removeChildren时会造成不能释放(测试多次,结果不一,建议还是做如下处理)。
    解决:
    img.source = null;
    this.removeChild(img);
    img = null;
    Loader、SWFLoader、声音、视频、Effect等…
    如果是加载SWF文件,先停止播放。
    停止声音的播放
    停止正在播放的影片剪辑(Movieclip)
    关闭任何连接的网络对象,例如Loader正在加载,要先close。
    取消对摄像头或者麦克风的引用
    取消事件监听器
    停止任何正在运行的定时器,clearInterval()
    停止任何Timer对象,timer.stop()
    停止正在播放的效果(Effect)
    其他
    binding也疑似有memory leak 问题。
    引用以及内存泄露相关博文和资料:
    http://blogs.adobe.com/aharui/2007/03/garbage_collection_and_memory.html
    http://www.craftymind.com/2008/04/09/kick-starting-the-garbage-collector-in-actionscript-3-with-air/
    http://www.cnblogs.com/janyou/archive/2008/11/25/1340753.html
    http://www.dreamingwell.com/articles/archives/2008/05/understanding_m.php
    总结:由于之前Flash一直是在网页上使用,一般网页都是看完就关掉的,估计Adobe在内存回收这块也没有下太大的功夫,现在AIR的出现使得内存管理也相当重要了,并且,AIR本身对内存的消耗就相当大,一个没有任何内容的初始创建的AIR程序,就得占掉10-20M+的内存…AIR还需改善.

    收集了不少的会导致内存泄露的情况:
    事件监听:
    对父级对象加了监听函数,会造成内存泄露,例:
    override protected function mouseDownHandler(…):void {systemManager.addEventListener(“mouseUp”, mouseUpHandler);……}解决:在销毁对象的时候,remove掉这些监听,虽然弱引用也可以避免这些问题,但自己掌控感觉更好。
    但以下几种情况不会造成内存泄露:
    弱引用:someObject.addEventListener(MouseClick.CLICK, handlerFunction, false, 0, true);对自己的引用:this.addEventListener(MouseClick.CLICK, handlerFunction);子对象的引用:private var childObject:UIComponent = new UIComponent;addChild(childObject);childObject.addEventListener(MouseEvent.CLICK, clickHandler);总之…有addEventListener,就removeEventListener一下吧,要为自己做的事负责~哈哈
    清除引用
    remove掉子对象后并不会删除该对象,他还保留在内存中,应该将引用设置为null
    removeChildren(obj);obj = null;
    静态成员
    Class (或MXML)中有:
    public static var _eventService : MyService=new MyService();解决:在dispose时,需要设置:
    _eventService =null;module (未解决)
    moduleLoader unloadModule后ModuleInfo 并不会被GC.Garbage Collection in a MultiCore Modular Pipes Application这篇文章介绍了一种GC策略,感觉对于ModuleInfo 的GC无效。(未尝试、未遇到)
    CSS样式
    module 中如果使用了shell的CSS定义或是<mx:Style> 这样的定义,那么这个module将不能GC.弹出的窗口应该是同样的结果.解决方法,使用动态CSS文件module init中
    StyleManager.loadStyleDeclarations(“css/myStyle.swf”);module dispose中
    StyleManager.unloadStyleDeclarations(“css/myStyle.swf”);TextInput/Textarea(未解决)
    如果module中有window使用了TextInput/Textarea控件,不点击没有问题,只要点上去,那么很遗憾了,module和所在窗体将不能被GC.这个BUG非常严重,目前还没有解决方法。memory leak when using TextInput and TextArea when click the keyboard 这里面附加的解决方法无效。通过profiler分析,应该和Focusmanager有关,只有一点击就不会释放。
    CursorManager.setCursor
    使用了
    cursorID = CursorManager.setCursor(iconClosed);dispose时要
    CursorManager.removeCursor(cursorID); Bitmap
    如果使用Bitmap,结束时需要调用其dispose方法,否则内存消耗巨大。另外,BitmapData是可以共享使用的,多个Bitmap可以使用同一BitmapData,节省不少内存。
    var bmp:Bitmap  =new Bitmap();
    ……..
    if (bmp.bitmapData!=null) {    bmp.bitmapData.dispose();}Image
    包含了Image对象时,在removeChildren时会造成不能释放(测试多次,结果不一,建议还是做如下处理)。解决:
    img.source = null;this.removeChild(img);img = null;Loader、SWFLoader、声音、视频、Effect等…
    如果是加载SWF文件,先停止播放。停止声音的播放停止正在播放的影片剪辑(Movieclip)关闭任何连接的网络对象,例如Loader正在加载,要先close。取消对摄像头或者麦克风的引用取消事件监听器停止任何正在运行的定时器,clearInterval()停止任何Timer对象,timer.stop()停止正在播放的效果(Effect)其他
    binding也疑似有memory leak 问题。
    引用以及内存泄露相关博文和资料:http://blogs.adobe.com/aharui/2007/03/garbage_collection_and_memory.html

    http://www.craftymind.com/2008/04/09/kick-starting-the-garbage-collector-in-actionscript-3-with-air/

    http://www.cnblogs.com/janyou/archive/2008/11/25/1340753.html

    http://www.dreamingwell.com/articles/archives/2008/05/understanding_m.php

    总结:由于之前Flash一直是在网页上使用,一般网页都是看完就关掉的,估计Adobe在内存回收这块也没有下太大的功夫,现在AIR的出现使得内存管理也相当重要了,并且,AIR本身对内存的消耗就相当大,一个没有任何内容的初始创建的AIR程序,就得占掉10-20M+的内存…AIR还需改善.

     

    as 动画融合投掷、拖拽、碰撞的例子

    先看一下效果:(拖动小球往一个方向抛出,小球可获得加速度)

    源码如下:

    package {
    	import flash.display.Sprite;
    	import flash.display.StageAlign;
    	import flash.display.StageScaleMode;
    	import flash.events.Event;
    	import flash.events.MouseEvent;
    	public class Throwing extends Sprite {
    		private var ball:Ball;
    		private var vx:Number;
    		private var vy:Number;
    		private var bounce:Number = -0.7;
    		private var gravity:Number = .5;
    		private var oldX:Number;
    		private var oldY:Number; 
    
    		public function Throwing() {
    			init();
    		}
    		private function init():void {
    			graphics.beginFill(0xffffff,0.8);
    			graphics.drawRoundRect(0,0,2000,1200,0);
    			//设置自动尺寸匹配
    			stage.scaleMode = StageScaleMode.NO_SCALE;
    			stage.align=StageAlign.TOP_LEFT;
    			ball = new Ball();
    			ball.x = stage.stageWidth / 2;
    			ball.y = stage.stageHeight / 2;
    			//横纵向加速度
    			vx = Math.random() * 10 - 5;
    			vy = -10;
    			addChild(ball);
    			ball.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
    			addEventListener(Event.ENTER_FRAME, onEnterFrame);
    		}
    		private function onEnterFrame(event:Event):void {
    		vy += gravity; ball.x += vx;
    		ball.y += vy; var left:Number = 0;
    		var right:Number = stage.stageWidth;
    		var top:Number = 0;
    		var bottom:Number = stage.stageHeight;
    		if (ball.x + ball.radius > right) {
    				ball.x = right - ball.radius;
    				vx *= bounce;
    			}else if (ball.x - ball.radius < left) {
    				ball.x = left + ball.radius; vx *= bounce;
    		}
    		if (ball.y + ball.radius > bottom) {
    				ball.y = bottom - ball.radius; vy *= bounce;
    			}else if (ball.y - ball.radius < top) {
    				ball.y = top + ball.radius; vy *= bounce;
    			}
    		}
    		private function onMouseDown(event:MouseEvent):void {
    			oldX = ball.x; oldY = ball.y;
    			stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
    			ball.startDrag();
    			removeEventListener(Event.ENTER_FRAME, onEnterFrame);
    			addEventListener(Event.ENTER_FRAME, trackVelocity);
    		}
    		private function onMouseUp(event:MouseEvent):void {
    			stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
    			ball.stopDrag();
    			removeEventListener(Event.ENTER_FRAME, trackVelocity);
    			addEventListener(Event.ENTER_FRAME, onEnterFrame);
    		}
    		private function trackVelocity(event:Event):void {
    			vx = ball.x - oldX;
    			vy = ball.y - oldY;
    			trace(oldX+"======="+ball.x);
    			oldX = ball.x;
    			oldY = ball.y;
    		}
    	}
    }
    
     

    基于FLASH平台的3D RIA应用-网上世博会

    2010上海世界博览会之网上世博会

    http://www.expo.cn

    1、[园区揽胜—园区]
    园区揽胜是网上世博会BS平台的核心体验内容。
    用户通过[园区揽胜]进入园区,页面出现上海世博园地图,海宝自动讲解园区内容。
    页面下方左侧,适时显示网站最新信息;用户在页面下方进行五个片区的选择,点击片区可分别进行体验。
    点击 按钮,可以暂停海宝当前讲解,点击暂停,按钮变成 ,点击继续进行讲解。

    2、[园区揽胜—片区]
    选择片区进入。海宝自动讲解片区内容。
    点击 按钮,暂停海宝当前讲解,点击暂停,按钮变成 ,点击继续进行播放。
    点击 按钮,切入下一个片区体验。
    点击  按钮,返回园区,用户重新对片区进行选择。
    以A片区为例,用户到达A片区,页面显示A片区地图。片区展馆以特殊的标识在地图区动态显示。
    (1)、双击地图上展馆,快速进入展馆体验。
    (2)、点击下方展馆推荐,可进行展馆体验。

    3、[园区揽胜—展馆]
    以中国馆为例,用户进入中国馆,海宝自动介绍中国馆内容。
    点击 按钮,暂停海宝当前讲解,点击暂停,按钮变成 ,点击继续进行播放。
    点击 按钮,切入下一个展馆体验。
    点击 按钮,返回片区地图,用户重新选择展馆体验。
    以A片区为例,用户到达A片区,页面显示A片区地图。片区展馆以特殊的标识在地图区动态显示。
    (1)、双击地图上展馆,快速进入展馆体验。
    (2)、点击下方展馆推荐,可进行展馆体验。

    用户在中国馆内可进行多种功能的体验。

    (1) 平视转转看进入平视转转看的环视体验,可上下左右拖动地图。

    (2) 俯视转转看 
    高空俯视展馆的外观,拖动展馆可进行多角度的浏览。

    (3) 加入收藏将展馆加入收藏夹,以便用户登录时能快速进入与浏览。
    注:此功能只有注册/登录用户才能使用,普通游客例外。

    4、园区地图体验
    通过点击页面右上方 功能键,进入上海世博园园区地图。
    此体验方式提供园区揽胜、园区活动、深度聚焦的三种不同类别的内容体验。是以分类选择的方式,提供用户不同内容体验,通过类别选择用户能快速选择需要的信息。
    鼠标滚动可对地图区进行放大缩小,通过左上角的地图功能,也可对园区进行缩放;

    (1)园区揽胜

    选择园区揽胜,五大片区分别以不同的颜色覆盖在园区地图;

    双击A片区,地图放大片区内容,A片区所有展馆以标注点的形式显示在地图上。
    点击中国馆,提供中国馆的三种体验模式。

      全景:到达该展馆外,海宝自动介绍展馆内容,可进行平视转转看、俯视转转看、加入收藏四种功能的选择。(同上园区揽胜中的展馆体验)

      俯视转转看:以高空俯视展馆外观。拖动展馆可进行多角度的浏览。

      平视转转看:进入平视转转看的环视体验,可上下左右拖动地图。

     

    RPG风格的文本系统——Make an RPG-Style Text System for Your Next Game

    在这个教程里面我们将要创建一个文本系统,它跟你见过的大多数角色扮演游戏的文本系统是一样的。我们的类要动态显示说话角
    色的图标。并逐个字母的显示每块对话的内容。

    最终结果的展示

    下面这个例子就是我们将要制作的文本系统
    RPG Style Text System (37)

    第一步:建立你的flash文件
    创建一个新的flash文件(actionscript 3).根据你的游戏具体情况设置影片参数,在这个演示中我设置影片大小为500*300,黑色

    的背景,30帧/秒

    第二步:添加背景图片
    你通常会把游戏中的文本模块放到图像或动画的上面,在这个演示里我只用了一张图片把站在雪景里的所有需要的角色放到了一起。把背景图片放到单独的一层里面起名叫做“background”

    第三步:创建RPGText影片剪辑
    在舞台上创建一个新的影片剪辑(插入〉影片剪辑)命名为“RPGText”.在这个元件属性里面购选“Export for Actionscript”设

    置类的名字为“RPGText”. 我们将使用这个类名链接代码和影片剪辑。设置完成单击ok。如果你看到这样的警告“定义的类可能没

    有找到”。那是正确的,它的意思是还没有任何代码链接到这个元件上。
    给你的影片剪辑实例命名为“rpgText”记住,当我们谈到大写的RPGText时,它表示的就是类或者是影片剪辑,如果是小写的

    rpgText,那么它就是类的一个实例。

    第四步:添加文字面板背景
    在新建的RPGText影片剪辑里面画一个矩形。用它作为人物图标和说话框的背景。你也可以根据自己的嗜好来设计它,但必须保证它

    的宽度能横跨整个影片并且高度大小不能覆盖太多的游戏空间。
    我设置的大小是500像素宽(匹配我的影片)100像素高。我用从#666666到#999999(从暗灰到亮灰)的过渡色填充

    快速提示:画一个特殊尺寸的矩形,选择矩形工具按住Alt键单击舞台你会得到一个对话框,可以输入矩形的尺寸。

    第五步:角色图标的影片剪辑
    在RPGText影片剪辑新添加一个层,命名为“icon”。创建一个新的影片剪辑命名为“characterIcon”并在icon层添加这个影片实例“characterIcon”。

    并在新建的characterIcon影片剪辑里面创建两个新层“icons”和“labels” 。icon层包含所有的角色图标(一个图标对应一个关键桢)而labes层设置帧标签,设置帧标签的目的是为了准确定位角色。

    导入(或者是在flash里面绘制)每个将要说话角色的图标,在这个演示里我做了75*75像素的jpg图片,把它们添加到图标层。为每一个新的角色做一个关键桢。他们的显示顺序并不重要。但必须保证每个图标的位置在x:0,y:0。因为只有这样做,当角色切换的时候才不会有跳动的感觉。

    第六步:添加帧标签
    现在为labels层创建关键帧。快速的方法是选择这些帧按F6键。
    为每个关键帧添加显示在该帧上对应角色的名字。如果你添加一个空桢(F5),它可以很容易让你读取你的关键帧的内容,但是必

    须保证你的标签在对应图标关键帧的上方。

    而且必须保证每个标签的命名不一样。如果你有两个角色的名字是一样的你需要区别它们(例如:(‘John_L’ 和 ‘John_K’ )

    第七步:画一个说话框
    回到RPGText影片剪辑,创建一个新的层叫做“textBackground”。
    画一个说话框。我用一个圆角矩形简单画了一个,你可以根据自己的需要做。让它充满大部分的背景。在角色图标的旁边。
    选中你的说话框转换成为影片剪辑(修改->转换元件),现在他变成了影片剪辑,我们可以给它添加投影滤镜。我设置我的投影滤镜黑色,50%强度,5像素的模糊(blur),1像素的距离。

    第八步添加动态文字区域
    在RPGText中创建一个新的层叫做“text”,使用文本(text)工具在该层上画一个文本区域。让它的大小刚刚符合说话框的大小。
    设置这个文本区域为多行,定义实例名为“txt”。记得嵌入字体。我使用的是13pt courier

    第九步添加“下一个”按钮
    我们需要一种方式让玩家在阅读完当前文字后能看到下一段文字,让我们在拐角处添加一个“下一个”按钮。
    在RPGText上创建一个新的层叫做“button”添加一个新的按钮元件叫做“b_next”.给你的按钮设计四种状态。我使用的是一个下标的小箭头,因为我在很多的游戏中看到它,把它放在对话框右侧的角落里。不要担心给它一个实例名。我一会在解释

    第十步创建一个文档类
    创建一个新的actionscript文件叫做“Main.as”添加代码
    package {
    import flash.display.MovieClip;
    public class Main extends MovieClip {

    // CONSTRUCTOR
    public function Main() {
    }
    }
    }
    在flash里面设置Main为文档类,如果你想快速重温文档类的使用方法,我认为威廉斯迈克尔的一片快速提示的文章是最好的选择。

    第十一步添加文本区
    如果你在开发游戏的时候,你会把文本区的处理放到别处,但是现在我要把它放到文档类里面。在Main类的构造方法里面添加这些代码
    var textBlocks:Array = new Array(
    ["Kid",     "Look, a robot!"],
    ["Abe",     "BLEEP-BLOOP. I am an Autonomous Botanical Engineer. You can call me ABE."],
    ["Kid",     "Hi Abe. Meet Frosty the Snowman."],
    ["Frosty",  "Happy Birthday!"],
    ["Abe",     "BEEP-BIP. Hello, Frosty."],
    ["Abe",     "Does this frog belong to you?"],
    ["Frog",    "Ribbit..."],
    ["Kid",     "No I've never seen him before. Aren't you cold frog?"],
    ["Frog",    "Ribbit..."]
    );

    rpgText.textBlocks = textBlocks;
    这里我们创建了一个二维数组(一个数组嵌套另一个数组)保存我们场景中用到的语言脚本。在你改变任何东西的时候,注意一下

    它的结构,每个数组是一个分开的文本内容
    它包含两个元素。第一个是角色的名字,第二个是角色要说什么。这个文本区列出的是在场景中出现的次序。
    最后一行仅仅是把textBlocks数组赋值给rpgText影片实例。(记住,rpgText是影片剪辑RPGText的实例名)。更多的稍后再说。
    来吧,编辑这段代码让它符合你自己的需要。但要格外注意的是角色的命名和你characterIcon影片剪辑里面的帧标签是否对应

    第十二步创建RPGText类
    我们终于开始写RPGText类的代码了
    创建一个新的actionscript文件命名为“RPGText.as”,添加代码如下
    package {
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.display.MovieClip;
    import flash.media.Sound;
    public class RPGText extends MovieClip {
    private const SPEAKER:int = 0;
    private const TEXT:int = 1;
    private var _currentTextBlockIndex:int=0;
    private var _currentTextBlock:String;
    private var _textBlocks:Array;
    // CONSTRUCTOR
    public function RPGText() {
    }

    }
    }
    这仅仅是一个基本的类结构。它不能做任何事情。但是我们先来看看他都包括了什么
    前几行,导入我们需要的类库
    定以这个类扩展自MovieClip类。我们需要这么做的原因是这个类要链接到库里面的RPGText影片剪辑。
    我定义了两个常量,SPEAKER和TEXT,用他保存textBlocks里说话者的名字和内容
    _currentTextBlockIndex变量追踪当前的显示对象
    _currentTextBlock获得实际的文本内容
    _textBlocks持有整个文本的数组
    最后是一个空的构造器

    备注:我是用带下划线的变量名表示私有变量

    第十三步textBlocks设置方法
    由于我们的_textBlocks是私有的所以我们需要一个方法把它传递出去,好让我们在Main类里面设置这个文本区域。我们创建一个

    setter方法。添加在RPGText类构造方法的下面
    public function set textBlocks(txt:Array):void {
    _textBlocks = txt;
    }
    setters最酷的是可以通过方法把一个私有属性变成一个公共属性。我们在Main类的第11行是这样做的
    rpgText.textBlocks = textBlocks;

    第十四步添加updataText方法
    在RPGText类里面添加这个方法
    private function updateText(e:Event):void {
    if(txt.text.length < _currentTextBlock.length){
    txt.text = _currentTextBlock.substr(0, txt.text.length+1);
    } else {
    removeEventListener(Event.ENTER_FRAME, updateText);
    fillText();
    }
    }
    这个方法是这个类的核心功能,让我们自己看一下这都发生了什么。
    第27行这个方法接收一个事件作为参数我们通过ENTER_FRAME事件调用它
    第28行我们比较txt和_currentTextBlock里面的字母的数量
    第29行如果是txt里面的字母数量少,则我们用substr方法获得从0到txt字母数量这么多个,把截得的字符串添加到文本区域里面实

    现字符逐个添加到文本区域里面的效果
    第31行如果txt和_currentTextBlock的字符数量相同则移除ENTER_FRAME监听事件。
    第32行调用fillText方法。我们下面将要实现这个方法。

    第十五步添加fillText方法
    在RPGText类里面添加则个方法
    private function fillText(e:MouseEvent = null):void {
    txt.text = _currentTextBlock;
    if(_currentTextBlockIndex < _textBlocks.length-1){
    addEventListener(MouseEvent.CLICK, nextTextBlock);
    }
    }
    这个方法的主要目的是通过变量_currentTextBlock(37行)填充文本区域。我们让updateText方法来控制动画的播放,这样做可以确保不会出现问题。我们也可以把方法挂靠到“next”按钮上,让玩家掠过文本动画直接显示文本内容注意这个方法接受一个鼠标事件作为参数,我们把它默认设置为null。我们可以让这个方法作为鼠标事件监听器,因为它可以接收事件,因为我们可以给事件一个默认值,当然我们也可以不需要发送任何事件直接在updateText方法的结尾处调用当我们填充完文本区域后,我们检查是否到达文本块所在数组的末尾。(看_currentBlockIndex是否小于_textBlock数组元素的个数 )如果没有到达末尾,我们就添加一个单击事件监听器调用nextTextBlock方法继续显示文本。

    第十六步关于单击监听器
    还记得开始在我们创建“下一步”按钮的时候,我曾经说个不要着急给这个按钮起实例名吗?你注意到最后一步我们如何链接单击监听器给RPGText 影片剪辑代替按钮?这样做可以让游戏者单击影片的任何地方继续。我们其实根本就不需要这个按钮,但是我觉得有这样一个按钮可以给用户一些提示内容。当然这也仅是个人意见。如果你想给这个按钮一个名字并且给它关联一个单击事件也没有问题,但我觉得让它有一个大一点的单击区域使用会很方便。

    第十七步添加nextTextBlock方法

    返回来,在RPGText类里面添加方法
    private function nextTextBlock(e:MouseEvent):void {
    removeEventListener(MouseEvent.CLICK, nextTextBlock);
    txt.text = “”; // clear the text
    _currentTextBlockIndex++;
    _currentTextBlock = _textBlocks[_currentTextBlockIndex][TEXT]; // set the text
    characterIcon.gotoAndStop(_textBlocks[_currentTextBlockIndex][SPEAKER]); // set the character icon
    addEventListener(Event.ENTER_FRAME, updateText); // start updating the text
    addEventListener(MouseEvent.CLICK, fillText);
    }
    起始的三行很简单。移除鼠标移动事件监听,清除文本区域,增加_currentTextBlockIndex变量值并指向下一个文本块
    第四十七行用TEXT常数从_textBlocks数组中取出当前的文本字符串给_currentTextBlock赋值。下一步我们用SPEAKER常量获得当前角色的名字。因为在characterIcon影片剪辑里面角色的名字和帧的标签是匹配的。我们可以用gotoAndStop设置角色图标显示的位置。最后我们添加一个事件监听器开始键入新的文本字符串并且增加一个单击事件执行fillText。

    第18步添加startText方法
    我们已经做完所有的一切,那么剩下要做的事情是添加一个方法让所有的一切开始。我们定义一个公共方法“startText”,因为他是一个公共方法,让我们把它放到RPGText头部,仅在的textBlocks设置器的下方
    public function startText():void {
    _currentTextBlock = _textBlocks[_currentTextBlockIndex][TEXT];
    characterIcon.gotoAndStop(_textBlocks[_currentTextBlockIndex][SPEAKER]);
    addEventListener(Event.ENTER_FRAME, updateText);
    addEventListener(MouseEvent.CLICK, fillText);
    }
    是不是似曾相识?这个代码和nextTextBlock方法做的事情几乎相同。它设置当前文本和角色图标,为updateText和fillText添加监听事件。因为这个方法仅仅在文本第一次显示的时候使用,跟nextTextBlock方法不同的是我们不用清除这个文本区域或者是增加_currentTextBlockIndex。

    第十九步调用startText方法
    现在我们有一个公共方法可以让对话开始了。那么接下来我们把它放到程序里面。
    在Main类构造方法的最底一行添加rpgText.startText();
    这里仅仅是调用RPGText类的startText方法。这样所有的一切就开始了。

    第二十步添加声音
    你可能要测试一下你们的影片,看看它们是不是都已经正常工作了。那么现在就差一件事情了没有做了那就是声音。为文本显示的时候配一个声音,我们可以找一个或者是单独做一个。我们必须保证选择的声音比较短小,因为这个声音随着文本显示循环播放。一个小的“boop”或者是按钮单击的声音是最好的。
    导入声音文件到flash文件,勾选 “Export for Actionscript” 给它一个类名字叫做“TypingSound”

    让声音播放我们只需要在RPGText类里面添加两行代码。首先我们需要声音的实例。在类的开始其它三个私有变量的下面添加
    private var _typingSound:Sound = new TypingSound();
    现在我们向下找updateText方法添加一行让每次文本更新的时候都播放声音。
    private function updateText(e:Event):void {
    if(txt.text.length < _currentTextBlock.length){
    txt.text = _currentTextBlock.substr(0, txt.text.length+1);
    _typingSound.play();
    } else {
    removeEventListener(Event.ENTER_FRAME, updateText);
    fillText();
    }
    }

    第二十一步谈一下它的未来
    上面做的所有工作,的仅仅是为这个例子服务的。如果你想把它整合到游戏里面,那么你好有好多工作要做。
    首先,依据你自己游戏建立对话方式,你肯定会把文本块脱离文档类单独拿出来。你可能有一个场景类,用它来管理人物语言或者是一个字符串类保存所有对话。
    其次,你可能会思考,文本模块在什么时候,怎么样出现在你的游戏中。你可能会添加一个过渡动画来实现如在对话开始和结束的时候让它在底部滑入滑出。你也可能想监听当对话结束后隐藏文本模块或者开始下一段对话。
    因为我们已经校验最后的文本块是否进入fillText方法。所以你可以很容易添加对话结束时的处理方式。在这个教程里面并没有包含这些话题,因为你要根据自己的游戏去做这些事情。这些已经足够帮你开始做了。
    我希望你能喜欢这篇教程!留下你的评语让我知道你们的想法。