PDA

View Full Version : Flash Random Image Loader help needed...



shanek
04-25-2007, 07:52 PM
I was hoping someone could help me with a slight modification to my code? You see currently this code has a minimum and maximum value association (in this case from 1 to 20) so if there is no image named say "8.jpg" then the script fails. Could you show me how to modify it to continue on until it succeeds in finding an image even if I set the max value to 1000 and there are only 30 images available? The client wants to drop photos into the directory without restriction as to how many are actually in there. And if no image with a certain number is currently in the directory then the script should just carry on to the next image available. Additionally, is there a way to have this script loop at a preset duration so that the page refreshes with a new image say every 20 or 30 seconds.

Here is the original script:

MovieClip.prototype.setRand = function() {
largest= 20;
lowest = 1;
rand = ((Math.floor(Math.random()*100)%(largest-lowest+1))+lowest);
loadMovie(+rand+".jpg", "myLoader");
}

setRand();



Thanks in advance for any help you can provide. :)

nwalton
04-25-2007, 09:22 PM
This looks like some older coding conventions... What versions of Flash and Actionscript are you using?

In AS 2.0 I'd use a MovieClipLoader to bring in all the clips. I'm trying to come up with a good way for Flash to generate a list of the images that are actually there, so it doesn't have to run through a bunch of failures every time it tries to load a new clip. I'll get back to you on it...

shanek
04-25-2007, 09:43 PM
I'm using my spanking new version of Flash CS3, but I believe it is actionscript 2.0.

I appreciate the help as this is a real time crunch.

nwalton
04-26-2007, 01:45 AM
Okay, I've got a couple of items for you. First, I tried to make an initial test that would see what images are available. It takes a minute to run, so it's better if there aren't too many images. Here's the code, placed on a frame in your movie:


stop();

var thisMovie:MovieClip = this; // A reference to the current movie

// The movieClipLoader and listener
var my_mcl:MovieClipLoader = new MovieClipLoader();
var clipListener1:Object = new Object();

// An array to hold valid path names
var images:Array = new Array();

// Variables to facilitate the check
var maxImages:Number = 100;
var currentImage:Number = 1;
var imagePath:String = "images/"
var currentImagePath:String = imagePath + currentImage + ".jpg";

// A movieClip to hold the images temporarily
var check_mc:MovieClip = this.createEmptyMovieClip("check_mc",0);
check_mc._alpha = 0; // make it invisible

// Start the load check
my_mcl.loadClip(currentImagePath, check_mc);


// Loads the next image in the sequence
function checkNextImage(){
currentImage++;
currentImagePath = imagePath + currentImage + ".jpg";
my_mcl.loadClip(currentImagePath, check_mc);
}


// Loading events
clipListener1.onLoadStart = function(){
trace("Added: " + currentImagePath);
images.push(currentImagePath);
checkNextImage();
}
clipListener1.onLoadError = function(){
if(currentImage < maxImages){
checkNextImage();
} else {
thisMovie.gotoAndStop("display");
}
}
my_mcl.addListener(clipListener1);

nwalton
04-26-2007, 01:54 AM
Then here's what I have on the "display" frame. I've tried to comment things so you could follow better what I'm doing:


stop();
trace(images);

// Display your images randomly

var imageArray:Array = images; // Just grabs the array from frame 1 so you remember it's there
var numImages:Number = imageArray.length; // The number of valid images
var thisImage:String; // Property for the current image
var delayTime:Number = 5000; // The delay, in milliseconds that you want between image switches (1 sec = 1000 ms)

my_mcl.removeListener(clipListener1); // Gets rid of the checking actions

// Get an image to display
getNewImage();


// Gets a new image path from the array and call the function to display that image
function getNewImage(){
var newImgNum:Number = randRange(0, (numImages - 1)); // Get a random item number in the array
var newImage:String = imageArray[newImgNum]; // Get the image path from the array

if (newImage != thisImage){ // If it's not the same as what's displayed
displayImage(newImage); // Calls the function below
setTimeout(getNewImage, delayTime); // Calls this function again in a set amount of time
thisImage = newImage; // Sets the current image property
} else {
getNewImage(); // if the image called is the same as the one that's displayed, get a new one
}
}


// Displays the image
function displayImage(path:String){
trace(path);
// Your code here
}

// Gets a random number within a range
function randRange(min:Number, max:Number):Number {
var randomNum:Number = Math.floor(Math.random() * (max - min + 1)) + min;
return randomNum;
}

nwalton
04-26-2007, 01:56 AM
And here's the test file I used:

980

shanek
04-26-2007, 06:42 AM
Thanks. I'll have a look at it and give it a test. I have read though that using arrays for this type of stuff has quite a bit of overhead and taxes the CPU quite a bit. The only other thing I can think of is that the client is a photographer and will always be dumping new photos into the directory, so there may end up being quite a bit of them to parse. Does this script parse each time the page is loaded?

nwalton
04-26-2007, 06:54 AM
Yes, the script will run through the possibilities each time the flash file is loaded.

This use of the array shouldn't tax the system much, since it's only used to hold values that are accessed one by one instead of as a group. The thing that is slow is looping through all 100 or 1000 numbers of images that could be there. If it's likely that most of the numbers will be present, I'd probably build it a little differently.

Also, if it's maybe okay to have the first image load first, you could have the loop running in the background while that image is already displayed. Then it could be random after that.

What I've usually done in cases like this is create an XML file that defines all of the available images. But if you haven't done it before it can be a little hard to work with. And you have to update the XML every time you add or remove an image.

