Feb 24, 2011
Posted on Feb 24, 2011 in Hints and Tips | 10 comments
Twice a month, we revisit some of our readers’ favorite posts from throughout the history of Activetuts+. This tutorial was first published in October, 2009 (and led to my inviting Michael to be Activetuts+ Tech Editor!)
This is a really simple technique which you can use to add the illusion of depth to any side-scroller game. Whilst I’m explaining how it’s achieved, we’ll also take a look at making infinitely repeating backgrounds.
Introduction
You can see the basic parallax scrolling effect at work in the demo. By adjusting the speeds at which certain objects scroll, we can change how near or far away they appear to be.
This tutorial will explain how to code the effect, as well as how to make the game’s camera appear to follow the car. Lastly, it’ll explain how to create infinitely repeating backgrounds, just like in Scooby Doo.
Step 1: The Setup
If you’re using Flash, create a new ActionScript 3.0 Flash file. Set the size of the stage to be whatever you like; I’ve chosen the default 550 by 400 pixels.
If you’re not using the Flash IDE, don’t worry; just create a new AS3 project. The zip file contains a SWC with all my graphics, so you can use those just by adding it to your library. Skip all the drawing steps if you do so.
If you are using the Flash IDE but you don’t want to draw anything, the zip also contains a FLA file containing all my MovieClips
Step 2: Draw a Car
Create a new MovieClip symbol and draw a car. You can animate it if you like. Here’s mine:
Try to centre the car so that its registration point (the little cross) is about half-way along. This will make it easier for the camera to follow it later.
Step 3: Export Your Car for ActionScript
Right-click your car symbol in the Library and select Properties:
Give your car a Class (Car will do) and check the Export for ActionScript box (this lets us access the car using code). Also, check the Export in first frame box (otherwise, we’ll have to make a preloader).
Step 4: Draw a Road
Create another new symbol, but this time draw a road:
Make it wider than the stage, but unlike the car, align the registration point with the left edge of the road. This will help later on, when we need to turn it into a repeating pattern.
Just like you did for the car, give the road a Class, export it for ActionScript and export it in the first frame.
Step 5: Create the Document Class
Create a new AS file and paste the following code into it:
package
{
import flash.display.MovieClip;
public class ParallaxDemo extends MovieClip
{
public function ParallaxDemo()
{
}
}
}
Save this as ParallaxDemo.as, in the same folder as your FLA (or as your project, if you’re not using the IDE).
If you’re using the IDE, be sure to set this as your document class in the Properties Panel of your document:
Step 6: Set Up the Car and the Road
Create new instances of your car and road in the AS file: (lines 6, 7, 11, 12)
package
{
import flash.display.MovieClip;
public class ParallaxDemo extends MovieClip
{
public var car:Car;
public var road:Road;
public function ParallaxDemo()
{
car = new Car();
road = new Road();
}
}
}
Step 7: Position the Car and the Road
If you’re using my graphics, you can just copy the following code (lines 14-17:
package
{
import flash.display.MovieClip;
public class ParallaxDemo extends MovieClip
{
public var car:Car;
public var road:Road;
public function ParallaxDemo()
{
car = new Car();
road = new Road();
car.x = 275.0;
car.y = 235.0;
road.x = 0.0;
road.y = 294.0;
}
}
}
Otherwise, you’ll need to figure out where your car and road should be placed at the start. Create a new Layer in your FLA’s timeline, then make it into a Guide Layer by right-clicking it and selecting Guide. Flash will ignore anything you do in this layer when it creates a SWF, so drag your car and road symbols here.
Make sure the left edge of your road is aligned with the left edge of the stage, and that the car is roughly in the centre (horizontally). Then adjust them so that they fit together:
Now take my code from above and adjust it to match the x- and y- coordinates of your car and road. By clicking on your car or road, you’ll be able to see these values in the Properties panel.
Step 8: Add your Symbols to the Stage
If you test your movie now, you’ll see nothing. We need to addChild() the car and road to the stage:
public function ParallaxDemo()
{
car = new Car();
road = new Road();
car.x = 275.0;
car.y = 235.0;
road.x = 0.0;
road.y = 294.0;
stage.addChild( road );
stage.addChild( car );
}
(Make sure you add the road first, or it’ll cover the car!)
Test your movie now, and it should look like this:
Great! Well, OK, it’s nothing spectacular yet. But now the setup’s out of the way, we can make this more interesting. For starters, let’s get this car moving…
Step 9: Add an ENTER_FRAME Event Listener
Alter your document class to add an event listener to be triggered on each frame: (lines 4, 23, 26-29)
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class ParallaxDemo extends MovieClip
{
public var car:Car;
public var road:Road;
public function ParallaxDemo()
{
car = new Car();
road = new Road();
car.x = 275.0;
car.y = 235.0;
road.x = 0.0;
road.y = 294.0;
stage.addChild( road );
stage.addChild( car );
addEventListener( Event.ENTER_FRAME, onEnterFrame );
}
public function onEnterFrame( evt:Event ):void
{
}
}
}
If you kept the default frame rate of 12fps, the onEnterFrame() function will be called every 1/12th of a second.
Step 10: Move That Car!
If we keep increasing the car’s x-position…
public function onEnterFrame( evt:Event ):void
{
car.x = car.x + 10;
//if you're up for a challenge, try adding basic
//keyboard controls to let the player accelerate
//and decelerate.
}
…we can make the car move forwards…
…right off the edge of the screen!
Step 11: Follow That Car!
This is hardly ideal; after a few seconds we can’t even see the car any more. So let’s make the “camera” appear to follow the car.
What exactly does this mean? Well, basically we need the car to stay in the same place, while the road appears to move backwards.
That means we could do something like this:
public function onEnterFrame( evt:Event ):void
{
road.x = road.x - 10;
}
…but this would just complicate things later. For example, imagine if we wanted to add other cars to the road, or powerups, or oil slicks, or anything at all; we’d have to move every single one of them backwards in the onEnterFrame() function.
No, there is a much simpler technique we can use. Instead of addChild()-ing the car and road to the stage, we create a new object, addChild() them to that, and then move this object backwards in the onEnterFrame() function.
It sounds more complicated than it is. Let me show you the actual code:
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class ParallaxDemo extends MovieClip
{
public var car:Car;
public var road:Road;
public var roadContainer:MovieClip;
public function ParallaxDemo()
{
car = new Car();
road = new Road();
car.x = 275.0;
car.y = 235.0;
road.x = 0.0;
road.y = 294.0;
roadContainer = new MovieClip();
roadContainer.addChild( road );
roadContainer.addChild( car );
stage.addChild( roadContainer );
addEventListener( Event.ENTER_FRAME, onEnterFrame );
}
public function onEnterFrame( evt:Event ):void
{
car.x = car.x + 10;
roadContainer.x = roadContainer.x - 10;
}
}
}
In lines 9 and 21 we create a new, blank MovieClip called roadContainer. Flash automatically sets its x and y values to 0.
In lines 22 and 23 we add the road and the car to the roadContainer, instead of the stage. In line 25 we add the roadContainer itself to the stage – and since the car and road are now added to the roadContainer, this lets us see them on the stage.
Line 32 is the most important part. Here, we move the roadContainer backwards by the same amount that we just moved the car forwards. This means that everything inside the roadContainer gets moved left by 10 pixels, but since the car has just been moved 10 pixels to the right, it stays in the centre of the screen.
It’s a bit like running up the down escalator. If you walk up at the same speed that it’s moving down, then to a person standing on the stairs next to you, you don’t seem to be moving.
The overall effect:
The car stays in the centre! Great. Well, great apart from the gaping white hole. But we’ll get to that. Now if you want to add more cars to the road, all you have to do is addChild() them to the roadContainer.
Step 12: Improve the Following
The trouble with just moving the whole container backwards a little bit every frame is that it’s not very flexible. What if the player uses a powerup to teleport the car 100 pixels forwards instead of 10? What if we want to make the camera centre on a different car?
When the SWF first loads, the car’s x-position is 275, and the roadContainer’s x-position is 0. How do they each change over time?
- Start: car.x is 275, roadContainer.x is 0
- Frame 1: car.x is 285, roadContainer.x is -10
- Frame 2: car.x is 295, roadContainer.x is -20
- Frame 3: car.x is 305, roadContainer.x is -30
Do you see a general rule connecting the two? If not, check this out:
- Start: car.x is 275, roadContainer.x is 275 – 275
- Frame 1: car.x is 285, roadContainer.x is 275 – 285
- Frame 2: car.x is 295, roadContainer.x is 275 – 295
- Frame 3: car.x is 305, roadContainer.x is 275 – 305
The connection is a little more obvious now! Let’s put it into code:
public function onEnterFrame( evt:Event ):void
{
car.x = car.x + 10;
roadContainer.x = 275 - car.x;
}
You can do what you like with the car now. Speed it up, teleport it forwards a random number of pixels, stop it moving – whatever! The camera will still follow it.
And if you want to make the camera follow a different object, just replace car.x with otherObject.x in the line we just changed.
Step 13: Extend the Road
Time to fix the endless white void of nothingness at the end of the road.
The simplest way to make the road longer is just to add another instance of the road symbol to the right of our existing symbol, like so: (lines 9, 22, 23, 27)
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class ParallaxDemo extends MovieClip
{
public var car:Car;
public var road:Road;
public var road2:Road;
public var roadContainer:MovieClip;
public function ParallaxDemo()
{
car = new Car();
road = new Road();
road2 = new Road();
car.x = 275.0;
car.y = 235.0;
road.x = 0.0;
road.y = 294.0;
road2.x = road.x + road.width;
road2.y = road.y;
roadContainer = new MovieClip();
roadContainer.addChild( road );
roadContainer.addChild( road2 );
roadContainer.addChild( car );
stage.addChild( roadContainer );
addEventListener( Event.ENTER_FRAME, onEnterFrame );
}
public function onEnterFrame( evt:Event ):void
{
car.x = car.x + 10;
roadContainer.x = 275 - car.x;
}
}
}
Here’s how mine looks when it’s run:
Oh dear. Better fix that gap.
Step 14: Mind the Gap
(If you’re not drawing your own graphics, skip to Step 17.)
The problem is in line 22 of the above code, road2.x = road.x + road.width. The road’s width value must be slightly larger than my road actually appears to be.
Even if your road doesn’t have the same problem, it still might not fit together perfectly. So head back to your FLA and drag another Road symbol from the library to your Guide layer.
Make sure it’s got the same y-position as the first road segment, then move it along horizontally until there’s no gap:
Step 15: Tweak the Join
If the edges of your two symbols don’t quite join together neatly, double-click one of them. You’ll be able to edit it and immediately see how the changes you make affect the other:
Use this trick to adjust the edges of the symbol so that the join is clean.
Step 16: Work Out the Breadth
Instead of using road.width to figure out where the second road segment should be placed, we’ll use a number I call the breadth.
To find this number for your road, just take the x-position of your right-most road symbol (in your Guide layer), and subtract the x-position of your left-most road symbol.
All you’re doing here is figuring out how many pixels apart your two road segments have to be in order to get the same perfect join you just created in Flash.
Step 17: Add a Breadth Variable
Create a new Number variable, roadBreadth, and set its value to the number you worked out in the previous step: (If you’re using my graphics, that number is 653.7.)
public class ParallaxDemo extends MovieClip
{
public var car:Car;
public var road:Road;
public var road2:Road;
public var roadContainer:MovieClip;
public var roadBreadth:Number;
public function ParallaxDemo()
{
car = new Car();
road = new Road();
road2 = new Road();
roadBreadth = 653.7;
Step 18: Replace Width with Breadth
Replace the line:
road2.x = road.x + road.width;
with:
road2.x = road.x + roadBreadth;
Now test it out. There should be no gap:
Great! We still run into the endless white void, though…
Step 19: Make the Background Repeat Infinitely
We could create a road3 and a road4 and a road5 and so on, positioning them each to the right of the one before them, but no matter how many segments we created, the car would reach the end of them eventually.
For a better solution, think back to when you were a child. Did you ever play that game where you pretend the floor is made of lava, but you have to get to the other end of the room somehow? (If not, heck, go play it now, it’s great fun.)
I don’t know about you, but in my house, sofa cushions were considered to be lava-resistant, able to be used as stepping-stones. We only had a couple, which wasn’t enough to reach the end of the room – but eventually I figured out how to make them reach further.
I’d lay the two cushions down to make a short path, and walk over to the second one. Then, I’d pick up the one behind me, drop it in front of me, and step across to it. By repeatedly picking up the one behind me and moving it in front of me, I could get to anywhere I pleased.
We can use the same technique to make the road last forever, without having to use more than two segments. All we have to do is detect when a road segment is “behind” the camera, and move it in front of it.
What do I mean by “behind” the camera? I mean that the right-hand edge of the segment is off the left-hand edge of the stage. We can use this if-statement to check that:
if ( road.x + roadBreadth + roadContainer.x < 0 )
{
//road is behind the camera
}
Curious as to why this works? If not, skip to the next step. Otherwise, let me explain:
- road.x is how many pixels to the right the left-hand edge of road is from the left-hand edge of roadContainer
- road.x + roadBreadth is how many pixels to the right the right-hand edge of road is from the left-hand edge of roadContainer
- roadContainer.x is how many pixels to the right the left-hand edge of roadContainer is from the left-hand edge of the stage (since roadContainer is constantly moving to the left, this will usually be negative)
- So, ( road.x + roadBreadth + roadContainer.x ) is how many pixels to the right the right-hand edge of road is from the left-hand edge of the stage.
Phew! OK, I'll admit, that's pretty confusing. If you'd like a deeper explanation, feel free to ask in the comments
Step 20: Move the Road in Front of the Camera
Now that we can tell when the road segment is behind the camera, we need to move it in front of the camera again.
If we moved the road to the right by roadBreadth number of pixels, it would be in the exact same place as the other road segment. So, we need to move it to the right by twice that amount:
if ( road.x + roadBreadth + roadContainer.x < 0 )
{
road.x = road.x + (2 * roadBreadth);
}
Put that in your onEnterFrame() function, and test it out:
As you can see, one road segment is repeating, but the other isn't yet.
Step 21: Move the Other Road Segment
We can just copy the above code for our other road segment, road2:
public function onEnterFrame( evt:Event ):void
{
car.x = car.x + 25;
roadContainer.x = 275 - car.x;
if ( road.x + roadBreadth + roadContainer.x < 0 )
{
road.x = road.x + (2 * roadBreadth);
}
if ( road2.x + roadBreadth + roadContainer.x < 0 )
{
road2.x = road2.x + (2 * roadBreadth);
}
}
Test it out again:
Fantastic! An infinitely looping, side-scrolling background
Now to create the actual parallax effect...
Step 22: Create Rolling Hills
(Skip this step if you're using my graphics.)
We're going to need a repeating background to show off the parallax scrolling. I've chosen hills, but you could make buildings, forests, alien sculptures - anything you like!
There are a few tricks you can use to make what you draw look like it's further away than the car:
- Use duller colours (for instance, a darker shade of green for your grass)
- Draw less detail (no individual tufts of grass)
- Add a "blurred" effect to the edges (because the camera is focused on the car)
Follow the same basic steps we used for drawing the road:
- Make the symbol wider than the stage
- Align the symbol so that the registration point is at the left-hand edge
- Give it a class name, export it for ActionScript, and export it in the first frame
- Tweak the join to make sure two symbols fit together neatly
- Figure out the "breadth" of the symbol
Here's mine:
Step 23: Code the Hills
The code regarding the hills is almost exactly the same as the code we just wrote regarding the roads. Have a go at writing it yourself. I've pasted my AS file with all the new additions below, so you can refer to it if you like:
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class ParallaxDemo extends MovieClip
{
public var car:Car;
public var road:Road;
public var road2:Road;
public var roadContainer:MovieClip;
public var roadBreadth:Number;
public var hills:Hills;
public var hills2:Hills;
public var hillsBreadth:Number;
public var hillsContainer:MovieClip;
public function ParallaxDemo()
{
car = new Car();
road = new Road();
road2 = new Road();
roadBreadth = 653.7;
hills = new Hills();
hills2 = new Hills();
hillsBreadth = 890.5;
car.x = 275.0;
car.y = 235.0;
road.x = 0.0;
road.y = 294.0;
road2.x = road.x + roadBreadth;
road2.y = road.y;
hills.x = 0;
hills.y = 14.5;
hills2.x = hills.x + hillsBreadth;
hills2.y = hills.y;
roadContainer = new MovieClip();
roadContainer.addChild( road );
roadContainer.addChild( road2 );
roadContainer.addChild( car );
hillsContainer = new MovieClip();
hillsContainer.addChild( hills );
hillsContainer.addChild( hills2 );
stage.addChild( hillsContainer );
stage.addChild( roadContainer );
addEventListener( Event.ENTER_FRAME, onEnterFrame );
}
public function onEnterFrame( evt:Event ):void
{
car.x = car.x + 10;
roadContainer.x = 275 - car.x;
if ( road.x + roadBreadth + roadContainer.x < 0 )
{
road.x = road.x + (2 * roadBreadth);
}
if ( road2.x + roadBreadth + roadContainer.x < 0 )
{
road2.x = road2.x + (2 * roadBreadth);
}
hillsContainer.x = 275 - car.x;
if ( hills.x + hillsBreadth + hillsContainer.x < 0 )
{
hills.x = hills.x + (2 * hillsBreadth);
}
if ( hills2.x + hillsBreadth + hillsContainer.x < 0 )
{
hills2.x = hills2.x + (2 * hillsBreadth);
}
}
}
}
(The new lines are 12-15, 24-26, 35-38, 45-47, 49, and 67-75. How did you do?)
Here is the result:
You might be wondering why I've bothered creating a hillsContainer. If so, then nicely spotted! We could just addChild() the hills to the roadContainer - but creating a new container for the background is what lets us create the actual parallax effect.
Step 24: The Actual Parallax Effect
The effect only requires changing one line of code:
hillsContainer.x = 275 - car.x;
into this:
hillsContainer.x = (275 - car.x) * 1/5;
This makes the hills scroll at 1/5th the speed of the road and car.
It looks like this:
You don't have to use 1/5; make this value larger or smaller until the speed feels right to you.
Why does this work? Well, remember that we see things in a cone of vision; the further away something is the more of it we can see. So if we walk past two objects of the same size, but one is further away, the closer of the two will appear to move faster, like so:
Let's add another background layer, even further away than the hills.
Step 25: Create Mountains
This is exactly the same as creating the road and the hills, so I'm not even going to paste the code this time! All I'll do is post a picture of my mountains..
..tell you that my mountains' breadth is 751.5, x is 0 and y is 63.0; remind you to create a new mountainContainer MovieClip; and let you know that my mountains scroll at 1/16th the speed of my road.
Oh, and show you the result:
Step 26: Create the Sky
The sky is nice and easy. Since it's really far away, it scrolls so slowly that it looks like it's barely scrolling at all. Clouds and birds move, of course, and the Sun rises and sets, but none of this is due to any parallax scrolling effect. This means we don't have to make anything in the sky scroll!
(The exception to this is if the camera is travelling really, really fast - like, the speed of an aeroplane or rocket. Even then, be sure to make it scroll very slowly.)
So, no need to worry about breadth here, or creating an infinitely repeating image. It's still a good idea to make a skyContainer, though, just to keep things consistent. My sky is just a blue rectangle:
If you place it at x=0, y=0 it'll cover the whole stage. Here's what it looks like in the SWF:
Step 27: Create a Big Tree in the Foreground
We've created a lot of background objects, but nothing closer to the camera than the car. As I'm sure you realise, such an object would have to scroll faster than the roadContainer, so let's try this.
For my foreground object, I've drawn a tree:
The tree's a little different from the other objects we've made so far because it's not made to loop - it stands alone, it won't join to another tree standing next to it. This means that we only ever need one tree on screen at any one time (especially since it's so big!)
So we only need one Tree object in the code as well. Write the code for this object. If you're using my graphics, the starting x-position will be 780.0 and the y-position will be 175.0.
Since the tree will scroll, we still need a treeContainer, and we still need a treeBreadth. However, this time, the treeBreadth just controls the number of pixels between each tree. I've used a nice round 1000.0 for mine.
Step 28: Scroll the Tree
Since there's only one tree, the scrolling code is much simpler:
treeContainer.x = (275 - car.x) * 3;
if ( tree.x + treeBreadth + treeContainer.x < 0 )
{
tree.x = tree.x + (2 * treeBreadth);
}
Nothing complicated
Just note that it scrolls three times faster than the road. Here is the final result:
Congratulations! You've created a dynamically scrolling camera, infinitely repeating backgrounds, and a pseudo-3D parallax effect
Further Ideas to Try
Here are few more things you can do with the same code:
If you're creating a shoot-'em-up and you'd like all your explosions to appear closer to the camera than your enemies, simply create a new explosionsContainer, addChild() any explosions to that, and make it scroll at the same speed as the enemiesContainer.
Put the player's score, their lives counter, the mute and pause buttons, and any other parts of your game's interface into a single container. Place this container in front of all other containers, but don't make it scroll. This is an easy way to keep a game's camera and assets separate from its interface.
Try having one container stay still while making the containers in front of it and behind it scroll in opposite directions. This creates a cool rotation effect, as seen about five minutes into this clip from Disney's Snow White!
Conclusion
Thanks for reading this tutorial; I hope you enjoyed it. If anything was unclear at all, or if you'd like to ask any questions about the effect, please post a comment below.
Speaking of comments, if you create anything using this tutorial, I'd love it if you posted a link so I could see it



View full post on Activetuts+
Feb 22, 2011
Posted on Feb 22, 2011 in Hints and Tips | 0 comments
During this tutorial we’re going to tie math and design together. We’ll explore Branden Hall and Joshua Davis’ HYPE framework and create generative art from code.
Final Result Preview
Let’s take a look at the final result we will be working towards:
Step 1: Project Structure
Before diving head-long into the code let’s take a brief moment to familiarize ourselves with the project files.
Inside the source .zip file you will find a folder for each significant step, so that you can see exactly what changes have been made. Also, you will find a folder called Base, make a copy of this folder as this is will serve as our starting point.
Inside the Base folder we have a bin folder where our SWF will be published. A src folder which contains our ActionScript 3 and Flash Files and lastly a lib folder where we will store the HYPE framework’s SWC files.
Step 2: Getting HYPE
Next up, we need to grab the latest version of the HYPE framework from its home at www.hypeframework.org.
Once the download has completed, open the .zip file. You’ll find two SWC files named hype-framework.swc and hype-extended.swc. Copy both of these to your Base\lib folder.
These SWC files are essentially a collection of source files for the framework, all rolled in to one file for ease.
Step 3: Adding SWCS to Flash
The final step needed to get everything up and running is to tell Flash to look for the two new SWC files when we compile the movie, otherwise it will throw a whole bunch of errors our way, not nice!
Open the Main.fla inside the Base\src folder, then choose File, Publish Settings. Select the Flash tab as shown, in the new window that opens select the Library Path tab.
Press the “Browse TO SWC” File button and proceed to add both SWC files to the Flash file. Once this is complete it’s time to start adding some code!
Step 4: Init HYPE
Open up the Main.as source file in your chosen editor. Add the following private properties and the initHype() method:
public class Main extends MovieClip
{
// private properties
private var bitmapCanvas:BitmapCanvas;
private var clipContainer:Sprite;
private var objectPool:ObjectPool;
/**
* constructor
*/
public function Main()
{
// inits the Hype framework
initHype();
}
/**
* initiation of the Hype members we will be using and configuration prior
* to running the animation
*/
private function initHype():void
{
// the clipContainer is used as a parent for all of our objects
clipContainer = new Sprite();
addChild(clipContainer);
}
}
In the next few steps we’ll be looking at each of these objects we’ve added as private properties, starting with the clipContainer Sprite.
As our design is going to have over a hundred objects all moving around the screen at once, we’re going to need something to house them all – just adding them to the Stage will become problematic further down the line. The answer is to create a regular AS3 Sprite to act as a parent.
Step 5: The BitmapCanvas
The first real part of HYPE, the BitmapCanvas can be thought of as a Sprite or better still, a Bitmap/BitmapData to which we will be painting our objects, each frame, like a painters canvas.
We create it just below the clipContainer code and define it with a width and height to match the Stage. We add it to the Stage but also tell it to startCapture(clipContainer, true), this simply tells the BitmapCanvas to take a snapshot of the clipContainer each frame. For now though, keep this commented out!
/**
* initiation of the Hype members we will be using and configuration prior
* to running the animation
*/
private function initHype():void
{
// the clipContainer is used as a parent for all of our objects
clipContainer = new Sprite();
addChild(clipContainer);
// think of the BitmapCanvas as an empty space we will 'paint'
// every frame with new image data
bitmapCanvas = new BitmapCanvas(stage.stageWidth, stage.stageHeight);
//bitmapCanvas.startCapture(clipContainer, true);
addChild(bitmapCanvas);
}
}
Step 6: The ObjectPool
If you have worked with games you’ve probably come across the concept of an ObjectPool. As creating new objects is too much of a hit on the processor we create a pool of a specified amount of objects before the game or application begins. We would then use the objects from this pool and upon running out we would recycle and reuse them all again, which avoids creating new objects. This is commonly used for bullets/lasers in games and the same logic is used in HYPE.
If you take a look at the Main.fla Library in Flash you will see I’ve created a MovieClip called circleShape and given it the Linkage Identifier of circleShape so we can create multiple copies of this object with code; this is what our ObjectPool will house.
Add the ObjectPool below the BitmapCanvas code, like so:
/**
* initiation of the Hype members we will be using and configuration prior
* to running the animation
*/
private function initHype():void
{
// the clipContainer is used as a parent for all of our objects
clipContainer = new Sprite();
addChild(clipContainer);
// think of the BitmapCanvas as an empty space we will 'paint'
// every frame with new image data
bitmapCanvas = new BitmapCanvas(stage.stageWidth, stage.stageHeight);
//bitmapCanvas.startCapture(clipContainer, true);
addChild(bitmapCanvas);
// create a collection of 10 objects and store them in an ObjectPool
// for use in the animation
objectPool = new ObjectPool(circleShape, 10);
}
Step 7: Creating Objects Using ObjectPool.request();
Now we have our core players setup, the clipContainer, the BitmapCanvas and the ObjectPool with its 10 clips, it’s time to start making things move.
To get an item from the ObjectPool we can use objectPool.request(); which will give us a circleShape MovieClip from the Flash Library to work with.
The ObjectPool also gives us the objectPool.onRequestObject() method which is a handy way to assign properties of a clip each time we request one. Add the following below where you instantiated the ObjectPool:
// create a collection of 10 objects and store them in an ObjectPool
// for use in the animation
objectPool = new ObjectPool(circleShape, 10);
// each time we request a new shape from the pool
// it will perform the following
objectPool.onRequestObject = function(clip:MovieClip):void
{
clip.x = Math.random() * stage.stageWidth;
clip.y = Math.random() * stage.stageHeight;
clipContainer.addChild(clip);
}
Step 8: See the Result
With that new code added, every time we request an object from the pool by using objectPool.request() it will create a circleShape. Add it to the clipContainer and position it randomly on the screen. You can test this by amending the constructor to look like the following:
/**
* constructor
*/
public function Main()
{
// inits the Hype framework
initHype();
objectPool.request();
}
If all went well you should have a single, lonely circle on the screen.
Step 9: Requesting all Objects at Once
Do you remember we set the ObjectPool size to 10? Well we’re going to up the ante and increase this to 100 objects by changing the following:
// create a collection of 10 objects and store them in an ObjectPool
// for use in the animation
objectPool = new ObjectPool(circleShape, 100);
We can amend the earlier request statement to read as requestAll() like this:
/**
* constructor
*/
public function Main()
{
// inits the Hype framework
initHype();
objectPool.requestAll();
}
Now we should have 100 circles scattered over the screen’s area.
Step 10: Adding FixedVibrations
Now we have our 100 circleShapes distributed around the screen it’s time to make our design come to life by adding movement.
Let’s start by applying a FixedVibration to the alpha and scale properties of each clip. We can use the ObjectPools onRequestObject method to implement it as shown:
// create a collection of 10 objects and store them in an ObjectPool
// for use in the animation
objectPool = new ObjectPool(circleShape, 100);
// each time we request a new shape from the pool
// it will perform the following
objectPool.onRequestObject = function(clip:MovieClip):void
{
clip.x = Math.random() * stage.stageWidth;
clip.y = Math.random() * stage.stageHeight;
// add a FixedVibration to the alpha and scale properties of each circleShape when requested
var alphaVib:FixedVibration = new FixedVibration(clip, "alpha", 0.9, 0.05, 0.5, 1.5, false);
var scaleVib:FixedVibration = new FixedVibration(clip, "scale", 0.9, 0.05, 0.05, 0.8, false);
alphaVib.start();
scaleVib.start();
clipContainer.addChild(clip);
}
Let’s have a closer look at the FixedVibration objects we created. Each FixedVibration object we create takes 7 parameters, respectively they are as follows:
- The object to apply the
FixedVibration to, in our case our circleShape called “clip”.
- The property to apply the
FixedVibration to, this time we’re working with the alpha and scale properties.
- The third parameter is the
Spring of the FixedVibration, the higher the number the more ‘springy’ the movement. A value between 0 and 1 will work best.
- Next up is the
Ease of the vibration, the lower the value the quicker it will slide between the following two values. A value between 0 and 1 will work best.
- The minimum value is up next, this will be the lowest the the vibration will hit.
- Similarly, the maximum value will be the maximum value the vibration will hit.
- Finally, the last parameter is relative, default this to
false.
So how do all of these fit together? Let’s look at how the scale property is affected by the FixedVibration. It’s given Min and Max values of 0.05 and 0.8, the Spring value is pretty high at 0.9 and the Ease is pretty low at 0.05 making it scale erratically and fast.
Have a play around with these values to get a feel for how they influence the movement.
When we test our Flash file we should get something like this:
Step 11: Adding a VariableVibration
Very similar to the FixedVibration, the VariableVibration will adjust a property of an object with a value that fluctuates. The difference being that the VariableVibration isn’t linear as the name suggests.
Amend your code as follows to place the clips to the center of the Stage, only this time we’ll apply a VariableVibration to the x and y values to start seeing some movement!
// each time we request a new shape from the pool
// it will perform the following
objectPool.onRequestObject = function(clip:MovieClip):void
{
clip.x = stage.stageWidth/2;
clip.y = stage.stageHeight/2;
// add a VariableVibration for the x/y movement of each circleShape
var xVib:VariableVibration = new VariableVibration(clip, "x", 0.97, 0.03, 40);
var yVib:VariableVibration = new VariableVibration(clip, "y", 0.97, 0.03, 40);
xVib.start();
yVib.start();
// add a FixedVibration to the alpha and scale properties of each circleShape when requested
var alphaVib:FixedVibration = new FixedVibration(clip, "alpha", 0.9, 0.05, 0.5, 1.5, false);
var scaleVib:FixedVibration = new FixedVibration(clip, "scale", 0.9, 0.05, 0.05, 0.8, false);
alphaVib.start();
scaleVib.start();
clipContainer.addChild(clip);
}
Let’s have a closer look at the VariableVibration objects we created. Each VariableVibration object we create takes only 5 parameters, respectively they are as follows:
- The object to apply the
VariableVibration to, in our case our circleShape called “clip”.
- The property to apply the
VariableVibration to, this time we’re working with the x and y properties.
- The third parameter is the
Spring of the vibration.
- Next up is the
Ease of the vibration.
- The final parameter is the
Range of values that is produced. The higher the number the more erratic the effect.
Our Flash file should look something like this when published:
Step 12: Adding Some Wow
It’s starting to look good, but we can do much better! Remember that bitmapCanvas.startCapture() line I asked you to keep uncommented way back in Step 6? Go ahead and uncomment it then test your movie again.
This is more like it!
Step 13: A Quick Trick for Rotation
A very simple trick to add a spiraling movement is to add another vibration to the clip’s rotation property like so:
// each time we request a new shape from the pool
// it will perform the following
objectPool.onRequestObject = function(clip:MovieClip):void
{
clip.x = stage.stageWidth/2;
clip.y = stage.stageHeight/2;
// add a VariableVibration for the x/y movement of each circleShape
var xVib:VariableVibration = new VariableVibration(clip, "x", 0.97, 0.03, 40);
var yVib:VariableVibration = new VariableVibration(clip, "y", 0.97, 0.03, 40);
xVib.start();
yVib.start();
// add a FixedVibration to the alpha and scale properties of each circleShape when requested
var alphaVib:FixedVibration = new FixedVibration(clip, "alpha", 0.9, 0.05, 0.5, 1.5, false);
var scaleVib:FixedVibration = new FixedVibration(clip, "scale", 0.9, 0.05, 0.05, 0.8, false);
alphaVib.start();
scaleVib.start();
// add a FixedVibration to the rotation of the circleShape
var rotationVib:FixedVibration = new FixedVibration(clip, "rotation", 0.9, 0.05, 0, 360, false);
rotationVib.start();
clipContainer.addChild(clip);
}
Step 14: A Quick Trick for Rotation
Before testing this jump over to Flash and open the circleShape MovieClip in the Library.
As shown, drag the circle just off from center in any direction. The further you move it from center, the more spirals will appear in your design when you publish:
Step 15: ExitShapes
One problem with our current animation is that once the clips move off the screen, they very rarely come back. We can solve this little problem by creating an ExitShapeTrigger.
An ExitShapeTrigger is an area considered safe for the clip. When the clip leaves this area we need to perform some kind of function, such as requesting a new clip from the ObjectPool.
We define an ExitShapeTrigger as below:
// each time we request a new shape from the pool
// it will perform the following
objectPool.onRequestObject = function(clip:MovieClip):void
{
clip.x = stage.stageWidth/2;
clip.y = stage.stageHeight/2;
// add a VariableVibration for the x/y movement of each circleShape
var xVib:VariableVibration = new VariableVibration(clip, "x", 0.97, 0.03, 40);
var yVib:VariableVibration = new VariableVibration(clip, "y", 0.97, 0.03, 40);
xVib.start();
yVib.start();
// add a FixedVibration to the alpha and scale properties of each circleShape when requested
var alphaVib:FixedVibration = new FixedVibration(clip, "alpha", 0.9, 0.05, 0.5, 1.5, false);
var scaleVib:FixedVibration = new FixedVibration(clip, "scale", 0.9, 0.05, 0.05, 0.8, false);
alphaVib.start();
scaleVib.start();
// add a FixedVibration to the rotation of the circleShape
var rotationVib:FixedVibration = new FixedVibration(clip, "rotation", 0.9, 0.05, 0, 360, false);
rotationVib.start();
// define an ExitShape
var exit:ExitShapeTrigger = new ExitShapeTrigger(onExitShape, clip, exitShape, true);
exit.start();
clipContainer.addChild(clip);
}
// recycle objects
private function onExitShape(clip:MovieClip):void
{
trace("circleShape left the screen!");
}
This will create an ExitShapeTrigger with the following parameters:
- The method to trigger when the event has occurred.
- The
MovieClip to test if it is out of the given area.
- The
MovieClip used to define the safe area, you might have already noticed we’ve already created this, called it exitShape and placed it on the Stage in Flash.
- The last parameter is the
Enter Once flag, just set this to true for now.
Step 16: ObjectPool Release
Following on from the ExitShape we introduced in the last step, we’re going to simply edit the onExitShape method so that whenever a clip moves off the screen, we’ll delete it and request a new one from the ObjectPool.
Until now we’ve been working with the request() and requestAll() methods of the ObjectPool, when we want to delete the old one we use the release(clip) method:
// recycle objects
private function onExitShape(clip:MovieClip):void
{
// remove from the ObjectPool and the clipContainer
objectPool.release(clip);
clipContainer.removeChild(clip);
// get a new clip from the ObjectPool
objectPool.request();
}
Step 17: Adding a Blur
HYPE features the ability to very easily add filters such as blur and glow to objects. To add a touch more pizzazz to the design we’re going to add a BlurFilter to the project using the FilterCanvasRhythm:
// think of the BitmapCanvas as an empty space we will 'paint'
// every frame with new image data
bitmapCanvas = new BitmapCanvas(stage.stageWidth, stage.stageHeight);
bitmapCanvas.startCapture(clipContainer, true);
addChild(bitmapCanvas);
// adding a blur
var blur:FilterCanvasRhythm = new FilterCanvasRhythm([new BlurFilter(1.1, 1.1, 1)], bitmapCanvas);
blur.start(TimeType.TIME, 100);
// create a collection of objects and store them in an ObjectPool
// for use in the animation
objectPool = new ObjectPool(circleShape, 100);
The above code creates a FilterCanvasRhythm which takes a Filter as a parameter and applies it to the bitmapCanvas we declared earlier.
Test the project, it’s really starting to come together now!
Step 18: Adding Some Diversity
We can easily add a little depth to the composition by adding more shapes in to the mix. Rather than having to create and manage several ObjectPools, we can add frames to the original circleShape we used and randomly select which frame to play.
Try this now, edit the circleShape object in the Flash Library. Create a new Keyframe, select a new color and draw a new shape. Go ahead and create a few Keyframes of your own, in the next step we’ll look at implementing them with code. This is our new shape:
..compared with our old shape:
Step 19: Choosing Random Frames for circleShape
With our circleShape now sporting a few new Keyframes we can simply insert this single line of code to choose a frame to use each time we call objectPool.request():
// each time we request a new shape from the pool
// it will perform the following
objectPool.onRequestObject = function(clip:MovieClip):void
{
clip.x = stage.stageWidth/2;
clip.y = stage.stageHeight/2;
// choose a random frame
clip.gotoAndStop(Math.ceil(Math.random() * 3));
// add a VariableVibration for the x/y movement of each circleShape
var xVib:VariableVibration = new VariableVibration(clip, "x", 0.97, 0.03, 40);
var yVib:VariableVibration = new VariableVibration(clip, "y", 0.97, 0.03, 40);
xVib.start();
yVib.start();
// add a FixedVibration to the alpha and scale properties of each circleShape when requested
var alphaVib:FixedVibration = new FixedVibration(clip, "alpha", 0.9, 0.05, 0.5, 1.5, false);
var scaleVib:FixedVibration = new FixedVibration(clip, "scale", 0.9, 0.05, 0.05, 0.8, false);
alphaVib.start();
scaleVib.start();
// add a FixedVibration to the rotation of the circleShape
var rotationVib:FixedVibration = new FixedVibration(clip, "rotation", 0.9, 0.05, 0, 360, false);
rotationVib.start();
// define an ExitShape
var exit:ExitShapeTrigger = new ExitShapeTrigger(onExitShape, clip, exitShape, true);
exit.start();
clipContainer.addChild(clip);
}
As a quick note, the random frame code above will switch between frames 1, 2 and 3. You may need to adjust this to the amount of frames in your circleShape.
Step 20: Finish
It’s time to test your movie and bask in the mixture of funky patterns and colors as the HYPE framework takes your code and mixes it into a piece of generative art.
Heres the final code for reference:
package
{
import hype.extended.behavior.FixedVibration;
import flash.display.Sprite;
import flash.display.MovieClip;
import flash.filters.BlurFilter;
import hype.extended.behavior.VariableVibration;
import hype.extended.rhythm.FilterCanvasRhythm;
import hype.extended.trigger.ExitShapeTrigger;
import hype.framework.core.ObjectPool;
import hype.framework.core.TimeType;
import hype.framework.display.BitmapCanvas;
/**
* A tutorial to introduce HYPE. A visual framework
* by Branden Hall and Joshua David for creating
* generative / iterative design with code.
*
* @author Anton Mills
* @version 06/02/2011
*/
public class Main extends MovieClip
{
// private properties
private var bitmapCanvas:BitmapCanvas;
private var clipContainer:Sprite;
private var objectPool:ObjectPool;
/**
* constructor
*/
public function Main()
{
// inits the Hype framework
initHype();
// begin sequence
objectPool.requestAll();
}
/**
* initiation of the Hype members we will be using and configuration prior
* to running the animation
*/
private function initHype():void
{
// the clipContainer is used as a parent for all of our sprites
clipContainer = new Sprite();
addChild(clipContainer);
// think of the BitmapCanvas as an empty space we will 'paint'
// every frame with new image data
bitmapCanvas = new BitmapCanvas(stage.stageWidth, stage.stageHeight);
bitmapCanvas.startCapture(clipContainer, true);
addChild(bitmapCanvas);
// adding a blur
var blur:FilterCanvasRhythm = new FilterCanvasRhythm([new BlurFilter(1.1, 1.1, 1)], bitmapCanvas);
blur.start(TimeType.TIME, 100);
// create a collection of objects and store them in an ObjectPool
// for use in the animation
objectPool = new ObjectPool(circleShape, 100);
// each time we request a new shape from the pool
// it will perform the following
objectPool.onRequestObject = function(clip:MovieClip):void
{
clip.x = stage.stageWidth/2;
clip.y = stage.stageHeight/2;
// choose a random frame
clip.gotoAndStop(Math.ceil(Math.random() * 3));
// add a VariableVibration for the x/y movement of each circleShape
var xVib:VariableVibration = new VariableVibration(clip, "x", 0.97, 0.03, 40);
var yVib:VariableVibration = new VariableVibration(clip, "y", 0.97, 0.03, 40);
xVib.start();
yVib.start();
// add a FixedVibration to the alpha and scale properties of each circleShape when requested
var alphaVib:FixedVibration = new FixedVibration(clip, "alpha", 0.9, 0.05, 0.5, 1.5, false);
var scaleVib:FixedVibration = new FixedVibration(clip, "scale", 0.9, 0.05, 0.05, 0.8, false);
alphaVib.start();
scaleVib.start();
// add a FixedVibration to the rotation of the circleShape
var rotationVib:FixedVibration = new FixedVibration(clip, "rotation", 0.9, 0.05, 0, 360, false);
rotationVib.start();
// define an ExitShape
var exit:ExitShapeTrigger = new ExitShapeTrigger(onExitShape, clip, exitShape, true);
exit.start();
clipContainer.addChild(clip);
};
}
// recycle objects
private function onExitShape(clip:MovieClip):void
{
objectPool.release(clip);
clipContainer.removeChild(clip);
objectPool.request();
}
}
}
Conclusion
This just about wraps up introducing the HYPE framework, thanks very much for your time. I hope you enjoyed it and remember we only scratched the surface of some of the fantastic effects that can be made with the framework. Please do check out the HYPE framework website at www.hypeframework.org for some fantastic examples of the framework and how others have taken it to the next level with Away3D/Papervision integration!
More HYPE Resources on Activetuts+



View full post on Activetuts+