使用TweenMax與TimelineMax仿造一個模板怪獸的效果

前言:


該模板的標號為24063,本文將探討的只是其中相冊裏面照片相互轉換時的一個動畫效果,如圖:


in-middle-of-effect-playing

關於這個效果的原理,之後我會在HTMW類別裏面寫一篇文章來介紹。而這裡將重點放在如何使用TimelineMax上面。


準備:


還是先去官網下載:http://www.greensock.com/tweenlite/

另外,主要類的在線文檔:

http://www.greensock.com/as/docs/tween/com/greensock/TweenMax.html

http://www.greensock.com/as/docs/tween/com/greensock/TimelineMax.html


正文開始:


Open Flash Pro CS5.0, create a .fla file, save it as GlowingGridEffect.fla; then create a class file: main.as; and copy the lib folder of TweenMax into the same directory. And then we setup our class skeleton:


package transitionEffect.effects 
{
	import flash.display.Sprite;
	import flash.display.BitmapData;
	import flash.display.Bitmap;
	import flash.display.BlendMode;
	
	import com.greensock.*;   
	import com.greensock.data.TweenMaxVars;
	import com.greensock.plugins.TweenPlugin;  
    import com.greensock.plugins.ColorTransformPlugin; 
	
	public class GlowingGridEffect 
	{
		private var _effect:Sprite;
		
		private var _image1:Sprite;
		private var _image2:Sprite;
		private var _image3:Sprite;
		
		private var _squares1:Array;
		private var _squares2:Array;
		
		private var _maskContainer1:Sprite;
		private var _maskContainer2:Sprite;
		
		private var _image1Cont:Sprite;
		
		private var _maskTimeline1:TimelineMax;
		private var _maskTimeline2:TimelineMax;
		private var _overallTimeline:TimelineMax;
		
		public function GlowingGridEffect() 
		{
			
		}
		
		public function getReady():Sprite
		{

		}
		
		private function onEffectPlayed():void
		{
		
		}
		
		public function play():void
		{
			
		}

	}
	
}

getReady() is the method we place most of our code for setting up our animations with TweenMax.


And now, let's take a look of the over view of this effect's structure:


overview-of-effect-layers

There are totally four visual elements which are transforming in terms of their color tone, size and perhaps positions. The one on the top is a video produced in After Effect, its five blue lines flying, two horizontally, three vertically:


shining-lines-vid   


But I'm not going to include this video in my project, I will dismiss it. So, now, the next up is the other three transforming images. Indeed they are copies of the same picture. The bottom two have masks coming with transformation, and the animation of masks are the same, they run on their own.


The mask is a matrix of squares, with 3 col and 4 rows:


mask-overview


And each square enlarges its size on its own:


mask-square

 

But there is one trick here: the enlarging transformations of each square, they are not kicked off simultaneously, there are delays. That makes the image be revealing piece by piece.


So, now what we are going to do is to draw 12 squares and position them like the figure shows:


this._squares1 = new Array();
this._maskContainer1 = new Sprite();
			
