circlecube

RSS comments
LinkedIn Twitter delicious fb last.fm

Author Archive

as3animation coverKeith Peter‘s Foundation Actionscript 3.0 Animation: Making Things Move!

Can I just say WOW! Being a student of art and animation before turning to the flash world, I love how Keith is able to explain programming in terms that are very easy to understand and follow. I’ve been a huge fan of his since I first peeked at Flash Math Creativity and Flash Math Creativity, Second Edition. I then followed to his bit-101 site and devoured his tutorials there: gravity, easing, elasticity, etc…

This book helps me transition all those techniques I’ve incorporated into my practices from actionscript 2 to actionscript 3. He also teaches me more about object oriented programming with the same simplicity he explained gravity years ago. It’s a great read and an essential part of my collection. I could safely say that I’ve learned more (at least as much as) from Keith’s work than anyone else in the industry. Anything from him always make sense and inspires my code and projects to be better. So go get his book to support him!

Also, friends of ed makes available the source code that goes with the text here.

Thanks Keith — and keep up the great work!

8 Feb 2009

Foundation Actionscript 3.0 Animation: Making Things Move! | Review

Author: Evan Mullins | Filed under: review

parallax_thumbI’ve had quite a few questions about how to make depth in flash. Earlier (like, 2 years ago) I put up an experiment file to give some interactive depth to some sketchbook sketches, see Floating Sketches. I’ve finally gotten around to translating that into as3. It’s still the same basic idea, Create layers of levels, and have each one respond to the mouse a little differently. The ‘closer’ depths will move faster while the farther away depths will be slower. A simple technique called Parallax.

  1. Seperate the scene into layers
  2. Place the layers in the correct depth
  3. Make closer layers react fast and farther layers slower

Example

Get Adobe Flash player

parallax_thumb

Actionscript

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
//define number of layer.
var numLayers:uint = 15;
//number of items in a layer
var numBallsPerLayer:uint = 100;
var defaultBallSize:uint = 25;

var stageWidth3d:uint = 800;
var stageHeight3d:uint = 800;

var layers:Array = new Array();
//init
makeMatrix();
//3d created by layers and placing objects on each layer - the layer has it's own distance, simulated by movement and alpha

function makeMatrix():void {
    //walk through desired number of layers
    for (var layerNum:uint=0; layerNum<numLayers; layerNum++){
        //make layer object to add balls to
        var thisLayer:MovieClip = new MovieClip();
        addChild(thisLayer);
        layers.push(thisLayer);
        //create desired number of balls per layer
        for (var ballNum:uint=0; ballNum<numBallsPerLayer; ballNum++){
            //trace("layer: "+layerNum +"; ball: "+ballNum);
            var c1:Number = randomColor();
            var c2:Number = randomColor();
           
            //create ball
            var thisBall:MovieClip = new MovieClip();
            thisBall.graphics.beginFill(c1, .9);
            thisBall.graphics.lineStyle(defaultBallSize/3, c2, .9);
            thisBall.graphics.drawCircle(defaultBallSize, defaultBallSize, defaultBallSize);
            thisBall.graphics.endFill();
           
            //apply filter to ball
            var myGradientGlowFilter = new GradientGlowFilter(0,
                                                  0,
                                                  [c1, c2, c1],
                                                  [0, .9, 1],
                                                  [0, 63, 255],
                                                  20,
                                                  20,
                                                  .9,
                                                  BitmapFilterQuality.HIGH,
                                                  BitmapFilterType.OUTER,
                                                  false);
            var myBlurFilter = new BlurFilter((numLayers-layerNum)/numLayers*5, (numLayers-layerNum)/numLayers*5, 1);
            var filtersArray:Array = new Array(myGradientGlowFilter, myBlurFilter);
            thisBall.filters = filtersArray;
           
            thisLayer.addChild(thisBall);

            //coordinates
            thisBall.x = Math.random() * stageWidth3d * layerNum;
            thisBall.y = Math.random() * stageHeight3d * layerNum;
            //size
            thisBall.scaleY = thisBall.scaleX = layerNum/numLayers * (Math.random() + 1);
           
            //ball animation
            thisBall.layer = layerNum;
            thisBall.addEventListener(Event.ENTER_FRAME, animateBall);
        }
       
        //layer depth/alpha
        thisLayer.alpha = layerNum/numLayers;
       
    }
    //listeners to animate from mouse movement
    addEventListener(Event.ENTER_FRAME, positionLayer);

}

var easingStrength:Number = 10;

function positionLayer(e:Event):void{
    for (var layerNum:uint=0; layerNum<numLayers; layerNum++){
        //move layers according to mouse poosition
        var xv:Number = (stage.stageWidth-layers[layerNum].width)/stage.stageWidth;
        layers[layerNum].x -= (layers[layerNum].x - xv * mouseX) / easingStrength;
        var yv:Number = (stage.stageHeight-layers[layerNum].height)/stage.stageHeight;
        layers[layerNum].y -= (layers[layerNum].y - yv * mouseY) / easingStrength;
    }
}

