"Imagination is more important than knowledge." -Albert Einstein

Cocos2D is Flash for the iPhone

Posted: August 15th, 2010 | Author: admin | Filed under: Uncategorized | 1 Comment »

This is really the one line advice I needed. I’ve dabbled with iPhone apps for a couple of months now, but building temperature converters, table views and sliders bored me to death! So it wasn’t until I went out for some hummus with my friend that he suggested I download the Cocos2D framework. 2 days later I’m hooked. and basically, I just want to put down some things so I don’t forget — stuff that would help me translate AS3 to xCode. The stuff below is really all from the first page of the beginner tutorials, but it is so similar to how flash works (or at least, how I’m used to work with flash) that I wanted to point it out.

Here are some early findings:

how to create a sprite and add it to the display list:

CCSprite *mySprite;
mySprite = [CCSprite spriteWithFile: @"image.png"];
mySprite.position = ccp( 100, 100 );
[self addChild:mySprite];

how to add an enterFrame Event:

// schedule a repeating callback on every frame
[self schedule:@selector(nextFrame:)];

and how the enterFrame function looks like:

- (void) nextFrame:(ccTime)dt {
    mySprite.position = ccp( mySprite.position.x + 100*dt, mySprite.position.y );
    if (mySprite.position.x > 480+32) {
        mySprite.position = ccp( -32, mySprite.position.y );
    }
}

AIR Apps running on Android

Posted: May 20th, 2010 | Author: admin | Filed under: AS3, Mobile | 1 Comment »

We finally have a public Beta to play with and start experimenting with creating Flash Apps for the Android. Get one for yourself here: http://labs.adobe.com/technologies/air2/android/.

Here is a small app I ported from flash. The cool thing is that you don’t need to change any of your code, expect for accounting for the small screen. Of course there are the new multitouch functions that you can take advantage of, but that’s like an added bonus. Check it out. make some apps!

Fun with Flash on Android from Itai Asseo on Vimeo.


Circular Slider

Posted: January 8th, 2010 | Author: admin | Filed under: Uncategorized | 8 Comments »

One of the challanges in the design of www.flurrious.com was getting those circular sliders in. Of course you can fake it and create an animation of a slider and control the timeline from 0-100, but that’s lame and not so easy to modify (like change the radius, sweep angle etc.). so, I set to create a circular slider.

I had the basic principles in place: create a circle, and create a beginSwipe andgle and an endSwipe angle. done:

the code looks something like this:

package  
{
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.Event;

    /**
     * @author iasseo
     */

    public class CircularSlider extends MovieClip
    {
        private var _circ : Sprite;
        private var _startAngle : Number = 90;
        private var _angleRange : Number = 30;
        private var _angleShape : Sprite;
        private var _radius : Number = 250;
        private var topAngle : Number;
        private var bottmAngle : Number;

        public function CircularSlider()
        {
            calcAngles();
            drawCircle();
            initAngle();
            addEventListener(Event.ENTER_FRAME, onEF);
        }
       

        private function calcAngles() : void
        {
            topAngle = _startAngle - _angleRange - 90;
            topAngle = topAngle / 180 * Math.PI;
            bottmAngle = _startAngle + _angleRange - 90;
            bottmAngle = bottmAngle / 180 * Math.PI;
        }


        private function initAngle() : void
        {
            _angleShape = new Sprite();
            _angleShape.x = stage.stageWidth/2;
            _angleShape.y = stage.stageHeight/2;
            addChild(_angleShape);
        }

        private function drawAngle() : void
        {
            _angleShape.graphics.lineStyle(2, 0xff0000);
            _angleShape.graphics.lineTo(Math.cos(topAngle)*_radius, Math.sin(topAngle)*_radius);
            _angleShape.graphics.lineStyle(2, 0x00ff00);
            _angleShape.graphics.lineTo(Math.cos(bottmAngle)*_radius, Math.sin(bottmAngle)*_radius);
            _angleShape.graphics.lineStyle(2, 0xff0000);
            _angleShape.graphics.lineTo(0, 0);
        }

        private function drawCircle() : void
        {
            _circ = new Sprite();
            _circ.graphics.lineStyle(1,0xffffff);
            _circ.graphics.drawCircle(0, 0, _radius);
            _circ.graphics.endFill();
            _circ.x = stage.stageWidth/2;
            _circ.y = stage.stageHeight/2;
            addChild(_circ);
        }
       
        private function onEF(e:Event):void
        {
            _angleRange = Math.abs(stage.stageHeight/2 - mouseX);
             _angleShape.graphics.clear();
             calcAngles();
             drawAngle();
        }
    }
}

