Final Result Preview

Let's take a look at the final result we will be working towards:

Doodle an image in the box with your mouse, and hit the Save button. Refresh this page in your browser, and click Load. You'll see your doodle reappear, having been loaded from your hard drive; the background animation will even be on the same frame as it was before!

Step 1: Setting Up Our Document Class

Let's begin by creating a new .fla. Save it and open up the properties panel in Flash. I am using Flash CS5, but this tutorial should work with every Flash CS version. In the properties panel, push the Edit button and make sure that your settings are identical to the image below:

Step 2: Document Class Setup

Now that we've setup our .fla, let's begin our Document Class. To begin, open up your favorite ActionScript code editor and save an .as file called "Main.as" in the same directory as your .fla. Next go into the "Publish" panel of Flash. Set the "Class" textfield to "Main". Now open Main.as and copy and paste the following code to create our Main document class.

Step 3: Our Main Object

Now we are going to create our main MovieClip. It will contain 3 frames. Each one with a colored shape. Draw a red rectangle, turn it into a MovieClip with F8 and set the name of the MovieClip to "myObject". Make sure that the registration point is the top left corner. Then create two new empty frames inside the MovieClip. Fill one up with a green triangle and the other with a blue circle.

The final result should look a bit like this:

Step 4: Using a ComboBox

Now we are going to use a ComboBox, which is basically a Drop-down list. Make sure that the instance of myObject on the stage is also labeled myObject. Then open: Window > Components and drag the "ComboBox" item onto the library. If you aren't using the Flash IDE, you need to Right Click > Export to SWC the ComboBox in the library.

Now we can create the "myComboBox" variable, placed above the constructor function.

private var myComboBox:ComboBox = new ComboBox()

Next add the following code to your Main() constructor:

//Stops the myObject MovieClip on the first frame
myObject.gotoAndStop(1)
//Adds the following Objects to the ComboBox
and gives them each unique labels
myComboBox.addItem({label:"Rectangle"})
myComboBox.addItem({label:"Circle"})
myComboBox.addItem({label:"Triangle"})
//Adds the ComboBox
addChild(myComboBox)
//Moves it to the correct coordinates
myComboBox.move(280,150)

Here is a snapshot of what your application should look like when run:

Step 5: Changing myObject Frames

We want our MovieClip to change frames when we select a different item!

Let's begin by adding an EventListener to our constructor - the Event.CHANGE event listener - which checks to see when the selected object in the ComboBox changes. This is exactly when the user chooses a new ComboBox item.

myComboBox.addEventListener(Event.CHANGE,changeObjectFrame)

Next we shall create the changeObjectFrame() function. This function checks to see what the current label on the ComboBox is, which is the name of the object the user has selected. It will then go to the correct frame of myObject to display the selected object type.

You can now go ahead and compile the application. You should be able to switch to a different object by selecting it from the drop-down menu.

Step 6: Adding Animation

Next, let's add some animation to our program. Go into the myObject MovieClip on the first frame. Select all of the red rectangle and push F8 to turn it into a MovieClip. Make sure that the registration point is at the top left corner. Do this with every shape inside the myObject MovieClip

Next we will have to give each MovieClip an animation. Go into the rectangle shape MovieClip and Right Click > Create Shape Tween on the red shape filling.

Then select the 60th frame of the MovieClip on the timeline and push F6 to create a new keyframe. Do this with the 30th frame as well. Now you can just go to the 30th frame and change the color of the shape fill. I have chosen to change the color to a golden orange. Now if you play the animation, the color should change from Red > Orange > Red.

Go ahead and do this for each shape in the myObject MovieClip. Now you can go ahead and compile the application; each selected shape will change colors.

The current application should act like this:

Step 7: Doodle Canvas

Now, let's allow the user to draw a little custom doodle on the MovieClip. This is similar to my last tutorial in which we allowed the user to draw a custom design on the player. However, we will take it one step further in this tutorial by allowing the user to SAVE his message. But let's save that for later!

Let's get started by setting up an instance of the Shape class. Add this code above your constructor:

private var myCanvas:Shape = new Shape()

Next we are going to add the myCanvas variable to the stage... Add this code to the bottom of our constructor.

addChild(myCanvas))

Step 8: Doodles

We'll do this very quickly. If you want more explanation on how to use the Shape class for drawing, please check my other tutorial.

Start by creating a mouseIsDown variable...

//Checks to see if the mouse is down
private var mouseIsDown:Boolean = false

Now you can test out the program and it should be drawing fine. However, we still haven't limited the drawing space of our canvas, so drawings outside of the myObject boundaries still show. In the next step, we will solve all of this!

