收藏 分享(赏)

拼图游戏ActionScript 3.doc

上传人:dcs1276 文档编号:8402820 上传时间:2019-06-24 格式:DOC 页数:29 大小:135KB
下载 相关 举报
拼图游戏ActionScript 3.doc_第1页
第1页 / 共29页
拼图游戏ActionScript 3.doc_第2页
第2页 / 共29页
拼图游戏ActionScript 3.doc_第3页
第3页 / 共29页
拼图游戏ActionScript 3.doc_第4页
第4页 / 共29页
拼图游戏ActionScript 3.doc_第5页
第5页 / 共29页
点击查看更多>>
资源描述

1、本章将综合运用 ActionScript 3.0 的知识,编写一个具有一定复杂度的拼图游戏。游戏中将加载一副外部图像,并生成随机拼图。用户可以通过鼠标控制图块,也可以通过键盘控制图块。游戏还具有简单的录像功能,能够记录和还原用户的操作。13.1 程序分析在开始编写游戏代码之前,需要分析游戏的功能和模块划分,确定用户的操作方式。13.1.1 游戏功能游戏能够加载一副外部图像,并动态的创建游戏场景。在玩家执行游戏时,程序创建如图 13-1 所示的游戏场景。图 13-1 拼图游戏场景游戏场景中包含三种主要元素:游戏舞台、位图画板、空白画板。加载的外部位图被分割为众多小块,每个小块对应一个位图画板。空

2、白画板是一个自由区域,允许用户将其他位图画板移动至该区域。游戏舞台提供了游戏的屏幕界面,是所有游戏元素的载体。13.1.2 操作分析交互游戏必须提供交互功能。游戏中将会有鼠标控制和 键盘控制两种交互方式。当用户使用鼠标操作游戏屏幕画板时,游戏程序需要处理画板的移动。所有的位图画板都能够接受用户的鼠标单击。但是只有空白画板邻接 的位图画板才能移动。即只有空白画板上方、下方、左侧、右侧相邻的位图画板可以被移动。鼠标控制将是游戏的主要控制方式。但是,游戏也能提供键盘控制方式。用户仅依靠四个方向键,就可以完成游戏。当用户按下方向键时,游戏能智能寻找合理的位图画板,并移动和交换该画板同空白画板之间的位置

3、。13.1.3 模块划分位图画板和空白画板具有许多相同的属性,例如大小、屏幕位置等。所以可以设计一个模块,管理位图画板和空白画板。在本例中,使用 GameSlot 类管理所有的屏幕画板。位图画板和空白画板都是屏幕画板。位图画板拥有图像信息,而空白画板只包含单色填充信 息。为了操作分割成小块的位图数据,程序需要建立相应的模块。本例中将建立 ImgSlot 类管理位图图块,每一个位图画板都包含一个位图图块。空白画板也 包含一个位图图块,但是该图块仅包含单色填充。根据以上分析,可以将 ImgSlot 类的实例作为成员添加至 GameSlot 类中。13.1.4 执行过程游戏将首先加载外部图像,并利用

4、相关算法将其切割为小块。所有的位图图块都会以随机的次序装入屏幕画板,不能有遗漏。在游戏场创建后,程序必须侦听用户的交互操作。用户会提供操作命令,移动屏幕画板。程序根据用户的指令,交换屏幕画板的位置。在本例中,位图画板之间不能交换,只有位图画板和空白画板之间可以交换位置。游戏进行时,用户采用鼠标或者键盘调整屏幕画板的位置,程序要及时检查画板位置,当所有的位图画板处在正确位置时,游戏玩家就能取得胜利。13.2 编写游戏原型对于功能较为复杂的项目,一般需要开发一个实现最核心功能的原型。在编写原型的过程中,实现游戏的最基本结构和功能。除了最基本的程序功能之外,原型中应该包含丰富的调试信息输出,以便于程

