ActionScript.org Flash, Flex and ActionScript Resources - http://www.actionscript.org/resources
Loading random Background and/or Screensaver
http://www.actionscript.org/resources/articles/176/1/Loading-random-Background-andor-Screensaver/Page1.html
Xavier Martin

Addicted to flash for a long time now.

http://dev.webbymx.net

 
By Xavier Martin
Published on September 9, 2005
 

Introduction and Php
Download FLA | example

I. INTRODUCTION

Ok, the aim of this tutorial is to provide a simple way to add a background (and/or a screensaver) to your website with text field showing how many bites are loaded. In this tutorial we will start first with the background. Then we will see the screensaver.


II. SETTING UP YOUR WORKSPACE
Assuming that "MainFolder" is the folder where you will put the final swf.

Create in "MainFolder" a new folder named "background". This is the folder where the background image files and one php file will be.
Create in "MainFolder" a new folder named "screensaver". This is the folder where the screensaver image files and one php file will be.
Create in "MainFolder" a new folder named "inc". This is the folder where you will put the const.inc.php file (and all the other include file you can use for your future website).

So you should have something like this:
MainFolder
  • background
  • inc
  • screensaver


III. THE PHP FILES 
a. config.inc.php
First, as all developers I suppose, we will create inside the MainFolder a "config.inc.php" file. This file is here to help development. In fact, all our php files will call this one to get the WEBSITE's PATH.
Here is the file:

[php]
<?php

//folder for include file

$C_INC = $C_ROOT."inc/";

//folder for background file

$C_BG = $C_ROOT."background/";

//folder for screensaver file

$C_SS = $C_ROOT."screensaver/";

?>

[/php]

The $C_ROOT var will be sent by php file including the config.inc.php, it refers to the MainFolder folder. We will see this later on the tutorial.

b. const.inc.php
Now create a new "const.inc.php" php file inside the "inc" folder. This file will have all the constants needed (for our tutorial and for your future website).
Here is the file:

[php]
<?php

//all the valid extension for the background

$C_MYEXTENSION = array ( 'jpg', 'jpeg', 'png', 'gif', 'swf' );

//all the valid extensions for the screensaver

$C_MYEXTENSIONSS = array ( 'swf' );

?>

[/php]

In this file we are creating two arrays. The first one is holding all the extension for the background file, the second for the screensaver. I hope it's enough clear. I could put all in one file, but I think it is better this way: one php file for path, another one for constants used.

c. listfile.php
Ok, now we need to make a php file that will check inside a folder all the file, then keep only the file with the extension we want (those which are define in "const.inc.php"). The php file will finally echo the name of the file to the flash movie.
We will save the file in the folder "background" with the name "listfile.php".

[php]
<?php

//give the relative path of the root (MainFolder) of the
//website.

$C_ROOT = "../";

//get the config.inc.php then know all the relative path from the root.

include_once $C_ROOT."config.inc.php";

//include all the constant like our array of extension

include_once $C_INC."const.inc.php";

//opening the current folder

$handle=opendir(".");

//make an empty array that will get our background
//filename of the actual folder

$ourFile = array();

// while next file in the folder exist

while ($file = readdir($handle)) {
        
// don't check ./ and ../
        
if ( ($file != ".") && ($file != "..")) {
 
// split the string in an array, substring
// separate by a '.'

$ext = explode('.', $file);
 
// how many value in the array
 
$howmany = count(ext);
 
// redefine the var ext. Get the extension ie the
// last substring
 
$ext = strtolower($ext[$howmany]);

// check the extension of the file. If the
// extension is on our array (const.inc.php file)

// then add the filename to our array of
// background
  
 if( in_array ($ext, $C_MYEXTENSION) ) array_push($ourFile, $file);
       
 };

};

// selecting one of the value of the ourFile array, means
// that we are taking one of the background file name

$theFile = $ourFile[array_rand($ourFile)];