function animateBall(e:Event):void{
    e.target.x += (Math.random() - .5) * 2 * e.target.layer/numLayers;
    e.target.y += (Math.random() - .5) * 2 * e.target.layer/numLayers;
}

function randomColor():Number{
    return Math.floor(Math.random() * 16777215);
}

Source

depth.fla

30 Jan 2009

Dynamic 3d space | Floating Sketches Tutorial

Author: Evan Mullins | Filed under: tutorial

FormulaFIVE is here!

sales letter video

The wait is over. FormulaFIVE is LIVE!

19 Jan 2009

FormulaFIVE Launch from StomperNet is a go!

Author: Evan Mullins | Filed under: work

constrain proportions jpgI’ve had that exact task numerous time while scripting actionscript. I have a source image loaded externally or a mc within the program and I need to fit it into a certain area (width x height) but keep the aspect ratio the same or as photoshop calls it “constrain proportions”. I’ve done this with fancy and not so fancy formulas and equations, but finally I had it and created a simple function that would do it every time. Figured it was worth sharing cause if I’ve googled it before then others most likely will too!

This is more than just setting the width and height of an object, because that way the image is easily skewed and the natural proportions are messed up. If you want to just use scale you need to know the dimensions of the image being resized, and that’s just not scalable (no pun intended).

What we have to do is to do both. Assign the width and height to skew it, and then scale it to correct the proportion. So if we want to resize an image when we don’t know it’s current size to fit into a 300 pixel square we set the width and height of that image to 300 and then a bit of logic that can be summed up in one line:

1
mc.scaleX < mc.scaleY ? mc.scaleY = mc.scaleX : mc.scaleX = mc.scaleY;

That says if the x scale is larger than the y scale set the x to the y scale amount, and vice versa. It’s basically setting both scales to the smaller of the two. This works because we don’t know the original size of the image, but actionscript does. scaleX and scaleY are ratios of the current width and height to the originals. A little complicated I know, but that’s why I’ve made the function below. I know how to use it and now I don’t have to think about skewing and then scaling back to keep my aspect ratio or proportion. You should see how to use it just by looking at it:

1
resizeMe(mc:MovieClip, maxW:Number, maxH:Number=0, constrainProportions:Boolean=true)

Pass in the movieClip you want to resize, and the size you want it to fit into. So with the same example above, just do

1
resizeMe(image, 300);

Example

Here’s an interactive example to show what I mean. It loads an external image and you click and drag the mouse around to resize it. To toggle whether you want to constrain proportions use the space bar. Type a url to any image you want to test it with and press load, or hit ‘enter’.

Get Adobe Flash player

Here’s a screenshot of me playing with a photo in here NOT constraining proportions.
constrain proportions jpg

Source (AS3)

The resizing function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//The resizing function
// parameters
// required: mc = the movieClip to resize
// required: maxW = either the size of the box to resize to, or just the maximum desired width
// optional: maxH = if desired resize area is not a square, the maximum desired height. default is to match to maxW (so if you want to resize to 200x200, just send 200 once)
// optional: constrainProportions = boolean to determine if you want to constrain proportions or skew image. default true.
function resizeMe(mc:MovieClip, maxW:Number, maxH:Number=0, constrainProportions:Boolean=true):void{
    maxH = maxH == 0 ? maxW : maxH;
    mc.width = maxW;
    mc.height = maxH;
    if (constrainProportions) {
        mc.scaleX < mc.scaleY ? mc.scaleY = mc.scaleX : mc.scaleX = mc.scaleY;
    }
}

The full source

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
var defaultUrl:String = "http://blog.circlecube.com/wp-content/uploads/2008/11/circlecubelogo4.png";
var image:MovieClip = new MovieClip();
loadImage();
function loadImage(url:String=""):void {
    if (url == "" || url == defaultToLoadString) url = defaultUrl;
    //clear image
    image.visible = false;
    image = new MovieClip();
    //add image
    var ldr:Loader = new Loader();
    var urlReq:URLRequest = new URLRequest(url);
    trace("loading image: " + url);
    ldr.load(urlReq);
    ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, imageCompleteHandler);
    image.addChild(ldr);
    addChild(image);
}

function imageCompleteHandler(e:Event):void {
    resizeMe(image, stage.stageWidth)
}

//The resizing function
// parameters
// required: mc = the movieClip to resize
// required: maxW = either the size of the box to resize to, or just the maximum desired width
// optional: maxH = if desired resize area is not a square, the maximum desired height. default is to match to maxW (so if you want to resize to 200x200, just send 200 once)
// optional: constrainProportions = boolean to determine if you want to constrain proportions or skew image. default true.
function resizeMe(mc:MovieClip, maxW:Number, maxH:Number=0, constrainProportions:Boolean=true):void{
    maxH = maxH == 0 ? maxW : maxH;
    mc.width = maxW;
    mc.height = maxH;
    if (constrainProportions) {
        mc.scaleX < mc.scaleY ? mc.scaleY = mc.scaleX : mc.scaleX = mc.scaleY;
    }
}