Next, I needed to place the scroll handlebar at the top of the sweep (top of green line in picture), and have it be draggable to the bottom of the sweep. To do that, I calculated the X,Y position of the top and bottom (which I already have in the code), and upon click, I created a rectangle that represented the bounding box for the drag operation. Then, I calculated the percentage point of the handle inside that bounding box to get the 0-1 result, and using the Y position, extracted what the X position would be:

The only problem is that now, when I remove the guides (the circle and angles), I am left with only the slider… and I need the arc so the slider has some visual representation. There are 2 solutions for that. Simple solution: mask the circle… easy to do. here’s the result:

A solution that’s a bit more complex is to DRAW the arc.. that’s where I was happy to find this nice post by the algorythmist. So, using this code, you can then create a nice circular slider:

now all that’s left to do is output the percentage from the slider and you got yourself a nice circular slider!

here’s the final code:

package  
{
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.geom.Rectangle;

    /**
     * @author iasseo
     */

    public class CircularSlider extends MovieClip
    {
        private var _circ : Sprite;
        private var _startAngle : Number = 90;
        private var _angleRange : Number = 30;
        private var _angleShape : Sprite;
        private var _radius : Number = 250;
        private var topAngle : Number;
        private var bottmAngle : Number;
        private var _handle : Sprite;
        private var _box : Sprite;
        private var _handleHolder : Sprite;
        private var _mask : Sprite;

        public function CircularSlider()
        {
            calcAngles();
            drawCircle();
            initAngle();
            drawAngle();
            drawSegments();
           
            createHandle();
        }
       
        private function createHandle() : void
        {
            _handleHolder = new Sprite();
            _handleHolder.x = stage.stageWidth/2;
            _handleHolder.y = stage.stageHeight/2;
            addChild(_handleHolder);
            _handle = new Sprite();
            _handle.graphics.beginFill(0xcccccc);
            _handle.graphics.drawCircle(0, 0, 10);
            _handle.graphics.endFill();
            _handle.buttonMode = true;
            _handle.x = Math.cos(topAngle)*_radius;
            _handle.y = Math.sin(topAngle)*_radius;
            _handleHolder.addChild(_handle);
           
            _handle.addEventListener(MouseEvent.MOUSE_DOWN, onStartDrag);
        }
       
        private function onStartDrag(e : MouseEvent) : void
        {
            makeBox();
            drawBox();
            var rect : Rectangle = _box.getRect(_box);
            _handle.startDrag(false, rect);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            stage.addEventListener(MouseEvent.MOUSE_UP, onStopDrag);
        }
       
        private function onMouseMove(e : MouseEvent) : void
        {
            e.updateAfterEvent();
            var rect : Rectangle = _box.getRect(_box);
            var dist : Number = rect.height;
            var per : Number = (_handle.y + dist/2)/dist;
            var a : Number = _startAngle - _angleRange;
            var b : Number = _startAngle + _angleRange;
            var r : Number = b-a;
            var targetAngle :Number = a + r*per;
            targetAngle = targetAngle / 180 * Math.PI;
            _handle.x = Math.sin(targetAngle)*_radius + 2;
        }

        private function onStopDrag(e : MouseEvent) : void
        {
            removeBox();
            _handle.stopDrag();
            _handle.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            stage.removeEventListener(MouseEvent.MOUSE_UP, onStopDrag);
            stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
        }
       
        private function removeBox() : void
        {
            _box.graphics.clear();
            removeChild(_box);
        }

        private function drawBox() : void
        {
            _box.graphics.lineStyle(1,0xffffff, 0);
            _box.graphics.moveTo(Math.cos(topAngle)*_radius, Math.sin(topAngle)*_radius);
            _box.graphics.lineTo(_radius, Math.sin(topAngle)*_radius);
            _box.graphics.lineTo(_radius, Math.sin(bottmAngle)*_radius);
            _box.graphics.lineTo(Math.cos(topAngle)*_radius, Math.sin(bottmAngle)*_radius);
            _box.graphics.lineTo(Math.cos(bottmAngle) * _radius, Math.sin(topAngle)*_radius);
        }

        private function makeBox() : void
        {
            _box = new Sprite();
            _box.x = stage.stageWidth/2;
            _box.y = stage.stageHeight/2;
            _box.mouseEnabled = false;
            _box.mouseChildren = false;
            addChild(_box);
           
        }

        private function calcAngles() : void
        {
            topAngle = _startAngle - _angleRange - 90;
            topAngle = topAngle / 180 * Math.PI;
            bottmAngle = _startAngle + _angleRange - 90;
            bottmAngle = bottmAngle / 180 * Math.PI;
        }

        private function drawSegments() : void
        {
            _angleShape.graphics.lineStyle(2, 0x0000ff);
            // FROM THE ALGORYTHMIST -- http://algorithmist.wordpress.com/2009/12/01/drawing-circular-segments-in-actionscript/
            // now that start and end angle are fixed, draw a set of quads no more than PI/4 in arc at once
          var angleDelta:Number = bottmAngle - topAngle;
          var numSeg:Number     = Math.ceil(angleDelta*4.0/Math.PI);
          var arc:Number        = angleDelta/numSeg;
       
          // p is the vector from the origin of the wedge to (p0X,p0Y)
          // q is the vector from the origin of the wedge to (p2X,p2Y)
          // the vector p+q bisects the angle between p and q.  The middle interpolation point is
          // 'radius' units along that bisector.
          var pX:Number    = _radius*Math.cos(topAngle);
          var pY:Number    = _radius*Math.sin(topAngle);
          var p0X:Number   = pX;
          var p0Y:Number   = pY;
          var qX:Number    = 0;
          var qY:Number    = 0;
          var angle:Number = topAngle;
         
          // initial point at startAngle
          var startX:Number = _radius*Math.cos(topAngle);
          var startY:Number = _radius*Math.sin(topAngle);
          _angleShape.graphics.moveTo( startX, startY );
       
          var radInv:Number = 1.0/_radius;
       
          // approximate each arc with a quad. Bezier
          for( var i:uint=0; i<numSeg; ++i )
          {
            angle         += arc;
            qX             = _radius*Math.cos(angle);
            qY             = _radius*Math.sin(angle);
            var p2X:Number = qX;
            var p2Y:Number = qY;
       
            // unit vector in direction of bisector - alternative approach is two more trig. calcs to compute the coordinates.
            // let's have some fun and do it a different way.
            var dX:Number = (pX+qX)*radInv;
            var dY:Number = (pY+qY)*radInv;
            var d:Number  = Math.sqrt(dX*dX + dY*dY);
            dX /= d;
            dY /= d;
       
            // middle interpolation point is a distance of 'radius' units along direction of bisecting unit vector
            var p1X:Number = _radius*dX;
            var p1Y:Number = _radius*dY;
       
            // compute control point so that quad. Bezier passes through (p0X,p0Y), (p1X,p1Y), and (p2X,p2Y) at t=0.5
            var cX:Number = 2.0*p1X - 0.5*(p0X + p2X);
            var cY:Number = 2.0*p1Y - 0.5*(p0Y + p2Y);
       
            // You can compute the control point directly with nothing but sin & cos, but if memory serves it takes
            // four more trig comps. for a total of six per loop iteration.
             _angleShape.graphics.curveTo(cX, cY, p2X, p2Y);
            // end point is start point for next iteration
            p0X = p2X;
            p0Y = p2Y;
            pX  = qX;
            pY  = qY;
          }
        }

        private function initAngle() : void
        {
            _angleShape = new Sprite();
            _angleShape.x = stage.stageWidth/2;
            _angleShape.y = stage.stageHeight/2;
            addChild(_angleShape);
        }

        private function drawAngle() : void
        {
            _angleShape.graphics.lineStyle(2, 0xff0000);
           
           
            _angleShape.graphics.lineTo(Math.cos(topAngle)*_radius, Math.sin(topAngle)*_radius);
            _angleShape.graphics.lineStyle(2, 0x00ff00);
            _angleShape.graphics.lineTo(Math.cos(bottmAngle)*_radius, Math.sin(bottmAngle)*_radius);
            _angleShape.graphics.lineStyle(2, 0xff0000);
            _angleShape.graphics.lineTo(0, 0);
        }

        private function drawCircle() : void
        {
            _circ = new Sprite();
            _circ.graphics.lineStyle(1,0xffffff);
            _circ.graphics.drawCircle(0, 0, _radius);
            _circ.graphics.endFill();
            _circ.x = stage.stageWidth/2;
            _circ.y = stage.stageHeight/2;
           
           
            // TO MASK OUT THE CIRCLE, YOU CAN USE THIS:
            /*_mask = new Sprite();
            _mask.x = stage.stageWidth/2;
            _mask.y = stage.stageHeight/2;
            _mask.mouseEnabled = false;
            _mask.mouseChildren = false;
            addChild(_mask);
           
            _mask.graphics.beginFill(0xff0000, 1);
            _mask.graphics.drawRect(Math.cos(topAngle)*_radius, Math.sin(topAngle)*_radius, _radius-Math.cos(topAngle)*_radius + 1, _radius/2-Math.sin(topAngle)*_radius);
             *
             */


            _circ.mask = _mask;
            addChild(_circ);
        }
       
    }
}