//deleting the handler

closedir($handle);

//send it to flash

echo "&thefile=".$theFile."&";

?>

[/php]

Ok, so now we have a php file that echo a filename, like eg:
"Myfirstpic.jpg".

This file is inside the folder "background", so you need to put some background image files inside the "background" folder.

Then test the file by opening your browser like:
[code]localhost/your_Path_to_MainFolder_From_the_Root_of_The_Webserver/background/lisfile.php[/code]
You should have something like:
[code]&thefile=Myfirstpic.jpg& [/code]

For the screensaver it's the same thing.
Just copy this file, and some image files inside the "screensaver" folder.

Ok so all the php side is done :)

Let's go in Flash now !!! (I was impatient too)



The background



IV. THE FLASH FILES

a. What we need
Ok. So we want to make a class that load a random image file.
The name of the image file is sent by the php file.
We want a dynamic textfield displaying how many bytes are load in total bytes.

We will add some extra stuff:

  • the background will be able to refresh itself every X seconds.
  • the container will hold TWO containers. Then we will load image the first time in the first sub container, the second in the second sub container, the third in the first sub container... In fact we are using modulo 2. Why? Because while loading the movie we want the background to be displayed. If we are not using this way, when loading a new background inside the container, no background will be displayed during the loading time.

So we will use that object/type inside the class:
  • LoadVars object for loading php file
  • MovieClip for the main container and the sub container
  • MovieClipLoader and listener to get the bytes loaded and all the event (start loading, while loading, end loading, displaying movieclip, on error loading)
  • Numbers var to hold the delay, start time of the delay, and the ID of the interval calling the function that will check if the delay is passed.
  • textField which displaying the info
    This is all we can know for now I think.


b. Add new method to MovieClip class
[as]
MovieClip.prototype.scaleToStage= function () {
 
 //get the value that help me rescaling the mc

this._xscale = 100;

this._yscale = 100;
 
var W = this._width;

var H = this._height;

var RW = Stage.width;

var RH = Stage.height;

//rescaling
 
this._xscale = (RW/W)*100;

this._yscale = (RH/H)*100;

this._x = 0;

this._y = 0;

}

[/as]

Some brief explanations:
Why did we use the OLD WAY to add new method to the MovieClip?
Because we need to be able to create new empty movie clip at runtime, and if we are using the new way (means defining a new class extended MovieClip) we are not able to associate at runtime the new class to the MovieClip object created (update 2006: this is no more true ,check for MCE).
This function is rescaling the MovieClip to the stage's size and setting _x and _y to 0.

c. The loadBackground class
Ok so let's start declaring our loadBackground class now:
[as]
class froggies.loadBackground {

        private var _nDelay:Number;
 
        private var _nSICheck:Number;

        private var _nStartTime:Number;
 
        private var _nModulo:Number;

        private var _oBackground:Object;

        private var _mcBackground:MovieClip;

        private var _mcFirstBackground:MovieClip;

        private var _mcSecondBackground:MovieClip;

        private var _mclBackground:MovieClipLoader;

        private var _sFolder:String;

        private var _tfDispInfo:TextField;