var constrainOn:Boolean = true;
var isPressed:Boolean = false;

stage.addEventListener(MouseEvent.MOUSE_MOVE, moved);
stage.addEventListener(MouseEvent.MOUSE_DOWN, pressed);
stage.addEventListener(MouseEvent.MOUSE_UP, released);
stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownListener);

function keyDownListener(e:KeyboardEvent) {
    if (e.keyCode == 32){//spacebar
        toggled(e);
    }
    if(e.keyCode == 13){//enter
        loadImagePress(e);
    }
}

function moved(e:Event):void{
    if (isPressed)
    resizeMe(image, mouseX, mouseY, constrainOn);
}
function pressed(e:MouseEvent):void{
    isPressed = true;
    moved(e);
}
function released(e:MouseEvent):void{
    isPressed = false;
}
function toggled(e:Event):void{
    constrainOn = !constrainOn;
    moved(e);
}
var defaultToLoadString:String = "type url of image to load";
toLoad.text = defaultToLoadString;
toLoad.addEventListener(FocusEvent.FOCUS_IN, toLoadFocus);
toLoad.addEventListener(FocusEvent.FOCUS_OUT, toLoadBlur);
function toLoadFocus(e:FocusEvent):void{
    if (toLoad.text == defaultToLoadString)
    toLoad.text = "";
}
function toLoadBlur(e:FocusEvent):void{
    if (toLoad.text == "")
    toLoad.text = defaultToLoadString;
}
loadBtn.addEventListener(MouseEvent.CLICK, loadImagePress);
function loadImagePress(e:Event):void{
    loadImage(toLoad.text);
}

Download

constrainProportions.fla

And as usual, let me know if you’ve got any comments questions or suggestions! Thanks,

Overview

Earlier I wrote a tutorial article about asfunction in as2. Now that I’ m into as3, surprise surprise asfunction has been depreciated and now to replace it is the LINK TextEvent. Dispatched when a user clicks a hyperlink in an HTML-enabled text field, where the URL begins with “event:”. The remainder of the URL after “event:” will be placed in the text property of the LINK event.
This differs from the asfunction method in that we must add an event listener (addEventListener) to the textField object, the event listener specifies which function will be called in the event of a link click and there is no way to send arguments along with the event (AFAIK). But it’s easy enought to use one link event function for all your link events and put in a simple switch statement to coordinate the desired results…

Steps

  1. Use event in the href attribute. (href=”event:eventText”)
  2. Listen to the textField (theTextField.addEventListener(TextEvent.LINK, linkHandler);)
  3. Handle the link event (function linkHandler(linkEvent:TextEvent):void {…)

Example

Get Adobe Flash player

Actionscript

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
var myHTMLText:String = "Sample text in an html enabled text box.\n"+
"Here's a normal link to <a href='http://bloc.circlecube.com'>circlecube</a> putting the link into the href attribute like normal!\n"+
"<a href='event:clickLink'>Click this circlecube</a>, to see the text event link in action! \n"+
"And some more links that don't go anywhere, but they do call functions in actionscript. "+
"Click this to move <a href='event:moveUp'>UP</a>, click me move back "+
"<a href='event:moveDown'>DOWN</a>.\n"+
"Also, one last example <a href='event:testing'>click for a trace test</a>";

//create and initialize css
var myCSS:StyleSheet = new StyleSheet();
myCSS.setStyle("a:link", {color:'#0000CC',textDecoration:'none'});
myCSS.setStyle("a:hover", {color:'#0000FF',textDecoration:'underline'});
myHTML.styleSheet = myCSS;
myHTML.htmlText = myHTMLText;

myHTML.addEventListener(TextEvent.LINK, linkHandler);

function linkHandler(linkEvent:TextEvent):void {
    switch (linkEvent.text) {
        case "clickLink":
            clickLink();
            break;
        case "moveUp":
            moveUp();
            break;
        case "moveDown":
            moveDown();
            break;
        default:
            giveFeedback(linkEvent.text);
    }  
}
//function to be called from html text
function clickLink():void {
    giveFeedback("Hyperlink clicked!");
    var myURL:String = "http://blog.circlecube.com";
    var myRequest:URLRequest = new URLRequest(myURL);
    try {            
        navigateToURL(myRequest);
    }
    catch (e:Error) {
        // handle error here
        giveFeedback(e);
    }
}

//another function to be called from html text, recieves one argument
function moveUp():void {
    feedback.y -= 10;
    giveFeedback("Up");
}

//a simple trick to allow passing of multiple arguments
function moveDown():void {
    feedback.y += 10;
    giveFeedback("Down");
}

function giveFeedback(str):void {
    trace(str);
    feedback.appendText(str +"\n");
    feedback.scrollV = feedback.maxScrollV;
}

Source

Download the fla here: textlinkevent_as3.fla