Playing with another transition effect made possible by the 3d capabilities of Flash Player 10, gave rise to the example below.
The initial object seen is just a quickly thrown together MovieClip to demonstrate that interactive items can be transited as well as static images. After that first mc, though, all you’ll see is a bunch of random movie posters.
Because I added a new transition to my transitions package, I touched up the OBO_BillboardTransition class a little bit and made both implement an ITransition interface. If interested, all script is below:
The interface:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package com.onebyonedesign.transitions { import flash.display.DisplayObject; public interface ITransition { function start():void; function get direction():String; function set direction(value:String):void; function get currentimage():DisplayObject; function set currentimage(value:DisplayObject):void; function get newimage():DisplayObject; function set newimage(value:DisplayObject):void; function set time(value:Number):void; function get time():Number; } } |
The OBO_BoxTransition class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
package com.onebyonedesign.transitions { import caurina.transitions.Tweener; import flash.display.DisplayObject; import flash.display.DisplayObjectContainer; import flash.display.Sprite; import flash.events.Event; import flash.events.EventDispatcher; /** * 3D "Box like" transition between to images, sprites, or movieclips. * Throws Event.COMPLETE when transition is finished. * Requires caurina.transitions package. * @author Devon O. */ public class OBO_BoxTransition extends EventDispatcher implements ITransition { public static const UP:String = "up"; public static const DOWN:String = "down"; public static const LEFT:String = "left"; public static const RIGHT:String = "right"; private var _direction:String; private var _currentimage:DisplayObject; private var _newimage:DisplayObject; private var _time:Number; private var _imgparent:DisplayObjectContainer; private var _box:Sprite; private var _orgIndex:int; private var _orgY:Number; private var _orgX:Number; /** * * @param image that will be transitioned out (must already be on display list). * @param image that will be transitioned in * @param direction in which the out image should travel. * Choices are OBO_BoxTransition.LEFT, OBO_BoxTransition.RIGHT, OBO_BoxTransition.UP, or OBO_BoxTransition.DOWN * @param time in seconds transition should take place. */ public function OBO_BoxTransition(currentimage:DisplayObject, newimage:DisplayObject, direction:String = "left", time:Number = 1) { _imgparent = currentimage.parent; _orgX = currentimage.x; _orgY = currentimage.y; _currentimage = currentimage; _newimage = newimage; _time = time; _direction = direction; } public function start():void { init(); beginTransition(); } public function get direction():String { return _direction; } public function set direction(value:String):void { _direction = value; } public function get currentimage():DisplayObject { return _currentimage; } public function set currentimage(value:DisplayObject):void { _currentimage = value; } public function get newimage():DisplayObject { return _newimage; } public function set newimage(value:DisplayObject):void { _newimage = value; } public function get time():Number { return _time; } public function set time(value:Number):void { _time = value; } private function init():void { var w:int = _currentimage.width * .5; var h:int = _currentimage.height * .5; _orgIndex = _imgparent.getChildIndex(_currentimage); _box = new Sprite(); _box.x = _currentimage.x; _box.y = _currentimage.y; _imgparent.addChildAt(_box, _orgIndex); _box.x += _currentimage.width * .5; _box.y += _currentimage.height * .5; _currentimage.y = -_currentimage.height * .5; _currentimage.x = -_currentimage.width * .5; switch(_direction) { case "up" : _box["z"] = h; _currentimage["z"] -= h; _newimage.x = _currentimage.x; _newimage.y = _currentimage.y + (h * 2); _newimage["rotationX"] = 90; _newimage["z"] -= h; _box.addChild(_newimage); break; case "down" : _box["z"] = h; _currentimage["z"] -= h; _newimage.x = _currentimage.x; _newimage.y = _currentimage.y; _newimage["rotationX"] = -90; _newimage["z"] += h; _box.addChild(_newimage); break; case "left" : _box["z"] = w; _currentimage["z"] -= w; _newimage.x = _currentimage.x + (w * 2); _newimage.y = _currentimage.y; _newimage["rotationY"] = -90; _newimage["z"] -= w; _box.addChild(_newimage); break; case "right" : _box["z"] = w; _currentimage["z"] -= w; _newimage.x = _currentimage.x; _newimage.y = _currentimage.y; _newimage["rotationY"] = 90; _newimage["z"] += w; _box.addChild(_newimage); break; } _box.addChild(_currentimage); } private function beginTransition():void { switch(_direction) { case "up" : flipUp(); break; case "down" : flipDown(); break; case "left" : flipLeft(); break; case "right" : flipRight(); break; } } private function flipLeft():void { Tweener.addTween(_box, { rotationY:90, time:_time, transition:"easeOutQuad", onUpdate:checkAngle, onComplete:transitionDone } ); } private function flipRight():void { Tweener.addTween(_box, { rotationY:-90, time:_time, transition:"easeOutQuad", onUpdate:checkAngle, onComplete:transitionDone } ); } private function flipUp():void { Tweener.addTween(_box, { rotationX:-90, time:_time, transition:"easeOutQuad", onUpdate:checkAngle, onComplete:transitionDone } ); } private function flipDown():void { Tweener.addTween(_box, { rotationX:90, time:_time, transition:"easeOutQuad", onUpdate:checkAngle, onComplete:transitionDone } ); } private function checkAngle():void { if (Math.abs(_box["rotationY"]) > 75 || Math.abs(_box["rotationX"]) > 75) { _currentimage.visible = false; } } private function transitionDone():void { _imgparent.removeChild(_box); _box = null; _newimage.x = _orgX; _newimage.y = _orgY; _newimage["z"] = 0; _newimage["rotationY"] = 0; _newimage["rotationX"] = 0; _imgparent.addChildAt(_newimage, _orgIndex); dispatchEvent(new Event(Event.COMPLETE)); } } } |
The OBO_BillboardTransition class (same effect as my last post, so no need for a demo .swf):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
package com.onebyonedesign.transitions { import caurina.transitions.Tweener; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.DisplayObject; import flash.display.DisplayObjectContainer; import flash.display.Sprite; import flash.events.Event; import flash.events.EventDispatcher; import flash.events.TimerEvent; import flash.geom.Matrix; import flash.geom.Point; import flash.geom.Rectangle; import flash.utils.Timer; /** * @author Devon O. */ public class OBO_BillboardTransition extends EventDispatcher implements ITransition { public static const HORIZONTAL:String = "horizontal"; public static const VERTICAL:String = "vertical"; private var _imgparent:DisplayObjectContainer; private var _timer:Timer; private var _direction:String; private var _currentimage:DisplayObject; private var _newimage:DisplayObject; private var _time:Number; private var _numsections:int; private var _sections:Vector.<Sprite>; private var _bmpdataObjects:Vector.<BitmapData>; private var _bmpObjects:Vector.<Bitmap>; private var _numDone:int; private var _sectionHolder:Sprite = new Sprite(); /** * OBO_BillboardTransition class. Transitions two DisplayObject instances in a "spinning billboard" fashion. * Throws Event.COMPLETE when transition is finished. * Requires caurina.transitions package. Google for "Tweener" on GoogleCode. * * @param The DisplayObjectContainer parenting the image that will be transitioned out. * @param The image to be transitioned out (must already be on display list) * @param The image that will be transitioned in (should be same size as currentimage) * @param The number of spinning sections * @param Either OBO_BillboardTransition.HORIZONTAL or OBO_BillboardTransition.VERTICAL ("horizontal" or "vertical") */ public function OBO_BillboardTransition(currentimage:DisplayObject, newimage:DisplayObject, numsections:int, direction:String = "horizontal", time:Number = .25) { _imgparent = currentimage.parent; _currentimage = currentimage; _newimage = newimage; _numsections = numsections; _time = time; _direction = direction; } /** * Call this to begin the transition. */ public function start():void { init(); _timer = new Timer(100, _numsections); _timer.addEventListener(TimerEvent.TIMER, timerHandler); _timer.start(); } public function get direction():String { return _direction; } public function set direction(value:String):void { _direction = value; } public function get currentimage():DisplayObject { return _currentimage; } public function set currentimage(value:DisplayObject):void { _currentimage = value; } public function get newimage():DisplayObject { return _newimage; } public function set newimage(value:DisplayObject):void { _newimage = value; } public function get time():Number { return _time; } public function set time(value:Number):void { _time = value; } public function get numsections():int { return _numsections; } public function set numsections(value:int):void { _numsections = value; } private function init():void { _numDone = 0; _sections = new Vector.<Sprite>(); _bmpdataObjects = new Vector.<BitmapData>(); _bmpObjects = new Vector.<Bitmap>(); _sectionHolder = new Sprite(); switch(_direction) { case "horizontal" : createHorizontalSections(); break; case "vertical" : createVerticalSections(); break; } } private function createHorizontalSections():void { var sectionHeight:Number = _currentimage.height / _numsections; var sectionWidth:Number = _currentimage.width; var point:Point = new Point(); var frontData:BitmapData = new BitmapData(_currentimage.width, _currentimage.height); var backData:BitmapData = new BitmapData(_newimage.width, _newimage.height); frontData.draw(_currentimage); backData.draw(_newimage, new Matrix(1, 0, 0, -1, 0, _newimage.height)); _bmpdataObjects.push(frontData, backData); for (var i:int = 0; i < _numsections; i++) { var fbmd:BitmapData = new BitmapData(sectionWidth, sectionHeight); var bbmd:BitmapData = new BitmapData(sectionWidth, sectionHeight); fbmd.copyPixels(frontData, new Rectangle(0, i * sectionHeight, sectionWidth, sectionHeight), point); bbmd.copyPixels(backData, new Rectangle(0, ((_numsections - 1) - i) * sectionHeight, sectionWidth, sectionHeight), point); _bmpdataObjects.push(fbmd, bbmd); var fbmp:Bitmap = new Bitmap(fbmd); var bbmp:Bitmap = new Bitmap(bbmd); _bmpObjects.push(fbmp, bbmp); var s:Sprite = new Sprite(); fbmp.x -= sectionWidth * .5; fbmp.y -= sectionHeight * .5; bbmp.x -= sectionWidth * .5; bbmp.y -= sectionHeight * .5; s.addChild(bbmp); s.addChild(fbmp); s.x = sectionWidth * .5; s.y = i * sectionHeight + sectionHeight * .5; _sections.push(s); _sectionHolder.addChild(s); } _sectionHolder.x = _currentimage.x; _sectionHolder.y = _currentimage.y; _imgparent.addChildAt(_sectionHolder, _imgparent.getChildIndex(_currentimage)); _imgparent.removeChild(_currentimage); } private function createVerticalSections():void { var sectionHeight:Number = _currentimage.height; var sectionWidth:Number = _currentimage.width / _numsections; var point:Point = new Point(); var frontData:BitmapData = new BitmapData(_currentimage.width, _currentimage.height); var backData:BitmapData = new BitmapData(_newimage.width, _newimage.height); frontData.draw(_currentimage); backData.draw(_newimage, new Matrix(-1, 0, 0, 1, _newimage.width)); _bmpdataObjects.push(frontData, backData); for (var i:int = 0; i < _numsections; i++) { var fbmd:BitmapData = new BitmapData(sectionWidth, sectionHeight); var bbmd:BitmapData = new BitmapData(sectionWidth, sectionHeight); fbmd.copyPixels(frontData, new Rectangle(i * sectionWidth, 0, sectionWidth, sectionHeight), point); bbmd.copyPixels(backData, new Rectangle(((_numsections - 1) - i) * sectionWidth, 0, sectionWidth, sectionHeight), point); _bmpdataObjects.push(fbmd, bbmd); var fbmp:Bitmap = new Bitmap(fbmd); var bbmp:Bitmap = new Bitmap(bbmd); _bmpObjects.push(fbmp, bbmp); var s:Sprite = new Sprite(); fbmp.x -= sectionWidth * .5; fbmp.y -= sectionHeight * .5; bbmp.x -= sectionWidth * .5; bbmp.y -= sectionHeight * .5; s.addChild(bbmp); s.addChild(fbmp); s.x = i * sectionWidth + sectionWidth * .5; s.y = sectionHeight * .5; _sections.push(s); _sectionHolder.addChild(s); } _sectionHolder.x = _currentimage.x; _sectionHolder.y = _currentimage.y; _imgparent.addChildAt(_sectionHolder, _imgparent.getChildIndex(_currentimage)); _imgparent.removeChild(_currentimage); } private function timerHandler(event:TimerEvent):void { switch(_direction) { case "horizontal" : flipHorizontalSection(event.currentTarget.currentCount - 1); break; case "vertical" : flipVerticalSection(event.currentTarget.currentCount - 1); break; } } private function flipHorizontalSection(count:int):void { var section:Sprite = _sections[count]; Tweener.addTween(section, { rotationX:180, time:_time, transition:"easeOutQuad", onUpdate:checkAngle, onUpdateParams:[section], onComplete:tallyDone } ); } private function flipVerticalSection(count:int):void { var section:Sprite = _sections[count]; Tweener.addTween(section, { rotationY:-180, time:_time, transition:"easeOutQuad", onUpdate:checkAngle, onUpdateParams:[section], onComplete:tallyDone } ); } private function checkAngle(s:Sprite):void { if (s["rotationX"] > 90 || s["rotationY"] < -90) { s.getChildAt(1).visible = false; } } private function tallyDone():void { if (++_numDone == _numsecti繁ns) { swapImage(); cleanup(); dispatchEvent(new Event(Event.COMPLETE)); } } private function swapImage():void { _newimage.x = _sectionHolder.x; _newimage.y = _sectionHolder.y; var ind:int = _imgparent.getChildIndex(_sectionHolder); _imgparent.removeChild(_sectionHolder); _imgparent.addChildAt(_newimage, ind); } private function cleanup():void { var i:int = _bmpdataObjects.length; while (i--) { _bmpdataObjects[i].dispose(); delete _bmpdataObjects[i]; } i = _bmpObjects.length; while (i--) { delete _bmpObjects[i]; } i = _sections.length; while (i--) { delete _sections[i]; } _sections = null; _bmpdataObjects = null; _bmpObjects = null; _sectionHolder = null; _currentimage = null; _timer.removeEventListener(TimerEvent.TIMER, timerHandler); _timer.reset(); _timer = null; } } } |
And finally, a document class to test the box transition:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
package { import com.onebyonedesign.transitions.OBO_BoxTransition; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.MovieClip; import flash.display.SimpleButton; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.filters.DropShadowFilter; /** * Demonstration of OBO_BoxTransition */ public class Main extends MovieClip { // items in library or on stage public var upButton:SimpleButton; public var downButton:SimpleButton; public var leftButton:SimpleButton; public var rightButton:SimpleButton; private var data1:BitmapData = new Img1(0, 0); private var data2:BitmapData = new Img2(0, 0); private var data3:BitmapData = new Img3(0, 0); private var data4:BitmapData = new Img4(0, 0); private var data5:BitmapData = new Img5(0, 0); private var bitmapDataArray:Array = []; private var buttonArray:Array = []; private var imageHolder:Sprite = new Sprite(); private var trans:OBO_BoxTransition; private var dropShadow:DropShadowFilter = new DropShadowFilter(3, 90, 0x000000, 1, 5, 5, 1, 3); public function Main():void { bitmapDataArray.push(data1, data2, data3, data4, data5); buttonArray.push(upButton, downButton, leftButton, rightButton); var interactiveImage:Clip = new Clip(); imageHolder.x = 125; imageHolder.y = 100; imageHolder.filters = [dropShadow]; imageHolder.addChild(interactiveImage); addChild(imageHolder); trans = new OBO_BoxTransition(interactiveImage, randomImage()); trans.addEventListener(Event.COMPLETE, transitionCompleteHandler); downButton.addEventListener(MouseEvent.CLICK, downHandler); upButton.addEventListener(MouseEvent.CLICK, upHandler); leftButton.addEventListener(MouseEvent.CLICK, leftHandler); rightButton.addEventListener(MouseEvent.CLICK, rightHandler); } private function downHandler(event:MouseEvent):void { enableButtons(false); trans.direction = OBO_BoxTransition.DOWN; trans.start(); } private function upHandler(event:MouseEvent):void { enableButtons(false); trans.direction = OBO_BoxTransition.UP; trans.start(); } private function leftHandler(event:MouseEvent):void { enableButtons(false); trans.direction = OBO_BoxTransition.LEFT; trans.start(); } private function rightHandler(event:MouseEvent):void { enableButtons(false); trans.direction = OBO_BoxTransition.RIGHT; trans.start(); } private function transitionCompleteHandler(event:Event):void { trans.currentimage = trans.newimage; trans.newimage = randomImage(); enableButtons(true); } private function enableButtons(whichWay:Boolean):void { var i:int = buttonArray.length; while (i--) { buttonArray[i].enabled = whichWay; } } private function randomImage():Bitmap { var dat:BitmapData = bitmapDataArray[Math.floor(Math.random() * bitmapDataArray.length)]; return new Bitmap(dat); } } } |
And completely offtopic, but while doing a little google surfing after the Virgin Prunes, I discovered this lengthy but interesting read on the Goth music scene in England back in the day. Like strolling down the halls of high school. Interesting and entertaining stuff for folks into that sort of thing. You know who you are...
I’m seeing errors double-clicking on an arrow
Hey, sen – what sort of errors? And just how fast are you double clicking? And what version of FP10 – beta 1 or beta 2 – or is there a newer one I completely missed out on? In any case, clicking like a madman, I can’t produce any error…
Awesome!
Nice work.
How are you targeting flash player 10 from the Flash IDE? I know it can be done from mxmlc at the command line or from flexbuilder, but I am not sure how you are doing this?
Hey, Tony, thanks for the comments. I’m on the beta testing team – hence the IDE integration. Everything there though could easily be done with the mxml compiler like I did with the billboard transition. I just wanted to play with some new toys…
Oh, okay that’s what I thought, I’m like he’s got to have the CS4 beta of Flash, or something. Yeah, I’m just going to try your examples with Flex, I have it all setup there. Cool, thanks for the kick ass tutorials.
Hi, this looks very nice! Can u please tell me how i can get this example to work. i got your classes and i think i set up everything right, but when i test my movie, i get a TypeError: Error #1009 at Main()…what´s my mistake?
thanks
Seeing Error too, if I click on a arrow before the box stops:
FP Version: 10,0,2,54 (Firefox)
ArgumentError: Error #2025: El objeto DisplayObject proporcionado debe ser un elemento secundario del llamador.
at flash.display::DisplayObjectContainer/getChildIndex()
at com.onebyonedesign.transitions::OBO_BoxTransition/init()
at com.onebyonedesign.transitions::OBO_BoxTransition/start()
at Main/rightHandler()
Hey SdR, check out this post:https://blog.onebyonedesign.com/?p=95 . The error was fixed – I was just too lazy to upload a new demo .swf
Nicola, not sure what may be causing the error, but I suspect you may not have the buttons or images in the library (that would be my first guess, anyway).
Hi Devon O.
very sleeek
i wonder if you could make an easy tutorial about this one
also i wonder if i could get a copy of your flash just to check out how you do it coz im still a bit of confused if not still ok
thanks more power
Hi,
Very good tutorial. This really help understand how to make 3d transition effects in AS3.0