AS3: DistortionTweener

View Example 1
View Example 2
View Example 3
View Documentation
Download Class & Example Files

The DistortionTweener allows you to distort four points of an object. It is an easy to way make distortions such as trapezoids on a movie clip.

The DistortionTweener uses Ruben Swieringa's DistortImage class and is based on a sample .FLA provided by Tam Ho on how to use DistortImage in Flash.

Actionscript:
  1. /**
  2. * The DistortionTweener allows you to distort four points of an object. It is an easy to way make distortions such as trapezoids on a movie clip.
  3. *
  4. * The DistortionTweener uses Ruben Swieringa's DistortImage class (http://www.rubenswieringa.com/blog/distortimage) and is based on a sample .FLA provided by Tam Ho (http://www.flashteam.com.au) on how to use DistortImage in Flash.
  5. *
  6. * @usage
  7. * <code>
  8. * <pre>
  9. import com.reintroducing.transitions.DistortionTweener;
  10. import fl.transitions.easing.Regular;
  11. var dt:DistortionTweener = new DistortionTweener(s, clip_mc, tl, tr, br, bl, 5);
  12. dt.addEventListener(Event.INIT, onDistortStarted);
  13. dt.addEventListener(Event.COMPLETE, onDistortFinished);
  14. dt.tweenTo(new Point(-50, -50), new Point(410, -50), new Point(310, 266), new Point(50, 266), Regular.easeIn, .5);
  15. // fired off when the distortion tween starts
  16. function onDistortStarted($evt:Event):void
  17. {
  18.     trace("Starting the distortion.");
  19. }
  20. // fired off whent he distortion tween ends
  21. function onDistortFinished($evt:Event):void
  22. {
  23.     trace("Finished the distortion.");
  24. }
  25. * </pre>
  26. * </code>
  27. *
  28. * @author Matt Przybylski [http://www.reintroducing.com]
  29. * @version 1.0
  30. */
  31.  
  32. package com.reintroducing.transitions
  33. {
  34.     import flash.display.Bitmap;
  35.     import flash.display.BitmapData;
  36.     import flash.display.MovieClip;
  37.     import flash.display.Shape;
  38.     import flash.events.Event;
  39.     import flash.events.EventDispatcher;
  40.     import flash.geom.Point;
  41.    
  42.     import org.flashsandy.display.DistortImage;
  43.    
  44.     import fl.transitions.Tween;
  45.     import fl.transitions.TweenEvent;   
  46.  
  47.     public class DistortionTweener extends EventDispatcher
  48.     {
  49. //- PRIVATE & PROTECTED VARIABLES -------------------------------------------------------------------------
  50.  
  51.         private var _holder:*;
  52.         private var _mc:MovieClip;
  53.         private var _mcWidth:Number;
  54.         private var _mcHeight:Number;
  55.         private var _bmd:BitmapData;
  56.         private var _bmp:Bitmap;
  57.         private var _container:Shape;
  58.         private var _tl:Point;
  59.         private var _tr:Point;
  60.         private var _br:Point;
  61.         private var _bl:Point;
  62.         private var _distortion:DistortImage;
  63.         private var _tweenFunc:Function;
  64.         private var _tweenTime:Number;
  65.         private var _precision:uint;
  66.        
  67.         // tweens
  68.         private var _tlXTween:Tween;
  69.         private var _tlYTween:Tween;
  70.         private var _trXTween:Tween;
  71.         private var _trYTween:Tween;
  72.         private var _brXTween:Tween;
  73.         private var _brYTween:Tween;
  74.         private var _blXTween:Tween;
  75.         private var _blYTween:Tween;
  76.        
  77. //- PUBLIC & INTERNAL VARIABLES ---------------------------------------------------------------------------
  78.        
  79.         public static const DEFAULT_NAME:String = "com.reintroducing.transitions.DistortionTweener";
  80.        
  81. //- CONSTRUCTOR -------------------------------------------------------------------------------------------
  82.    
  83.         /**
  84.          * Creates a new instance of the DistortionTweener class.  The point values are relative to the holder clip, NOT the stage.
  85.          *
  86.          * @usage <pre><code>var dt:DistortionTweener = new DistortionTweener($holder, $mc, $tl, $tr, $br, $bl, $precision);</code></pre>
  87.          *
  88.          * @param $holder The DisplayObject that will be used to hold your distorted bitmap
  89.          * @param $mc The source movie clip that will be used to copy into the bitmap that will be distorted
  90.          * @param $tl The top left point to use in the distortion
  91.          * @param $tr The top right point to use in the distortion
  92.          * @param $br The bottom right point to use in the distortion
  93.          * @param $bl The bottom left point to use in the distortion
  94.          * @param $precision A uint representing the value to use as the precision in the DistortImage class
  95.          */
  96.        
  97.         public function DistortionTweener($holder:*, $mc:MovieClip, $tl:Point, $tr:Point, $br:Point, $bl:Point, $precision:uint):void
  98.         {
  99.             this._holder    = $holder;
  100.             this._mc       = $mc;
  101.             this._mcWidth   = this._mc.width;
  102.             this._mcHeight  = this._mc.height;
  103.             this._tl       = $tl;
  104.             this._tr       = $tr;
  105.             this._br       = $br;
  106.             this._bl       = $bl;
  107.             this._precision = $precision;
  108.            
  109.             this.init();
  110.         }
  111.        
  112. //- PRIVATE & PROTECTED METHODS ---------------------------------------------------------------------------
  113.        
  114.         private function init():void
  115.         {
  116.             this._mc.visible = false;
  117.            
  118.             this._bmd     = new BitmapData(this._mcWidth, this._mcHeight, true, 0x00FFFFFF);
  119.             this._bmd.draw(this._mc);
  120.            
  121.             this._bmp     = new Bitmap(this._bmd);
  122.             this._container = new Shape();
  123.            
  124.             this._holder.addChild(this._container);
  125.            
  126.             this._distortion = new DistortImage(this._mcWidth, this._mcHeight, this._precision, this._precision);
  127.             this._distortion.setTransform(this._container.graphics, this._bmp.bitmapData, this._tl, this._tr, this._br, this._bl);
  128.         }
  129.  
  130. //- PUBLIC & INTERNAL METHODS -----------------------------------------------------------------------------
  131.    
  132.         /**
  133.          * Tweens the distortion. As with the constructor, the point values are relative to the holder clip, NOT the stage.
  134.          *
  135.          * <p>
  136.          * The tweenTo method dispatches two events:
  137.          * <ul>
  138.          * <li>Event.INIT: Dispatched when the tweening begins</li>
  139.          * <li>Event.COMPLETE: Dispatched when the tweening ends</li>
  140.          * </ul>
  141.          * </p>
  142.          *
  143.          * @usage <pre><code>dt.tweenTo(new Point(-50, -50), new Point(410, -50), new Point(310, 266), new Point(50, 266), Regular.easeIn, .5);</code></pre>
  144.          *
  145.          * @param $tl The top left point to end the tween at
  146.          * @param $tr The top right point to end the tween at
  147.          * @param $br The bottom right point to end the tween at
  148.          * @param $bl The bottom left point to end the tween at
  149.          * @param $tweenFunc The easing function to use in the tween
  150.          * @param $time The duration, in seconds, of the tween
  151.          *
  152.          * @return Nothing
  153.          */
  154.        
  155.         public function tweenTo($tl:Point, $tr:Point, $br:Point, $bl:Point, $tweenFunc:Function, $time:Number):void
  156.         {
  157.             this.dispatchEvent(new Event(Event.INIT));
  158.            
  159.             this._tweenFunc = $tweenFunc;
  160.             this._tweenTime = $time;
  161.            
  162.             // top left tweens
  163.             this._tlXTween = new Tween(this._tl, "x", this._tweenFunc, this._tl.x, $tl.x, this._tweenTime, true);
  164.             this._tlYTween = new Tween(this._tl, "y", this._tweenFunc, this._tl.y, $tl.y, this._tweenTime, true);
  165.            
  166.             // top right tweens
  167.             this._trXTween = new Tween(this._tr, "x", this._tweenFunc, this._tr.x, $tr.x, this._tweenTime, true);
  168.             this._trYTween = new Tween(this._tr, "y", this._tweenFunc, this._tr.y, $tr.y, this._tweenTime, true);
  169.            
  170.             // bottom right tweens
  171.             this._brXTween = new Tween(this._br, "x", this._tweenFunc, this._br.x, $br.x, this._tweenTime, true);
  172.             this._brYTween = new Tween(this._br, "y", this._tweenFunc, this._br.y, $br.y, this._tweenTime, true);
  173.            
  174.             // bottom left tweens
  175.             this._blXTween = new Tween(this._bl, "x", this._tweenFunc, this._bl.x, $bl.x, this._tweenTime, true);
  176.             this._blYTween = new Tween(this._bl, "y", this._tweenFunc, this._bl.y, $bl.y, this._tweenTime, true);
  177.            
  178.             this._blYTween.addEventListener(TweenEvent.MOTION_CHANGE, render);
  179.             this._blYTween.addEventListener(TweenEvent.MOTION_FINISH, onFinished);
  180.         }
  181.        
  182.         /**
  183.          * Resets the bitmap to the specified points.
  184.          *
  185.          * @usage <pre><code>dt.reset(new Point(0, 0), new Point(clip_mc.width, 0), new Point(clip_mc.width, clip_mc.height), new Point(0, clip_mc.height));</code></pre>
  186.          *
  187.          * @param $tl The top left point to use in the distortion
  188.          * @param $tr The top right point to use in the distortion
  189.          * @param $br The bottom right point to use in the distortion
  190.          * @param $bl The bottom left point to use in the distortion
  191.          *
  192.          * @return Nothing
  193.          */
  194.        
  195.         public function reset($tl:Point, $tr:Point, $br:Point, $bl:Point):void
  196.         {
  197.             this._tl = $tl;
  198.             this._tr = $tr;
  199.             this._br = $br;
  200.             this._bl = $bl;
  201.            
  202.             this._container.graphics.clear();
  203.             this._holder.removeChild(this._container);
  204.            
  205.             this._container = null;
  206.             this._container = new Shape();
  207.            
  208.             this._holder.addChild(this._container);
  209.         }
  210.        
  211.         /**
  212.          * Cleans up the DistortionTweener for garbage collection.
  213.          *
  214.          * @usage <pre><code>dt.destroy();</code></pre>
  215.          *
  216.          * @return Nothing
  217.          */
  218.        
  219.         public function destroy():void
  220.         {
  221.             this._bmd.dispose();
  222.            
  223.             this._container.graphics.clear();
  224.             this._holder.removeChild(this._container);
  225.            
  226.             this._bmd = null;
  227.             this._bmp = null;
  228.             this._container = null;
  229.             this._holder = null;
  230.             this._distortion = null;
  231.         }
  232.    
  233. //- EVENT HANDLERS ----------------------------------------------------------------------------------------
  234.    
  235.         // Dispatched during the MOTION_CHANGE event to update the distorted graphics.
  236.         private function render($evt:TweenEvent):void
  237.         {
  238.             this._container.graphics.clear();
  239.             this._distortion.setTransform(this._container.graphics, this._bmp.bitmapData, this._tl, this._tr, this._br, this._bl);
  240.         }
  241.        
  242.         // Dispatches a COMPLETE event when the distortion is finished.
  243.         private function onFinished($evt:TweenEvent):void
  244.         {
  245.             this._blYTween.removeEventListener(TweenEvent.MOTION_CHANGE, render);
  246.             this._blYTween.removeEventListener(TweenEvent.MOTION_FINISH, onFinished);
  247.            
  248.             this._tlXTween = null;
  249.             this._tlYTween = null;
  250.             this._trXTween = null;
  251.             this._trYTween = null;
  252.             this._brXTween = null;
  253.             this._brYTween = null;
  254.             this._blXTween = null;
  255.             this._blYTween = null;
  256.            
  257.             this.dispatchEvent(new Event(Event.COMPLETE));
  258.         }
  259.    
  260. //- GETTERS & SETTERS -------------------------------------------------------------------------------------
  261.    
  262.        
  263.    
  264. //- HELPERS -----------------------------------------------------------------------------------------------
  265.    
  266.         public override function toString():String
  267.         {
  268.             return "com.reintroducing.transitions.DistortionTweener";
  269.         }
  270.    
  271. //- END CLASS ---------------------------------------------------------------------------------------------
  272.     }
  273. }

