ActionScript.org Flash, Flex and ActionScript Resources - http://www.actionscript.org/resources
E-Cards and other Dynamic Systems
http://www.actionscript.org/resources/articles/108/1/E-Cards-and-other-Dynamic-Systems/Page1.html
Jesse Stratford
Jesse lives and works in Melbourne Australia. He is the Cofounder and a Director of http://ActionScript.org. A Flash enthusiast, teacher, author, freelancer and speaker Jesse enjoys participating in the http://ActionScript.org community and the wider Flash scene when he has time. 
By Jesse Stratford
Published on September 9, 2005
 
Tutorial details:
Written by: Jesse Stratford [email:jessestratford@actionscript.org]
Time: 30 - 60 minutes
Difficulty Level: Intermediate / Advanced
Requirements: Flash 5 or higher, PHP.
Topics Covered: How to create a dynamic system which allows users to customize a SWF's layout and save their customizations for later review.
Assumed knowledge: A sound understanding of Intermediate ActionScript. Some server side scripting knowledge would help too.

Example and description
Tutorial details:
Written by: Jesse Stratford [email:jessestratford@actionscript.org]
Time: 30 - 60 minutes
Difficulty Level: Intermediate / Advanced
Requirements: Flash 5, PHP compatibility.
Topics Covered: How to create a dynamic system which allows users to customize a SWF's layout and save these settings for review later.
Assumed knowledge: This tutorial isn't easy. You need a sound understanding of Intermediate ActionScript and some technical back-end knowledge would help too.

Grab the source to this project. You will need it in this tutorial.

First thing's first: "What's with the difficulty rating on this one - Intermediate / Advanced ??"
That is there to show you that this tutorial isn't as easy as some of the other Intermediate level tutorials and I'm not going to hold your hand in this one as much as I normally do. I assume that you are capable of doing a project like this before you begin. If you're a newbie/beginner, the sad truth is that if you try this tutorial you will probably waste both of our time, because you will post lots of questions about it on the Forums. Don't get me wrong, I'm in favor of Beginners trying new things, just not stuff which is way over their head. This is a difficult task, please learn the basics first.

With that said, welcome to those of you who didn't just press Alt-F4. This task isn't terribly difficult but I anticipate this will be a popular tutorial amongst people with no Flash experience because everyone seems to want to be able to do this sort of thing, and most aren't willing to start at the beginning.

In this tutorial we're going to cover how to create a dynamic content storage and recall facility. I've decided to make the application an ECard system but the truth is that this tutorial could be used to create similar effects to those on Yugop.com (with a lot of advance alterations) or a simple guest book.


Breaking the problem down
Let's start by thinking about the task logically. What processes are involved in passing information between two parties who don't have direct contact?

If I come up to you in street and whisper something in your ear, then tell you to pass it on to some other guy down the road, you would have to store a fair bit of data in your head. You would have to store the string, or sentence I whispered to you - like "You're ugly" (no offense) - as well as where I was when I told you, and where you were and indeed, what I look like, and which guy you were supposed to pass it on to. This way, when you walk down the street and tell the big muscley guy I pointed out "You're ugly", and he punches you in the face, you know how to track me down to beat me up :o)

This example's a bit off the point but it's indicative of what we have to do when creating these sorts of systems. There is a fair bit of information we need to collect and pass around. So those of you who were thinking "How did he get Flash to save a SWF file?" have probably worked out by now that I didn't. All I did was store the important information about the structure you created, then pass that information on to you when you came back to view the card. Then, using that info I reconstructed the structure in a new Flash file. Pretty neat huh? I think so too.

It's about now that you should be opening up those source files you just downloaded and taking a look. Start with:

Writer.fla

The more astute of you will have noticed that the SWF embedded above isn't the same as the movie you were sent to when you got your notification email. In fact they are completely different files, and most of you can guess from the names that one writes the data and one reads it back in and reconstructs.

Start on the "Choose" scene, that's the one with the big red and green buttons. OK let's break this down. Frame 1 has the following code:

[as]stop ();
items = new Array();
// dropItem removes an unwanted item from an array
function dropItem (item) {
 for (j=0; j<=items.length; j++) {
  if (items[j] == item) {
   fst = items.slice(0, j);
   snd = items.slice(j+1, items.length);
   items = fst.concat(snd);
  }
 }
}[/as]

Like I say, I'm not going to lead you by the hand in this tutorial, so that means, no line by line breakdowns of code functionality. Suffice to say this dropItem() function removes an element from an array if it exists. Enough of that, take a look at the buttons (let's look at the red and green buttons under the word "blue"):

The green button has:

[as]on (release) {
 // add this object to the list of chosen object
 _root.items.push("blue");
}[/as]

The red button has:

[as]on (release) {
 // remove this object from the list of chosen object
 _root.dropItem("blue");
}[/as]


Gathering the data part 1
So the green button adds the word "blue" to the array 'items' on the _root level. Why? Because we need to know which elements we want to include in the card... if all your cards are going to contain the same content, with customized text or something, then you can skip this step.