Drawing Snowflakes: Part 1

Posted: January 7th, 2010 | Author: admin | Filed under: Uncategorized | No Comments »

So, like I said in my last post, I’m going to dedicate these few next posts to go over some of the techniques I used to create Flurrious.com.

The first thing I want to go over is the creation of the drawing application. The architecture of it is pretty simple, but crucial to making it work well, and having it be extendable and modular. My first step was to create the canvas. since a snowflake has an ice crystal formation, it has to have 6 sides.  So my first step is to draw 6 triangles that form a hexagon:

The code for this is pretty simple, looks like this:

package  
{
    import flash.display.MovieClip;
    import flash.display.Sprite;

    /**
     * @author iasseo
     */

    public class SnowFlake extends MovieClip
    {
        private const SLICES : Number = 6;
        private const RADIUS : Number = 300;
       
        private var _sliceArray : Array = new Array();
        private var _angle : Number;

        public function SnowFlake()
        {
            _angle = Math.PI / SLICES;
            createFlakeStage();
        }
       
        private function createFlakeStage() : void
        {
            for (var n : Number = 0;n < SLICES; n++)
            {
                var slice : Sprite = createSlice(_angle);
                slice.x = stage.stageWidth / 2;
                slice.y = stage.stageHeight / 2;
                slice.rotation = 360 / SLICES * n;
                _sliceArray.push(slice);
                addChild(slice);
            }
        }
       
        private function createSlice(angle : Number) : Sprite
        {
            var slice : Sprite = new Sprite();
            slice.graphics.moveTo(0, 0);
            slice.graphics.lineStyle(1,0);
            slice.graphics.beginFill(0,.1);
            slice.graphics.lineTo(Math.cos((angle)-Math.PI/2)*RADIUS, Math.sin((angle)-Math.PI/2)*RADIUS);
            slice.graphics.lineTo(Math.cos(-(angle)-Math.PI/2)*RADIUS, Math.sin(-(angle)-Math.PI/2)*RADIUS);
            slice.graphics.lineTo(0, 0);
            slice.graphics.endFill();
           
            slice.graphics.moveTo(0, 0);
            slice.graphics.lineTo(0,Math.sin((_angle)-Math.PI/2)*RADIUS);
            slice.graphics.endFill();
            return slice;
        }
    }
}

