Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
Mr Pablo

Load mixed assets and playing sequentially?

Recommended Posts

I am having some trouble with LoaderMax when trying to create a "slideshow" of various asset types.

 

I am using parse() to load an array of SWFs and mp4 files.

 

Now, I can add everything to an array and I can seem to play the first SWF using content.rawContent.play(); but then I'm totaly stuck on how to play the next file which is an mp4 video.

 

I'm not even sure if I should add the loader content to an array?

 

In the end, I want to be able to loop through a handful of files saved locally without causing a memory leak. I can do this without LoaderMax, but the assets stay in memory and eventually all the RAM is eaten up.

 

The website makes LoaderMax seem the best solution, but I simply do not know how to implement what I want it to do.

 

I have searched and no one has tried loading different asset types in a loop, so I am stuck.

 

Below is my current code, but I'm stuck on how to advance and make the files play one after another, ideally from an array or the loader itself (does the loader store the file data?) so as to not load the file afresh each time.

 

function loadAssets(playListXml):void
{
	LoaderMax.activate([ImageLoader, SWFLoader, VideoLoader]);
	
	var urls:Array = new Array();
	
	for each(var i in playlistXml.playlist.file_path)
	{
		var file:File = File.userDirectory.resolvePath("test/"+i);
		var filePath = file.nativePath;
		
		urls.push("file://"+filePath);
	}
	
	queue = LoaderMax.parse(urls,
							{maxConnections: 2,
							onError: _onErrorHandler,
							onComplete: _onCompleteHandler,
							onChildComplete: _onChildCompleteHandler,
							onProgress: _progressHandler},
							{autoPlay: false,
							container: container,
							width: 1280,
							height: 720,
							scaleMode: "stretch",
							y: 0,
							x: 0});
	queue.load();
}

function _onErrorHandler(e:LoaderEvent):void
{
	trace(e.text);
}
function _progressHandler(e:LoaderEvent):void {
    trace(e.target.progress);
}
 
function _onChildCompleteHandler(e:LoaderEvent):void {
    trace(e.target + " loaded");
    e.target.content.visible = false;
}
 
function _onCompleteHandler(e:LoaderEvent):void {
    trace("all swfs loaded");
}

 

Hope you can help!

 

EDIT: Would it be best to use a LoaderMax XML file to achieve this? I am interacting with an API on a server to get the playlist order, so I could easily get a XML file that LoaderMAx can read (listing the proper loaders etc) Will LoaderMax be able to play the files in sequence and order if i feed it the XML?

Link to comment
Share on other sites

Hi and welcome to the GreenSock forums.

 

The issue is that different loader types have different ways of being played.

 

To play a swf, you need to find the SWFLoader's rawContent and invoke it's play() or gotoAndPlay() methods

 

To play a video, you can call the VideoLoader's playVideo() or gotoVideoTime() methods.

 

You need to detect what type of loader is next in your slideshow and play its content via the appropriate method.

 

I built a very simple file to illustrate this concept.

3 loaders are appended to a LoaderMax and a next button lets you see and play (where applicable) each image, swf and video.

 

As for creating your LoaderMax, yes you can use an XMLLoader to define all your loaders externally or use an Array and parse().

 

Here is the code I used. The important stuff is in showNextAsset()

 

 

 

import com.greensock.events.LoaderEvent;
import com.greensock.loading.*;


var slideShow:LoaderMax = new LoaderMax({onComplete:completeHandler})


slideShow.append(new ImageLoader("crab.png"));
slideShow.append(new SWFLoader("module.swf", {autoPlay:false}));
slideShow.append(new VideoLoader("angrybirds.flv", {autoPlay:false})) ;


slideShow.load();


var currentIndex:int = 0;


function completeHandler(e:LoaderEvent):void{
    trace("assets loaded");
    showAsset(currentIndex);
    }
    
    