5、序代码的追踪和改进。在本例中,游戏原型被限定为最基础的程序支持功能。本节要建立的游戏原型如同一幢建筑的地基,在最终的作品中发挥基础的作用。从编码风格的角度考察,在编写游戏原型时采用的代码更趋于清晰和易懂,而不是偏重性能和效率。13.2.1 创建游戏舞台本节将详细介绍如何创建游戏的舞台。(1)项目准备。运行 Flash CS3 IDE 环境。新建 ActionScript 3.0 项目“imgpuzzle.fla”,舞台宽度设置为 550 像素,高度设置为 400 像素。准备一幅宽 390 像素、高 390 像素的图像,命名为 “img.gif”。将图片“img.gif”同 imgpuzzle.

6、fla 置于同一文件夹内。(2)创建加载器。选中项目“imgpuzzle.fla”的第一帧,打开代码编辑器输入以下代码:var imgpath:URLRequest=new URLRequest(“img.gif“);var imgloader:Loader=new Loader();imgloader.load(imgpath);这段代码创建一个 Loader 加载对象,用来载入外部图像文件“img.gif”。考虑到加载的速度不可能同代码的执行一致,应该在程序中使用事件侦听,处理加载成功的事 件通知。Loader 类不能直接处理加载事件,必须在 Loader 对象的 contentLoade

7、rInfo 属性对象上绑定事件侦听器。imgloader.contentLoaderInfo.addEventListener(Event.COMPLETE,onloaddone);这一行代码将一个名为 onloaddone 的事件侦听器同加载对象的Event.COMPLETE 事件绑定。当图片加载完成后,FlashPlayer 将发送Event.COMPLETE 事件,触发该侦听器。由于是原型,此处暂时不追踪图片的加载进度消息。(3)保存全局位图对象。在编写事件响应函数的函数 体之前,应该考虑程序中所需的全局变量。需要创建一个全局对象 GAME_FIELD,该对象应该是一个显示对象容器,包含

8、所要创建的拼图图版。目前不必为 GAME_FIELD 对象提供时间轴,所以只需要使用 Sprite 类型即可。为了方便处理加载的图像,应该建立一个全局 BitmapData 变量。由于图片的数据在加载完成前尚不确定,所以暂时只能声明 GAME_FIELD 标识符。不必使用 new 关键字和构造函数去创建内存实体。/拼图图版容器var GAME_FIELD:Sprite=new Sprite();GAME_FIELD.y=5;GAME_FIELD.x=5;/全局图像数据var gamebmd:BitmapData;(4)定义图块数量。拼图游戏中,一个很重要的数据是拼图的图块数量。一般而言,拼图应

9、该由正方形的等宽等高图块构成。图块的数量应该是大于 0的自然数,例如 9、16、25 等。在代码中声明一个 uint 类型的全局变量 BLOCK_NUM,利用该变量记录拼图总有效图块的平方根。如果 BLOCK_NUM 为 6,则图像将被分割为 36 个图块;如果 BLOCK_NUM 为 3,则图像将被分割为 9 个图块。分割的块数越多,游戏就越耗时,难度也就越大。如果拼图游戏仅分割为 4 个有效图块,则在数学上可以证明这样的游戏不能完成。因此 BLOCK_NUM 的取值应该大于等于 3。在完整的程序中,可以由用户指定该数值。在本例中暂时设置 BLOCK_NUM 的取值为 3。/图像块总数的平方

10、根var BLOCK_NUM:uint;BLOCK_NUM=3;(5)加载侦听函数。为了取得加载图像的像素信息,请在 Event.COMPLETE事件的侦听函数中,添加以下代码:function onloaddone(par:Event):void /加载图像的像素信息gamebmd=par.target.content.bitmapData;/处理游戏内容stage.addChild(GAME_FIELD);虽然游戏目前还没有任何实际内容,但是这些代码可以完成图像的载入,并将图像的像素数据保存在内存中。在随后的代码中,可以使用变量 gamebmd访问这些数据。为了测试图像是否被成功加载,建立

