动画的基本定义是通过随时间变化改变图像而产生的运动或变化的视觉效果。此示例的目标是创建月球绕其垂直轴旋转的视觉效果。然而,对于动画而言,您可以忽略该示例中球形扭曲方面的问题。假设已加载并用作月球图像数据源的实际图像如下:
如您所见,该图像并不是一个或几个球体;它是月球表面的一张矩形照片。因为该照片刚好是在月球赤道上拍摄的,所以图像中靠近图像顶部和底部的部分发生拉伸和扭曲。若要消除图像的扭曲使其具有球形外观,我们将使用置换图滤镜(在后面进行介绍)。但是,因为该源图像是矩形,所以若要产生旋转球体的视觉效果,代码只要能完成水平滑动月球表面照片的操作即可。
请注意,该图像实际上由月球表面照片的两个副本彼此相接而成。该图像是要从中重复复制图像数据来创建动画外观的源图像。通过两个图像副本彼此相接,会更容易产生连续、不间断的滚动效果。让我们逐步浏览动画生成的过程来看看这是如何实现的。
该过程实际上涉及两个单独的 ActionScript 对象。首先,有加载的源图像,在代码中由名为
textureMap
的 BitmapData 实例表示。如前所述,外部图像加载后,将用图像数据来填充
textureMap
,使用的代码如下:
textureMap = event.target.content.bitmapData;
textureMap
的内容是矩形的月球图像。另外,为了产生旋转动画,该代码使用名为
sphere
的 Bitmap 实例,该实例是在屏幕上显示月球图像的实际显示对象。与
textureMap
一样,
sphere
对象也是在
imageLoadComplete()
方法中创建并使用其初始图像数据填充,使用的代码如下:
sphere = new Bitmap();
sphere.bitmapData = new BitmapData(textureMap.width / 2, textureMap.height);
sphere.bitmapData.copyPixels(textureMap,
new Rectangle(0, 0, sphere.width, sphere.height),
new Point(0, 0));
如代码所示,
sphere
被实例化了。其
bitmapData
属性(通过
sphere
显示的原始图像数据)具有与
textureMap
相同的高度和一半的宽度。换句话说,
sphere
的内容将是一幅月球照片的大小(因为
textureMap
图像包含并排的两幅月球照片)。接下来,用图像数据填充
bitmapData
属性,填充时使用的是
copyPixels()
方法。
copyPixels()
方法调用中的参数指示以下几点:
-
第一个参数指示从
textureMap
复制图像数据。
-
第二个参数(新的 Rectangle 实例)指定图像快照应该从
textureMap
的哪部分拍摄;在本例中,快照是从
textureMap
左上角开始的一个矩形(由前两个
Rectangle()
参数
0, 0
指示),矩形快照的宽度和高度与
sphere
的
width
和
height
属性一致。
-
第三个参数(新的 Point 实例)的 x 和 y 值都为
0
,它定义了像素数据的目标位置 — 本例中为
sphere.bitmapData
的左上角 (0, 0)。
从视觉表示形式上看,该代码将复制下图中用轮廓线标出的、
textureMap
的像素,并将其粘贴到
sphere
上。换句话说,
sphere
的 BitmapData 内容是这里加亮的
textureMap
部分:
然而请记住,这只是
sphere
的初始状态 — 复制到
sphere
上的第一项图像内容。
加载源图像并创建
sphere
之后,由
imageLoadComplete()
方法执行的最终任务是设置动画。动画由名为
rotationTimer
的 Timer 实例驱动,该实例由以下代码创建并启动:
var rotationTimer:Timer = new Timer(15);
rotationTimer.addEventListener(TimerEvent.TIMER, rotateMoon);
rotationTimer.start();
代码首先创建名为
rotationTimer
的 Timer 实例;传递给
Timer()
构造函数的参数指示
rotationTimer
应每 15 毫秒触发一次其
timer
事件。接下来将调用
addEventListener()
方法,以指定在发生
timer
事件 (
TimerEvent.TIMER
) 时调用
rotateMoon()
方法。最后,计时器实际上是通过调用其
start()
方法启动的。
根据
rotationTimer
的定义方式,约每 15 毫秒 Flash Player 调用一次 MoonSphere 类中的
rotateMoon()
方法(用于产生月球动画)。
rotateMoon()
方法的源代码如下:
private function rotateMoon(event:TimerEvent):void
{
sourceX += 1;
if (sourceX > textureMap.width / 2)
{
sourceX = 0;
}
sphere.Data.copyPixels(textureMap,
new Rectangle(sourceX, 0, sphere.width, sphere.height),
new Point(0, 0));
event.updateAfterEvent();
}
该代码实现以下三方面的操作:
-
变量
sourceX
的值(最初设为 0)增加 1。
sourceX += 1;
您将看到,
sourceX
用于确定
textureMap
中的位置(从该位置将像素复制到
sphere
),因此该代码会产生在
textureMap
上将矩形向右移动一个像素的效果。返回到视觉表示形式,经过几个动画循环之后,源矩形将向右移动几个像素,如下所示:
经过几个循环之后,矩形将进一步移动:
像素复制位置的这种平稳渐进式移动是动画制作的关键。通过缓慢、连续地将源位置移动到右侧,
sphere
中显示在屏幕上的图像显示为连续地滑向左侧。这就是源图像 (
textureMap
) 需要两个月球表面照片副本的原因。由于矩形连续移动到右侧,因此大多数时间该矩形不是在一张月球照片上而是与两张月球照片发生重叠。
-
随着源矩形缓慢移到右侧,会出现一个问题。最后,矩形将到达
textureMap
的右边缘,它将用完要复制到
sphere
上的月球照片像素:
下一行代码将解决这个问题:
if (sourceX >= textureMap.width / 2)
{
sourceX = 0;
}
该代码检查
sourceX
(矩形的左边缘)是否已到达
textureMap
的中部。如果是,它会将
sourceX
重置为 0,将其移回到
textureMap
的左边缘并重新开始循环:
-
计算出适当的
sourceX
值后,创建动画的最后一步是将新的源矩形像素实际复制到
sphere
上。实现这一操作的代码与最初填充
sphere
的代码(如前面所述)非常类似;唯一的不同是:在本例的
new Rectangle()
构造函数调用中,矩形的左边缘位于
sourceX
:
sphere.bitmapData.copyPixels(textureMap,
new Rectangle(sourceX, 0, sphere.width, sphere.height),
new Point(0, 0));
请记住,此代码每 15 毫秒重复调用一次。由于源矩形的位置是连续移动的,并且像素被复制到
sphere
上,因此在屏幕上显示为由
sphere
表示的月球照片图像发生连续滑动。换句话说,月球显示为连续旋转。