function showAsset(index:int):void{
    
    var currentAsset = slideShow.getChildAt(index);
    trace("currentAsset = " + currentAsset);
    
    //detect what type of asset needs to be shown and played
    if(currentAsset is ImageLoader){
        trace("ImageLoader detected");
        }
        
    if(currentAsset is VideoLoader){
        trace("VideoLoader detected");
        currentAsset.gotoVideoTime(0, true);
        }    
        
    if(currentAsset is SWFLoader){
        trace("SWFLoader detected");
        currentAsset.rawContent.gotoAndPlay(1);
        }    
        
    addChild(currentAsset.content);    
    addChild(next_btn);
    }    
    
next_btn.addEventListener(MouseEvent.CLICK, getNextAssetIndex)


function getNextAssetIndex(e:MouseEvent):void{
//add logic here to loop back to the beginning and hide/stop previous asset   
    currentIndex++; 
    showAsset(currentIndex);
    }
 

note I am using the slideShow LoaderMax's getChildAt() method to grab the next asset. You don't need to build your own array of loaders, LoaderMax has 1 ready for you.

 

Attached is a CS5 file with external assets. Use your greensock files to compile

 

    

mixedAssets_CS5.zip

Link to comment
Share on other sites

This is excellent, thank you!

 

I am looking to have the clips play autonomously, where can I add an onComplete event for the child Loaders? Do I add it to the LoaderMax object, and that knows to add it to each child and listen for the event?

 

How easy would it be to convert this to read from the XmlLoader? (the XMLLoader is my best option, as the content is going to be picked by a user via a website)

 

Cheers once again!

 

EDIT - hmm, tried adding a onChildComplete event listener, and it kind of works, but it plays the clips in order of them finishing loading. I want the first asset to show, play and then fire an event on complete to activate the next asset loader. Also, is there a way to show the image for X number of seconds?

Link to comment
Share on other sites

the onComplete that gets attached to a loader fires when the asset is done loading... not done playing.

 

For each loader type there are different ways of knowing when it is done playing() and some loaders like an ImageLoader load content that doesn't play at all.

 

When you display an ImageLoader you can use TweenLite.delayedCall() to call a function after a set number of seconds and optionally pass parameters

 

 

 

TweenLite.delayedCall(4, getNextAssetIndex)
 

Check the TweenLite docs for more info

 

For SWFLoader's you really don't know when a swf is done playing. I have previously used an ENTER_FRAME event to check to see if a SWFLoader's rawContent's _currentFrame is equal to its totalFrames like this:

 

 

 

if (currentLoader.rawContent.currentFrame == currentLoader.rawContent.totalFrames) {

        trace("swf done");

        //hide and stop current swf
        currentLoader.content.visible = false;

        currentLoader.rawContent.stop();

        //set up and play the next swf

        initCurrentLoader();
    }
 

Here is an example that uses this technique to load 4 swfs and "glues them together" to play in sequcence autonomously: http://snorkl.tv/dev/loadPlaySwfs/

files:loadSWFsPlaySequence.zip

 

 

For a VideoLoader you can listen for the VIDEO_COMPLETE event and then display the next asset: 

http://forums.greensock.com/topic/6947-videoloader-playback-end-function/?hl=video_complete#entry25717

 

http://www.greensock.com/as/docs/tween/com/greensock/loading/VideoLoader.html#VIDEO_COMPLETE

 

So once you detect what type of asset is being shown and played, you can activate the appropriate method to detect when its done playing.

 

XMLLoader would be a great tool for loading and tracking the progress of your multiple assets. 

It isn't going to help in any way regarding how to respond to when the assets are done playing though. Once everything is loaded you are still going to need to use techniques similar to the ones mentioned above. 

Link to comment
Share on other sites

Once again, thank you for your input! The image, swf and video loader stuff kind of makes sense, with detecting the start and end of the asset.

 

I started to set up the XMLLoader and was wondering, how do I grab each Loader, in order, automatically from the XML file?

 

My XML looks like this:

 

 

 

