I have finally lost my battle with a client and am conforming to their request: "I want the text content to be stored in an external .xml file so we can edit easily."
I'm happy for the many tutorials out on the web that helped me to learn this stuff, but I was surprised that I didn't find a single one that did EXACTLY what I wanted. So, I banged it out and am sharing it so you can shorten your development cycle.
Goal: From an external XML file, load a page header and content into two separate dynamic boxes, and then have those boxes update as you move from page to page.
Sounds easy right? Here is what I did to create and test my solution.
1) I created a Flash CS4/AS 3.0 document with four layers: Actions, Buttons, Dynamic Text and Background
2) On the background layer, I created a color gradient background
3) On the buttons layer, I created a simple back and next button
4) On the Dynamic Text layer, I created two dynamic text boxes. I called the smaller one at the top titleText and the larger one for the content descText.
Ok...pretty straight forward.
I then created my button listeners for the back and next buttons and put this code on the Actions layer:
nextBut.addEventListener(MouseEvent.CLICK, goNext);
backBut.addEventListener(MouseEvent.CLICK, goBack);
function goNext(event:MouseEvent):void {
nextFrame();
}
function goBack(event:MouseEvent):void {
prevFrame();
}
From there, I wrote some sample XML and called it "course.xml":
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<pages>
<page pTitle="Welcome">Welcome to dynamically loaded text.</page>
<page pTitle="How to Do It">Here is how it works.</page>
<page pTitle="Simple">Once you have it figured out, its easy.</page>
<page pTitle="Final Page">No really...its pretty easy</page>
</pages>
This is a simple set of four pages. In each page tag, I included an attribute called "pTitle" which is the page title. The content is between the page tags. So, page 1 is "Welcome" with the content "Welcome to dynamically loaded text".
Now, here is the AS 3.0 to load and parse the XML.
var myXML:XML = new XML();
var XMLURL:String = "course.xml";
var myXMLURL:URLRequest = new URLRequest(XMLURL);
var myLoader:URLLoader = new URLLoader(myXMLURL);
myLoader.addEventListener("complete", xmlLoaded);
function xmlLoaded(event:Event):void
{
myXML = XML(event.target.data);
titleText.text=myXML.page[0].@pTitle;
descText.text=myXML.page[0];
}
The first line sets up a variable container for the XML file. The second line sets up the call to the .xml path. The third and forth line loads the XML and the fifth line waits for it to load. When it does, it loads the XML content into the variable myXML.
The next two lines of the function pick out the individual XML elements we want to use. In this case. the text field titleText gets the XML field page's first child's pTitle variable, and the descText gets the XML field page's first content.
But WAIT! Why are we calling string [0] instead of string [1]? Well, XML starts it count from 0...nuff said. When you want page 3's content, you look at the XML child[2]. Don't let it mess with you like it did with me...Accept it and move quietly on...
Now, if you want to add more pages, you add more frames. If you want to load the newer content into the subsequent text fields, you use the following code:
titleText.text=myXML.page[1].@pTitle;
descText.text=myXML.page[1];
on the Actions layer of frame/page 2...
titleText.text=myXML.page[2].@pTitle;
descText.text=myXML.page[2];
on page 3 and so on...
What happens is this...as the user advances to the next frame, the text box content changes to the new XML content. You have to change the string attribute, but as long as you do, the correct content will display.
And, if you want to digest this in some working files, all the code and .fla are available here. This zip file includes the final .fla, .swf and the .xml file.
I hope this saves you time as you develop your own XML driven eLearning projects.
One of my clients has had a cool vision for her eLearning projects and it involves avatars - not the blue smurfy giants, but the digital characters/cartoons that help lead your learners through the training.
I've done quite a bit of it in the past, but it always adds to the cost because I hire an illustrator/cartoonist to develop my characters. Whenever I hire out, it costs me and the clients more money. As budgets dried up last year, it was a pretty quiet year for avatars.
However, I've developed some eLearning for this client in the past, they were used to my pricing structure, and I didn't want to look like I was price spiking. So, I figured that I would see if there were some avatars available online that weren't too cheesy, and that I could pick up cheaply so as to not pass the cost onto the client.
After a long and painful search, I am happy to have found this site: Cartoon Solutions. It's not a site specifically for eLearning, but for Flash cartoons. It contains dozens of characters that you can download for a steal ($22.00 or so, $50 for the character plus 18 animations). Men, women, kids, animals, plus backgrounds and props, all in the same toony "style". And, when you buy, you get the .fla file with all the embedded mouth and hand positions so you can drop them right into your project.
As you know, 90% of my stuff is build in Flash so this was a perfect fit. While designed for Flash cartoons, I found them to be a perfect fit for these new eLearning projects.
The best part: My client LOVED the rapid prototype. If you know Flash and want to add a toony look to your eLearning, check out Cartoon Solutions!
I was doing some work for a client and had to load in some .swf files generated by a 3rd party program. I admit it - I LOVE text effects. I like fades, but when the text can bounce or flip or swirl in, sometimes it adds a bit of snazz to the eLearning project. As long as you don't overdo it, I think the learner's get a kick out of the occasional bits of visual eye candy.
On my Mac, I use a program called Text-Osterone, from a company called Vertical Moon. The software allows you to create a bunch of editable special effects you can apply to text. The current version only seems to export to an AS 2.0 version .fla, so I export the file to a .swf and then dynamically load it in. (I am working ever so hard to leave AS 2.0 behind me...)
Of course, in AS 3.0, it requires a bunch of code lines to load the external .swf, but my solution below pares it down to the bare basics.
First, make sure the .swf you want to load is in the same directory as the .swf loading it. You can play with paths if you like, but for this code, just keep the whole shebang together.
When you want to load the .swf, add a key frame and then add the following code:
var swfRequest:URLRequest = new URLRequest("connect.swf");
var swfLoader:Loader = new Loader();
The first line sets up a variable called swfRequest and it points to the .swf you want to load. In my example, the .swf I want to load is called "connect.swf". The second line preps a variable called swfLoader to...well...initiate a load...(insert random inappropriate comment here)...
Next lines:
swfLoader.load(swfRequest); addChild(swfLoader);
This next line loads the connect.swf into the variable swfLoader. The addChild line plops the .swf onto the stage. That's it. Sure, its a lot more work than the old LoadMovie(); AS 2.0 command, but it does the job.
Now, if you want to place the .swf in a particular location on the stage, you can manipulate it's coordinates once its been loaded into your main .swf.
swfLoader.x=10; swfLoader.y=120;
This sets the X and Y placement of the .swf after its been loaded in. Of course, you can place it wherever you want. Remember, that the X and Y coordinates are relative to the main timeline (if this is where you dropped this code) or relative to the coordinates INSIDE a movie symbol (if you drop this code into a movie symbol.) The final code looks like this (with comments added):
// Load the SWF into the Variable swfRequest
var swfRequest:URLRequest = new URLRequest("connect.swf");
var swfLoader:Loader = new Loader();
// Bring the SWF into the SWF
swfLoader.load(swfRequest);
addChild(swfLoader);
//Position the SWF
swfLoader.x=10;
swfLoader.y=120;
There are some other tutorials online, but I am a big fan of keeping things simple. If you need to load a .swf and position it on the stage, this ActionScript 3.0 code sample will work every time. Have fun!
It's that time of the year again, when Vegas calls the educational technologists out from their dark work rooms, and when instructional designers and facilitators alike decide to figure out this eLearning stuff and come out to Las Vegas for the ASTD TechKnowledge Conference.
This is going to be another great year with ASTD, and I wanted to let everyone know that I will be presenting three separate sessions regarding Flash CS4.
I'll be presenting a "Getting Started with Flash" pre-conference session on 1/26/10! Its a fun primer to get you up and running using Flash, but is targeted towards the eLearning professional. It's for the new learners, but will be a full day of Flash related fun. (Can you say "Flash Related Fun" ten times fast?)
Also, I will have two Creation Stations on Flash called "Flash Animation: Basics of Making Things Move" on Wednesday the 27th and Friday the 29th of January. This is a 90 minute hands-on session where you will learn the basics of symbols and tweening in Flash CS4. Yes, it's pretty basic, but will be a blast, especially if you are brand new to Flash CS4.
I'll be blogging and podcasting from the General Sessions and sometimes from the concurrent sessions I'll be attending.
I am coming into Vegas on Monday night and leaving on Friday afternoon, and I am usually walking the floor or expo when I'm not in session. Feel free to say "hello" if you see me wandering around! Also, I will be attending the "Meet to Eat"sessions in the evenings, so if you want to connect with me ~ I'd love to talk tech!
Just an FYI...I lost about four hours development time today because Flash CS4 continually crashed after a 2 second live time. Yep...open a file and then 2 seconds later it would close down.
Here were my steps to resolve it on my Mac with OS X:
1) Repair Disk Permissions
2) Reset preferences
3) Reset user settings
4) Uninstall and then reinstall
None of this worked.
5) 45 minutes on hold with tech support who directed me to a web page, FOUR TIMES, that resulted in a 404 error each time.
Finally, the solution that worked is to
6) Turn off all my fonts. Yep, turn all of them off in Font Book, and then turn them back on as the system calls for them, or as Flash needs them.
Turn off my fonts!!! Since when do fonts cause an expensive and complex program like Flash to crash. Whatever.
It's easy to turn off fonts in Font Book (right mouse click on Computer and choose Disable Fonts) and the Mac asks permission to turn them on as you need them, but here's the kicker.
It worked fine last night. Today, I didn't install any fonts, I just opened Flash files and wanted to work. What mystical creature got into my Mac last night and played with font settings?
I don't know, but man, I hope this saves you a call to Adobe tech support...Adobe, I love ya, but please get me a stable version of Flash.
I love Flash. In my opinion, regardless of skill level, Flash CS4 is still the best overall development tool for eLearning. Yes, I am a fan of some of the eLearning suites, but for me, developing from a blank slate where anything is possible is a wonderful thing.
When I first started out, however, a blank slate was scary. I was clueless on where to begin let alone best practices. Coming from a web background, I knew how to design for the web, but to use Flash as the main development platform opened up a wide range of choices. Over the years, I've narrowed down my development methods to three option. Everything I currently design follows one of these three methods.
Method One: HTML Pages
For SCORM based projects and for very large projects, I use a simple strategy of creating Flash "pages", attach it to a single HTML page and then link all those "pages" together. This allows me to use HTML linking to move from page to page, and results in very small Flash files. A single "screen" or concept appears on each "page", and the user moves from HTML page to HTML page. The benefit to this method is that the file sizes are small and SCORM tracking can be easily implemented. The downside to this is that you have to be very creative when passing variables from HTML page to HTML page and that there are a TON of files to keep track of. Each "page" consists of a single HTML document and single .swf file. I would say 25% of my current development uses this methodology.
Method Two: One Large .SWF file
My most popular method is to create one large SWF file that has the entire eLearning program contained within it. I use each frame of the movie as a single "page", and use lots of embedded movie symbols on the timeline. Even though users are moving from frame to frame, using movie symbols allows me to cram lots of content onto each of those frames. The benefit is that it is really easy to edit and implement, but the .fla file gets huge if you have lots of media. Also, Flash CS4 chokes on embedded movie symbols (on my Mac only it seems...) I compensate for the larger .fla files by externally calling the video and audio files and keeping them out of the final .swf. SCORM can be a pain to implement (especially if you want to track each module as a separate SCO), but its possible with some hard work. About 70% of my eLearning is built using this method.
Method Three: One .SWF that Loads Additional .SWFs
I used to build the majority of my eLearning using this method, but AS3 has made the strategy code intensive. Rather than fight it, I've adopted my methods and learned some workarounds, but this is still a great methodology used by developers. Basically, a single .swf is loaded in a single HTML page. This single .swf file contains navigation elements and the basic interface for the eLearning project. At launch, the single .swf loads a second .swf file, displaying content and information. As the user clicks on different pages and modules, the second .swf file is replaced by new .swf files as the user navigates through the project. The benefits include smaller overall files, faster load time and sleek user experience. The down side is that this loading and unloading used to be easy in AS2, but is a chore in AS3. Also, similar to method one, you have lots and lots of .swf files to keep track of.
These are the methods I use every day to build my programs for my customers. I'm sure that there are others out there, and I'd be interested in hearing those! Let me know what you think!
In the past week, I've received three emails regarding linking to MS Word Docs and PDF files from within a Flash movie. It's relatively easy, but the differences between doing it in ActionScript 2.0 and 3.0 are significant.
In ActionScript 2.0, linking to a file uses the
getURL
function. Now, normally you'd use the
getURL
to launch a web page or open a new browser window by attaching the following code to a button symbol:
on (release){
getURL("http://www.thomastalkstech.com");
}
This tells Flash that when the user has clicked on and released the mouse button, launch the web site in the same browser window. If you wanted to open it in a new window, you would need to append the command like so:
on (release){
getURL("http://www.thomastalkstech.com","_blank");
}
The addition of the target variable (_blank) tells the browser to open in a new window.
Because the .swf sits in an HTML file, it thinks its part of a web site. Regardless of whether or not you have the files sitting on a web server, when you launch the .swf it runs in the browser. This means that the files that sit in the same directory as the .swf are accessible using the
getURL
function.
So, if you had a .pdf file on the web server and you wanted to link to it from your Flash movie, you would use this code:
on (release){
getURL("myCoolFile.pdf","_blank");
}
and Flash would link to the PDF from within the Flash movie. Absolute and relative pathing work as well, so if you had stored the .pdf file in a directory called /pdf, you could use this code:
on (release){
getURL("/pdf/myCoolFile.pdf","_blank");
}
IMPORTANT NOTE: The pathing in the Flash file needs to be from the HTML file holding the .swf file. It gets confusing and frustrating, but if you path the ActionScript from the HTML file holding the .swf, it will find the document without a problem. It used to kill me because sometimes I'd path from the .swf, then move the .swf to a new directory and it would mess up my links. If you use root relative pathing it won't be an issue, but if you use relative pathing, be sure to path from the HTML file holding the Flash.
You can link to any file using the getURL code outlined above.
Of course, in AS3 they had to go out of their way to make it more difficult...instead of three lines, its now seven lines of code. Again, not difficult, but more details need to be added to launch the URL.
First, create a new variable for the URL. We are calling the variable 'request'.
var request:URLRequest = new URLRequest("http://www.dwebstudios.com");
Then, create a button instance and call it whatever you'd like. In the example below, the button's name is called myButton. You are going to create the function call for myButton using EventListener.
myButton.addEventListener(MouseEvent.CLICK, goWeb);
So, we've created the listener to launch the function goWeb, so we create that next:
function goWeb(event:MouseEvent):void {
navigateToURL(request, "_blank");
}
So, the entire code block is:
var request:URLRequest = new URLRequest("http://www.dwebstudios.com");
myButton.addEventListener(MouseEvent.CLICK, goWeb);
function goWeb(event:MouseEvent):void {
navigateToURL(request, "_blank");
}
To link to a document, replace the variable in the URLRequest object with your .pdf name or file name and it will launch as expeted. The same rules apply for the target string and pathing as in AS2, but the entire code block is longer and more dramatic.
var request:URLRequest = new URLRequest("myCoolFile.pdf");
myButton.addEventListener(MouseEvent.CLICK, goPDF);
function goPDF(event:MouseEvent):void {
navigateToURL(request, "_blank");
}
So that's it! I hope this helps!
P.S. If you want to link to an email address you use the same code as above in AS 2 and 3 but you replace the object with 'mailto:yourMail@yourEmail.com'.
AS 2
on (release){
getURL("mailto:yourMail@yourEmail.com");
}
AS 3
var mail:URLRequest = new URLRequest("mailto:yourMail@yourEmail.com");
myButton.addEventListener(MouseEvent.CLICK, goMail);
function goMail(event:MouseEvent):void {
navigateToURL(mail);
}
One of the most important elements to include in any eLearning project is a way to display current page numbers and total page numbers for your learners. Adults like finish lines, and there is something comforting about knowing how many pages you will need to work through when taking eLearning, as well as knowing where you are inside the eLearning program: "Page 10 of 100" feels different than "Page 98 of 100".
I used to do it all with regular old text fields in Flash, but with ActionScript 3.0, there are some calls you can make to identify where the user is at on the time-line. Combine this with a design methodology and a couple dynamic text boxes and you can create something that is quickly customized and scalable.
First, from a methodology perspective, you need to decide that each single frame of your Flash movie will be a single page in your eLearning project. You can have content and interactive media built into Movie Symbols, so you don't have to feel tied down to the single frame, but choosing to utilize the embedded symbols onto a single frame can help you better organize your overall project. This, by the way, is my preferred style of programming - a 30 frame eLearning project feels like 30 "screens" to the end user. Even though there is a ton of content dropped into Movie Symbols on each frame, this method works best for me and my development methodology.
Second, you need to add the ActionScript necessary to identify frame location. The ActionScript:
currentFrame
identifies where the user is on the time-line, while the ActionScript:
totalFrames
looks at the total number of frames in the movie.
Applying the code takes a bit of a twist, but once you think through it, its easy - when the user moves to a new frame (ala Next or Back button), then refresh the page counter and re-populate the current frame.
I create my page counter on a single layer with a Back button, Dynamic Text field (current frame), Dynamic Text field (total frames) and then a Next button.

