In my last post (about the OBO_BoxTransition), Senocular had mentioned in a comment that the demo app was throwing an error when double clicking. While he never did come back to say what the error was, he’s a pretty sharp cookie, so I figured there had to be something to it. So, I finally downloaded the Flash 10 Debug player (which, incidentally, is now available), ran the .swf in it and saw immediately what the problem was. The bottom line is that the buttons, which I knew should not be clicked in rapid succession, were still firing an Event.CLICK event even after I had called a disabling method which, in short, looped through an array of SimpleButton instances (don’t know why I didn’t choose a Vector – still getting used to the idea, I suppose) and set each member’s enabled property to false. You’d think that would make the SimpleButton’s unclickable, but you’d be wrong. For a brief moment, even with a false enabled property, they are still able to be clicked and will still dispatch the corresponding event. On an impulse, however, I made the quick change from enabled to mouseEnabled and – shazam! – no more double click blues. I am not sure why using the mouseEnabled property should succeed where just plain enabled fails when dealing with SimpleButton objects, but, in the future, just to be on the safe side, I’m sticking to mouseEnabled. And just to be on the really safe side, I rewrote the init() method of the OBO_BoxTransition class using a try…catch block that guarantees the transition will not try to take place if the _currentimage is not a child of the _imgparent (which is really what the underlying error was blabbing at me). You can see the revised class file in its entirety below, if interested.
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; import flash.events.ProgressEvent; /** * 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 { try { 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); } catch (e:Error) { // Error suppression. User has attempted to flip image in the process of transition. } } 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)); } } }
gTween
Grant Skinner just released a new tweening by the name of gTween. Now, personally I’m getting nearly as bored (or perhaps overwhelmed is a better word) with tweening engines as I am with 3D engines, but let’s face it, when Grant Skinner talks actionscript, actionscripters listen. So, I downloaded the thing and gave it a test drive and have to say, not too shabby. I especially like the AS3 event handling syntax (rather than the callback syntax that most other engines seem to use). I also rather liked the proxy property. Very clever and very useful. Kind of missed having an update event, but it was easy enough to add one myself to the tickHandler method. GTween also comes with some easy to use sequencing and built in resource management (and from Grant Skinner, that’s saying a lot). A full list of features is included in the documentation:
frame or time based animation engine works with any numeric properties on any object (not just display objects) sequenced tweens using nextTween synchronized child tweens pause and resume individual tweens or all tweens jump directly to the end or beginning of a tween with .end() or .beginning() jump to any arbitrary point in the tween with .position auto hide for alpha tweens, sets visible to false when alpha is 0 or less with .autoHide smart tweening for rotation (rotates in the shortest direction) with .useSmartRotation uses setSize calls when supported for width and height tweens (good for Flash and Flex components) complete, activate and init events configurable progress events indicate when specified points in the tween are reached smart garbage collector interactions (prevents collection while active, allows collection if target is collected) uses any standard ActionScript tween functions support for tweening objects like colorTransform and matrix that need to be reassigned to a property
Overall, I really like it, but to be honest, I probably won’t be switching from Tweener, which I’ve really come to appreciate. Of course, it’s really not a matter of picking one over another, but using the right tool for the right job, and I am certain that gTween will be just what the doctor ordered sooner or later.
Useful Library Links Galore
If you’ve been hard up to find any useful AS3 libraries lately, I just ran across a great collection. So much code – so little time…
SWFExplorer
I haven’t tried this out yet, but if it’s from Thibault Imbert, it has to be good. It’s a handy utility class that will rummage through a loaded .swf file and sniff out the names of included classes and return them in Array form. Of course they can then be used with Application.getDefinition() to construct instances. Not sure how useful it would be at runtime, but maybe as an AIR application that allows you to explore .swf files given to you as resource libraries by fellow developers, etc. I know there’s times already that I could have used something of the sort.
And Now for Something Completely Different
Quite possibly my favorite musician David Tibet (David Michael Bunting) of Current 93 is not only a musical super genius, but student of Coptic (for those who don’t know Current 93’s probably largest influence is early Christian mythology and many of Tibet’s lyrics, writings, paintings, etc show a distinctly Gnostic flavor, many of the Gnostic texts being written in, you guessed it, Coptic). Recently, Tibet attended the 2nd International Summer School of Coptic Papyrology in Leipzig (quite a mouthful) and worked with the professor there translating a so far unpublished vellum codex of the Martyrdom of the Coptic Saint Apa Prau. You can get a gander of him in the Leipzig newspaper, Leipziger Volkszeitung here. Great stuff. I’m sure some of this experience will seep into the Hallucinatory Mountain trilogy currently in the works. The caption reads:
What could be meant by this? In the library of the University of Leipzig, the English researcher David Tibet tries to decipher fragments of text about the Egyptian saint Apa Prau. His most important work tools are his magnifying glasses, whether on his head or in his hand. He is one of twenty academics from all over the world who are in Leipzig learning to read the contents of old papri. The week-long course was organised by the library and the Egyptian Institute.
Date:
20 August, 2008