Archive for August, 2007

Papervision 3D + Line3D + Tweener - Part 1

Here’s my initial experiment using the new Line3D class addition to papervision from Andy Zupko. My example is in its early stages, needs some fade and remove functionality, possibly use of a Null 3D object for the lines to draw from,. Becuase of this it has obvious performance issues after it draw for a bit. Hence the “Part 1″ ;)

Update - I decided to remove the example as it bogs down the page if it’s running for a while. It’s in dire need of incremental removal and garbage collection.

I don’t think the Line3D object has been merged into the regular updates to pv3d, but you can get the class in the source files below and from Andy’s site as well.

Back Story: I came up with an AS3 version of a 2D version of this inspired by Felix Turner and his Bezier Tween AS2 Class. I’ll post the code for that soon since I seem to be in the spirit of doing everything backwards these days.

Here’s the code:

package com.hydrotik {

        import flash.events.Event;
        import flash.display.MovieClip;
        import flash.display.Stage;
        import flash.display.Sprite;
        import caurina.transitions.Tweener;
        import com.ascb.util.NumberUtilities;
        import org.papervision3d.core.proto.*;
        import org.papervision3d.core.geom.*;
        import org.papervision3d.scenes.*;
        import org.papervision3d.cameras.*;
        import org.papervision3d.objects.*;
        import org.papervision3d.materials.*;

        public class Hydro3D extends Sprite {
               
                private const STAGE_WIDTH              :Number = 500;
                private const STAGE_HEIGHT            :Number = 300;
                private const ANIMATION_TIME    :Number = 8;
                private const ANIMATION_TYPE    :String = “easeoutquad”;
                private var controlPoints              :Array;
                private var itemArray         :Array;
                private var trailArray      :Array;
                private var currTrailArray            :Array;
                private var lineArray         :Array;
                private var count                            :int = 0;
                private var container       :Sprite;
                private var scene           :MovieScene3D;
                private var camera          :Camera3D;

                public function Hydro3D():void {

                        controlPoints = [];
                        itemArray = [];
                        trailArray = [];
                        currTrailArray = [];
                        lineArray = [];
                       
                       
                        //container
                        container = new Sprite();
                        addChild( container );
                        container.x = STAGE_WIDTH/2;
                        container.y = STAGE_HEIGHT/2;
                       
                        //scene
                        scene = new MovieScene3D( container );
                       
                        //camera
                        camera = new Camera3D();
                        camera.z = -200;
                       
                        //Dot color
                        var color:ColorMaterial = new ColorMaterial(0×666666, .5);

                        for (var i:uint = 0; i < 2; i++) {
                               
                                trailArray[i] = new Sphere(color, 1, 2, 2);
                                scene.addChild(trailArray[i]);
                               
                                itemArray[i] = new Sphere(color, 5, 5, 10);
                                scene.addChild(itemArray[i]);
                               
                                lineArray[i] = new Line3D([new Vertex3D(0, 0, 0), new Vertex3D(0, 0, 0)], 0×333333, 1, 1);
                                scene.addChild(lineArray[i]);
                        }
                       
                        addEventListener( Event.ENTER_FRAME, onEnterFrame );
                       
                        moveIt();
                }
               
                private function moveIt():void {
                        var deltaX:Number = NumberUtilities.random(-800, 800);
                        var deltaY:Number = NumberUtilities.random(-800, 800);
                        var deltaZ:Number = NumberUtilities.random(-800, 800);
                       
                        for (var i:uint = 0; i < itemArray.length; i++) {

                                var trailList:Array = [];
                                for (var q:int = 0; q < 10; q++) {
                                        trailList.push({
                                                x:NumberUtilities.random(0, STAGE_WIDTH),
                                                y:NumberUtilities.random(0, STAGE_HEIGHT),
                                                z:NumberUtilities.random(-200, 200)
                                        });
                                }
                                Tweener.addTween(trailArray[i], {
                                        x:deltaX,
                                        y:deltaY,
                                        z:deltaZ,
                                        _bezier:trailList,
                                        time:ANIMATION_TIME,
                                        transition:ANIMATION_TYPE
                                });
                               
                               
                                var bezierList:Array = [];
                                for (var v:int = 0; v < 10; v++) {
                                        bezierList.push({
                                                x:NumberUtilities.random(0, STAGE_WIDTH),
                                                y:NumberUtilities.random(0, STAGE_HEIGHT),
                                                z:NumberUtilities.random(-200, 200)
                                        });
                                }
                       
                                if(i == itemArray.length - 1){
                                        Tweener.addTween(itemArray[i], {
                                                x:deltaX,
                                                y:deltaY,
                                                z:deltaZ,
                                                _bezier:bezierList,
                                                time:ANIMATION_TIME,
                                                transition:ANIMATION_TYPE,
                                                onComplete: moveIt
                                        });
                                }else{
                                        Tweener.addTween(itemArray[i], {
                                                x:deltaX,
                                                y:deltaY,
                                                z:deltaZ,
                                                _bezier:bezierList,
                                                time:ANIMATION_TIME,
                                                transition:ANIMATION_TYPE
                                        });
                                }
                               
                        }
                       
                }
               
                private function onEnterFrame( event: Event ):void {
                        camera.x +=((container.mouseX*10) - camera.x) * 0.005;
                        camera.y +=((container.mouseY*10) - camera.y) * 0.005;
       
       
                        for (var i:int = 0; i < itemArray.length; i++) {
                                lineArray[i].addVertex(new Vertex3D(trailArray[i].x, trailArray[i].y, trailArray[i].z));
                        }
                       
                        scene.renderCamera( camera );
                };

        }
}