I start with setting up the variable names like so:
var frames:Number; var totals:Number; frames=currentFrame; totals=totalFrames;
This sets up the variables and then pulls the data from currentFrame and totalFrames into those variables.
Then, I have to set up my Dynamic Text variables:
myLocation.text=(String(frames)); myTotalPages.text=(String(totals));
I have two Dynamic Text fields named myLocation and myTotalPages. Variables called as numbers do not display in Dynamic Text fields, so I have to convert them to text by re-categorizing them as Strings. I know...silly step, but it is the only way to take the number variables and display them as text.
Then, I add the code for my Back and Next button listeners:
next_but.addEventListener(MouseEvent.CLICK, goNext); back_but.addEventListener(MouseEvent.CLICK, goBack);
And then the functions for the Back and Next buttons:
function goNext(event:MouseEvent):void {
nextFrame();
frames=currentFrame;
myLocation.text=(String(frames));
}
function goBack(event:MouseEvent):void {
prevFrame();
frames=currentFrame;
myLocation.text=(String(frames));
}
Notice I use nextFrame() and prevFrame() to move the user back and forth. Also, I recall the
currentFrame
variable and then re-populate the Dynamic Text box with that updated data.
The
myTotalPages
doesn't update, as the user cannot control how many pages are in the total project, but if you, as the developer, want to add more frames, you don't need to reprogram the page counter. Some designers manually put the total number of pages in as a generic Text box, but adding and removing frames means you would need to change that number on each page. Using
currentFrame
allows it to be dynamically generated at run time, regardless of the total size of the project.
I'm sorry I've been away for so long...traveling around the United States teaching and speaking keeps me busy, but I hope this entry is helpful to you.
One of the most frustrating things for me to learn in AS 3.0 was being able to find my movie clips in the code. I usually work on a single Flash timeline with lots of nested movie clips that make up my elearning: Frame 1 has an intro movie clip, Frame 2 introduces the course, etc.
My frustration with AS3.0 is that I couldn't figure out how to control my main movie from within my nested movie symbol. For example, in Frame 1, my intro movie plays, and then ends on a screen that explains the learning objectives. There is a big "Start the Training" button, and when the user clicks on it, the ROOT of the Flash movie advances to frame 2, where a new movie symbol plays.
Not that hard right? Old ActionScript code:
_root.play();
Not any more. I'm stubborn...I want AS 3.0 to work like AS 2.0. Suck it up buttercup, it won't. The reality is AS 3.0 doesn't see the "stage" or even the "timeline", relative to the objects. Think of it this way...in AS 1.0 and 2.0, objects added to your movie existed on the timeline, and Flash knew where they were at based on where on the timeline you placed them. They were "happyBall instance on frame 1 of the main timeline(root)."
In AS 3.0, movie clips just "are". Very zen like, I know, but in AS 3.0, they are defined as themselves. It doesn't matter where they are on the timeline - their identity is not connected to where they are placed. So, trying to add "root" to an AS 3.0 object is like trying to tell a book to go back to the printing press where it was created. Can't do it on its own - it has no awareness of its location.
After searching around the web, and finding a ton of different solutions (some of which seemed overly complicated, especially the ones that said to replace
_root
with just
root
...doesn't work...nice try), the kind developers at Yahoo found a working solution. It goes back to the day when you were able to identify anything based on its location, relative to the root. The code looks like this:
MovieClip(this.root)
So, in our example, in the movie clip, we have a button that advances to the next frame of the main timeline. There is a movie with some text and a button (named clickMe) in it. In the Movie clip, you would add this code:
clickMe.addEventListener(MouseEvent.CLICK, goClickMe);
function goClickMe(event:MouseEvent):void {
MovieClip(this.root).play();
}
You can control the main timeline from within movie clips using that bit of code.
I hope this helps you as much as it helped me. Maybe its no longer a best practice to embed ActionScript in movies that control other things besides that movie symbol, but for a guy like me that wants to move from AS 2.0 to 3.0 quickly, I'm going to hang my hat on these little tricks to help me rapidly develop my projects.
Oh...and if you want to download a sample to see this in action click here. Its a Flash CS4/AS 3.0 file that shows you the controls I'm talking about.
This tutorial was my presentation at the ASTD TK 08 show in San Antonio Texas. While running the creation stations at this year's conference, many people asked me about the materials I used for last year's session. Yes, the main interface is CS3, not the current CS4, but ActionScript hasn't changed. Therefore, this manual can be very helpful if you are making the bridge to AS 3.0 from AS 2.0, or you want to just get started with AS 3.0.
Foundational ActionScript 3.0 with Flash CS3 for the Online Learning Developer
ASTD TK 2008
Module 1: Communicating with ActionScript
Module 2: Using and Writing Functions
Module 3: Basic Interactivity
Module 4: Decision Making
Module 5: Text and Text Fields
Module 6: Video and Audio
Module 7: Creating Online Learning
In Module 7, I have created two (2) sample AS 3.0 eLearning interfaces that can be used to easily drop in content. The first one (Template 001) is a single .swf file and it is a time-line based, "menu on the left" driven course. It is a single file which is quick and easy to use. Functions included in interface 001:
The .fla and .swf code is in the module 7/template001 directory.
The second interface is a bit more advanced. It consists of a single .swf file containing the menu and interface elements. However, when the user clicks on the menu, it dynamically loads the new module .swf files into itself. I used to use this technique in AS 2.0 all the time:
loadMovieNum
It was my favorite function!
Unfortunately, they killed it in AS 3.0.
This template contains the code for building eLearning using AS 3.0 that mirrors the functionality I used to enjoy in AS 2.0. Functions included in Interface 002:
The .fla and .swf code for the start page and all the additional pages is in the module 7/template002 directory.
This course took a lot of time and work to complete. I offer you these two templates so that they can potentially shave a ton of time off of your eLearning development, or provide you with code snippets to use in your own projects. Please feel free to download and use as you see fit.
However I ask you:
Thanks and enjoy the tutorial! And if you donate, thank you very much for the contribution!