艺虎动画 > 为你的flash游戏制作rpg风格的文本系统 flash游戏开发 flash游戏设计制作

为你的flash游戏制作rpg风格的文本系统 flash游戏开发 flash游戏设计制作

翼虎动漫   2010-8-13

 

 

 

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

最终结果的展示
下面这个例子就是我们将要制作的文本系统
源代码下载:sourceFiles.zip

第一步:建立你的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方法。所以你可以很容易添加对话结束时的处理方式。在这个教程里面并没有包含这些话题,因为你要根据自己的游戏去做这些事情。这些已经足够帮你开始做了。