导演写“拼图”
现在世界上很多大公司都用Director制作自己的多媒体教学光盘。这包括微软、苹果、Adobe等等(虽然这些公司都不是多媒体制作公司)。最近20世纪福克斯公司推出了《X档案无限制访问》(我最喜欢的电视剧《X档案》的数据光盘),也使用了Director和QuikTime VR技术。不仅国外越来越多的人使用Director编写多媒体光盘,国内也有很多人从事Director的编程工作。Director现在已经成为多媒体制作工具事实上的标准。但是,相比较而言,我们对Director的使用还处于较低水平。我看过很多国内多媒体公司制作的CD,大部分的交互控件都很简单,无非就是闪烁的按钮和图像。点击它们进入其他场景,如幻灯片。估计有无数的goto xx语句和一大堆美工做的二次元动画。这种光盘还不如PowerPoint(开个玩笑)。原因有很多,最重要的是我们的程序员对Lingo语言没有很好的掌握,直接影响了创意的选择。如果程序员不能用Director实现创意,很多原创的想法都会被撤销。所以程序员对Lingo语言的使用直接影响最终产品的质量。这就需要更多的导演程序员全面掌握Lingo。我就是来抛砖引玉的,和很多导演迷分享一下我做小游戏的经验。
很多人都玩过拼图,我也是拼图爱好者很久了。我第一次在麦金塔上玩拼图。后来一个偶然的机会,我得到了一个苹果的Adobe Illustrator的安装光盘。无意中发现了一个拼图,上面有维纳斯的头像(这是Illustrator的启动画面),发现是导演写的(香港导演4.0制作的《与刘小慧共度一周》也设计了一个拼图)。当时我已经开始使用Director编写多媒体演示程序(那是1995),但是缺乏Lingo的高级功能。通常,我编写的程序使用了许多函数,但我从未使用过列表和对象等数据结构。在某些情况下,这种编程往往事倍功半。三年前,我用Director写了第一个“拼图”。这个版本花了我很长时间(大概一周),程序代码很长很乱。后来连我自己都不明白。随着对Lingo越来越了解,我逐渐意识到以前写的程序中不使用列表是多么的愚蠢。前几天又和导演写了新版的《七巧板》。不仅减少了原代码(更容易理解),而且只用了两个小时。现在我们逐步分析如何用Director写出一个“拼图”。
使用列表是编写拼图游戏的关键。可以说,在Lingo编程中,列表比对象更重要。因为使用Lingo面向对象函数的用户比使用其传统数据结构函数的用户少(国外使用Lingo对象的用户很多)。我写的“七巧板”的界面。
首先,我做了16张BMP拼图,每张大小为100 * 100像素。分别代表上图中的16小拼图,命名为1.bmp,2.bmp,3.bmp,4.bmp,5.bmp,...并将这些16文件导入到Director中。它们是角色库中1到16的角色。
同时,我们将这些16的谜题依次排列在1到16频道上。
现在,我们将讨论使用Director编写“拼图”的想法。在线替换角色函数(Lingo中的sprite的memberNum)是使用的最重要的函数。就是当我们用鼠标点击对应的向导通道时,我们用16谜题中唯一的空白位图角色替换了被点击向导的角色。有几个难点需要注意。第一,这个替换不是任意的,只能移动空白周围的纵横拼图。举个例子,
只有数字为6,9,7,14的拼图可以绕着上图中的空白方块移动。其他谜题点击时不会替换成空白。当空白块在不同的通道中时,需要建立可移动通道的列表。这里用一个全局变量gEmpty来存储角色为空的通道号;第二,每次开始“拼图”都要随机排列拼图,每次的图案都不一样。有必要为每个渠道建立一个角色列表;第三,必须建立一个判断条件,最后玩家能够拼出第一张图所示的图案,说明玩家已经成功拼出了图案。这就需要建立一个列表,即最终图案中各通道的字库列表,即list Finish = [1,2,3,4,5,6,7,8,9,10,11,12,65448。为了与最终的列表结束进行比较,当当前帧循环时,在当前帧每次退出时,生成每个通道的临时角色列表;还有一点就是第一次进入循环帧时需要根据随机列表更换所有通道的角色,但在接下来的几个循环中每次进入循环帧都不需要,所以需要一个决策变量来决定是否是第一次进入循环帧。
看似复杂,但实际做起来没那么麻烦。相比用其他高级语言写这个程序,Lingo需要你用新的思路来考虑编程。它可以让你在不涉及很多编程细节的情况下,更多地思考解决问题的方法,而且它的功能性不如传统的脚本语言。
导演写“拼图”
首先,我们需要自己编写几个函数(或个人句柄)。
第一个函数是generateList函数,它生成16个随机列表。
其具体代码如下:
论生成列表
全球gEmpty,随机列表
set randomList = []
重复x = 1到16
addAt(randomList,random(x),x)
结束重复
结束
因为Lingo不提供随机排列列表的功能,Lingo!《高级指南》中的一段代码,通过在循环语句中使用addAt()和random()函数,巧妙地生成了一个随机列表。它首先在循环中随机生成列表位置,并将其赋给1-16中的值。当addAt()函数在列表中的相同位置增加一个值时,会将位置向后推,这种特殊的工作模式不再重复。
第二个也是最重要的功能是exchange()。它有一个参数。该参数是频道号。在点击垂直或水平相邻于一个空格的拼图游戏时,两者的角色要对调,即空格所在的通道改变被点击通道的角色,被点击通道的角色改变为空格。并将点击的频道号分配给变量gEmpty,该变量标识空白频道所在的频道。函数中的变量x是一个临时变量,用来在替换时临时存储数据。
在交易所
全球增长
将x设置为sprite gEmpty的成员数
将sprite gEmpty的memberNum设置为sprite n的memberNum
将sprite n的memberNum设置为x
更新阶段
设置gEmpty = n
结束
该功能用于每个循环帧的通道1-16,其用法如下:
鼠标抬起时
导演写“拼图”
我已经描述了所有写的函数,剩下的一步是最后也是最关键的一步。也就是说,在循环帧的帧脚本中调用这些函数。
具体的框架脚本如下:
全局gEmpty,randomList,First,Finish,Tmp,m1,m2,m3,m4,m5,m6,m7,
m8,m9,m10,m11,m12,m13,m14,m15,m16,mList,M
在进入框架时
如果First = 0,则
重复i = 1到16
puppetsprite i,TRUE
将sprite i的memberNum设置为getAt(randomList,I)
结束重复
先设置= 1
如果…就会结束
如果Finish = Tmp,那么
走框架+ 1
其他
设置tmp = []
如果…就会结束
设置M =移动(移动)
结束
在enterframe上的传入帧事件处理程序中,首先根据变量first判断是否第一次进入当前循环帧,判断条件为First是否为0。如果是,通道1-16的角色将根据randomList列表中的值进行更新。更新后,首先将变量赋值为1。以便下次不执行该操作。然后比较最终列表Finish和临时列表Tmp是否相同,如果相同,则拼图结束。跳到结束帧。否则继续在当前帧循环,将tmp列表赋值为空,避免由于对exitFrame的操作而造成tmp列表重叠。最后,获得空白在当前频道时的可移动列表m。
在现有框架上
重复x = 1到16
addAt(Tmp,sprite x的成员)
结束重复
去画框
结束
在exitFrame上的exit frame事件处理程序中,通过loop生成当前通道角色的临时列表Tmp,并在当前帧中使用go frame进行循环。
所有的程序代码都已经描述过了。如果把这些16的图片换成自己喜欢的图片的拼图,就可以生成自己风格的拼图。从上面你会发现Lingo编程真的不一样。这么简单的代码就能在短时间内写出这样的游戏。