If you found this post useful, please consider leaving a comment, subscribing to the feed, or making a small donation.

26 Comments

[...] here for [...]

Nice one Matt! Do note that I can't really take credit for the distortion-technique myself, DistortImage was originally written by Thomas Pfeiffer, I merely ported it to an Actionscript3.0 class.

That is absolutely correct. I forgot to mention that in my posts but if anyone reads the DistortImage credits, hopefully they will see that. Thanks Ruben.

Hi Matt,

SWEET! Can you please release an AS2 version of this, pretty please!?

please, please, please..... its all I really want for the holidays.... please!

no love for an AS2 version ..... ;-)

Sorry WT, there wasn't any plans for an AS2 version of this really. You could probably convert it easily but you'd have to get Thomas Pfeiffer's AS2 DistortImage class as Ruben mentioned he used on his AS3 conversion and the rest should just be AS3 to AS2 code conversion. If I have some free time I may try to get it up but I've got a lot of other things in the works for the site that I'd rather get done first so when I do finally get free time I'm going to be working on those before I would an AS2 version of this. :P

[...] Download full source code and check examples. No Comments Leave a Commenttrackback addressThere was an error with your comment, please try again. name (required)email (will not be published) (required)url [...]

Hi!

I loved your class, but I have a problem with it.
I want to keep my MC after distorting it. It is important to me because in my project I'm distorting 5 clips, and I wrote a lot of code involving them. But when I'm finished with distorting, I guess my clip becomes trapped in container sprite. So I loose it when I call destroy method. Also I can't do anything with my MC's (like tween them) because they are in container.

