Creating a Preloader


The Chapter 12 directory on the CD has a subdirectory called preloader. In this subdirectory, you will find a file named preloader.fla that contains the implementation we're about to create. There are two symbols in the library of this .fla. The first symbol is the progressBar symbol, which contains only a red rectangle and is shown in Figure 12.3. The second symbols is the preloader symbol, which contains some text saying Loading, please wait , an instance of the progressBar named progressBar , and a dynamic text field showing a percentage. This percentage text field is tied to the variable _root.percentageComplete . The preloader symbol is shown in Figure 12.4.


Figure 12.3: The progressBar symbol will show the user how much of the load has been completed after we attach the code.
click to expand
Figure 12.4: The preloader symbol contains several items that show the user how the load is progressing.

On the stage, I have instantiated the preloader symbol once and named it preloader . When the load is complete, we'll remove this preloader instance; the only thing left will be the clip we've loaded into.

We are going to reuse the movie loader that we built earlier to be the basis of the preloader. Then we can define the event handlers for the movieClipLoader class to handle the various points along the way to loading the movie. Let's start with the following basic code on frame 1:

 startLoad("http://blog.infinitumdesign.com/maze.swf"); function startLoad(url) {      _root.createEmptyMovieClip("mc", 0);      var loader = new MovieClipLoader();      loader.loadClip(url, mc); } 

I've taken away the Load button for this example. It should be fine to just immediately load the game when the movie opens. Otherwise, the code is the same as before.

Notice that I've used a path to an .swf file on my own Web site. This is a little maze-building tool. I added some audio to export out so that it's close to 100 KB. This should give you a big enough load to see the progress bar working when you test. If you need a better look, you can always use a path to some .swf you created that is really large and has lots of art and sound. That way, you can closely watch the progress bar as it updates. You'll need to put the .swf you are loading somewhere other than the system you're viewing it on, though, or the load will be nearly instant because the file doesn't have to cross a network ”just the journey from your hard drive to your RAM.

When we start a new load, we need to perform a couple of operations. We need to set the movie we are loading to be invisible so that it doesn't pop up halfway loaded. Also, we need to set the preloader bar to a state where it shows nothing having loaded. To do that, we must set the percentage to be 0 and the xscale of the preloader bar to be 0. As the movie loads, we'll increase the xscale to be whatever percentage of the movie has loaded.

Although we could simply add the code to perform these operations inside our startLoad function, let's be a little more formal about it for now. We can define the onLoadStart event handler for the movieClipLoader instance, loader . This code will only run when the loadClip method is used. onLoadStart is always called with one argument, which is a reference to the target movie where the external file is being loaded. Here is the code for this event handler:

 startLoad("http://www.medusastudios.com/pushy.swf"); function startLoad(url) {      _root.createEmptyMovieClip("mc", 0);      var loader = new MovieClipLoader();      loader.loadClip(url, mc);  loader.onLoadStart = function(loadTarget) {   loadTarget._visible=false   preloader.progressBar._xscale = 0;   percentageComplete = 0;  }; } 

I decided to use the visible property to set the game that is loading to be invisible. We'll turn the visibility back on when the whole game has loaded. After that, there are two lines of code resetting the progress bar.

Next , we need to think about what goes on while the game is loading. Whenever Flash determines that a chunk of the movie has loaded, it makes a call to another event handler on loader . This one is called onLoadProgress . There is no guarantee that this handler will ever be called. If you are loading a local file, the process sometimes happens so fast that onLoadProgress is not triggered because the start and end of the load process are so close.