<data>
    <LoaderMax name="dynamicLoaderMax" load="true">
        <VideoLoader name="video1" url="video1.mp4" autoPlay="false" height="720" width="1280" />
        <ImageLoader name="crab" url="crab.png" />
        <SWFLoader name="module" url="module.swf" autoPlay="false" />
        <VideoLoader name="video2" url="video2.mp4" autoPlay="false" height="720" width="1280" />
    </LoaderMax>
</data>
 

 

And I am able to grab a single Loader using:

 

 

 

var currentAsset = LoaderMax.getLoader("video2");
 

But in order to have them all play one after another, I need to be able to reference the Loaders by an index or such, but the only thing I can find in the API docs is to grab the Loaders by name or URL - hardly dynamic!

 

Another quick question - am I able to use URL Variables with a SWF Loader? I need to be able to pass along various bits of data to the child SWF (which house a snippet of code to grab the LoaderInfo.Parameters)

 

Cheers :D

Link to comment
Share on other sites

You wisely nested your loaders in a LoaderMax node in your xml. This will make it easy to access the loader's through your dynamicLoaderMax LoaderMax.

 

So, just like in previous examples you can do

 

currentAsset = dynamicLoaderMax.getChildAt(someIndex);

 

As for passing data into your loaded swf's, since your xml is dynamically generated I would suggest adding that data to the attributes in your SWFLoader node 

 

 

 

 <VideoLoader name="video2" url="video2.mp4" director="Jim Horn" producer="Jane Doe" autoPlay="false" height="720" width="1280" />
 

notice the director and producer attributes. XMLLoader will automatically store these values in

that VideoLoader's vars's object and you can access it like so:

 

 

 

thatVideoLoader.vars.director
 

 

Or you can even nest more robustly organized xml with the VideoLoader

 

 

 

 

<VideoLoader name="video2" url="video2.mp4" autoPlay="false" height="720" width="1280" >
<info>
        <director>Joe Horn</director>
        <producer>Jane Doe</producer>
    </info>
</VideoLoader>
 

For more info on how to associate and access custom data with loaders in xml see the 2nd and 3rd code samples here and their descriptions:

 

http://api.greensock.com/as/com/greensock/loading/XMLLoader.html

Link to comment
Share on other sites

That's fantastic!

 

Didn't spot the dynamicLoader in the docs, oops!

 

As for these loader variables, I understand calling them inside the current project, with 

 

theSWFLoader.vars.foo
 

But how would I call them inside the SWF being loaded? Do they act the same as URLVariables? Can I use 

 

var foo = loaderInfo.parameters['foo'];
 

Thanks :)

 

EDIT - I tried using currentAsset = dynamicLoaderMax.getChildAt(0); and it didn't work. "dynamicLoaderMax" is the name of the LoaderMax in the XML, but the XMLLoader is called xmlDoc, does that matter?

 

I was able to get something with var currentAsset = LoaderMax.getContent("dynamicLoaderMax"); but even whilst being able to grab the assets with an index number, the functions like playVideo() are not working e.g. currentAsset[2].playVideo(); should play the VideoLoader at node 3 (o starting index), but it doesnt. Video loads, but doesnt play.

Link to comment
Share on other sites

 

EDIT - I tried using currentAsset = dynamicLoaderMax.getChildAt(0); and it didn't work. 

 

Sorry, I should have been more clear. You would first have to create a reference to dynamicLoaderMax like

 

 

 

//first find the LoaderMax in the xml
var dynamicLoaderMax = Loader.getLoader("dynamicLoaderMax");

//now its safe to do
currentAsset = dynamicLoaderMax.getChildAt(0);
 

Also, be careful with getContent() and getLoader(). It's the VideoLoader that has the playVideo() method not the content of the VideoLoader. I think when you tried to work your way around not being able to get the getChildAt() code to work things got mixed up as the content of a LoaderMax is an array of the content of all the sub-loaders, whereas getChildAt() returns a loader.

 