Can you help me with that?

I would be very gratefull.

Best regards,
Vjekoslav Ratkajec

Hey Vjekoslav,
The DistortionTweener doesn't affect your clip, it makes a duplicate of your clip in the form of a BitmapData and it puts that in the container and runs the distortion on that. If you're using the code from my example, i specifically in there put code to hide the original movie clip and then show it after the transformation is complete, so all you would have to do in your code is to follow that same model.

now, if you're talking about distorting your clip and then trying to do things to the distorted clip, that won't work, because that can't take events or anything like that. the distortion tweener is only for tweening distortions to and from movie clips, you can't tween it into a distorted state and then do anything on it because your actual clip isnt the one being distorted. make sense?

Hi Matt,

thanks for the fast reply!

Well I found what was bothering me and why didn't clip appear after destorying it.
It's working fine now, but just to let you know, I added:

this._mc.visible = true;

in destroy method.

So mine working version of your class is:
public function destroy():void
{
this._bmd.dispose();
this._mc.visible = true;
this._container.graphics.clear();
this._holder.removeChild(this._container);

this._bmd = null;
this._bmp = null;
this._container = null;
this._holder = null;
this._distortion = null;
}

Thank you again, you helped me alot!

Best regards,
Vjekoslav Ratkajec

no problem, glad it helped!