The red button on the other hand, runs the dropItem() function and passes the word "blue". So dropItem() goes through and if "blue" is in the array it removes it. This allows you to change your mind and decide you don't want the blue box after all. Note that you can only change your mind on this first screen, I have not allowed for removing elements later in the process (although it shouldn't be too hard to incorporate).

The buttons under the word "Green" do the same thing but - shock! - they don't pass the word "blue", they instead pass the word "green".

OK, on to the Edit Scene. Frame 1 has:

[as]stop ();
for (j=0; j<items.length; j++) {
 name = items[j]+j;
 _root.attachmovie(items[j], name, j+1);
 _root[name]._x = (j+1)*100;
 _root[name]._y = (j+1)*100;
 _root[name+"x"] = _root[name]._x;
 _root[name+"y"] = _root[name]._y;
}[/as]

Check the Library (Control L) and you will find that there are two movies clips there called "blue" and "green". "So that's why he's been talking about blue and green!" you all think. No, not quite. If you right click the movies clips and select Linkage you will notice they have Linkage IDs of "blue" and "green" - that's the important bit! Those of you who don't know what Linkage does should read the Beginner level attachmovie tutorial. So this code goes through and attaches a copy of each of the previously chosen movie clips to the stage, allocation them each an arbitrary _x and _y value just so you can see them as two clearly separate entities and drag them where you want.

The only other important code in this scene is IN the blue and green MCs which you wont be able to see as they aren't attached to the stage in the editing environment. So open up you library and edit one of the two, either one, they're both the same except for the color. The important code here is on the button which is the top bar with the words "Drag Me!" on it. Right click and check the actions assigned to the bar and you will find these actions:

[as]on (press) {
 startDrag (this);
}
on (release) {
 stopDrag ();
 set ("_root."+this._name+"x", this._x);
 set ("_root."+this._name+"y", this._y);
}[/as]

So the first thing we know is that this bar makes the movie draggable. What else do we notice? Well, when dropped this movie sets some crazy variables. These variables will be named according to the movie's own instance name (assigned above using the attachmovie command) and they store the _x and _y of this movie. Note that they will be updated each time the user drags and drops this window so a user can movie the objects around as much as they want in this Edit scene and our program will record only the final locations. Why are we recording this data? Because when we reconstruct the movie later on, if we don't know where the objects go on the stage, it's not going to look anything like it did when your user created the original.


Gathering the data part 2
Finally, on to the Finalizing Scene, here all the code is on the next arrow and it's documented so I'm not going to explain what it does. Note: Since this version uses loadVariables the button will appear to do nothing if you don't add another gotoAndPlay(x) command on it, directing it to a screen that says "Thank You" or something.

[as]on (release) {
 // did they enter an email addy yet?
 if (_root.email != "" && _root.email != null) {
  // This code generates a (hopefully) unique session
  // ID for this card. If you end up with overlaps you're either
  // very succesful or extremely unlucky
  myDate = new Date();
  ranNum = Math.round(Math.random()*1000000);
  ranChar = chr(Math.round(Math.random()*24)+97);
  session = (mydate.getMonth()+""+myDate.getDate()+""
   +mydate.getFullYear()+""+ranNum+ranChar);
  // Now we construct the layoutString which goes to the reader.swf
  layoutLength = items.length;
  for (j=0; j<layoutLength; j++) {
   name = items[j];
   xpos = _root[name+j+"x"];
   ypos = _root[name+j+"y"];
   text = escape(_root[name+j].text);
   // if the layoutString exists, append data
   if (layoutString != null) {
    layoutString = layoutString+","+name+","+xpos+","+ypos+","+text;
   } else {
    // layoutString doesn't exist, create it
    layoutString = name+","+xpos+","+ypos+","+text;
   }
  }
  // Since we're now going to send variables to a script, 
  // let's clean up those we don't need
  delete items;
  delete j;
  delete name;
  delete myDate;
  delete ranNum;
  delete ranChar;
  delete layoutLength;
  delete xpos;
  delete ypos;
  delete text;
  // Passing the variables:
  // Here I'm using LoadVariables because I want the user to
  // stay IN the flash file when they send their card. If you
  // want them to be re-directed to your PHP page use get URL
  // getURL ("e-card.php", "", "GET");
  loadVariablesNum ("e-card.php", 0, "GET");
 } else {
  // no email addy enterred, report error
  _root.email = "You didn't enter an email! :)";
 }
}[/as]

Note that some lines have been manually line wrapped for tutorial layout neatness.

Once again, welcome to those of you who weren't scared off by that long paragraph of code :o) By reading the comments and using your ActionScripting knowledge you will see that it's actually all quite straight forward stuff. All it does is convert all the important data in our movie into a nice long string, which we then pass to our PHP file. Speaking of which, let's turn the page...


The PHP: storing / retrieving the data
E-card.php

This section of the system is the part where we 'store' the data for use later. Before you ask, yes you can do this with CGI or ASP, or JSP, or whatever scripting language you know, but I know PHP so that's what I've used. The code goes like this:

[php]<?php
$fd = fopen("$session.txt", "w");
fwrite($fd, "locationString=$layoutString&contentLoaded=true");
fclose($fd);