11、临时的 Bitmap 对象,将gamebmd 展示在舞台上:var tempbp:Bitmap= new Bitmap(gamebmd);GAME_FIELD.addChild(tempbp);程序的执行结果如图 13-2 所示。图 13-2 加载外部图像至此,游戏的舞台框架就被成功创建了。13.2.2 图块类的划分对于拼图游戏,应该包含两种类型的图块:保存像素数 据的图块,以及负责屏幕显示的图块。像素数据不会随着用户的操作和游戏的进行而变化,但是屏幕显示却可能由于环境的需要而不断修改。在 ActionScript 3.0 中,可以创建两个显示对象,分别处理图像像素数据图块(位图图块)和屏幕显

12、示图块(屏幕画板)。例如,对于拼图游戏中的图块 A,其位置可以随着用户 的操作不断改变,但是其显示的图像内容却保持不变。利用 Bitmap 对象保存像素数据,而利用一个显示对象容器对象(例如 Sprite 实例),保存图块的 位置信息。在程序开始执行时,将 Bitmap 作为子显示对象,利用“addChild()”方法加入显示对象容器的列表中。为了更方便地操作这两种对象, 应该分别建立相应的自定义类进行管理。(1)ImgSlot 类:位图图块,保存和记录像素图块。(2)GameSlot 类:屏幕画板,接受用户单击,负责图块的屏幕显示。为了便于遍历和操作,可以考虑使用数组管理这些类的对象。13.

13、2.3 ImgSlot 类首先创建位图图块的 ImgSlot 类,负责保存图块的像素信息:package import flash.display.Bitmap;public class ImgSlot public var img:Bitmap;public var horizonSerial:uint;public var verticalSerial:uint;在 ImgSlot 类中,定义了三个属性。 img:Bitmap保存像素数据。但该属性不必是 BitmapData 对象,而是使用 Bitmap 显示对象,以减轻代码其他位置的工作量。 horizonSerial:uint图像像素

14、块的水平编号。 verticalSerial:uint图像像素块的垂直编号。在创建 ImgSlot 类的实例时,不仅要提供 img:Bitmap 属性,还必须提供horizonSerial:uint 属性和 verticalSerial:uint 属性。图块来源于加载的图像, 并根据 BLOCK_NUM 的值进行切割。利用 horizonSerial:uint 属性和verticalSerial:uint 属性保存图块在原始图像 中的水平位置和垂直位置。当游戏进行时,需要判断图块的屏幕位置是否同 horizonSerial:uint 属性和 verticalSerial:uint 属性匹配,进

15、而确定用户是否成功完成了拼图游戏。horizonSerial:uint 属性和 verticalSerial:uint 属性必须在创建图块时记录,不应在代码的其他位置修改。但是为了满足外部访问的需要,暂时将其设置为 public 属性。在完整的程序中,可以考虑使用 setter/getter 存取器保护该数据的安全。13.2.4 创建位图图块由于 ImgSlot 类的属性比较简单,所以可以在构造函数中直接创建并进行初始化。编辑 ImgSlot 类的构造函数如下:package import flash.display.Bitmap;public class ImgSlot /属性声明funct

16、ion ImgSlot(slotbitmap:Bitmap=null,h:int=0,v:int=0) img=slotbitmap;horizonSerial=h;verticalSerial=v;ImgSlot 类的构造函数接受三个参数,分别为:利用相应的位图像素数据创建的 Bitmap 显示对象、水平序列号、垂直序列号。将上述代码保存为 ImgSlot.as 文件,并保存在主程序的同级目录下。使用下面的语句,可以在 FLA 文件中创建一个 ImgSlot 类的实例:/示例代码,不必添加在程序中impor ImgSlot;var bmd:BitmapData=new BitmapData(

17、100,100);var myBitmap:Bitmap=new Bitmap( bmd );var gameImageBlock:ImgSlot=new ImgSlot(myBitmap,1,1);创建的 ImgSlot 类实例对象并不是显示对象,因此不能直接添加至显示列表。该类的对象实例可以用做更高级图块显示类的属性。13.2.5 GameSlot 类为了将图块的像素数据显示在屏幕上,GameSlot 类必须是一个显示对象类,而且需要作为显示对象容器,并接受用户的鼠标操作。因此考虑使用 Sprite 类作为基类,并添加所需的属性进行扩展。为了为编译器提供充分的信息,需要导入 Sprite