Hi Matt,

Can distortionTweener be used to recreate the Mac style squeeze transition as displayed here:

http://www.scottgmorgan.com/blog/index.php/2007/11/15/grant-skinners-osx-squeeze-effect-in-as3/

http://www.gskinner.com/blog/archives/2007/11/squeeze_effect.html

If so how? I've been trying at it but can't get it. Seems like easing for the top and bottom parts of the the slide are different in the osx style transition. And I don't think two distortionTweens can be applied to the same mc at the same time.

Is this effect possible with DistortionTweener or DistortImage classes?

Hey Evan,
Unfortunately you can't achieve that effect with it. You can get something similar (because the distortion is only applied to four points) but not that exact thing. You can use it to distort it into a trapezoidal shape and then tween the two top points out to form a rectangle, but thats about it.

Thanks for your prompt reply Matt and your generous contribution of Distortion Tweener to actionscripters. Your answer was a surprise to me as I had expected you to say that Mac style effect was doable but I definitely take your word for it.

I was hoping to have a Mac OS style "swoosh" transition effect for a little app I'm working on using the Distort Image or DistortionTweener but I now know better. I had thought that maybe DistortImage could do the trick with different easing and/or tweening values for top-r/l and bottomr/l at different rates but I have been saved a lot of frustration and time by knowing now that it is not doable.