mail($email, "You have recieved an E-Card", "You have recieved an E-Card, an online card create by a friend or associate. To view your e-card please goto http://www.YOUR-URL.com/e-card/reader.php?session=$session", "From: PHPMailer Reply-To: $from X-Mailer: PHP/" . phpversion());
?>[/php]

It's not as bad as it looks. All it does is:

  1. You passed a variable 'session' before (from your write.swf) which was a unique string. This takes that string and constructs a text file with that name. Yes a text file, this isn't a database tutorial, text files are good because they can be deleted later easier than database entries. Into that file it writes the layoutString that you passed from writer.swf and a constant variable contentLoaded which is assigned the value true and used for determining (later on) if all the variables are loaded yet.
  2. Next it sends an email off to the email address you specified in the 'email' input field in writer.swf, with the Subject: "You have received an E-Card", and a body with a bit of info in it. The important bit in this info is the line that reads: .../reader.php?session=$session what this does is sub in the session variable, so if my session was "123" this line would read "reader.php?session=123". Why's that important? Because the user's computer needs to know which text file their specific card's data is stored in. If I have 100 people reading this tutorial every day, I don't want to your cards to get mixed up, so I separate their data into randomly named text files, and send you a URL with the name of your file included...

So now we all know that the session is passed via the URL into the reader.php.

Reader.php

All this does is embed the session string into the reader.swf. It uses the simple infix URL syntax, similar to the GET method. I've discussed this in a previous tutorial but I forget which. Basically if I open a flash file using the URL followed by a variable name and value, Flash will import that variable and value. For instance: myFile.swf?myVar=123 will create a new String variable in myFile.swf called myVar. Note that as with loadVariables this variable is loaded in as a String so it's value will be "123" (the String) not 123 (the number). So the important bits of code in this PHP file are:

[code]<PARAM NAME=movie VALUE="reader.swf?session=<?php echo $session; ?>">[/code]

and

[code]<EMBED realsrc="reader.swf?session=<?php echo $session; ?>" src="http://www.actionscript.org/dev/admin/reader.swf?session=<?php echo $session; ?>" ... [/code]

So this parses our session variable and loads it into the reader.swf file, which we will now examine...


The Re-constructor: pulling it all together
Reader.swf

This is the reconstructor. You will note that the library contains much the same items as the Writer.swf library, with the same linkage names. Can you guess what we're going to do? That's right! We're going to load up the data from the session file (whose name we know because we've just passed it using Reader.php), and rebuild the layout from the ground up using setProperty and some other nifty tricks.

The Preparation Scene does exactly what the name would suggest. It loads the variables from the session file and loops until the contentLoaded variable has a value (now you see the reason for using that extra variable!) and then proceeds to the next scene.

The Content Layout Scene is where all the actions happen and all the code's on Frame 1:

[as]stop ();
// prepare loaded variables
// there are 4 elements in each of my array
// entries in the form:
// [mc name, _x, _y, text]
// thus I set my arrayLength = 4
arrayLength = 4;
// our loaded array has been loaded as a string
// which we must now convert into a valid array
// using the split object
locationArray = locationString.split(",");
// numOfElems tells how many objects are fully
// defined in the
// loaded array
numOfElems = locationArray.length/arrayLength;
// now we loop and place those elements defined
// in our array,
loopCount = 1;
for (j=0; j<=numOfElems; j++) {
 mc = locationArray.shift();
 xpos = Number(locationArray.shift());
 ypos = Number(locationArray.shift());
 text = unescape(locationArray.shift());
 _root.attachmovie(mc, mc+j, j);
 _root[mc+j]._x = xpos;
 _root[mc+j]._y = ypos;
 _root[mc+j].text = text;
}[/as]

More long code. All it does is takes the locationString variable from the session text file and convert it to an array. Then it loops through the elements and attaches movies and adapts their properties, like _x and _y appropriately... read though it and I'm sure you'll understand it. (For those of you who don't know, array.shift() takes the first element from an array and returns it, but unlike array[0] it actually removes it from the array.)

Finally note that you have to CHMOD the directory these files are uploaded into to 777 because we're creating new text files on the server. If you don't know how to do that, ask on the forums or do a search on the web, it's not hard.

That's all everyone, you now know the basic idea behind these sorts of applications. If you can think of a dazzling particle application be sure to let us know. If you have comments or suggestions please feel free to email me.

Jesse Stratford [email:jessestratford@actionscript.org] is the Co-Master of ActionScript.org and a freelance Flash developer and teacher. He is based in Australia and enjoys all things Flash.

NB: If you have comments or feedback please feel free to email me, but please do not email me Flash questions; the forums are provided for that purpose and you will get a faster answer by posting you question there.

If you have found this tutorial helpful, I hope that you will take 30 seconds to visit The Hunger Site where, with just one click you can make a free donation of food to a starving person in a third-world country. We do not benefit financially from this action; it is purely an act of charity.
This tutorial is protected by International Intellectual Property Rights laws and may not be reproduced or redistributed in full or part, without the prior written consent of the author. Unauthorized reproduction of this tutorial or its contents may result in prosecution. I've worked hard on this tutorial, please don't steal it.