To start this handler, add the following code right below onLoadStart :

 loader.onLoadProgress = function(loadTarget, bytesLoaded, bytesTotal) {           //we'll put our code in here next      }; 

Notice that this handler has a couple more arguments being passed to it. The two additional arguments store the values that indicate how many bytes of the target movie have loaded and how big the entire file is.

In this function, we need to do the updating for the progress bar. First we need to figure out how much of the movie has loaded and convert it to a percentage. Then we can use that percentage to scale the progress bar and set the text field reporting the percentage.

To get our percentage, we find the ratio of bytes loaded versus total bytes. This ratio gives us a number between 0 and 1. What we really want is a percentage between 0 and 100. To do this, we just have to scale up our ratio by multiplying it by 100.

To turn this concept into code, let's do the math but store the value in the temporary variable: percent . It makes sense to store this information in a variable because we will be using it twice:

 var percent = 100 * bytesLoaded/bytesTotal; 

The first time we use the percent variable will be to set the _ xscale of the progress bar to the percent loaded. Because the scale properties are based on percentages, our variable is already perfectly formatted:

 preloader.progressBar._xscale = percent; 

Next, we need to set the variable displayed over the progress bar. This time, though, our variable isn't a perfect fit. Although we do want to display a percentage, we don't want to display a potentially long decimal number. On a 100 K file, it's fine to display our load amount as an integer using Math.floor , as in the following:

 loader.onLoadProgress = function(loadTarget, bytesLoaded, bytesTotal) {            var percent = 100*bytesLoaded/bytesTotal;            preloader.progressBar._xscale = percent;  percentageComplete = Math.floor(percent);  }; 

That's it for onLoadProgress . If you are used to more traditional preloaders in Flash, you know that you normally need to write a condition to see if your movie has fully loaded. Now you don't need to do this; you can sit back and wait for onLoadComplete to trigger for you:

 loader.onLoadComplete = function(loadTarget) {             //we'll put code in here next      }; 

When our preloading is complete, we must take care of two simple administrative elements. We need to turn the target movie clip back to visible, and we need to make the preloader invisible:

 loader.onLoadComplete = function(loadTarget) {  loadTarget._visible = true;   preloader._visible = false;  }; 

That completes the groundwork for preloaders! From here, you can use the preloader code with your own preloader symbol to create custom loaders for any of your games . Just change the art to reflect the style of your game, and change the URL in the source.

Here is the source for the entire preloader:

 startLoad("http://www.medusastudios.com/pushy.swf"); function startLoad(url) {      _root.createEmptyMovieClip("mc", 0);      var loader = new MovieClipLoader();      loader.loadClip(url, mc);      loader.onLoadStart = function(loadTarget) {           loadTarget._visible=false           preloader.progressBar._xscale = 0;           percentageComplete = 0;      };      loader.onLoadProgress = function(loadTarget, bytesLoaded, bytesTotal) {           var percent = 100*bytesLoaded/bytesTotal;           preloader.progressBar._xscale = percent;           percentageComplete = Math.floor(percent);      };      loader.onLoadComplete = function(loadTarget) {           loadTarget._visible = true;           preloader._visible = false;      }; } 
Tip  

The movieClipLoader class has a few additional methods that are not covered in the example. View the Flash documentation for a complete listing.

You can also build fancy preloaders that play simple games or animations to amuse users while the real game downloads. Extending the preloader code I've given you allows you to build preloaders that are interesting interactive experiences. Just make sure that the .swf size of your preloader is small ”unless you want to build a preloader for your preloader. That might sound like overkill, but you'll find many of the really snazzy Flash sites actually do that.

In addition to movies, Flash can load text in a variety of formats. Let's explore one of these loading formats before moving on to more complex interactions.

Loading Text Files from the Server

Previously, we looked at how to load both .swf and .jpg files from the server. We also can load a third type of file: the text file. Loading the text file is similar to the previous loads, except that we use the loadVariables function. Loading text is a bit simpler than loading movies, so there isn't a built-in class with all the methods like we saw with movies.

LoadVariables allows you to specify key value pairs that will be assigned immediately to the specified movie. There is an unfortunate restriction to loading variables from a text file. You cannot load values into the built-in properties of a movie clip. You can only load user-defined variables .

In other words, from a text file, you can load properties for a movie clip, such as mass , strength , hitPoints , or any other value you want to create. However, you cannot load values for properties such as _x , _y , _xscale , _alpha , or any other built-in properties.

Tip  

You can work around this restriction easily enough. Just load temporary variables such as loadx, loady, loadrotation , and so on. Then when the load is finished (you'll see how to monitor this soon), you can assign the loaded variables into the movie clip properties they represent. For example,

 mc.loadVariables("my.txt");      //later, after the load is finished      mc._x = mc.loadx; mc.y = mc.loady; 

This example assumes that the my.txt file contains values for variables loadx and loady .

To perform the load, we use the loadVariables function, which has the following general form:

 void  myMovieClip  .loadVariables("  url  ", [  variables  ]); 

The URL is a string that contains the path and name of the file to load variables from. This works just like it did in the previous loads. The second, and optional, argument is used when sending data from your game to the server. We'll see how this works later in this chapter.

Note  

loadVariables does not technically have to load a text file. It can, for example, load text generated by a CGI script that returns a text string. We'll be doing this later in the chapter when we look at how to program the server. Right now, we're focused on how Flash can load data from the server without doing anything special to the server.

The movie clip where the text is loaded is not cleared with loadVariables like it was before. Instead, the variables inside the text file are added to whatever is currently in existence in the movie.

One final item to notice about loading variables is the structure of the text file. When you load a text file with loadVariables , the variables that are being loaded need to be listed in the file in a specific way.

Inside the text file, the variable names are separated from their values by the equal sign (=), much like when we define variables in the Flash environment. The major difference when writing variables for text files is that all of the variables go on one line. Where you would normally write a semicolon and a hard return, you only write an ampersand (&) symbol.

For example, if we wanted to hold variables for strength and hitPoints inside a text file to be loaded, we would include the following text inside the text file:

 strength=15&hitPoints=75 

To exemplify this further, I've created another .fla file in the Chapter 12 directory of the CD called txtloader.fla (found in the txtloader subdirectory). Inside it, we're loading these variables into a movie clip in a similar way to the previous examples. Assume that we have a text file called veggie.txt that contains strength=15&hitPoints=75 as the only text inside it.

One more piece of information that is relevant to loading text is that the variable names and values must be URL encoded. This means that, in addition to the formatting with the ampersand and equal signs, you must encode (escape) the names of the variables and their values. You must encode certain special characters so that the browser/Flash does not misunderstand their function. You've most likely seen this encoding plenty of times when surfing the Web. When you see long URLs with several percent signs (%) followed by numbers in them, you are viewing URL encoding with escaped values. If you would like to observe an example of this, type the following into a blank Flash movie:

 trace(escape("This string's value must be escaped")) 

The value you get back should be this:

 This%20string%E2%80%99s%20value%20must%20is%20escaped 

If you want to change the string back into easily readable text, try this:

 trace(unescape("This%20string%E2%80%99s%20value%20must%20is%20escaped")) 
Tip  

To be honest, the reason we're looking at loading text files from the server is to prepare us for later things. If you really need to load text data often and in bulk, you should consider looking into XML. XML allows a much more flexible style of file construction, which can aid you in loading the data. Flash supports XML, but we're not going to look into it here. In Appendix D," Web Resources and Further Reading," you'll find a link to a book about XML in Flash.

To get back to loading in text, let's start by scripting the button in our file like we have in previous examples. We are also going to create an empty movie clip, but this time, let's not create a wrapper function:

 loadButton.myText.text = "Load"; loadButton.onRelease = function(){      createEmptyMovieClip("veggie", 1); } 

After that, we can make a variable that stores the URL for the text file we want to load. Then we can call loadVariables on the movie clip that we want to load the text into:

 loadButton.myText.text = "Load"; loadButton.onRelease = function(){      createEmptyMovieClip("veggie", 1);  var myURL = "veggie.txt";   veggie.loadVariables(myURL);  } 

After the load has completed, the veggie clip will contain two new properties. One property is called strength and has a value of 15, and the other property is called hitPoints and has a value of 75.

We can try to demonstrate that the load worked correctly, but we'll run into a problem. Consider how we should prove to ourselves that the load was successful. How about adding some trace commands after the loadVariables call to output strength and hitPoint values so that we can confirm them? Consider the following code:

 loadButton.onRelease = function(){      createEmptyMovieClip("veggie", 1);      var myURL = "veggie.txt";      veggie.loadVariables(myURL);  trace(veggie.strength);   trace(veggie.hitPoints);  } 

We're adding traces to display our newly loaded values, but there is a problem. As you can see in Figure 12.5, the value of the trace is undefined .

click to expand
Figure 12.5: We're loading veggie with strength and hitPoint variables, but when we trace these, they are undefined .

I told you the loading process works, but clearly it doesn't. The question is, why do the trace s give us undefined instead of 15 and 75, as we expected?

LoadVariables is asynchronous. This means that Flash makes the call to the text file, but instead of pausing the movie until it gets a response, it continues and assumes that the text will come in later. Because it takes a few moments to perform the loadVariables call, the trace commands that came immediately after loadVariables are being executed before the server has responded with the data. We could, for example, set up an interval that would wait for a few seconds before tracing, but would that be long enough? In this next section, we'll look at the proper ways to determine when a load has been completed.

Note  

After the loadVariables function is called, it performs the load. However, the code that follows loadVariables is executed as soon as the load has been initiated. In other words, it does not wait for the load to finish before it continues.

In programming languages in general, a function that does not return until it's finished is said to be a blocking function.A function that returns immediately but might not finish its work until later is called nonblocking . With these definitions, you can see that loadVariables is a nonblocking function.

Triggering Actions at the End of a Load: onData

The subject of triggering events when your loads are complete is somewhat of a can of worms. Unfortunately, things are not as clean-cut as they should be, but bear with me and we'll get through it. To make this easy to follow, I'm going to talk about events triggered at the end of a load in two parts : one part for loadVariables and one part for loadMovie .

When you make a call to loadVariables , Flash takes a few moments to load the data; Flash takes longer if there is latency with the server or the data is large. It would be dangerous to attempt to use the data before all of it is loaded, so we need a way to trigger an event after the load is complete. How do we know when a load is complete? For loadVariables , we use the onData event.

Suppose that we have a movie clip and we attach a function to its onData event handler. We then call loadVariables on the clip. The onData function will execute when the load is complete, and not before. Let's use this to make our txtloader program trace the values of strength and hitPoints after they have been loaded. (This is what we tried to do a few pages ago and failed at.)

 loadButton.onRelease = function(){      createEmptyMovieClip("veggie", 1);      var myURL = "veggie.txt";  veggie.onData = function(){   trace("str: "+ veggie.strength);   trace("hp: "+ veggie.hitPoints);   }  veggie.loadVariables(myURL); } 

As you can see, we've added an onData function just before the loadVariables call. When the data has been fully loaded, the event will be triggered and the values will be traced, as shown in Figure 12.6.

click to expand
Figure 12.6: The onData event is triggered when the text that loadVariables is loading is completely in.

Cross-Domain Security Model

By default, you can access anything that is in the same domain as your file. For example, a file that is hosted on http://www.flash.com cannot access a file on http://www2.flash.com. This is a change from Flash MX and earlier. In earlier version of Flash, files that were within the same subdomain would be acceptable. (The preceding example passes the subdomain test.)

Flash Player 7 has become more restrictive because Macromedia has changed the security model to use policy files. You can now set up a crossdomain.xml on your servers that determines which domains can access files on that server. For more information about policy files, see the Flash documentation. (Look for cross-domain data access.)

Here is an example of a policy file. Notice that you can use wild cards and even refer to IP addresses specifically :

 <?xml version="1.0"?> <! http://www.infinitumdesign.com/crossdomain.xml > <cross-domain-policy>   <allow-access-from domain=" blog.infinitumdesign.com" />   <allow-access-from domain="*.infingames.com" />   <allow-access-from domain="128.0.0.1" /> </cross-domain-policy> 

The crossdomain.xml should be located on the root of the domain because that is where the Flash player looks. Also, if you don't have the nodes named as in the preceding example, Flash will function as if there were no policy file present.




Macromedia Flash MX 2004 Game Programming
Macromedia Flash MX 2004 Game Programming (Premier Press Game Development)
ISBN: 1592000363
EAN: 2147483647
Year: 2004
Pages: 161

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net