18、类和 Bitmap 类。同时,由于 GameSlot 类中需要使用自定义 ImgSlot 类,所以还需要使用 import 语句导入 ImgSlot 类。GameSlot 类的类框架代码如下:package import flash.display.Sprite;import flash.display.Bitmap;import ImgSlot;public class GameSlot extends Sprite/添加类体的代码在类的框架代码中,声明 GameSlot 类是 Sprite 类的子类,以便 GameSlot类的实例对象可以作为显示对象添加至显示列表,并接收用户的交互操作事件

19、。作为一个容器,GameSlot 对象需要接收一个位图对象,并将该对象作为自己的子显示对象。GameSlot 对象在舞台上的显示位置会随着用户的操作而变化。因此保存其位置信息的属性应该是公共的,以供类之外的代码访问。GameSlot 对象的位置信息将会分为两大类:舞台的坐标和游戏画板的序号。虽然可以根据 x 和 y 坐标经过运算获得画板序号,但是更稳妥的做法是不要将画板序号同具体的坐标位置绑定。这样做有助于维护游戏内部逻辑判断的独立性,避免屏幕复杂动画和视觉显示技巧对内部逻辑的干涉。因此在该类中,应该包含以下公共属性,用以记录位图对象和画板序号。 public var cont:Bitmap图

20、块位图。 public var horizonSerial:uint水平方向的画板序号。 public var verticalSerial:uint垂直方向的画板序号。为了简化操作,在本例中将使用自定义的 ImgSlot 对象作为位图对象,并且在 GameSlot 类中,声明 targeth 和 targetv 属性,保存 ImgSlot 对象的位置信息。位图的位置信息将是外部不可见的,仅供 GameSlot 类内部使用。 var targeth:uint位图在原始图像中的水平序号。 var targetv:uint位图在原始图像中的垂直序号。如果 GameSlot 对象的画板序号(hori

21、zonSerial 和 verticalSerial),同该对象所含位图的图像序号一致,则可以认为该画板被移动到了正确的位置。假如所有的画板都处在正确的位置,则游戏玩家就赢得了游戏。13.2.6 创建屏幕画板在创建 GameSlot 类的实例时,可以采用下面的代码:var myis:ImgSlot=new ImgSlot();/构建 ImgSlot 对象var mygs:GameSlot=new GameSlot();mygs.addChild(myis);不过这样的代码并不适 合快速建立画板。为了简化 FLA 中的代码,应该将创建画板的操作交给 GameSlot 类的构造函数执行。在使用 n

22、ew 和 GameSlot 构造函数时,必须 提供充足的参数。在构造函数中,需要引入三个参数。第一个参数是将要和画板绑定的图像块,这是一个 ImgSlot 对象。第二个参数和第三个参数是画板的序 列信息。下面的代码实现了 GameSlot 类的自定义构造函数:package import flash.display.Sprite;import flash.display.Bitmap;import ImgSlot;/扩展 Sprite 类,创建自定义 GameSlot 类public class GameSlot extends Sprite/自定义属性public var cont:Bitm

23、ap; /装载位图的引用。该属性是为了扩展功能public var horizonSerial:uint; / 屏幕画板的水平序列号public var verticalSerial:uint; /屏幕画板的垂直序列号var targeth:uint; /装载位图的水平序列号var targetv:uint; /装载位图的垂直序列号/构造函数function GameSlot(imgObject:ImgSlot=null,h:uint=0,v:uint=0) cont=imgObject.img; /保存位图对象的引用horizonSerial=h; /保存屏幕画板水平序列号verticalS