I’m almost positive there is a smoother and more efficient way to do this mathematically but I’m no math whiz. So in the meantime…


Lines3D Source

Thursday, August 30th, 2007

Black Magic Records and DJ Donovan

So I was a DJ/Producer way back in my raving days (pre silly looking pants era) in the early and mid 90’s under the name DJ Donovan. I actually put out a fair amount of records and remixes. Was on an Astralwerks compilation Unkownwerks in ‘98 and I even started my own label Intellihance Records which I gradually lost steam with in 2003ish? It’s even possible some people might find their way to this blog from that world. Anyways in 1996 I put out a record with Black Magic Records after moving to New Orleans to work with DJ Voodoo and The Liquid Method (DJ Demonixx/Mike Scott). They were part of the south eastern breakbeat scene down there. This record kind of formally kicked off my DJing and producing career (if you want to call it that). Nonetheless, I did a vanity search on iTunes and what do you know, that record popped up!.

BMJ005 DJ Donovan Freon and Passion Black Magic Records

I’m pretty confident that most of my work that came after this first record got better;) Maybe one of these days I’ll find a way to put some of the Intellihance stuff on iTunes.

Funny how things take you back in time.

Wednesday, August 22nd, 2007

SWFAddress

Earlier I posted a little javascript about how to deep link with the anchor variable in the url. I was surfing some design sites and found one using a similar method. Low and behold after viewing source, a complete script that sits on SWFObject called SWFAddress. I guess I am living under a rock.

Here’s an example:

myButton.onRelease = function() { 
    SWFAddress.setValue(‘/my-deep-link/’)
} 
SWFAddress.onChange = function() { 
    myNavigationLogic()
    SWFAddress.setTitle(‘My deep link’)
}

Here’s the site:
http://www.asual.com/swfaddress/

Here’s a direct link to getting started and good practices
http://www.asual.com/blog/swfaddress/2007/05/18/swfaddress-bad-practices.html

Tuesday, August 21st, 2007

PageFlip + Tweener AS3 Part 1

Update: I had a bit of an oversight in the code. This should be using the setChildIndex method instead of swap depths. I’ve added more pages, updated the code, and thanks to Harry Burt for catching that. Also thanks to him for the addition of the page turning back code. There still is an issue with depth levels if the user clicks on the pages too fast. Still haven’t had time to address that, but I think by adding a dispatcher at the midway point, the depth can be set then.

I’m sure most people have had the urge/need to do some sort of interface using that slick page flipping code that was floating around in the AS1 and AS2 heyday. They might be slightly dated, but I still like them in the right context. Obviously you can find the AS2 version out there. As for AS3, if you’re lazy efficient like me, you did a search to see what was out there. First I came across Didier Brun’s class PageFlip which is located Here. He gives a great example but you are only left with the usage code of this:

var render:Shape=new Shape();
var page0:BitmapData=new page0().bitmapData;
var page1:BitmapData=new page1().bitmapData;

render.x=50;
render.y=50;
addChild(render);

var o:Object=PageFlip.computeFlip(      new Point(60,190),    // flipped point
                                                new Point(1,1),  // of bottom-right corner
                                                page0.width,        // size of the sheet
                                                page1.height,
                                                true,            // in horizontal mode
                                                1);                         // sensibility to one

PageFlip.drawBitmapSheet(o,                         // computeflip returned object
                                                render,     // target
                                                page0,    // bitmap page 0
                                                page1);  // bitmap page 1
 

That’s great, but more then likely it left you wondering what came next. Didier’s excellent class is the foundation for all that is page flipping in AS3 (unless of course you want to reinvent the wheel). That being said, the next step was seeing hoe to put the core code into action. My next search took me to Ruben Swieringa’s site. He has an amazing and fully functioning flex application using Didier’s PageFlip class. Check it out Here. Pretty solid and feature rich, and it’s available for use. Kudos to him. However, if you are like me and you don’t work with flex, Ruben’s fine work simply serves as an example of the complexity of making the book fully interactive.

So I decided to embark on my own simpler, AS3 only version. I doubt it will be nearly as feature rich as Ruben’s flex version, but at the very least I can post a moving foundation for people to see and build upon.

I think the most exciting thing for me was how easy it was to use Tweener to flip a page using its bezier property along with it’s onUpdate callback.

[SWF]http://blog.hydrotik.com/wp-content/pageflip.swf, 500, 300[/SWF]

This is great for a flipPage() method, but obviously we’ll want to turn the page with mouse interaction as well. More of that to come later. But for the time being here’s the Page class with a simple turning animation and some events:

package com.hydrotik.book{
        import flash.display.Sprite;
        import flash.display.Shape;
        import flash.display.Bitmap;
        import flash.display.BitmapData;
        import flash.events.MouseEvent;
        import flash.events.EventDispatcher;
        import flash.geom.Point;

        import com.foxaweb.pageflip.PageFlip;
       
        import caurina.transitions.Tweener;
       
        public class Page extends EventDispatcher {
               
                private var _scope:*;
               
                private var flip:Point;
               
                private var front:BitmapData;
               
                private var back:BitmapData;
               
                private var render:Shape;
               
                private var _width:Number;
               
                private var _height:Number;
               
                private var _page:Sprite;
               
                private var _oPage:Page;
               
                private var _name:String;
               
               
                public function getName():String {
                        return _name;
                }
               
               
                public function Page(scope:*, w:Number, h:Number, x:Number, y:Number, m1:*, m2:*, name:String) {
                        _scope = scope;
                        _width = w;
                        _height = h;
                        _oPage = this;
                       
                        trace(_oPage);
                        _name = name;
                        _page = new Sprite()
                        _page.x = x;
                        _page.y = y;
                        _scope.addChild(_page);
                       
                        render = new Shape();
                        _page.addChild(render);
                       
                        front = new BitmapData(_width, _height, true, 0);
                        front.draw(m1);
                        back = new BitmapData(_width, _height, true, 0);
                        back.draw(m2);

                        flip = new Point(_width, _height);
                        drawPage();
                        _page.addEventListener(MouseEvent.CLICK, turnPageForward);
                }
               
                private function turnPageForward(event:MouseEvent = null):void{
                        dispatchEvent(new PageEvent(PageEvent.FLIP_START, _page, _oPage, true));
                        _page.removeEventListener(MouseEvent.CLICK, turnPageForward);
                        _page.addEventListener(MouseEvent.CLICK, turnPageBack);
                       
                       
                        Tweener.addTween(flip, {
                                x:-_width,
                                y:_height,
                                _bezier:{x:0, y:0},
                                time:1.5,
                                transition:“easeinoutexpo”,
                                onUpdate:drawPage,
                                onComplete:onPageDone
                        });
                }
               
                private function turnPageBack(event:MouseEvent = null):void{
                        dispatchEvent(new PageEvent(PageEvent.FLIP_START, _page, _oPage, true));
            _page.addEventListener(MouseEvent.CLICK, turnPageForward);
            _page.removeEventListener(MouseEvent.CLICK, turnPageBack);
           
           
            Tweener.addTween(flip, {
                x:_width,
                y:_height,
                _bezier:{x:0, y:0},
                time:1.5,
                transition:“easeinoutexpo”,
                onUpdate:drawPage,
                onComplete:onPageDone
            });
        }

                private function drawPage():void{
                        render.graphics.clear()
                        var o:Object = PageFlip.computeFlip(flip,// flipped point
                                        new Point(1,1),// of bottom-right corner
                                        front.width,// size of the sheet
                                        back.height,
                                        true,// in horizontal mode
                                        1);// sensibility to one                            // sensibility to one
                        PageFlip.drawBitmapSheet(o,// computeflip returned object
                                        render,// target
                                        front,// bitmap page 0
                                        back);// bitmap page 1
                }

               
                private function onPageDone():void{
                        dispatchEvent(new PageEvent(PageEvent.FLIP_COMPLETE, _page, _oPage, true));
                }
                       
        }

}