Now, even though this is my canvas which I’m using to capture the mouse events, I’m going to draw the actual shapes on a separate Sprite, so I can have better control. In order to do that, I’m going to place 6 empty Sprites in the center of the hexagon, each one rotated, just like the triangles I drew. I’ll add a new function – createShapeHolders() – to the constructor (notice that I’m disabling all MouseEvents for these ’shapes’, because I want to control them from the canvas I drew earlier). For each of the triangles (which are separate Sprites), I’m going to add a MouseEvent, which will trigger the drawing application. I’m going to add that to the ‘for loop’ in the createFlakeStage() function, and I’m also adding 3 MouseEvent functions: beginShape, renderShape and endShape.

When I click on any of the triangles now, beginShape() will save the slice I clicked on as _slice (added as a private var to the class), and trigger a MOUSE_MOVE event. Then, as I move the mouse, the renderShape() function will draw on all 6 sides of the hexagon:


CLICK TO SEE THIS IN ACTION

package  
{
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.MouseEvent;

    /**
     * @author iasseo
     */

    public class SnowFlake extends MovieClip
    {
        private const SLICES : Number = 6;
        private const RADIUS : Number = 300;
       
        private var _sliceArray : Array = new Array();
        private var _angle : Number;
        private var _shapeHolders : Vector.<Sprite> = new Vector.<Sprite>();
        private var _slice : Sprite;  

        public function SnowFlake()
        {
            _angle = Math.PI / SLICES;
            createFlakeStage();
            createShapeHolders();
        }
       
        private function createShapeHolders() : void
        {
            for (var n : Number = 0;n < SLICES; n++)
            {
                var shape : Sprite = new Sprite();
                shape.mouseEnabled = false;
                shape.mouseChildren = false;
                shape.x = stage.stageWidth / 2;
                shape.y = stage.stageHeight / 2;
                _shapeHolders.push(shape);
                shape.rotation = 360 / SLICES * n;
                addChild(shape);
            }
        }

        private function createFlakeStage() : void
        {
            for (var n : Number = 0;n < SLICES; n++)
            {
                var slice : Sprite = createSlice(_angle);
                slice.x = stage.stageWidth / 2;
                slice.y = stage.stageHeight / 2;
                slice.rotation = 360 / SLICES * n;
                slice.addEventListener(MouseEvent.MOUSE_DOWN, beginShape);
                slice.alpha = 1;
                _sliceArray.push(slice);
                addChild(slice);
            }
        }
       
        private function createSlice(angle : Number) : Sprite
        {
            var slice : Sprite = new Sprite();
            slice.graphics.moveTo(0, 0);
            slice.graphics.lineStyle(1,0);
            slice.graphics.beginFill(0,.1);
            slice.graphics.lineTo(Math.cos((angle)-Math.PI/2)*RADIUS, Math.sin((angle)-Math.PI/2)*RADIUS);
            slice.graphics.lineTo(Math.cos(-(angle)-Math.PI/2)*RADIUS, Math.sin(-(angle)-Math.PI/2)*RADIUS);
            slice.graphics.lineTo(0, 0);
            slice.graphics.endFill();
           
            slice.graphics.moveTo(0, 0);
            slice.graphics.lineTo(0,Math.sin((_angle)-Math.PI/2)*RADIUS);
            slice.graphics.endFill();
            return slice;
        }
       
        private function beginShape(e : MouseEvent) : void
        {
            _slice = e.target as Sprite;
            for (var i : Number = 0;i < SLICES; i++)
            {
                _shapeHolders[i].graphics.lineStyle(1,0xFFFFFF);
                _shapeHolders[i].graphics.moveTo(_slice.mouseX, _slice.mouseY);
            }
           
            stage.addEventListener(MouseEvent.MOUSE_MOVE, renderShape);
            stage.addEventListener(MouseEvent.MOUSE_UP, endShape);
        }
       
        private function renderShape(e : MouseEvent) : void
        {
            for (var i : Number = 0;i < SLICES; i++)
            {
                _shapeHolders[i].graphics.lineTo(_slice.mouseX, _slice.mouseY);
            }
        }

        private function endShape(e : MouseEvent) : void
        {
            stage.removeEventListener(MouseEvent.MOUSE_MOVE, renderShape);
            stage.removeEventListener(MouseEvent.MOUSE_UP, endShape);
        }
    }
}