The other displacement map way of doing it I found was too processor intensive on slower computers (even in AS3).

In your estimation, would the something similar way of doing it with Distortion Tweener be as spectacular? What kind of even more spectacular slide transitions could be developed with Distortion Tweener then?

Evan,
I think something to look into which would maybe give you a similar effect (or something close) would be perlin noise and applying it to the movie clip you want to distort. Unfortunately I don't know off the top of my head how exactly youd go about it but if you play with it you may be able to get something close.

Have you downloaded and looked at Grant Skinner's file? I didn't but I'd imagine you could probably repurpose that somehow. Grant is a great coder so I'm sure you could go off of his files or maybe even ask him for some help.

Hi.

i`m kinda new to this, But is it possible to add a delay beefore the animation starts..?

-Kristian

Kristian,
Sure, before calling the tweenTo method just set your delay or call tweenTo anywhere you want it to happen in your code.

hi there,

great class. i just been think that you could replace the type of both the holder and the mc by DisplayObject. there is no need for a MovieClip, and the holder has to be a DisplayObject. anyways thanks for your effort, i will definitely use this class in upcoming projects.

cheers, jan

ooops. i'm sorry the holder of cource need to be at least a DisplayObjectContainer for the addchild method. stupid me.

Yow,

I'm new here today. i hope you could still reply. I'm reviewing your example 3 and practicing it. I'm trying to use Oval shapes but i can't seem to show the whole circle when i place this code:

"var dt:DistortionTweener = new DistortionTweener(c, oval_mc1, new Point(0, 0), new Point(oval_mc1.width, 0), new Point(oval_mc1.width, oval_mc1.height), new Point(0, oval_mc1.height), 5);"

whenever i do this without continuing the remaining bottom parts of the script it seems to show only 1/4 of the whole object(from center of the oval to bottom right). I'm not really sure if there should be a change on the x and y axis, i've tried but it seems to distort it way to much and still shows 1/4 of the whole oval.

Do you think its possible to Distort Ovals? if it is what should i change to show the whole oval?

Hey,

I've already figured why its not showing. Its seems that you just have to register the conversion of the movie clip symbol to top left and not center. Anyway, thanks for this review! Hopefully i could come up with something great with this! Peace!

[...] AS3: DistortionTweener Posted on 08.22.2008 to AS3 Subscribe to comments Comment | Trackback |  SHARETHIS.addEntry({ title: "AS3 Effects", url: "http://www.mikkolehtinen.com/as3/as3-effects/" }); [...]

[...] DistortionTweenerhttp://evolve.reintroducing.com/2007/11/18/as3/as3-distortiontweener/ [...]

[...] Distortion Tweener [...]

Leave a comment

(required)

(required)