Here’s the custom PageEvent class:

package com.hydrotik.book {
       
        import flash.events.Event;
       
       
    public class PageEvent extends Event {
               
                public static const FLIP_START:String = “flipStart”;
               
                public static const FLIP_COMPLETE:String = “flipComplete”;
               
                public var targ:*;
               
                public var page:Page;
               
                public function PageEvent(type:String, t:*, p:Page, bubbles:Boolean = false, cancelable:Boolean = false){
                        super(type, bubbles, cancelable);
                        targ = t;
                        page = p;
                }
        }
}

And here is the usage:

import com.hydrotik.book.Page;
import com.hydrotik.book.PageEvent;

var page5:Page = new Page(this, 200, 200, 250, 50, new Page5(), new Page6(), “Pages 5 and 6″);
page5.addEventListener(PageEvent.FLIP_START, onFlipStartHandler);
page5.addEventListener(PageEvent.FLIP_COMPLETE, onFlipCompleteHandler);

var page3:Page = new Page(this, 200, 200, 250, 50, new Page3(), new Page4(), “Pages 3 and 4″);
page3.addEventListener(PageEvent.FLIP_START, onFlipStartHandler);
page3.addEventListener(PageEvent.FLIP_COMPLETE, onFlipCompleteHandler);

var page1:Page = new Page(this, 200, 200, 250, 50, new Page1(), new Page2(), “Pages 1 and 2″);
page1.addEventListener(PageEvent.FLIP_START, onFlipStartHandler);
page1.addEventListener(PageEvent.FLIP_COMPLETE, onFlipCompleteHandler);

var prevPage:DisplayObject;

function onFlipStartHandler(event:PageEvent):void{
        trace(“Flip Started! “ + event.page.getName() + ” - “ + event.targ);
        setChildIndex(event.targthis.numChildren - 1)
}

function onFlipCompleteHandler(event:PageEvent):void{
        trace(“Flip Completed! “ + event.page.getName() + ” - “ + event.targ);
        prevPage = event.targ;
}

stop();

Simple, and not much going on here, but it’s easy to get a nice transition and we can see something happening! Next is calculating the mouse over the corner, getting a little rollover effect before turning the page, and being able to manually turn the page.

If anyone builds on this example or has one of their own, definitely let me know:)


Here’s the code:

PageFlip AS3 Source Part 1

Wednesday, August 15th, 2007

SWFObject Deeplinking

Here’s a simple and easy way I was able to link to primary navigation sections in an all flash site.

Basically when you add #video to the end of your URL the blow code will push that video string to a swfobject add variable method. I haven’t tried it yet but I think it would be easy to add a sub section by adding #video/2 or #video/interviews etc. and do a split in the javascript. In the example below the “,0″ is an appended index reference to a sub section within the flash. In my flash if the pageid variable equals “none” then it loads normally.

<div id=“splash”>
       