Now the only problem is that it doesn’t look like a symmetrical drawing… it basically copies the shape you’re drawing and places it in a circle. Now we need to add a reflection to the shape. So, to do that, we’ll have to add 2 Sprites to each of the ’shapes’ we created in the createShapeHolders() function. One of those shapes we’ll flip horizontally (scaleX = -1) and then, each time we trigger beginShape and renderShape, we’ll use the FP10 copyFrom() function to create a reflection effect. All we have left to do now is to hide the canvases, and start drawing! here is the result:


CLICK HERE TO SEE IT IN ACTION – CLICK AND DRAG NEAR THE CENTER OF THE STAGE

and here is the final code:

package  
{
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.MouseEvent;

    /**
     * @author iasseo
     */

    public class SnowFlake extends MovieClip
    {
        private const SLICES : Number = 6;
        private const RADIUS : Number = 300;
       
        private var _sliceArray : Array = new Array();
        private var _angle : Number;
        private var _shapeHolders : Vector.<Sprite> = new Vector.<Sprite>();
        private var _slice : Sprite;  

        public function SnowFlake()
        {
            _angle = Math.PI / SLICES;
            createFlakeStage();
            createShapeHolders();
        }
       
        private function createShapeHolders() : void
        {
            for (var n : Number = 0;n < SLICES; n++)
            {
                var shape : Sprite = new Sprite();
                shape.mouseEnabled = false;
                shape.mouseChildren = false;
                shape.addChild(new Sprite());
                shape.addChild(new Sprite());
                shape.getChildAt(1).scaleX = -1;
                shape.x = stage.stageWidth / 2;
                shape.y = stage.stageHeight / 2;
                _shapeHolders.push(shape);
                shape.rotation = 360 / SLICES * n;
                addChild(shape);
            }
        }

        private function createFlakeStage() : void
        {
            for (var n : Number = 0;n < SLICES; n++)
            {
                var slice : Sprite = createSlice(_angle);
                slice.x = stage.stageWidth / 2;
                slice.y = stage.stageHeight / 2;
                slice.rotation = 360 / SLICES * n;
                slice.addEventListener(MouseEvent.MOUSE_DOWN, beginShape);
                slice.alpha = 0;
                _sliceArray.push(slice);
                addChild(slice);
            }
        }
       
        private function createSlice(angle : Number) : Sprite
        {
            var slice : Sprite = new Sprite();
            slice.graphics.moveTo(0, 0);
            slice.graphics.lineStyle(1,0);
            slice.graphics.beginFill(0,.1);
            slice.graphics.lineTo(Math.cos((angle)-Math.PI/2)*RADIUS, Math.sin((angle)-Math.PI/2)*RADIUS);
            slice.graphics.lineTo(Math.cos(-(angle)-Math.PI/2)*RADIUS, Math.sin(-(angle)-Math.PI/2)*RADIUS);
            slice.graphics.lineTo(0, 0);
            slice.graphics.endFill();
           
            slice.graphics.moveTo(0, 0);
            slice.graphics.lineTo(0,Math.sin((_angle)-Math.PI/2)*RADIUS);
            slice.graphics.endFill();
            return slice;
        }
       
        private function beginShape(e : MouseEvent) : void
        {
            _slice = e.target as Sprite;
            for (var i : Number = 0;i < SLICES; i++)
            {
                var side1 : Sprite = _shapeHolders[i].getChildAt(0) as Sprite;
                var side2 : Sprite = _shapeHolders[i].getChildAt(1) as Sprite;
                side1.graphics.lineStyle(1,0xFFFFFF);
                side1.graphics.moveTo(_slice.mouseX, _slice.mouseY);
                side2.graphics.copyFrom(side1.graphics);
            }
           
            stage.addEventListener(MouseEvent.MOUSE_MOVE, renderShape);
            stage.addEventListener(MouseEvent.MOUSE_UP, endShape);
        }
       
        private function renderShape(e : MouseEvent) : void
        {
            for (var i : Number = 0;i < SLICES; i++)
            {
                var side1 : Sprite = _shapeHolders[i].getChildAt(0) as Sprite;
                var side2 : Sprite = _shapeHolders[i].getChildAt(1) as Sprite;
                side1.graphics.lineTo(_slice.mouseX, _slice.mouseY);
                side2.graphics.copyFrom(side1.graphics);
            }
        }

        private function endShape(e : MouseEvent) : void
        {
            stage.removeEventListener(MouseEvent.MOUSE_MOVE, renderShape);
            stage.removeEventListener(MouseEvent.MOUSE_UP, endShape);
        }
    }
}