Another option is to use javascript or PHP to read the contents of the directory, since they can do it a lot easier. Then you'd have to pass the variables to Flash.

I hope this helps, and that all the info isn't too confusing.

shanek
04-26-2007, 07:37 PM
Thanks. I will put some more thought into this.

nwalton
04-27-2007, 09:06 PM
I just found a method using Flash coupled with PHP that ought to work for what you're trying to do:

http://www.kirupa.com/developer/mx2004/external_array.htm

This passes an array to Flash containing the names of all the files in a directory. It could replace the code I had in frame 1, which essentially did the same thing. You'll probably have to modify the code a little, but this looks like an excellent solution to me, if PHP is installed on your server (which is pretty likely).

TalhaA
08-17-2007, 01:38 AM
Hi
This code is exactly what I've been looking for, although I couldn't make it work.
I just changed the path and img names but the only thing that I get is a blank screen.
I tested every step and it seems like it's working fine but jpg files do not display.
I'm new to this and I use AS 2.0. I really appreciate any help
Thanks

Medyman
08-17-2007, 01:42 PM
Check the registration points of your loader movieclip (they should be in the upper left) and/or post your source.

TalhaA
08-19-2007, 01:10 AM
Ok this is the code on the first frame.
"createEmptyMovieClip" creates check_mc on the stage right?
So it's automatically on the upper left corner.




stop();

var thisMovie:MovieClip = this; // A reference to the current movie

// The movieClipLoader and listener
var my_mcl:MovieClipLoader = new MovieClipLoader();
var clipListener1:Object = new Object();

// An array to hold valid path names
var images:Array = new Array();

// Variables to facilitate the check
var maxImages:Number = 3;
var currentImage:Number = 1;
var imagePath:String = "images/"
var currentImagePath:String = imagePath + currentImage + ".jpg";

// A movieClip to hold the images temporarily
var check_mc:MovieClip = this.createEmptyMovieClip("check_mc",0);
check_mc._alpha = 0;

// Start the load check
my_mcl.loadClip(currentImagePath, check_mc);


// Loads the next image in the sequence
function checkNextImage(){
currentImage++;
currentImagePath = imagePath + currentImage + ".jpg";
my_mcl.loadClip(currentImagePath, check_mc);
trace("checked " + currentImagePath);
}


// Loading events
clipListener1.onLoadStart = function(){
trace("Added: " + currentImagePath);
images.push(currentImagePath);
checkNextImage();
}
clipListener1.onLoadError = function(){
if(currentImage < maxImages){
checkNextImage();
} else {
thisMovie.gotoAndPlay("display");
}
}
my_mcl.addListener(clipListener1);

TalhaA
08-19-2007, 01:14 AM
And this is what's on display frame.
I can't see any problem but there is absolutely one :confused:




stop();
trace(images);

// Display your images randomly here

var imageArray:Array = images; // Just grabs the array from frame 1 so you remember it's there
var numImages:Number = imageArray.length; // The number of valid images
var thisImage:String; // Property for the current image
var delayTime:Number = 3000; // The delay, in milliseconds that you want between image switches (1 sec = 1000 ms)

my_mcl.removeListener(clipListener1); // Gets rid of the checking actions

// Get an image to display
getNewImage();


// Gets a new image path from the array and call the function to display that image
function getNewImage(){
var newImgNum:Number = randRange(0, (numImages - 1)); // Get a random item number in the array
var newImage:String = imageArray[newImgNum]; // Get the image path from the array

if (newImage != thisImage){ // If it's not the same as what's displayed
displayImage(newImage); // Calls the function below
setTimeout(getNewImage, delayTime); // Calls this function again in a set amount of time
thisImage = newImage; // Sets the current image property
} else {
getNewImage(); // if the image called is the same as the one that's displayed, get a new one
}
}


// Displays the image
function displayImage(path:String){

check_mc._alpha = 100
trace("displayed " + thisImage);
// Your code here
}

// Gets a random number within a range
function randRange(min:Number, max:Number):Number {
var randomNum:Number = Math.floor(Math.random() * (max - min + 1)) + min;
return randomNum;
}

Medyman
08-20-2007, 02:56 PM
I kinda skimmed over the code but didn't really pay much attention to it.
I build these all the time and I think your random picture function is way too needlessly complex with too much code especially since I didn't notice any XML loading, picture transition functions or preloader code.

Here's how I would do it in 12 lines of code:


var pics:Array = new Array();
pics[0] = "image1.jpg";
pics[1] = "image1.jpg";
pics[2] = "image1.jpg";
pics[3] = "image1.jpg";
function showRandomPic() {
var n:Number = Math.ceil(Math.random()*pics.length-1); //create random number
pic_mc.loadMovie(pics[n]); // load associated image from random number
}
var timer = setInterval(function () {//set up timer
showRandomPic();//run function
},1000);//load random pic every 1 second

It's just the most basic concept of a random picture without any bells and whistles.

TalhaA
08-20-2007, 10:59 PM
Thanks.
Is it complicated to avoid same pictures repeating right after?

Medyman
08-21-2007, 03:49 AM
Something like this:


var a:Array = new Array();

for(i=0;i<15;i++){

a[i] = i;

}

var stored:Number = Math.ceil(Math.random()*a.length-1);// generate first random number to store in memory

function randomNumber() {

var n:Number = Math.ceil(Math.random()*a.length-1);//generate random number for display

if (n == stored) {

ran();//run function again

} else {

stored = n; //store new random number into memory if not matching
trace(a[n]);

}
}
var timer = setInterval(function () {
randomNumber();
}, 100);