And yes, you can include URLVariables in the SWFLoader url that the loaded swf can access through this.loaderInfo.parameters (but note that files with url-encoded variables won't load when tested from Flash)

 

here's a basic example

 

urlParamsParent.fla frame 1:

 

 

import com.greensock.loading.*;
import com.greensock.events.LoaderEvent;


var swf:SWFLoader = new SWFLoader("urlParams.swf?company=greensock", {container:this});
swf.load();
 

urlParams.fla (loaded swf)

 

 

import flash.events.Event;


addEventListener(Event.ADDED_TO_STAGE, getParams);


function getParams(e:Event):void{
    var loaderParams:Object = this.loaderInfo.parameters;
    var_txt.text = "loaderParams \n"+loaderParams.company;
}
 
Link to comment
Share on other sites

Content is loading fine now :)

 

As for the URL Variables, what I was trying to ask is, can I used the additional XML node info, e.g. <links><link1/></links2> as the URL Variable?

 

Or do I have to use them as I do now, and as you just explained, with the parameter added to the url?

 

Ideally, I'd like to use the XML data to pass them along.

 

Does that make sense?

Link to comment
Share on other sites

Oh, ok. Nothing gets automatically passed or added to the loaderInfo.params.

 

You could have the main swf (that loads all the child swfs) pass that info to the child-swfs by passing data into a function in the child swf OR each child swf could find the SWFLoader that loaded it and then ask for the rawXML like so:

 

in a child swf after it has been added to the stage/display list:

 

 

var mySWFLoader:SWFLoader = ContentDisplay(this.parent).loader as SWFLoader;
var myXML:XML = mySWFLoader.vars.rawXML;
 

every SWFLoader places the loaded swf in a ContentDisplay object (similar to a sprite). So the parent of your swf is this ContentDisplay object. ContentDisplay objects have a loader property, which you guessed it, refers to the SWFLoader that created it. 

Link to comment
Share on other sites

Cheers, I'll look into it!

 

It's not a big issue, I could still tack the variables onto the end of the URL, as the XML Loader file is likely to be generated via an API, so it isn't out of the question, would have just made it neater if I could have simply used the XML style variables :)

 

Thanks once again for all your help!

 

Oh, is there a simple way to remove a loader from the stage? I noticed that if i clicked my button, the assets got laid over the top of each other, as it is simply saying "addChild(asset)" and more importantly, using LoaderMax like this, going round in circles with the assets, I shouldn't encounter a memory leak?

Link to comment
Share on other sites

To remove the content of your loader from the stage/display list use removeChild(), or removeChildAt()

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObjectContainer.html

 

I'm not aware of memory leaks being caused by an item being added to and removed from the display list. 

Link to comment
Share on other sites

something I've just encountered...

 

I am able to play one vidoe asset, then another. But when the second video ends and the function to play the first video again kicks in, the original video appears, but it's paused at the end of the video.

 

How do I make sure the videos are "reset"?

 

Should I use removeChild() on the VIDEO_COMPLETE? If I do use removeChild(), will the video get added again to the stage properly?

 

Thanks!

Link to comment
Share on other sites

Super, thanks!

 

My project is running really well, and error free (obv, it couldn't compile otherwise!) but I do have 1 warning.

 

I am declaring:

 

 

 

private var dynamicLoad:LoaderMax;

private var currentAsset;
 

 

For the following:

 

 

 

dynamicLoad = LoaderMax.getLoader("dynamicLoaderMax");
currentAsset = dynamicLoad.getChildAt(index);
 

The warning is about currentAsset not being type-cast. But I simply don't know what it is haha! I tried it as a LoaderItem, but it didn't like that at all! I even tried FlexContentDisplay, but no dice.

 

Do you know what it should be declared as?

Link to comment
Share on other sites

It's been a while since I used as3, so sorry if I get some of this mixed up (I'm sure someone will correct me).

 

Setting the type to * will suppress the compiler error related to 'untyped' variables e.g.

private var currentAsset:*
 