Flurrious.com

Posted: January 6th, 2010 | Author: admin | Filed under: Uncategorized | No Comments »

I haven’t posted anything is the past few weeks because I was busy working on Flurrious.com — Digitas’ ‘09 holiday card.  It let’s you draw a snowflake and send it to a friend — and watch all of the other snowflakes other people make.  For each snowflake sent, Digitas donates $1 to UNICEF.

The site has done MUCH better than expected — over 23,000 snowflakes were made (in less than 2 weeks), and almost $7,000 donated to UNICEF. The site is pretty small at 200kb, but so far we’ve served over 600GB of data to users (most of it is probably the snowflakes that are being saved as PNGs on the server).

flurrious

To create this application I had to do an extensive brush-up on my flash drawing API skills.  I’m using some of the new features from FP10 like IGraphicsPath and the 3D rotations (as well as Papervision3D). That graphics data is being saved in Vector arrays, and is stored on the database.  When you view a snowflake, that data is being passed back to flash, and then get’s drawn again with the same API.

In the next few posts I’ll talk about some of the techniques I used to create the application.  some of the highlights in my opinion are: saving and recreating vector data, creating smooth lines, and creating the circular slidres.  Creating the snowflake generative drawing I think was the least challenging thing in the site…

-itai


Looping videos in Papervision3D