for(var $x=0; $x<3; $x++)
{
	this._squares1[$x] = new Array();
	for(var $y=0; $y<4; $y++)
	{
		var $square1:Sprite = new Sprite();
		$square1.graphics.beginFill(0x0000FF);
		$square1.graphics.drawRect(0,0,9,5);
		$square1.graphics.endFill();
		$square1.x = $x * 197;
		$square1.y = $y * 117;
		this._maskContainer1.addChild($square1);
		this._squares1[$x].push($square1);

}


Its original dimension is 9 by 5 pixels, and it will be stretched to 197 by 117. The lines for that would be:


new TweenLite(  
				$square1,  
				17,  
				{
					scaleX: 22, 
					scaleY: 23.6, 
					ease: Quint.easeOut
				}  
			  )

But we need to setup this tweening animation for each square, and with delay:


animation-mask


here we can use 'district distance' to help with calculating the delay, the squares with the same district distance have the same delay, and the value of delay increase by 3 frames in radical direction.


Ok, now let's put them together, to setup the time line of the whole mask animation:


// draw the squares of mask 1
this._squares1 = new Array();
this._maskContainer1 = new Sprite();
this._maskTimeline1 = new TimelineMax({useFrames:true});

for(var $x=0; $x<3; $x++)
{
	this._squares1[$x] = new Array();
	for(var $y=0; $y<3; $y++)
	{
		var $square1:Sprite = new Sprite();
		$square1.graphics.beginFill(0x0000FF);
		$square1.graphics.drawRect(0,0,9,5);
		$square1.graphics.endFill();
		$square1.x = $x * 197;
		$square1.y = $y * 117;
		this._maskContainer1.addChild($square1);
		this._squares1[$x].push($square1);
		
		this._maskTimeline1.insert(  
									new TweenLite(  
													$square1,  
													17,  
													{
														scaleX:22, 
														scaleY:23.6, 
														ease: Quint.easeOut
													}  
												  ) ,
									(($x+$y) * 3 + 1)
								); 
	}
}


As you may guess, the second argument of insert() method indicates where to insert the animation into the time line of the animation, and that is how TimelineMax works, it combines multiple different animations. 


As its mask changes, the image1 is changing its size, position and its transparent as well:


// settle down the animation of image-1
this._image1.x = -177;
this._image1.y = -140;
this._image1.scaleX = 1.3;
this._image1.scaleY = 1.3;
//this._image1.blendMode = BlendMode.OVERLAY;	// not work
this._image1.alpha = 0.45;

this._effect.addChild(this._image1);
this._effect.addChild(this._maskContainer1);
this._image1.mask = this._maskContainer1;

this._maskTimeline1.insert(  
							new TweenLite(  
											this._image1,  
											26,  
											{
												alpha: 0.9, 
												ease: "linear"
											}  
										  ) ,
							1
								); 

this._maskTimeline1.insert(  
							new TweenLite(  
											this._image1,  
											26,  
											{
												x: 0, 
												y: 0, 
												scaleX: 1, 
												scaleY: 1, 
												ease: Quad.easeOut
											}  
										  ) ,
							1
								);

And now, we've already set up the animation of image1, _maskTimeline1 is the Timeline that contains all its animations. But there is not problem: in the original animation of TM, this image copy is put with 'OVERLAY' layer blend mode. But here, as test, if one Sprite is set up with this mode, and changing its attribute with TweenMax(or say, with AS), and with mask changing at meantime,it won't work. We will get back later.


And we set up the animation for image2 with the same logic:


// draw the squares of mask 2
this._squares2 = new Array();
this._maskContainer2 = new Sprite();
this._maskTimeline2 = new TimelineMax({useFrames:true});

for(var $u=0; $u<3; $u++)
{
	this._squares2[$u] = new Array();
	for(var $v=0; $v<4; $v++)
	{
		var $square2:Sprite = new Sprite();
		$square2.graphics.beginFill(0x0000FF);
		$square2.graphics.drawRect(0,0,9,5);
		$square2.graphics.endFill();
		$square2.x = $u * 197;
		$square2.y = $v * 117;
		this._maskContainer2.addChild($square2);
		this._squares2[$u].push($square2);
		
		this._maskTimeline2.insert(  
							new TweenLite(  
											$square2,  
											17,  
											{
												scaleX: 22, 
												scaleY: 23.6, 
												ease: Quint.easeOut
											}  
										  ) ,
							(($u+$v) * 3 + 2)
								); 
	}
}

// settle down the animation of image-2
this._image2.x = -177;
this._image2.y = -140;
this._image2.scaleX = 1.3;
this._image2.scaleY = 1.3;

this._effect.addChild(this._image2);
this._effect.addChild(this._maskContainer2);
this._image2.mask = this._maskContainer2;

//TweenMax.to(this._image2, 1, {colorTransform:{redOffset:255, greenOffset:255, blueOffset:255}});	// not always work

this._maskTimeline2.insert(
							new TweenMax(  
											this._image2,  
											1,  
											{
												colorTransform:{redOffset:255, greenOffset:255, blueOffset:255}, 
												ease: Quad.easeOut
											}
										  ),
							1
						   
						   );

this._maskTimeline2.insert(  
							new TweenMax(  
											this._image2,  
											32,  
											{
												colorTransform:{redOffset:0, greenOffset:0, blueOffset:0}, 
												ease: Quad.easeOut
											}
										  ) ,
							2
								); 

this._maskTimeline2.insert(  
							new TweenMax(  
											this._image2,  
											32,  
											{
												x: 0, 
												y: 0, 
												scaleX: 1, 
												scaleY: 1, 
												ease: Quad.easeOut
											}    
										  ) ,
							2
								);

Notes:


We use frame for timing method when we design the animation, so when I create the TimelineMax instance, I specified the useFrames option is true:


this._maskTimeline1 = new TimelineMax({useFrames:true});

Since we use color transform to change a Sprite's brightness, we must use statement to active plugin before that:


TweenPlugin.activate([ColorTransformPlugin]);

And, I comment out one line:


TweenMax.to(this._image2, 1, {colorTransform:{redOffset:255, greenOffset:255, blueOffset:255}});

Because I want to initialize the value before tweening its brightness, but it doesn't always work correctly.


So now, we have one timeline for image1 and image2, image3's animation is quite simple, only its alpha is changing by time. We need an overall TimelineMax instance to bundle up all these together:


this._image3.alpha = 0;

this._effect.addChild(this._image3);


this._overallTimeline = new TimelineMax({useFrames:true, onComplete:this.onEffectPlayed});
this._overallTimeline.gotoAndStop(1);
this._overallTimeline.insert(this._maskTimeline1, 1);
this._overallTimeline.insert(this._maskTimeline2, 4);

this._overallTimeline.insert(  
								new TweenLite(  
											this._image3,  
											17,  
											{
												alpha:1, 
												ease: "linear"
											}
										  ) ,
								26
							 );

Now,  _overallTimeline is the whole animation time line, so we stop it immediately after we created it. One thing to note is: after inserting one Tween object into TimelineMax, it gets played immediately, but the Sprite will stay at the state of the last moment of the animation, and that won't affect _overallTimeline's playing.


Problem of OVERLAY blendmode


Now get back to this problem, the work-around is pretty simple, to create a Sprite as container, put mask1 and image1 on it, and set this new container's blend mode to OVERLAY.


this._image1Cont = new Sprite();
this._image1Cont.addChild(this._image1);
this._image1Cont.addChild(this._maskContainer1);
this._image1.mask = this._maskContainer1;
this._image1Cont.blendMode = BlendMode.OVERLAY;

Problem of Instant Playing after creating Timeline

After create a instance of Timeline and insert a TweenMax/TweenLite instance into it, it immediately got played, and leave the DisplayObject with the ending status. That is not what we wish to be.



How to Change the Color-Transform before Tween it


Previously, I have to use TweenMax utility to tween the display object's color transform to its starting value, before tweening that:


TweenMax.to(
				this._imageCpy2, 
				0.06, 
				{
					colorTransform:{
							redOffset: this._settings.image2_color_offset_from, 
							greenOffset: this._settings.image2_color_offset_from, 
							blueOffset: this._settings.image2_color_offset_from
						}
				}
			);

And that arises problem that it always takes time, and you need to wait until it finishes the tween, then you can take next operation. So I create a TweenMax instance and insert it into the beginning of TimeLineMax, then each time when the timeline gets played, the color would be restored to normal, and then change to starting value, and then play the tween animation.


The solution comes from <Cook Book>:

cover-cook-book


关于这个问题,有一个独立的实验,实验源文件下载链接



Now we just use native Actionscript's functionality to change the display object's color transform to starting value, just like alpha, then it will be more straight and simple and efficient:


var $col2:ColorTransform = this._imageCpy2.transform.colorTransform;
$col2.redOffset = this._settings.image2_color_offset_from;
$col2.greenOffset = this._settings.image2_color_offset_from;
$col2.blueOffset = this._settings.image2_color_offset_from;
this._imageCpy2.transform.colorTransform = $col2;




References:





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值