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:
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!
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:
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!
privatefunctiononMouseMove(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; }
privatefunction 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; } }
// 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);
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:
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:
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:
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).
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…
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;
}
}
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):
here is the code involved with using the effect:
devide = new Devide(_loadedBitmap, 12, 0x000000);
addChild(devide);
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:
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:
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.