        function loadBackground (mcBackground, tfDispInfo, nDelay, sFolder) {

                //getting the properties send by the user

                _nDelay = nDelay;

                _mcBackground = mcBackground;

                _tfDispInfo = tfDispInfo;

                _sFolder = sFolder;

                _nStartTime = null;

                _nSICheck = null;

                _nModulo = -1;

                _oBackground = new Object();

                _mclBackground = new MovieClipLoader();

                _mcFirstBackground = _mcBackground.createEmptyMovieClip("mc0", 0);

                //if you want to change background every X milliseconds then need another mc to make transition without waiting the loading

                if (_nDelay != -1) _mcSecondBackground = _mcBackground.createEmptyMovieClip("mc1", 1);

                _oBackground._owner = this;
 
                //defining my object

                _oBackground.onLoadStart = function (cible_mc) {

                        cible_mc._visible = false;

                        cible_mc.gotoAndStop(1);

                        this._owner._tfDispInfo.text = "Loading starting";

                        this._owner._tfDispInfo._visible = true;

                }

                _oBackground.onLoadProgress = function (cible_mc, loadedBytes, totalBytes) {

                        cible_mc._visible = false;

                        cible_mc.gotoAndStop(1);

                        this._owner._tfDispInfo.text = "Loading "+Math.ceil(loadedBytes/1024)+" / "+Math.ceil(totalBytes/1024)+" kbytes";

                }

                _oBackground.onLoadComplete = function (cible_mc) {

                        cible_mc._visible = false;

                        cible_mc.gotoAndStop(1);

                        this._owner._tfDispInfo._visible = false;

                }

                _oBackground.onLoadInit = function (cible_mc) {

                        //scale the mc to the size of the stage;

                        this._owner._mclBackground.removeListener(this._owner._oBackground);

                        cible_mc.swapDepths(1);

                        cible_mc._parent.scaleToStage();

                        cible_mc._visible = true;

                        cible_mc.gotoAndPlay(1);

                        if(this._owner._nDelay != -1) this._owner.nextBackground(cible_mc);

                }

                _oBackground.onLoadError = function (cible_mc, errorCode) {

                        this._owner._mclBackground.removeListener(this._owner._oBackground);

                }

                Init();

        }


        private function Init():Void {

                newBackground();

        }


        private function newBackground ():Void {

                _tfDispInfo._visible = true;

                _tfDispInfo.text = "Loading php file";

                var _lvBackground:LoadVars = new LoadVars();

                _lvBackground._owner = this;

                //who's the next container?

                _nModulo++;

                var num:Number = _nModulo%2;

                //to make url unique

                var dMyDate:Date = new Date();

                var unique:Number = dMyDate.getTime();

                _lvBackground._nextContainer = _mcBackground["mc"+num];

                //loading the php file that returning the background

                _lvBackground.onLoad = function (ok):Void {

                        if(ok) {

                                /*********************************************************

                                Add the listener to the MoveiClipLoader object and

                                load the background inside the movieclip background
 
                               **********************************************************/
 
                               this._owner._mclBackground.unloadClip(this._nextContainer);

                               this._owner._mclBackground.addListener(this._owner._oBackground);
 
                               this._owner._mclBackground.loadClip(this._owner._sFolder+this.thefile, this._nextContainer);

                        }

                }

                _lvBackground.load(_sFolder+"listfile.php?"+unique);

        }


        private function nextBackground ():Void {

                _nStartTime = new Date().getTime();

                _nSICheck = setinterval(checktime, 48, this);

        }


        private function checktime (_owner):Void {

                var nNow:Number = new Date().getTime();

                if (nNow - _owner._nStartTime > _owner._nDelay) {

                        clearInterval(_owner._nSICheck);

                        _owner.newBackground();

                }

        }

}

[/as]


d. How this class is working?
We are creating a new class inside which is inside froggies package (class froggies.loadBackground ).
We are defining all the properties (var/object) used in this class. All are private (protected in fact).
Then is coming the constructor where we are setting up all the properties.

Four properties are setting up by parameters. It's the delay (if equal to -1 means no delay so no reloading), the MovieClip (container) which is holding the two sub containers, the textField which is displaying the bytes loaded, and the folder where the files (image and php) are.
The other are the

  • _nStartTime: we will call another background if currentTime - _nStartTime > _nDelay -,
  • _nSICheck which is holding the ID of the setinterval which is calling the function that checking if currentTime - _nStartTime > _nDelay
  • _nModulo that let us know in which sub container we have to load the new background, _oBackground which is the listener for the MovieClipLoader,
  • _mclBackground which is the MovieClipLoader.