However, that's more designed for when a variable could be one of several types you are expecting, rather than a consistent type you haven't figured out yet. It will make your compiler errors less useful (e.g. assigning a Boolean to a var typed as DisplayObject will cause an error, however if it was typed * but really needed a DisplayObject it won't tell you that). Also Flash will use more resources managing this untyped variable compared to one that is typed.

 

If dynamicLoad.getChildAt() could return items of different types, maybe * is for you, however maybe something like a super class could at least make it more specific (e.g. DisplayObject ?... pretty sure children have to be DisplayObjects)

 

You can usually figure out the type of a variable in one of these ways:

trace(typeof currentAsset); // only for primitives like Number, String etc though

// or

import flash.utils.* // home to the following functions -->

// specific class - this is the type you should use if currentAsset will always
// be of this type
trace(getQualifiedClassName(currentAsset));

// super class - you can actually set your type as this assuming currentAsset
// will always share this super class(e.g. Bitmap is a sub class of DisplayObject,
// and a Bitmap can be stored in a var of type DisplayObject), but accessing
// functions or vars of your sub class might trace as exceptions or something...
trace(getQualifiedSuperclassName(currentAsset));
Link to comment
Share on other sites

Thank you, very informative!

 

I've got another small problem, my SWF files are looping, and not stopping with my event listener!

 

I have:

 

 

 

public function trackSWFPlayback(e:Event):void
            {
                if (currentAsset.rawContent.currentFrame == currentAsset.rawContent.totalFrames) {
                    trace("swf done");
                    //hide and stop current swf
                    currentAsset.content.visible = false;
                    currentAsset.rawContent.stop();
                    //set up and play the next swf
                    getNextAssetIndex();
                }
            }
 

Initialised by:

 

 

 

if(currentAsset is SWFLoader){
                    trace("SWFLoader detected");
                    currentAsset.rawContent.gotoAndPlay(2);
                    currentAsset.addEventListener(Event.ENTER_FRAME, trackSWFPlayback);
                }
 

But it never fires. I have a video play, then this SWF, and another video should play after. the VIDEO_COMPLETE listener works perfect, but this method for stopping the SWF doesn't work oddly!

 

Any reason you can think why it wouldn't work?

 

Link to comment
Share on other sites

Are you saying the ENTER_FRAME never fires? or it never detects that the current swf has reached the last frame?

 

for you type-casting issue you could do:

 

import com.greensock.loading.core.LoaderItem;


//current asset will always be a LoaderItem: VideoLoader, SWFLoader, ImageLoader.
var currentAsset:LoaderItem;


//before calling methods specific to each LoaderItem type you would have to then cast the currentAsset as the specific type like so:


if(currentAsset is VideoLoader){
        trace("VideoLoader detected");
//cast currentAsset as a VideoLoader
        VideoLoader(currentAsset).gotoVideoTime(0, true);
        }    
        
    if(currentAsset is SWFLoader){
        trace("SWFLoader detected");
//cast currentAsset as a SWFLoader
        SWFLoader(currentAsset).rawContent.gotoAndPlay(1);
        }    
 

 

Using Jamie's dynamic suggestion: currentAsset:* would be easiest and totally fine.

Link to comment
Share on other sites

It was never firing. I fixed it by changing it from:

 

 

 

currentAsset.addEventListener(Event.ENTER_FRAME, foo);
 

 

 

to

 

 

 

addEventListener(Event.ENTER_FRAME, foo);
 

 

But the Video listener had to keep the currentAsset variable.

 

Weird!?

 

I have some new issues now, but I will create a new post for those :)

Link to comment
Share on other sites

  • 2 weeks later...

i just downloaded the "mixedAssets_CS5" and compiled. It's showing an error(1061: Call to a possibly undefined method getChildAt through a reference with static type com.greensock.loading:LoaderMax.)
 

Link to comment
Share on other sites

Hi Bose,

 

Please make sure you are using a recent version of LoaderMax. Just click the "get GSAP" button on the top left of this page and grab the latest as3 zip.

 

I just tested the files and they work fine. Keep in mind after the video is displayed, there are no more assets to show and if you try to load a fourth you will see a run time error. That file was just a quick demo to illustrate the general concepts.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×