24、erial=v; /保存屏幕画板垂直序列号targeth=imgObject.horizonSerial; /复制位图序号targetv=imgObject.verticalSerial; /复制位图序号this.addChild(cont); /添加至显示列表GameSlot 类的 cont 属性保存了画板的位图数据,即 ImgSlot 参数的 img属性,指向一个 Bitmap 对象。提供这个参数主要是为了扩展,一般并不需要修改位图的 数据。构造函数自动将 ImgSlot 对象的位置序号复制在GameSlot.targeth 和 GameSlot.targetv 之中。游戏代码应依据 Ga

25、meSlot.targeth 和 GameSlot.targetv 的值,判断画板是否处在正确的位置。在这种机制的保护下,如果用户出于某些需要改动 了 ImgSlot 对象(例如删除或替换了 ImgSlot 对象),也不会对游戏的基本逻辑产生毁灭性影响。13.2.7 判断画板位置画板的屏幕位置是公开的,可变的,但是其内部的 GameSlot.targeth 和GameSlot.targetv 属性记载着画板位图的正确位置,在画板创建时被赋值,并在之后的游戏过程中保持不变。在 GameSlot 类中创建一个名为 checkfix 的公共方法。该方法不需要参数,返回值为布尔类型。当利用 GameS

26、lot 对象的名称调用该方法时,将检测该方法的调用对象是否处在正确的所属位置。public function checkfix():Boolean var re:Boolean=false;if (horizonSerial=targeth return re;本方法在编码时,首先创建一个布尔类型的变量,并为其赋初值。然后通过 if 判断,修改这个变量,并使用 return 关键字返回此布尔变量。实现本方法,还可以有其他代码编写方式。虽然只是实现简单功能,但不健壮的代码依然会引发错误。下面的代码就是一个反面的例子:public function checkfix():Boolean if (h

27、orizonSerial=targeth else if(horizonSerial!=targeth | verticalSerial!=targetv)return false;这段代码的编码方式非常糟糕。代码虽然具有一定的逻辑,但是不利于编译器的分析判断,而且难于调试追踪方法中是否提供了正确的返回值。只有逐一对所有的屏幕画板执行检查,并且全部获得 true 返回值之后,才能认定玩家获胜。不要在 GameSlot 类的复位检查方法中删除位图数据和锁定画板位置。在实际的游戏中,在最终赢得游戏前,玩家可能会将屏幕画板在不同位置间反复移动。13.3 游戏场景在构建游戏原型的过程中,借助 Acti

28、onScript 3.0 代码实现了基本的功能支持:加载外部图像,并建立对加载完成事件的侦听。建立了 ImgSlot 类和 GameSlot 类,分别处理位图图块和屏幕画 板。在此基础上,不断整合和细化,建立具有简单游戏功能的游戏场景。13.3.1 分析游戏场景在拼图游戏中,游戏场景是一组按照水平和垂直顺序规则排列的画板。为了创建这样的游戏场景,需要解决三个问题。1图像数据的分割利用 Loader 类载入了外部图像数据,但是这样的数据是一个整体的图像,而不是分割的位图图块。必须使用位图的相关操作函数,将载入图像分割为小块区域,并装载入ImgSlot 中。在切分和装载的过程中,应该保存位图图块在

29、原始图像中的位置信息。2位图图块同屏幕画板的组合创建复杂的游戏场景,必然要依靠自定义的 ImgSlot 类和 GameSlot 类。图像数据切割成位图图块后,每个位图图块都具有固定的位置序号。在位图图块之间,序号是连续和规则的。但是在装载位图图块时,屏幕画板需要执行随机的抽样,以造成屏幕显示的乱序。3画板的屏幕显示将众多装载有分割位图图块的屏幕画板组装在一起,无缝的排列成可供玩家操作的游戏场景。在拼图游戏中,需要在拼图图版上留下一个空位,供用户移动图块。这个空位是一个特殊的 GameSlot,它不装载 FLA 外部加载图像的位图数据,而是以单色的色块填充。最终的游戏场景应该是众多 GameSl

30、ot 对象构成 的二维矩阵,每个 GameSlot 对象都乱序装载着固定的 ImgSlot 对象作为图像数据。为了便于对这些 GameSlot 对象执行移动、变形、消隐等操 作,可以考虑建立一个外部的 GAME_FIELD 显示对象容器,装载所有屏幕图块。13.3.2 场景基础创建“BuildGameField()”函数,作为创建场景操作的入口。function BuildGameField(srcbitmap:BitmapData,blockNum:uint):Array /函数体return new Array();“BuildGameField()”函数的具体实现将在随后节中详细介绍,目

31、前,读者应关注函数的所需功能和在整体代码中的位置。调用“BuildGameField()”函数时, 需要提供两个参数:外部加载图像的位图数据BitmapData,以及拼图游戏的图块数量设定。在“BuildGameField()”函数的函数体内, 需要执行位图分割,屏幕装载等任务。所有的屏幕画板都会在“BuildGameField()”函数中创建,并使用数组管理。在 “BuildGameField()”函数执行完毕后,返回这个包含屏幕画板的数组。当拼图游戏运行后,可能需要进行多轮游戏,每轮游戏的位图图像和图块分割数量可能会不同,因此, “BuildGameField()”函数的参数,需要在每次调

32、用“BuildGameField()”函数时直接指派,而不能利用全局常量直接提供。“BuildGameField()”函数需要操作全局对象 GAME_FIELD。作为一个最外层的容器,GAME_FIELD 将是所有屏幕画板在显示列表中的根基。在拼图游戏中,只会存在一个GAME_FIELD 对象,因此不需要将 GAME_FIELD 作为参数传递。应该在外部图像加载完毕后调用“BuildGameField()”函数。即在 Loader.content LoaderInfo 对象的 Event.COMPLETE 事件侦听器中,调用“BuildGameField()”函数。下面的代码是创建场景基础的实

33、际代码:/加载外部图像var imgpath:URLRequest=new URLRequest(“img.gif“);var imgloader:Loader=new Loader();imgloader.load(imgpath);imgloader.contentLoaderInfo.addEventListener(Event.COMPLETE,onloaddone);/位图数据var gamebmd:BitmapData;/场景容器var GAME_FIELD:Sprite=new Sprite();GAME_FIELD.y=5;GAME_FIELD.x=5;/屏幕图块数组var g

34、ameslot:Array;/拼图图块数量控制var BLOCK_NUM:uint;BLOCK_NUM=6;/侦听图像加载完成function onloaddone(par:Event):void gamebmd=par.target.content.bitmapData;/调用场景创建函数gameslot=BuildGameField(gamebmd,BLOCK_NUM);stage.addChild(GAME_FIELD);执行 “BuildGameField()”函数后,加载图像被分割为位图图块,并装载入 GameSlot 对象中。所有的屏幕画板不仅会装入数组,而且还将作为 GAME_F

35、IELD 容器的显示列表子结点。当“BuildGameField()”函数执行完毕后,只要将 GAME_FIELD 对象装入舞台显示列表, 则拼图游戏的所有屏幕画板都会显示在用户面前。至此,“BuildGameField()”函数的功能和在整个程序中的位置就十分清晰了。13.3.3 建立图块数组在 “BuildGameField()”函数中,将根据接受的参数,执行图块分割。“BuildGameField()”函数的参数 srcbitmap 是 BitmapData 数据,保存着完整的位图像素。另一个参数 blockNum 是一个 uint 数据,指定分割块的数量。为了进行图像分割,首先要依靠

36、“BuildGameField()”函数的两个参数,获得每个位图图块的像素尺寸。利用 BitamapData 的 height 和 width 属性,取得加 载图像的实际尺寸,并计算出每个图像块的宽和高。图块的宽高在程序执行期间是不变的,所以此处将它们声明为 const 常量:function BuildGameField(srcbitmap:BitmapData,blockNum:uint):Array /图块的宽,以像素为单位const blockwidth:uint=srcbitmap.width/blockNum;/图块的高,以像素为单位const blockheight:uint=s

37、rcbitmap.height/blockNum;/trace(blockwidth+“,“+blockheight);blockNum 参数 的含义是拼图游戏中每行和每列的图块数。处理这样的数据结构,最方便的方法是利用二维数组。ActionScript 3.0 中没有直接建立二维数组的语法。需要借助循环结构,为一维数组的每个元素创建新的一维数组。如果将外层的数组理解为水平向,内层的数组理解为垂直 向,则建立的数组结构就是二维的平面结构。下面的代码声明了名为 ary_imgblock 的数组,并借助循环,将其扩展为二维数组。这段代码包含一个嵌套的循环,循环因子为 aryj。在嵌套的循环中,可以

38、直接借助循环因子,操作二维数组 ary_imgblock 中的基层元素。function BuildGameField(srcbitmap:BitmapData,blockNum:uint):Array /计算图块宽高/双层循环var ary_imgblock:Array=new Array(blockNum);for (var aryi:uint=0; aryi=0; RC-) var tempint:int;tempint=Math.floor(Math.random()*ary_liner.length);rndAryRC=ary_linertempint;ary_liner.splic

39、e( tempint ,1);/trace(rndAryRC.HorizonSerial+“-“+rndAryRC.VerticalSerial);return rndAry;在这段代码中,借助了 ActionScript 3.0 中 Array 类的 spice 方法。“Array.splice()”方法可以从数组中剔除指定位置的元素,并将剔除后的数组更新,使其具有新的 length 长度。借助“Math.random()”方法,可以不停的从线性数组 ary_liner 中选择随机的剔除对象。在剔除前,将剔除对象保存在 rndAry 中,当 ary_liner 中的所有元素都被剔除后,rnd

40、Ary 就按照随机的顺序保存了所有的元素。考虑到拼图游戏的实际情况,需要对空白画板邻接的屏 幕画板进行保护,使其处在正确的位置。否则,玩家将不能顺利完成游戏。因此,在这段代码中,首先按照直接映射的方式,将 ary_liner 的最后一个元素 赋值给 rndAry 的最后一个元素。无论其余的元素如何随机,但是最后一个元素,即游戏场景内最后一行最后一列的画板,将永远保持正确的位置。至此,完整的“getLinerRandom()”函数就被建立了。该函数接受一个二维数组,并返回一个乱序的一维数组。返回数组的最后一个元素,始终指向传入数组的最后一个元素。13.3.6 创建画板数组装载位图图块之前,需要建

41、立相应的屏幕画板。同操作位图图块相似,管理屏幕画板也应该利用 ActionScript 3.0 提供的二维数组。可以在“BuildGameField()”函数中直接书写装载位图图块的代码,但是鉴于这段代码具有明确的功能,且代码行数较多,因此建议为这段代码编写一个函数。不过该函数应该仅由“BuildGameField()”函数内部调用。实现位图图块装载函数的步骤如下。(1)建立名为“setupgamefield()”的函数。function setupgamefield(bAry:Array,blockW:uint,blockH:uint,blocknum:uint):Array /装载位图图块

42、return new Array();该函数具有四个参数,但只有第一个参数是必需的。 bAry:Array保存位图图块的二维数组。在该数组中,每个基层元素都是一个 ImgSlot 对象。其余三个参数不是必需的,都可以通过第一个参数计算获得。但是为了简化函数运算,依然要求开发者在调用函数时直接提供: blockW:uint位图图块的宽度,使用像素表示。 blockH:uint位图图块的高度,使用像素表示。 blocknum:uint该值的平方是位图图块的个数。本例为了简化“setupgamefield()” 函数的编码,没有在 “setupgamefield()”函数中通过bAry 参数求得 b

43、lockW、blockH 和 blocknum。在实际的开发中,应 该避免这种编码风格,改为经过动态计算,获得与 bAry 匹配的 blockW、blockH 和 blocknum。在手工指派blockW、blockH 和 blocknum 时,如果提供了错误的值,将对函数的执行造成灾难性的后果。函数“setupgamefield()”将会返回一个数组,不过该数组与作为参数的 bAry 不同,它将保存所有屏幕画板对象,即 GameSlot 对象。(2)获得乱序位图图块。在“setupgamefield()”函数中,首先建立乱序线性数组,并使用“getLinerRandom()”方法,将 bAr

44、y 转化为乱序的线性数组:function setupgamefield(bAry:Array,blockW:uint,blockH:uint,blocknum:uint):Array /建立乱序数组var rndArry:Array=getLinerRandom(bAry);/trace(rndArry.length);由于已经建立了功能完备的“getLinerRandom()”函数,因此该步操作显得非常轻松。(3)创建图板数组。利用嵌套循环,创建二维数组,作为屏幕图板的管理数组:function setupgamefield(bAry:Array,blockW:uint,blockH:ui

45、nt,blocknum:uint):Array /建立乱序数组/创建屏幕画板数组var ary_gameslot=new Array(blocknum);for (var h:uint=0; hblocknum; h+) /创建二维数组ary_gamesloth=new Array(blocknum);/操作二维数组基层元素for (var v:uint=0; vblocknum; v+) /创建 GameSlot 对象/返回屏幕画板数组return ary_gameslot;代码中,使用 ary_gameslot 数组管理屏幕画板。该数组采用二维数组的形式,主要是为了进行直观的管理。ary_

46、gameslothv将指向游戏场景中第 v行第 h 列的屏幕画板。13.3.7 装载位图创建 GameSlot 对象,并装载位图的操作都在“setupgamefield()”函数的嵌套循环中进行。在屏幕画板中装载位图图块,不仅包括将位图图块加入 GameSlot 对象的显示列表,还包括记录图块信息、添加交互侦听、配置场景显示列表等操作。(1)创建屏幕画板。在创建 GameSlot 类时,已经考虑到创建 GameSlot 实例时简化代码的问题。因此,此处直接利用 GameSlot 类的强力自定义构造函数,可以快速创建屏幕画板。ary_gameslothv=new GameSlot( rndArr

47、y h*blocknum+v , h , v );由于 rndAry 保存了乱序的位图图块信息,所以使用 andAryh*blocknum+v,可以向(h,v)位置的屏幕画板提供无序的位图图块。 h 和 v 将作为屏幕画板的位置序号,表示第 v 行第 h 列的屏幕画板。(2)布置画板矩阵。屏幕画板应该在游戏场景中以密集矩阵的形式排列,因此需要计算每个屏幕画板的舞台位置:ary_gameslothv.x=h*blockW;ary_gameslothv.y=v*blockH;ary_gameslot 数组中的基层元素都是 GameSlot 对象,因此具备 GameSlot对象的属性。由于 Game

48、Slot 类是从 Sprite 类扩展而来,因此也继承了 x 和 y属性,分别表示 GamleSlot 显示对象的舞台坐标。(3)添加交互事件侦听。作为 Sprite 类的子类,GameSlot 类具有接收用户交互的能力。通过为每个 GameSlot 对象添加事件侦听,可以响应用户的鼠标操作。ary_gameslothv.addEventListener(MouseEvent.CLICK,eve_SlotClickHandler);/add event for mouse click此处暂时添加了对鼠标单击的侦听,侦听器将在后文实现。(4)加入游戏场景。由于 GAME_FIELD 将作为所有屏

49、幕图板的显示对象容器,所以在创建和配置好 GameSlot 对象后,应该直接将其加入 GAME_FIELD 对象的子显示列表。GAME_FIELD.addChild(ary_gameslothv);当函数执行 后,ary_gameslot 将作为返回值提供给函数的外部代码使用。虽然可以在其他位置将 ary_gameslot 数组的所有元素加入 GAME_FIELD 显示列表。但是在外部代码中添加显示列表,需要遍历二维数组,建立新的嵌套循环。而在函数“setupgamefield()”中实 现该功能,借助了现有的循环,无疑是最为简捷的方式。13.3.8 舞台空位拼图游戏中,需要存在一个舞台空位,以供玩家移动屏幕画板。在程序实现中,舞台空位也是一个 GameSlot 对象。不过该对象不需要加载图像的位图数据,也不需要接受用户的单击

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报