Posted: November 16th, 2009 | Author: admin | Filed under: papervision3D | No Comments »

I was working on an Augmented Reality bit this weekend which involved a looping video. Normally this is a harmless operation which involves a simple onStreamStatus event, that by passing a “NetStream.Play.Stop” triggers a _netStream.seek(0); function. But when I tried that in PV3d the video would not loop… it was pretty frustrating, but eventually I figured out that the VideoStreamMaterial class in the Papervision3D package stopped rendering upon a “NetStream.Play.Stop” event, but didn’t resume it on a “NetStream.Seek.Notify” event, which I had to manually add.



this is how the function looks like after the change:

private function onStreamStatus ( event:NetStatusEvent ):void
        {
            switch ( event.info.code )
            {
                case "NetStream.Play.Start":
                    animated = true;
                    break;
                case "NetStream.Unpause.Notify":
                    animated = true;   
                    break;
                case "NetStream.Seek.Notify":
                    animated = true;
                    break;
                case "NetStream.Play.Failed":
                    animated = false;
                    break;
                case "NetStream.Play.Stop":
                    animated = false;
                    break;
                case "NetStream.Play.StreamNotFound":
                    animated = false;
                    break;
                case "NetStream.Pause.Notify":
                    animated = false;
                    break;
            }          
        }

