I'm using Loader to add AMV1Movie (movie created using Toon Boom Studio) to my AS3.0 stage. How can I determine when AMV1Movie plays it's last frame?
Without dispatching something from the original movie, you'd have to poll it's currentFrame and numFrames properties, and that will only be accurate if the main timeline is an accurate depiction of the animation/program. If the AVM1Movie animates via code or has nested movieclips, there's no good way to know when it is "finished".
The best bet is to open it up and add an event to the end.
I use ForcibleLoader to load AVM1Movie as MovieClip:
var uic: UIComponent = ....
...
var loader:Loader = Loader(1uic.addChild(new Loader()));
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, startPlay);
var fLoader:ForcibleLoader = new ForcibleLoader(loader);
fLoader.load(new URLRequest("....swf"));
then I check if (movie.currentFrame + 1 >= movie.totalFrames)
I use this function to control uic.click event to stop and play movie:
private function controlSwf(event: Event): void {
var e: Event = event;
var movie: MovieClip = MovieClip(Loader(event.target).content);
if (movie.currentFrame + 1 >= movie.totalFrames) {
movie.gotoAndPlay(1);
play = true;
} else if (play) {
play = false;
movie.stop();
} else {
play = true;
movie.play();
}
}
Related
I have been looking for solutions around here but I can't seem to get it right.
Basically I am trying to load an external swf after clicking on a 'Next' button and it will automatically go to a specific frame eg. frame 8 instead of frame 1.
At first I've got an error of using of using MovieClip function in a Loader and such.
Here's my code
nextBtn.addEventListener(MouseEvent.CLICK, fl_ClickToLoadUnloadSWF_1);
var fl_Loader1:Loader;
var fl_ToLoad1:Boolean = true;
function fl_ClickToLoadUnloadSWF_1(event:MouseEvent):void
{
if(fl_ToLoad1)
{
fl_Loader1 = new Loader();
fl_Loader1.load(new URLRequest("projectnowd.swf"));
addChild(fl_Loader1);
var fl_Loader1:MovieClip = event.target.content as MovieClip;
fl_Loader1.gotoAndStop(8);
}
else
{
fl_Loader1.unload();
removeChild(fl_Loader1);
fl_Loader1 = null;
}
fl_ToLoad1 = !fl_ToLoad1;
}
You can access content of loaded swf only after event. Complete was dispatched while loading swf file on to the stage.
Define event handler method to start from 8 th frame
function loaderCompleteHandler(evt:Event):void {
var loadedMovie:MovieClipp = evt.currentTarget.content as MovieClip;
loadedMovie.gotoAndStop(8);
}
Replace if block with below lines of code
if(fl_ToLoad1)
{
fl_Loader1 = new Loader();
fl_Loader1.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteHandler);
fl_Loader1.load(new URLRequest("projectnowd.swf"));
addChild(fl_Loader1);
}
Happy coding :)
I have a movieclip "achtergrond" from my library which I put on stage with a function like this:
function set_game ()
{
oefNr = 4;
var bg:achtergrond = new achtergrond();
bg.x = 0;
bg.y = 0;
bg.name = "bg";
bg.gotoAndStop ("uit");
addChild (bg);
set_next ();
}
The movieclip contains 2 frames "aan" and "uit" and it starts on the frame "uit".
Further in my game I want to set the frame to "aan" while a sound is playing, like this:
function playSnd ():void
{
getChildByName("bg").gotoAndStop("aan");
snd = new Sound(new URLRequest("phonetic_" + curArr[curSnd] + ".mp3"));
cnl = snd.play();
cnl.addEventListener (Event.SOUND_COMPLETE, completeSnd);
}
But for the life of me I can't find the correct way to do this. Flash keeps going on about displayObjects and other things, and I have no clue why I can't address my movieclip. Actually, I have a clue, but no more than that. I don't understand this part of Flash very well yet.
The answer is that if I try to access my clip like this: this["bg"] or getChildByName("bg") I am referring to the DisplayObject.
This does not have all the methods of a MovieClip, like the gotoAndStop I need in this case.
I declared a new variable:
var movie:MovieClip;
Then I cast my DisplayObject as a MovieClip and put it into the var movie:
function set_game ()
{
oefNr = 4;
var bg:achtergrond = new achtergrond();
bg.x = 0;
bg.y = 0;
bg.name = "bg";
bg.gotoAndStop ("uit");
addChild (bg);
movie = this.getChildByName("bg") as MovieClip;
set_next ();
}
Now I can use MovieClip-specific methods like gotoAndStop:
function playSnd ():void
{
movie.gotoAndStop("aan");
snd = new Sound(new URLRequest("phonetic_" + curArr[curSnd] + ".mp3"));
cnl = snd.play();
cnl.addEventListener (Event.SOUND_COMPLETE, completeSnd);
}
Answer inspired by this answer
bg.name = "bg";
actually many times this code doesn't work properly. So, instead of setting name, you should get real instance name of your "achtergrond" object and than you have to use this instance name.
Another Solution:
I think achtergrond is single object so why do you use it with "getChildByName"? Use it like bg.gotoAndStop();.
I have this function where I want to get a movie clip (the function target) and change it to another one. The problem is that it obviously removes the movie clip before the new one is loaded.
var changePeca:Loader = new Loader;
var changeLoad:URLRequest = new URLRequest(e.target.name.substr(0,4)+".png");
changePeca.load(changeLoad);
e.target.removeChildAt(0);
e.target.addChild(changePeca);
I know that I must use the Event.COMPLETE thing, but how do I say which movie clip to remove, since I cant use e.target anymore?
"The problem is that it obviously removes the movie clip before the new
one is loaded."
Because you code says do so! :) You need to add the event listener which checks if the stuff is loaded.
private var holderMC:Sprite;
private var imageLoader:Loader;
private function load(e:Event):void
{
holderMC = e.target as Sprite // or something else you have there, just store it.
imageLoader = new Loader ();
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, handleLoadComplete)
imageLoader.load(new URLRequest(e.target.name.substr(0, 4) + ".png"));
}
private function handleLoadComplete(e:Event):void
{
if(holderMC.numChildren > 0)
holderMC.removeChildAt(0);
holderMC.addChild(imageLoader.content)
}
Using ONE Sound() object in Actionscript3, how can I play a one MP3 and then, when the user chooses a different one, play a second sound, using the SAME Sound() object?
EDIT: See my answer for how I did it.
You cannot use same Sound object to play multiple files.
Once load() is called on a Sound object, you can't later load a different sound file into that Sound object. To load a different sound file, create a new Sound object.
Ok, I actually did it using the following code. My bug was somewhere else in the FLA file, but this works. I made an uninitialized global variable and created the Sound() object LOCALLY inside of a function. While I'm technically using multiple sound objects, my references are all pointing to ONE object. Additionally, I can call these methods over one another for easier coding. This works for me:
/* -------------
Sound player
functions
------------ */
var snd:Sound; //the sound object
var sndC:SoundChannel; //the soudchannel used as "controller"
var sndT:SoundTransform; //soundTransform used for volume
var vol:Number = 1; //the volume of the song
var pan:Number = 0; //panning of the sound
var pos:Number = 0; //position of the song
var currentSound:String; //currently playing song?
function playSound(s:String){ //this function resets the sound and plays it
stopSound(sndC); //stop the sound from playing
snd = new Sound(); //reset the sound
snd.load(new URLRequest(s)); //load the desired sound
sndC = new SoundChannel(); //(re-)apply the sound channel
applyVolume(vol,pan,sndT,sndC); //apply the volume
sndC = snd.play(pos); //play it
sndC.addEventListener(Event.SOUND_COMPLETE, startSound); //remind it to restart playing when it's done
} //end function
function applyVolume(n:Number, p:Number, st:SoundTransform, sc:SoundChannel){ //takes an argument for the volume, pan, soundTYransform and soundChannel
sndT = new SoundTransform(n,p); //applies the soundTransfrom settings
sndC.soundTransform = sndT; //and attaches it to the soundChannel
} //end function
function stopSound(sndC:SoundChannel){ //this function stops a sound from playing
if(sndC != null){ //if the sound was used before (ie: playing)
if(currentLabel == "video-frame"){ //if we are in the video frame
pos = sndC.position; //store the position of the song to play from at a later time
}else{ //otherwise
pos = 0; //set the position at 0
} //end if
sndC.stop(); //stop it
} //end if
} //end function
function startSound(snd:Sound){ //restarts a sound when it's playing
if(snd != null){ //if the sound exists
sndC = snd.play(pos); //play it
} //end if
} //end function
I'm working on a flash app where I load multiple swf's. But the problem is that they have different framerates (12/25/30). If I add 2 swf's they both play at 25fps. I found numerous topic about this but I can't get it to work (in AS3). Does anyone know why it doesn't work and how to make it working?
public class MainClass extends MovieClip
{
var loader:Loader = new Loader();
var request:URLRequest;
var mcMedia:MovieClip = new MovieClip();
MovieClip.prototype.setFrameRate = function(frameRate:Number)
{
var mc:MovieClip = this;
if (mc.tweenFaster != null)
{
Timer(mc.tweenFaster).stop();
}
mc.tweenFaster = new Timer(1000/frameRate);
mc.tweenFaster.addEventListener(TimerEvent.TIMER, timelineFaster);
mc.tweenFaster.start();
function timelineFaster(event:TimerEvent = null)
{
if (mc.currentFrame == mc.totalFrames)
{
mc.tweenFaster.stop();
mc.gotoAndStop(1);
}
else
{
trace(mc.currentFrame);
mc.nextFrame();
}
event.updateAfterEvent();
}
}
public function MainClass()
{
configureListeners();
request = new URLRequest("data/7/7.swf");
try
{
loader.load(request);
}
catch (error:Error)
{
trace("Unable to load requested document.");
}
}
private function configureListeners():void
{
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
loader.contentLoaderInfo.addEventListener(Event.OPEN, openHandler);
loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressHandler);
loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
loader.contentLoaderInfo.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
}
private function completeHandler(event:Event):void
{
loader.content.scaleX = 550/event.target.width;
loader.content.scaleY = 400/event.target.height;
mcMedia.addChild(loader);
mcMedia.setFrameRate(12);
addChild(mcMedia);
}
In as3, if you're just looking to change the framerate, use stage.frameRate = 12; or whatever;
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/display/Stage.html#frameRate
In AS3, while you can use prototypes, you generally don't. I'd rewrite your setFrameRate function (which is badly named, shouldn't it be more.. tweenFaster, or matchFrameRate or something?)
I'd make a helper function like this:
package util{
//imports
public class TweenFasterMC extends MovieClip{
public var mc:MovieClip;
public function matchFrameRate(frameRate:Number):void
{
if (tweenFaster != null)
{
Timer(mc.tweenFaster).stop();
}
tweenFaster = new Timer(1000/frameRate);
tweenFaster.addEventListener(TimerEvent.TIMER, timelineFaster);
tweenFaster.start();
}
function timelineFaster(event:TimerEvent = null):void
{
if (currentFrame == totalFrames)
{
tweenFaster.stop();
gotoAndStop(1);
}
else
{
trace(currentFrame);
nextFrame();
}
event.updateAfterEvent();
}
}
Also, clean up your event listeners, that strong timer event listener will cause a lot of problems if you have a lot of mc's your applying this functionality to.
As far as I know all MovieClips in one flash player instance (sharing the same 'stage') will run at the same speed - there is no way to have two clips running at different speeds. So to adjust the speed you have to resort to calling gotoAndStop() on all MovieClips in the loaded clip at the right time - that won't be fun.
Code along the lines that quoo is showing will only work if the loaded swf contains just 1 MovieClip (no nesting) as far as I can see.
It seems to me that the most likely reason why this wouldn't work is that it requires every clip you load to be a simple, completely non-dynamic animation that loops for ever. If the loaded content is that simple, why not just adjust it to look better at 30fps? (If it's extremely long, a JSFL script could automate the process of adding extra frames.) Alternately, if the content isn't that simple, then attempting to change its timing by calling nextFrame from elsewhere is not going to give you what you want.
With all that said, if you're sure this is what you want to do but you're getting 0 as a return for currentFrame in your loaded content, are you sure they are AS3 SWFs? If they aren't, AS3/AS2 interoperation is a hairy subject that will warrant reading up on.
This is a real hassle, I've been scouring the net for an answer. I have particles following a path, and I want to change the speed that these particles follow the path dynamically, without changing the whole movie. just the particles movie clip.
I've tried greensock, but, that doesn't really work like i need.. i'd think there would be something that you can change dynamically for each mc, but, no dice.
the stage.frameset is only for the whole movie... argggggggg..... sucks..