I have an external SWF that I load into a Loader object.
I add this Loader object as a child to a MovieClip and add this MovieClip to my stage.
I now want to draw a transparent rectangular Sprite on top of the Loader object, that is just needed to catch mouse event.
(I need to know when the mouse rolled over and rolled out of the transparent layer).
.
If you're asking yourself - why do I need this transparent layer and not just catch the events on the Loader itself ? well, there are a lot of reasons for this, most of them have to do with the client requests, but also - because some externally loaded SWFs don't respond to the mouse events for some reason - so I need to 'trick' it and add my own transparent layer on top.
My problem is -
if I put the transparent layer as a child of the MovieClip that holds the Loader, then I get this hirarchy:
problem is - mouse events are caught by the top-most layer (the transparent-layer) and passed on to the MovieClip and the Stage.
The events aren't fired in the Loader object, and so - the SWF becomes non-interactive.
.
The other solution would be -
to somehow add the transparent layer as a child of the Loader object, like this:
then the events would be bubbled up to the Loader and the SWF.
Problem is - Loader class does not allow you to add child elements to it (except for the loaded SWF).
So can anyone offer advice how I can add a transparent layer on top of the SWF and still have mouse interaction with both the transparent layer and the SWF layer ?
The transparent layer is blocking the events of the loaded swf file. You need to use the mouseEnabled property to false for this layer.
I don't know if this work for you, but I think that this could be useful. Adds the following code in your main swf.
import flash.display.Loader;
import flash.events.Event;
import flash.events.MouseEvent;
import fl.transitions.Tween;
import fl.motion.easing.Linear;
// Disables the mouse interations
transparentLayer.mouseEnabled = false;
// Initialize with alpha 0
transparentLayer.alpha = 0;
// Cretes the loader
var loader:Loader = new Loader();
// Listen the complete event
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);
// Loads the external swf files
loader.load(new URLRequest("swf.swf"));
// Add in the background
addChildAt(loader, 0);
// Listen the complete event
function loadComplete (event:Event) {
// Add the mouse events to the loaded content
loader.contentLoaderInfo.content.addEventListener(MouseEvent.ROLL_OVER, mouseHandler);
loader.contentLoaderInfo.content.addEventListener(MouseEvent.ROLL_OUT, mouseHandler);
}
// Handles de mouse events of the loaded swf
function mouseHandler (event:MouseEvent)
{
switch (event.type)
{
case MouseEvent.ROLL_OVER :
// Shows the transparentLayer from the current alpha value to 1 in 1 second
new Tween(transparentLayer, "alpha", Linear.easeNone, transparentLayer.alpha, 1, 1, true);
break;
case MouseEvent.ROLL_OUT :
// Shows the transparentLayer from the current alpha value to 0 in 1 second
new Tween(transparentLayer, "alpha", Linear.easeNone, transparentLayer.alpha, 0, 1, true);
break;
}
}
The transparent layer lost all its interations, so you need apply the motion effects externally. Here you can download the project running http://cl.ly/LtfA
Related
I am building a Flash Game, I am doing this:
MainStage, with 11 frames
Mainstage Loads > Lobby.swf (1 frame)
Lobby Loads > Arrows.swf (1 frame)
I just want to control the main Stage from Arrows.swf , get the current frame, right arrow mainStage.current frame + 1, left arrow mainStage.current frame -1
I have tried the parent/child method
this.parent.parent
parent.parent
this.root
parent.root
every combination, I am also tracing and when I finally hit the mainStage it is saying cannot convert Stage to Display Object which I understand.
but how can I just get current frame of the "mainstage" needle and control it with gotoAndPlay or other such methods ?
I have solved it.
I didn't control the main stage what I did was, I reduced the main stage layer in the lobby layer when I load the left and right arrow I attach an event listener for a custom event.
In the arrows movie I have written a function to dispatch the event here are the lines of code I used
in the "main" stage of the movie you want to control:
//ball loader prep and load
var ballLoader:Loader = new Loader();
var ballRequest:URLRequest = new URLRequest("lobbyBalls.swf");
ballLoader.load(ballRequest);
ballLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, ballsLoaded);
function ballsLoaded(event:Event):void{
trace("ball Loader complete");
ballLoader.x = 50;
ballLoader.y = 200;
stage.addChild(ballLoader);
ballLoader.content.addEventListener("Previous", ctrlPrevFrame);
ballLoader.content.addEventListener("Next", ctrlNextFrame);
}
In the movie from which you want to control
import flash.events.Event;
leftArrow.addEventListener(MouseEvent.CLICK, prevEvent);
rightArrow.addEventListener(MouseEvent.CLICK, nextEvent);
function prevEvent(event:Event):void{
trace("prev");
dispatchEvent(new Event("Previous", true));
}
function nextEvent(event:Event):void{
trace("next");
dispatchEvent(new Event("Next", true));
}
Thanks anyways....
I have a swf file loaded into a main movie. When the child is finished playing, ie reaches its final frame, I would like the swf to unload. Can anyone tell me what bits I can add to this code?
//start button
start_button_aboriginal.addEventListener(MouseEvent.CLICK, fl_ClickToLoadUnloadSWF_3,false,0,true);
import fl.display.ProLoader;
var fl_ProLoader_3:ProLoader;
var fl_ToLoad_3:Boolean = true;
function fl_ClickToLoadUnloadSWF_3(event:MouseEvent):void
{
//ADDED APR02 START
fl_ProLoader_3.contentLoaderInfo.addEventListener(Event.INIT, childInitHandler);
fl_ProLoader_3.load(new URLRequest("myths/myth_aboriginal.swf"));
//ADDED APR02 END
if(fl_ToLoad_3)
{
fl_ProLoader_3 = new ProLoader();
fl_ProLoader_3.load(new URLRequest("myths/myth_aboriginal.swf"));
addChild(fl_ProLoader_3);
fl_ProLoader_3.x = 114;
fl_ProLoader_3.y = 41;
}
else
{
removeChild(fl_ProLoader_3);
fl_ProLoader_3.unloadAndStop();
fl_ProLoader_3 = null;
}
// Toggle whether you want to load or unload the SWF
fl_ToLoad_3 = !fl_ToLoad_3;
}
You could
1) Use the undocumented addFrameScript function defined in the MovieClip class to place a callback on the last frame of the child SWF. Useful if you don't have control over the code in your loaded SWF.
addFrameScript() has the following signature:
addFrameScript(frameNumber, callback); //frameNumber is zero-based (unlike in the Flash authoring suite, here you would enter 0 to refer to the first frame, and 1 for the second.)
In the parent SWF, add the following:
function fl_ClickToLoadUnloadSWF_3(event:MouseEvent):void {
...
fl_ProLoader_3.contentLoaderInfo.addEventListener(Event.INIT, childInitHandler);
fl_ProLoader_3.load(new URLRequest("myths/myth_aboriginal.swf"));
...
}
function childInitHandler(event:Event):void {
MovieClip(fl_ProLoader_3.content).addFrameScript(MovieClip(fl_ProLoader_3.content).totalFrames-1, unloadChild);
}
function unloadChild() {
fl_ProLoader_3.unloadAndStop();
}
If you're worried about addFrameScript going away - don't be. When you put code on the timeline, all that code is actually compiled into functions in the document class, with frame listeners added via addFrameScript.
Remember to define function unloadChild().
function unloadChild():void {
fl_ProLoader_3.unloadAndStop();
}
-OR-
2) Dispatch an event from your loaded SWF when it reaches the final frame.
In last frame of child SWF:
this.dispatchEvent(new Event("lastFrameReached"));
In parent SWF, add the following:
fl_ProLoader_3.content.addEventListener("lastFrameReached", unloadChild);
-OR-
3) Subscribe to the ENTER_FRAME event of the child and check if the child is on its last frame.
In parent SWF, add the following:
fl_ProLoader_3.content.addEventListener(Event.ENTER_FRAME, checkIfEnded);
function checkIfEnded(event:Event):void {
if (fl_ProLoader_3.content.currentFrame == fl_ProLoader_3.content.totalFrames) {
unloadChild();
}
}
I personally prefer addFrameScript - seems to me a cleaner solution. Callback runs once, you don't have to poll and you don't need to modify the child SWF.
There are a number of ways to solve this, and it has been asked many times...
Unload child swf on last frame of child swf
When External SWF has reached Frame X, how do I unload it?
That said, one way you could resolve this without creating event listeners on the child swf, is by periodically checking the child swf for the current frame. If it's the last one on the swf, call the unload method.
// once every second, indefinitely.
var tick:Timer = new Timer(1000, 0);
tick.addEventListener(TimerEvent.TIMER, checkSWF);
tick.start();
//Load something to the stage.
var loader:Loader = new Loader();
loader.load(new URLRequest("child.swf"));
addChild(loader);
function checkSWF(e:Event):void {
if (loader.content.currentFrame == loader.content.totalFrames) {
tick.stop(); // stop the timer
loader.unloadAndStop();
}
}
Mostly, problem is described in the title... I tried to load an external SWF file that contains some named MovieClip instances (exporting and naming is done by Flash CS5 software) and to add some of externaly loaded (named) MovieClip-s in MovieClip object which is created in my code. Problem appears when i add MOUSE_CLICK listener to parent MovieClip. Simply, it does not dispatch event when i click on it at the stage...
private var loader:Loader;
public function Example(){
loader = new Loader();
var request:URLRequest = ... // URL to external SWF
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadingCompleted)
loader.load(request);
}
private function loadingCompleted(event:Event):void{
var mc:MovieClip = loader.content as MovieClip;
var myMovie:MovieClip = new MovieClip();
myMovie.addChild(mc.getChildByName("object_name"));
myMovie.addEventListener(MouseEvent.CLICK, myMovieClicked);
addChild(myMovie); // myMovie (with nested mc) appears on the stage
}
private function myMovieClicked(evt:Event):void{
//never reached
}
EDIT: I didn't mention that i'm working in Flex using FlashBuilder 4.5 where i created ActionScript project. Code above is body of Example class, which is main SWF class.
EDIT AFTER ANSWER: myMovie.mouseChildren = false solves the problem. Earlier i tried to set mouseEnabled = true, and it didn't fix the problem. But i'm confused about event flow now... Even if child is target node, why mouse listener on parent MovieClip doesn't recieve event (in capture phase) when parent is still on event flow? Moreover, when i create another movie clip in my code (whit some simple shape inside) and add it to myMovie, everything works fine. What is so special when i obtain movie clip from externaly loaded SWF?
Have you tried doing myMovie.mouseEnabled = true and myMovie.mouseChildren = false ?
I've got a movieclip that is composed of 3 separate symbols. 2 of the symbols have their alpha tweened over 60 frames. 1 of the symbols is not tweened at all. All symbols are in separate layers, and there is a 4th, empty layer with a keyframe on frame 60 for actionscript.
The actionscript on frame 60 is simply "stop();" .
I am adding an instance of the movieclip to the stage dynamically from the document class. When I have "stop();" in there, the movieclip appears on the stage and skips straight to frame 60, where it succesfully stops.
Without "stop();" in there, the movieclip plays the alpha tweens perfectly, but obviously continuously loops.
Manually dispatching an Event.COMPLETE and listening for it does not work either and I would prefer not doing it that way anyway.
Here is the code that adds the movieclip to the stage:
//initialize the gameplay, remove title screen.
private function initialize_gameplay():void
{
//remove the title screen
initialize_title_screen(true);
this.screen_transition_obj = new tide_out_video();
this.addChild(this.screen_transition_obj);
this.game_board = new tidepool_gameboard();
this.screen_transition_obj.addEventListener(Event.COMPLETE,swap_transition_video_for_screen);
}
//replace the current transition video with the screen it was transitioning to
private function swap_transition_video_for_screen(e:Event){
this.addChild(this.game_board);
if(this.screen_transition_obj != null){
if(this.getChildByName(this.screen_transition_obj.name)){
this.removeChild(this.screen_transition_obj);
}
this.screen_transition_obj.removeEventListener(Event.COMPLETE, swap_transition_video_for_screen);
this.screen_transition_obj = null;
}
}
The movieclip's class is tidepool_gameboard and the property of the document class that stores the reference to it is game_board.
Any idea why putting stop(); on frame 60 of the movie clip is causing it to skip to the end without tweening?
UPDATE:
Adding the movieclip to the stage instantly instead of as the result of an event listener works properly, the problem only occurs when the movieclip is added in the event listner.
I can't believe I overlooked this, as it appears to be fairly obvious to me now.
In the code posted in the question, I've initialized a new instance of this.game_board, then added it to the stage after a delay based on an event listener for a video clip. The animation is playing, but it's playing before the clip ever is added to the stage.
Thanks go to alecmce who answered this question.
I did his Event.ADDED_TO_STAGE event listener, and it worked, which led me to realize that the MovieClip does not wait until it is added to the stage to start playing its own timeline, it simply starts the second you instantiate the object.
This is the new, fully functional code:
//initialize the gameplay, remove title screen.
private function initialize_gameplay():void
{
//remove the title screen
initialize_title_screen(true);
this.screen_transition_obj = new tide_out_video();
this.addChild(this.screen_transition_obj);
this.screen_transition_obj.addEventListener(Event.COMPLETE,swap_transition_video_for_screen);
}
//replace the current transition video with the screen it was transitioning to
private function swap_transition_video_for_screen(e:Event)
{
this.game_board = new tidepool_gameboard();
this.addChild(this.game_board);
if (this.screen_transition_obj != null)
{
if (this.getChildByName(this.screen_transition_obj.name))
{
this.removeChild(this.screen_transition_obj);
}
this.screen_transition_obj.removeEventListener(Event.COMPLETE, swap_transition_video_for_screen);
this.screen_transition_obj = null;
}
}
In AS2 there was an event onclipevent(load) that triggered when a movie clip was initialised on the stage. I have searched a lot but the only solution I can find for the same functionality in AS3 is to make a custom class for the movie clip. This is a bit overkill in my case as I only have one line of code to run and I'm trying to avoid lots of extra AS files in my project. I should note that my MovieClips are not dynamically added so events like Event.ADDED_TO_STAGE etc will not work.
Is there really no way to do onclipevent(load) in AS3?
There are no AS2 style clip events in AS3. If you want to avoid making a custom class for your clip, you could put the initialization code in a function and call it immediately when you create the clip, like this:
import flash.display.MovieClip;
function onClipLoad(clip : MovieClip) : void
{
// do onLoadStuff here
clip.x = 100;
clip.y = 10;
}
// call onClipLoad when the clip is created, either in code or via timeline
var myClip : MovieClip = new MyClip();
onClipLoad(myClip);
Even better, you could place this code on frame 1 of your MovieClip's timeline to automatically initialize instances of it:
var initialized : Boolean;
if(!initialized) {
initialized = true;
// do init code here
x = 100;
y = 10;
}