Bitmap division and animation with simple API

Posted: November 10th, 2009 | Author: admin | Filed under: Effects | No Comments »

I’m continuing my efforts to create an easy-to-use effect library. For now I’m concentrating on 2D matrix effects — the previous one was halfTone. This one is a devision of an image (or any displayObjects for that matter) into smaller segments.

here’s what it looks like (click to watch animation):
Picture 10

here is the code involved with using the effect:

devide = new Devide(_loadedBitmap, 12, 0x000000);
addChild(devide);
           
devide.swipeLeftToRight = 0;
           
seq = new TimelineLite({onComplete:restartTween});
seq.append(TweenLite.to(devide, 1, {swipeLeftToRight:1}));
seq.append(new TweenLite(devide, 1, {swipeRightToLeft:0}));
seq.append(new TweenLite(devide, 1, {swipeTopToBottom:1}));
seq.append(new TweenLite(devide, 1, {swipeBottomToTop:0}));

It is based on my previous work that I posted here.


Halftone effect with simple API

Posted: November 5th, 2009 | Author: admin | Filed under: Effects | No Comments »

I started working on an effect library with an easy-to-use API which will be easily attached to any tweening engine. I’m still working hard on the API and on how the whole thing is architectured, so I’m not going to include source code this time, but to give you a glimpse of how this is going to look, here’s an example of the Halftone effect which is going to be part of the Matrix2D package (it will include stuff like pixelate and explode effects).

the following effect is achieved simply by typing the following:

halfTone = new HalfTone(_loadedBitmap, 16);
addChild(halfTone);

but the fun part is animating the effect with a simple API. I’m using the new TweenLite v11, but any tween engine or really any other way (like controlling the swipe with the position of the mouse). here’s how I’m creating the different swipes in the example below:

halfTone.swipeLeftToRight = 0;
seq = new TimelineLite({onComplete:restartTween});
seq.append(new TweenLite(halfTone, 1, {swipeLeftToRight:1}));
seq.append(new TweenLite(halfTone, 1, {swipeRightToLeft:0}));
seq.append(new TweenLite(halfTone, 1, {swipeTopToBottom:1}),1);
seq.append(new TweenLite(halfTone, 1, {swipeBottomToTop:0}));
seq.append(new TweenLite(halfTone, 1, {swipeTLtoBR:1}),1);
seq.append(new TweenLite(halfTone, 1, {swipeTLtoBR:0}));

Picture 4

Special thanks to Joe Ferrari for helping me through the diagonal array math (still working on the BottomLeft to TopRight swipe)


Dynamic Grid Positioning v2

Posted: October 31st, 2009 | Author: admin | Filed under: Uncategorized | No Comments »

after some thought of how to make this more practical, I decided to make another version.

In this version the 2 boxes next to the selected box and the 2 above and below grow as well, and the response and alignment is much better.

here’s what it looks like now:

Picture 7

here is the source


Dynamic Grid Positioning

Posted: October 28th, 2009 | Author: admin | Filed under: Effects, tips and tricks | 1 Comment »

I had a couple of people ask me in the past couple of weeks about dynamic positioning of elements on a page, which change their position when other elements change size. Kind of like the ADIDAS WEBSITE effect.

The thing that is hard to get I think is a natural dynamic movement, and will be very apparent if you are doing this in an event-driven way. So I decided to do a quick example of how this would look like using a 2D matrix and using an EnterFrame event to detect the position of each element in the grid.

you can check out the result below:

Picture 60

basically, the way I set it up is to devide the grid into rows — each row has a Sprite that holds all of the elements in that row. On each frame, each one of the boxes checks the X and WIDTH of the box before it and changes it’s X position accordingly, and each Sprite Holder checks the Y and HEIGHT position of the row before it and calculates it’s position accordingly.

next I’ll try to use some collision detection and get a better real-world feel to it.

as always – here’s the SOURCE