</div>
<script type=“text/javascript”>
        // <![CDATA[
        var anchor = self.document.location.hash.substring(1);
       
        var section = (anchor == “”) ? “none” : anchor + “,0″;
       
        var so = new SWFObject(“swf/core.swf”, “site”, “990″, “748″, “9″, “#000000″);
        so.addVariable(“pageid”, section); // To deeplink to a section replace “none” with the linkid, for example: “gallery,1″);
        so.write(“splash”);
        // ]]>

</script>

Wednesday, August 15th, 2007

F.D.T. 3.0

I’ve been added to the beta testing team for the new version of F.D.T. for actionscript 3.0. I have loaded it up but have yet to really give it a test drive. I will add updates as I get more time with it. From what I’ve seen, it seems there is a while to go before a final release, but I know the peeps over there are working hard and will do a great job on it.

Wednesday, August 15th, 2007

QueueLoader AS3

Latest Version Info:
Click here for the current rev

Click here for the usage guide

Click here for the change log

Also click here for any posts related to the latest changes:
QueueLoader Updates

A while back Felix Raab from betriebsraum did a cool QueueLoader class for AS2 that I used often. I decided to update it for AS3 as my first port of my day to day utilitarian classes. It’s still in it’s early and raw stages, but at this point I’ve already been using it regularly.

Shortly I’ll post an example of an image gallery using the QueueLoader classes.

Here’s a simple example of how to use the class:

import com.hydrotik.utils.QueueLoader;
import com.hydrotik.utils.QueueLoaderEvent;

//Instantiate the QueueLoader
var _oLoader:QueueLoader = new QueueLoader();

//Run a loop that loads 3 images from the flashassets/images/slideshow folder
for (var i:int = 1; i < 4; i++) {
        //Set up the container
        var image:Sprite = new Sprite();
        image.name = “image_”+i;
        image.x = startX;
        addChild(image);
        //Add a load item to the loader
        _oLoader.addItem(“../flashassets/images/slideshow/”+i+“.jpg”, image, {title:“Image “+i});
        //Move the image over a bit
        startX = startX + 50;
}

//Add event listeners to the loader
_oLoader.addEventListener(QueueLoaderEvent.QUEUE_START, onQueueStart, false, 0, true);
_oLoader.addEventListener(QueueLoaderEvent.ITEM_START, onItemStart, false, 0, true);
_oLoader.addEventListener(QueueLoaderEvent.ITEM_PROGRESS, onItemProgress, false, 0, true);
_oLoader.addEventListener(QueueLoaderEvent.ITEM_INIT, onItemInit,false, 0, true);
_oLoader.addEventListener(QueueLoaderEvent.ITEM_ERROR, onItemError,false, 0, true);
_oLoader.addEventListener(QueueLoaderEvent.QUEUE_PROGRESS, onQueueProgress, false, 0, true);
_oLoader.addEventListener(QueueLoaderEvent.QUEUE_INIT, onQueueInit,false, 0, true);

//Run the loader
_oLoader.execute();

//Listener functions
function onQueueStart(event:QueueLoaderEvent):void {
        trace(“>> “+event.type);
}

function onItemStart(event:QueueLoaderEvent):void {
        trace(\t>> “+event.type, “item title: “+event.title);
}

function onItemProgress(event:QueueLoaderEvent):void {
        trace(\t>> “+event.type+“: “+[” percentage: “+event.percentage]);
}

function onQueueProgress(event:QueueLoaderEvent):void {
        trace(\t>> “+event.type+“: “+[” queuepercentage: “+event.queuepercentage]);
}

function onItemInit(event:QueueLoaderEvent):void {
        trace(\t>> event:” + event.type+” - “+[“target: “+event.targ, “w: “+event.width, “h: “+event.height]+\n);
}

function onItemError(event:QueueLoaderEvent):void {
        trace(\n>>”+event.message+\n);
}

function onQueueInit(event:QueueLoaderEvent):void {
        trace(“** “+event.type);
}


A more recent version of this code has been posted! Go HERE

Wednesday, August 15th, 2007

hello world!

My first post as an official blogger! Yes I know I am behind the times, but I’m still excited about being able to share with the world. I’ve spent a lot of time scouring the net for code, resources, and examples, and now I feel it’s time to give back. I have a few AS3 code related things I plan to get up here on the site shortly as soon as I get this thing set up to my liking. Hopefully I myself can become one of the many resources out there for people and maybe make a few new friends int he process.

Tuesday, August 14th, 2007