Ok then we are adding a new property to the _ oBackground object defining its parent: (_oBackground._owner = this;).

Then we are defining all the methods of this object:

  • onLoadStart , we are hiding the sub container, stopping it at frame 1, adding text on textField and showing it
  • onLoadProgress , we are hiding the sub container, stopping it at frame 1, and displaying inside the textField the bytes loaded on total bytes
  • onLoadcomplete , we are hiding the sub container, stopping it at frame 1, and make the textField invisible.
  • onLoadInit , we are removing the link between this listener and the sub container, putting the sub container to front, scaling the sub container to the stage's size, making it visible and playing it, and calling the function that check for the next background
  • onLoadError , we are just removing the link between the listener and the MovieClipLoader.

Then we are calling Init() function. Why making a function with just one call to another one? Because when we will do the screensaver class the Init will not be the same, but the constructor will be. That's all. If we are putting the newBackground call inside the constructor we must rewrite ALL the constructor for the screensaver class. We will see that later.
Ok now the functions (methods) of the class. I put comments on the code, so I think it's enough. That's why here I'm telling briefly what the function are doing.
 

  • newBackground is loading the php file, getting the random filename and then loading inside the sub container this file.
  • nextBackground is setting up _nStartTime to now and calling with interval checktime.
  • checktime is taking the current time and if currentTime - _nStartTime > _nDelay then call the newBackground methods.


The screensaver


V. AND FOR THE SCREENSAVER?

Ok for the screensaver there are some little things to add. But it will be quite easy after the loadBackground class.

a. What we need
Ok. What are our needs for the screensaver?
First we want it to reload every X seconds, but this thing has been already done in the loadBackground class (yehaaaaaaaaa).