Step 9: Masking

In my previous tutorial, the process of masking was very easy because each masked object remained the same throughout all of the application. This time, we need to have a mask that adjusts to each MovieClip.

Let's go ahead and Right Click > Copy our myObject on the stage. Now we need to Right Click > Paste in Place the object so it is exactly where our myObject was. Now change the instance name to "myObjectAsMask." Switch to the Main Class and add the following lines to the constructor:

//This should all be self-explanatory!
myCanvas.mask = myObjectAsMask
myObjectAsMask.gotoAndStop(1)

So far, the mask should only work for the first object. We need to adjust the changeObjectFrame function to change our mask to meet the new shape of myObject. Add the highlighted code to the changeObjectFrame function:

Step 10: The Save Button

Next up: we'll add a save button to our application. Later on this will save all our myObject's data into a SharedObject. Create a new Button and design it however you want. I have included my own button but showing you how to draw one is not important.

Drag an instance of the button onto the stage and give it the instance name of "saveStuff". Then add the following event listener to the constructor:

saveStuff.addEventListener(MouseEvent.CLICK, saveObjectData)

Next, add this empty function that we will use to add our code that saves the object.

private function saveObjectData(e:MouseEvent):void
{
}

Step 11: Creating and Accessing a New SharedObject

To start using the SharedObject class, we will need to create a new instance of the SharedObject class. If you haven't ever used the SharedObject class before, then this would be a good time to check out this tutorial on Working with SharedObjects to get a basic idea of how they work. Use this code to create a SharedObject:

Go inside the saveObjectData function and add the following code to begin our save operation:

// Creates a new array inside the program
var myDataArrayInProgram:Array = new Array()
// Adds some random data to our Array
myDataArrayInProgram.push("WhateverDataYouWant")
// Creates a variable inside the SharedObject
// and sets it's value to the value of our local
// array
mySaveData.data.myDataArray = myDataArrayInProgram
// "Flushes" the data away to be saved in the
// computer (although the name suggests otherwise,
// this actually stores the data!)
mySaveData.flush()

If you want to check to see if this code is effective, just add this snippet of code to the bottom of your function:

trace(mySaveData.data.myDataArray)

Step 12: Saving our Main MovieClip Data

So far, all is good. We've managed to create a SharedObject and have successfully stored a few bytes of data in it. The next step is to start preparing our program for reconstructing our MovieClip. In this step, we will add all of the necessary data to our SharedObject for our application to reconstruct the MovieClip from scratch.

To do this, we will need to push all of our data into the myDataArrayInProgram Array so it will be attached to our SharedObject. I've modified the saveObjectData function to do all of this. You can view it below:

If so, you probably have Strict Mode enabled in your flash settings. The problem is that getChildAt() returns a DisplayObject, and to flash, that could be a Bitmap, Sprite, MovieClip, etc. The issue with DisplayObject.currentFrame is that only the MovieClip Class has the currentFrame property, because no other class has any animation.

Editor: Alternatively, you could cast the object returned by getChildAt() as a MovieClip, like so:

myDataArrayInProgram.push((myObject.getChildAt(0) as MovieClip).currentFrame)

This tells Flash, "treat this object as a MovieClip".

Step 13: Creating a Load Button

We aren't at the stage yet where we can use our save data, but it is still good to create the UI option to load the SharedObject ahead of time. Just like the save button, you can design this button to be however you want; I'm not going to walk you through drawing it.

Create a new button and drag an instance onto the stage. Then set the instance name to "loadStuff".

And now just add the following Event Listener:

loadStuff.addEventListener(MouseEvent.CLICK, loadObjectData)

And create the loadObjectData function like so:

private function loadObjectData(e:MouseEvent):void
{
}

Step 14: Clear Everything Button

Now let's add a new button to our UI. This button will delete everything in our SharedObject and also wipe out the current doodle on myCanvas.

Just like the other buttons, I will choose my own graphic; you can choose your own or use mine.

This time you can set the instance name of the button to "clearStuff".

Step 15: BitmapData Snapshots

Now you are beginning to ask: "Why can't I save the user's doodle like any other property?" Unfortunately, Flash doesn't allow you to directly save MovieClips, Bitmaps, or even Shapes inside of a SharedObject, but you can do this by saving the pixel by pixel value OF the image.

You must be asking: "But the doodle isn't a bitmap, it's a user drawn vector image contained in shape?!" That's right, but we can convert it to Bitmap based data by taking a snapshot of it with the BitmapData class!

Go ahead and create the following variable above the constructor of our Main application:

private var bitmapDataSnapshot:BitmapData

This variable will be the "camera" that takes a snapshot of the doodle.

Now add the following highlighted lines to the saveObjectData function in the location shown below:

private function saveObjectData(e:MouseEvent):void
{
var myDataArrayInProgram:Array = new Array()
myDataArrayInProgram.push(myObject.x)
myDataArrayInProgram.push(myObject.currentFrame)
myDataArrayInProgram.push(myObject.getChildAt(0).currentFrame)
//Creates a new instance of the BitmapData class,
//makes it the size of the stage, enables transparency,
//and sets the fill to a transparent white
bitmapDataSnapshot = new BitmapData(640, 480,true,0)
//Tells the camera to take a snapshot
//of myCanvas, skips the next 3 parameters,
//and tells the snapshot area to only include
//the stuff covered by the myObject MovieClip
bitmapDataSnapshot.draw(myCanvas, null, null, null, new Rectangle(250, 30, 150, 100))
mySaveData.data.myDataArray = myDataArrayInProgram
mySaveData.flush()
trace(mySaveData.data.myDataArray)
}

Step 16: Saving BitmapData in a SharedObject

Let's wrap up the saving process of our program. Now that we have created a BitmapData instance with all of our myCanvas data, we need to store it inside a ByteArray to be sent into our SharedObject. To do this, we can use a very handy function inside of the BitmapData Class. It's name is getPixels().

getPixels() returns a ByteArray of all of the pixel data of a BitmapData. Unlike the BitmapData Class, ByteArrays can be stored inside SharedObjects so they are the right tool for saving our Doodle.

All you need to do is add this line of code in your saveObjectData function right after you finish doing your BitmapData work:

//Pushes the value of the returned
//ByteArray of the getPixels() function
//into myDataArrayInProgram
//getPixels() requires a Rectangle that
//shows what part of the object's pixels
//we actually want!
//NOTE: The current rectangle is only
//an approximation of where the doodle
//should show!
mySaveData.data.myDataArray.push(bitmapDataSnapshot.getPixels(new Rectangle(250, 30, 150, 100)))

On to the last step. Once the data is saved, we need to have the user refresh the page, to prove that their doodle has been saved to their hard drive, and not just stored in temporary memory. Draw a black box around the stage and add some text to it that asks the player to refresh. Then select the whole object and push F8. Make sure to check the "Export For Actionscript" box and set the "Class" to "refreshScreen". You can now delete the object on the stage...

Step 17: Reconstructing Our Doodle

It's time to reconstruct our entire Doodle from the ByteArray that we saved earlier!

You must be thinking: "What the heck do I do with a ByteArray, its just a bunch of garbled mumbo-jumbo!" And you are right, it is! Thankfully, Adobe has also given us a great function called setPixels() which you gives the same Rectangle and ByteArray, to recreate the same BitmapData you had!

Before we reconstruct our entire MovieClip, we should go ahead and run a test to see if we can reconstruct the BitmapData itself. Modify your loadObjectData function so it looks like this:

private function loadObjectData(e:MouseEvent):void
{
//Creates a BitmapData and makes
//it the size of the stage, and
//applys all of the old settings
var loadBitmapData:BitmapData = new BitmapData(640, 480, true, 1)
//Sets the pixels of loadBitmap
//using our old rectangle, and
//by accessing our SaveData ByteArray
//(4th item in myDataArray (myDataArray[3]))
loadBitmapData.setPixels(new Rectangle(250, 30, 150, 100), mySaveData.data.myDataArray[3])
//Creates a new Bitmap and tells it to
//load its image from loadBitmapData
var display:Bitmap = new Bitmap(loadBitmapData)
//Moves the object mask
//playhead to the right frame
myObjectAsMask.gotoAndStop(mySaveData.data.myDataArray[2])
//Masks the image with the mask
display.mask = myObjectAsMask
//Adds the Bitmap to the stage
addChild(display)
}

Step 18: Fully Reconstructing myObject

Now it's time to put this all together! First, right-click on myObject (in library) > Properties. Now check the "Export For Actionscript" box and set the "Class" to "myObjectType". Compare your properties to the ones in the image:

If it's all the same, then we are ready to go! Add this above our constructor:

Conclusion

As you can see, with a little bit of tweaking, it is absolutely possible to save all MovieClip data into SharedObjects for loading later on. This means that if you are writing a game, you can easily create save states instead of having small checkpoints...

Good luck on using this method of saving data on your games and applications, to help make your programs better than ever!