When the background will be loaded?
If the user is not moving the mouse for X seconds then the screensaver will load itself.
So we need an event on the MouseMove: each time the user will move the mouse, we will reset the startTime (don't forget the currentTime - _nStartTime > _nDelay). Then if the difference is bigger than the delay we will load the screensaver.

What else?
Every screensaver get a button to get out, or a mouse event. For my case I prefer to put an event on a button. So if the user is clicking the button, then he's coming back to the website. So we need a button and we need to define the onRelease event for this button.

b. the loadScreensaver class
Ok this is the class:

[as]class froggies.loadScreensaver extends froggies.loadBackground {
        //inherit from the loadBackground class
        private var _mcContinue:MovieClip;
        function loadScreensaver (mcBackground, tfDispInfo, nDelay, sFolder, btn) {
                //inherit from the loadBackroung constructor
                super(mcBackground, tfDispInfo, nDelay, sFolder);
                _mcBackground._owner = this;
                _mcBackground.onMouseMove = function() {
                        this._owner.clearDelay();
                }
                //btn you click to stop the screensaver
                _mcContinue = btn;
                //hidding the button
                _mcContinue._visible = false;
                _mcContinue._owner = this;
                _mcContinue.onRelease = function () {
                        this._owner._mcBackground.onMouseMove = function() {
                                this._owner.clearDelay();
                        }
                        this._owner.clearDelay();
                }
                _oBackground.onLoadComplete = function (cible_mc) {
                        delete(this._owner._mcBackground.onMouseMove);
                        this._owner._mcContinue._visible = true;
                        cible_mc._visible = false;
                        cible_mc.gotoAndStop(1);
                        this._owner._tfDispInfo._visible = false;
                }
        }
        private function Init():Void {
                nextBackground();
        }
        public function clearDelay ():Void {
                if(_nSICheck != null) {
                        //clearing the interval
                        clearInterval(_nSICheck);
                        _nSICheck = null;
                        //removing the listener --> stop loading the contents if loading
                        _mclBackground.removeListener(_oBackground);
                        _mclBackground.unloadClip(_mcBackground.mc0);
                        _mclBackground.unloadClip(_mcBackground.mc1);
                        //hidding the button
                        _mcContinue._visible = false;
                        //hidding the textField
                        _tfDispInfo._visible = false;
                        //hiding the container
                        _mcBackground.mc0._visible = false;
                        _mcBackground.mc1._visible = false;
                        //calling the nextScreensaver
                        nextBackground();
                }
        }
}
      [/as]


c. How this class is working?
We are making a new class inherit from the loadBackground class:
class froggies.loadScreensaver extends froggies.loadBackground
So the new class loadScreensaver get all the methods (functions) and properties (var) of the loadBackground class.
For the loadScreensaver class we need a button (a MovieClip object), so just add a new property to the one existing already:
private var _mcContinue:MovieClip;

Now the constructor.
We are adding some extra stuff and changing others.
So first we need to inherit from the loadBackground constructor - super(mcBackground, tfDispInfo, nDelay, sFolder); - then we are defining our extra stuff.

The main container have a MouseMove event on it where we are calling the method clearDelay - this._owner.clearDelay(); - , so before we need to know which is the owner of the container object - _mcBackground._owner = this; -.

NOTE: When you are using instance of class inside other class (like we have done with button eg, this is called composition) you need to specify the owner of the instance to be able to access the methods and properties of the class holding it.

Still in the constructor, we are setting up our button with the parameter sent in the constructor. Then we are hiding this button, and adding a onRelease event, that clearing the delay (so the screensaver will not more be display), and defining the onMouseMove event of the container.
Why redefining it, because we are deleting this event when the screensaver is loaded. (we want to click on a button, not moving the mouse).
When the screensaver is unload, we need to clearDelay each time the user movethe mouse, so we need to redefine the MouseMove event. That's why. (yeah I know it's a bit confusing but I can't find other way to explain it :/ hé don't forget I'm a froggy)

And we are finally redefining the onLoadComplete event of the listener. We are just adding 2 lines compare to the one in the loadBackground class. We are deleting the MouseMove event of the container (yes it's here) - delete(this._owner._mcBackground.onMouseMove); - and we are making the button visible.

Now the methods (functions) of this class:
Init() is not the same. Here we are calling the function nextBackground() because we want the screensaver to load after X seconds and not as soon as the movie start.

clearDelay() is clearing the setinterval calling the function checktime, removing the listener (stop loading the content then) and unloading the sub containers, hiding the continue button, hiding the info textField and hiding the sub containers, then calling nexBackground() which is checking if the screensaver have to be displayed (after X seconds).


VI. HOW TO USE THOSE CLASSES 
a. loadBackground
This is VERY SIMPLE. Just create a new fla . Then add 2 layers.
The upper one is the layer called "infoBG" where you must put the dynamic textField, and call it infoBackground .
Then come the layer "BG", where you need to put an empty MovieClip and call it backgroundImage .
The last one is the layer "action", where you are writing this code:

[as]import froggies.loadBackground
//This will load the Background only once
aBackground = new loadBackground(_root.backgroundImage, _root.infoBackground, -1, "./background/");
//This will load the Background every 1 minute
//aBackground = new loadBackground(_root.backgroundImage, _root.infoBackground, 60000, "./background/");
[/as]


 
b. loadScreensaver
This is VERY SIMPLE. Just create a new fla . Then add 2 layers.
The upper one is the layer called "infoSS" where you must put the dynamic textField, and call it infoScreensaver .
Then come the layer "SS", where you need to put an empty MovieClip and call it screensaverImage .
The last one is the layer "action", where you are writing this code:

[as]import froggies.loadScreensaver
//This will load the Screensaver every 1 minute
aScreensaver = new loadScreensaver(_root. screensaverImage, _root.infoScreensaver, 60000, "./background/");
[/as]


When using both it's the same thing. Don't forget to put screensaver container and text and button in a upper level than your background (see the fla joined).


VII Conclusion
I hope that you get all. If you need help and/or have comments/feedbacks, email me.
I'll be please to answer you.