Layering objects in Flash - actionscript-3

I was wondering what was the best way to change the layering of objects in Flash? My project is made up of mostly small individual movie clips. I want to better organize my objects into layers so that one set of movieclips can be shown above another at a given time without any conflicts. Any advice on the best way to do this would be great.
EDIT: Getting errors with the following:
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.DisplayObject;
import flash.events.Event;
import flash.events.MouseEvent;
var backgroundLayer:Sprite = new Sprite;
backgroundLayer.name = "backgroundLayer";
var gameLayer:Sprite = new Sprite;
gameLayer.name = "gameLayer";
var menuLayer:Sprite = new Sprite;
menuLayer.name = "menuLayer";
public function Main()
{
addChild(backgroundLayer);
addChild(gameLayer);
addChild(menuLayer);
Errors are:
1120: Access of undefined property backgroundLayer.
1120: Access of undefined property gameLayer.
1120: Access of undefined property menuLayer.
Thanks.

Probably the easiest way to do this is to make a hierarchy of DisplayObjectContainers or its subclasses. (Sprite, MovieClip, etc.) Once these are added to the stage in the proper order, any children of these containers will be "within" the layer of the container.
To move an object between these layers in code, you just have to oldLayer.removeChild(thing); newLayer.addChild(thing);.
Whether or not this is the "best" way to do this depends on what you are doing, but this is a way that I've done game object layering in the past.

Related

StageWebView in an AS3-Script

I allreday read a lot of helpful stuff in that forum. Now it's my first time I ask for specific help.
I'm pretty new to Flash and have a problem I struggle for more then a week now. The most efficient and elegant way for my problem is to put a StageWebView-Call into an as-File.
That would be the plan:
In my flash-File: Show a PDF document "xyz" and put it on the stage.
I alreday tried it with Switch-Case - But then I have trouble to get rid of the PDF's.
That was my Idea:
First the new as-File...
package {
import flash.display.MovieClip;
import flash.media.StageWebView;
import flash.geom.Rectangle;
import flash.filesystem.File;
import flash.display.Sprite;
import flash.display.Stage;
public class mypdf {
public var MyWebView:StageWebView
public var file:String
public var pdf:File
public function mypdf(ActFile:String) {
MyWebView = new StageWebView();
file = ActualFile; //MARKING #1
pdf = File.applicationDirectory.resolvePath(file);
MyWebView.stage = stage; //MARKING #2
MyWebView.viewPort = new Rectangle (200, 200, 400, 400);
MyWebView.loadURL(pdf.nativePath);
}
}
}
Than I want to call that in my flash-File...
stop();
var mynewpdf:mypdf = new mypdf("test.pdf");
Two erros are shown:
1120: Access of undefined property error ActualFile (at Marking #1)
1120: Access of undefined property error Stage (at Marking #2)
With a lot more work I could avoid the first error by defining a lot of different as-Scripts for each pdf.
My main problem is the second error.
It would be really nice if someone had any good ideas.
Bye,
Stephan
The second error means that you need to pass the stage to the web view. Either pass it to mypdf class as parameter, or make mypdf DisplayObject (extend Sprite for example) and add it to stage.
I'm not sure this will solve your issue anyways - I think StageWebView can simply display html. The PDF is displayed in your browser because an external plugin for that is launched.
In AIR the situation seems different: http://sujitreddyg.wordpress.com/2008/01/04/rendering-pdf-content-in-adobe-air-application/
StageWebView is wont support for nativePath, instead of using this, you can try with pdf.url. And StageWebView also having support for open .pdf files.
public function mypdf(ActFile:String) {
MyWebView = new StageWebView();
file = ActualFile; //MARKING #1
pdf = File.applicationDirectory.resolvePath(file);
MyWebView.stage = stage; //MARKING #2
MyWebView.viewPort = new Rectangle (200, 200, 400, 400);
addChild( MyWebView );
MyWebView.loadURL(pdf.url);
}
Because, StageWebView will support file:/// format, but in nativePath we got C://.., so, this will help you. Or
Simply convert your StageWebView to Display object, and then added it to your container by using addElement().
You can convert it by,
var _view:SpriteVisualElement = new SpriteVisualElement();
_view.addChild( MyWebView);
this.addElement( view );
To test by, simply call this method in added_to_stage method to test if stage is having or not. This error will come if stage is not setted means also.

Actionscript 3 Multiple sounds playing at the same time when accessing different movieclips

I am at the moment trying to create an interactive movie, structured so that each keyframe in the timeline contains a movieclip navigated to using buttons inside the movieclips, with the appropriate code inside the main timeline.
The problem right now is that when you access the movieclip inside frame 3, the sound from frame 2 also plays simultaneously. After doing some research i found that this appears to be a bug with flash itself, and most of the time is dealt with using SoundMixer.stopAll();. Sadly, i have no idea how to use it to kill the sound from frame 2 when only frame 3 is accessed.
I know that when accessing frame 2 instead, only frame 2 is played, which should mean that flash basically goes through all frames on the way to the frame you are supposed to go to.
This is the limited code i am using at the moment:
Frame 1:
import flash.events.MouseEvent;
import flash.display.SimpleButton;
import flash.media.SoundMixer;
stop();
var soundVar:int = 0;
var Choice1F:SimpleButton;
var Choice1R:SimpleButton;
this.Val1.Choice1F.addEventListener(MouseEvent.CLICK, function(me:MouseEvent):void{buttonHandler(me, 2)});
this.Val1.Choice1R.addEventListener(MouseEvent.CLICK, function(me:MouseEvent):void{buttonHandler(me, 3)});
function buttonHandler(e:MouseEvent, Value:int): void{
SoundMixer.stopAll();
soundVar = Value;
this.gotoAndPlay(Value);
}
Frame 2:
import flash.media.SoundMixer;
stop();
if(soundVar == 3){
SoundMixer.stopAll();
}
Frame 3 simply contains a stop(); statement. The code in frame 2 was a futile attempt from me to make it kill the sound on its way to frame 3. Hopefully, you guys can think of a better solution, if one even exists.
The correct structure of the project assumes that you control the playback of music and sounds with a special instance of custom class. And timeline you use only gave him command when and what to do.
One SoundChannel and couple of Sound's will do the trick.
You could use this one
package src.utils{
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.net.URLRequest;
public dynamic class BackgroundMusicPlayer extends Object{
public var playlist;
public var sndChannel;
private var ID;
public function BackgroundMusicPlayer(srcList:Array){
playlist=[];
for(var i=0;i<srcList.length;i++){
var src= new URLRequest(srcList[i]);
var newSound = new Sound(src);
playlist.push(newSound);
}
}
public function playMusic(id){
if (sndChannel!=undefined) {
sndChannel.stop();
}
sndChannel = playlist[id].play();
ID=id;
sndChannel.addEventListener("soundComplete",replayListener);
}
public function replayListener(e){
sndChannel = playlist[ID].play();
}
}
}
import class to you timeline, create instance passing him files list
var musicPlayer = new BackgroundMusicPlayer("music1.mp3","music2.mp3");
And then you want start some sound, call
musicPlayer.playMusic(0);
If you want use imported to project sounds, just share them to actionscript, give them class names and slightly modify given class constructor
public function BackgroundMusicPlayer(srcList:Array){
playlist=[];
for(var i=0;i<srcList.length;i++){
playlist.push(srcList[i]);
}
}
So your instance creation now should be
var musicPlayer = new BackgroundMusicPlayer(new MySound1(),new MySound2());

Adding to Stage in ActionScript 3 from a .as file

Note: Yes, I know that similar questions have been asked before. However, after following the answers in such questions I'm still stuck and can't find a solution to my problem.
I'm having a problem which requires adding DisplayObjects to the Flash stage. Since I have to Display elements of several different classes, I decided to create a class to work as an intermediary between the .as files and the addChild function called "Displayer" as shown below:
package
{
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.display.Stage;
public class Displayer extends Sprite //I read somewhere that DisplayObject
//as an extension can't be used for this, so Sprite will have to do.
{
private var _stage:Stage;
function Displayer()
{
_stage = new Stage;
}
public function displayElement(displayable:DisplayObject)
{
_stage.addChild(displayable);
}
}
}
I compile it and there appears a problem that I don't understand: Error #2012: Can't instantiate Stage class. Evidently, something in this code is either missing or out of place, but since it's so straightforward I fail to see what the problem can be. I'm sure that it's not very complicated, I probably just need an outsider's perspective.
The Stage object is not globally accessible. You need to access it through the stage property of a DisplayObject instance.
refer a following docs.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Stage.html
package
{
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.display.Stage;
public class Displayer extends Sprite
{
var isAddedToStage:Boolean;
public function Displayer()
{
if(stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event=null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
isAddedToStage = true;
}
public function displayElement(displayable:DisplayObject):void
{
if(isAddedToStage)
this.stage.addChild(displayable);
}
}
}
You don't instantiate the Stage class, as the error says. Just like you cannot instantiate the DisplayObject class (which is why you have to extend Sprite).
Basically, you have two options here:
1) You add the child from a DisplayObjectContainer instance.
var displayerInstance:Displayer = new Displayer();
this.addChild( displayerInstance );
You would run this from a DisplayObjectContainer object that has already been added to the global stage. There is only a single stage in every project, even if you embed SWFs, the stage property of the SWF is actually the stage property of the top level application. So if you have this Displayer instance nested inside a class which is nested inside another class that is created in your main application, you would have to run "addChild" in each of those classes to get the Displayer to show.
2) You cheat. This is not recommended, at all. Basically, you pass in the stage object of an object when you instantiate the Displayer class.
var displayerInstance:Displayer = new Displayer( this.stage );
public function Displayer( stage:Stage ) {
this.stage = stage;
if ( this.stage ) {
this.stage.addChild( this );
}
}
This is a method that is good for adding Singletons to the stage (except there is not constructor for a Singleton). I created a profiler just before Christmas that was a Singleton (And later found Scout, damnit) that used this method for adding things to the stage when appropriate.
Again, that second option is not recommended for this situation, but it is a possibility.
As an aside, you should never add things directly to Stage, unless there is a clear reason for doing so (such as a popup). You should follow the display list methodology, where a DisplayObjectContainer adds another DisplayObject or DisplayObject container as a child and so on and so forth so that they are all connected to the TopLevelApplication.
Ok, I think instantiating a stage class won't do because as the as3 documentation says: "The Stage object is not globally accessible. You need to access it through the stage property of a DisplayObject instance."
You should instead pass a reference to the Stage object to your Displayer class and you can get a reference to the stage object, as the docs say, via a display object instance.
So the constructor might now look like:
function Displayer( stage:Stage )
{
_stage = stage;
}
Assuming that the object which instantiates your Displayer is a child of the stage you can instantiate the Displayer by
displayer = new Displayer( stage );
If you use this approach there is no need for the Displayer class to extend anything or be added to the stage ( which is required btw in the approach of bitmapdata.com ).
There is always a simple solutions.if you need to add a child element into a stage from your class you can just pass the stage into your class as a object and add the child element into it, i did this for adding an image into my stage like this.
package {
import flash.display.Loader;
import flash.display.Sprite;
import flash.net.URLRequest;
import flash.display.Bitmap;
public class ImageLoader extends Sprite{
private var stageObj:Object; //create local variable to refarance stage
public function loadeimage(StageObject:Object, Url:String){ //StageObject will bring the stage refarance into the class
var reQuest:URLRequest = new URLRequest(Url);
loader.load(reQuest);
stageObj=StageObject; //make local refarance for stage inside the class
var image:Bitmap;
image=Bitmap(loader.content);
image.x = 100;
image.y = 100;
stageObj.addChild(image); // add whatever object into stage refarance and this means the real stage..
}
}
}
only the things with comments are important and you can save this file as ImageLoader.as and import it and use it like this.
import ImageLoader;
var IL:ImageLoader = new ImageLoader();
IL.loadeimage(this,"img.jpg");
its simple as that. i think this is what you have search for... good luck. (you can pass any container or parant container this or this.stage it doesn't matter your child will be a part of it.

How to convert a two-file preloader and game swf with Document class into single swf?

I have a game that I've made that runs in two files, one the preloader and one the swf. When I use these two files together they work fine, however some flash portals require only one SWF, so I'm trying to find the shortest-path way to convert it to use only one.
The game swf uses a Document Class that includes the package, class constructor, and tons of functions, and runs fine. I have lots of movieclips on the stage that I refer to in my code. The code is something like this (abridged):
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
...
public class Game extends MovieClip {
var EnemyArray:Array;
var HeroArray:Array;
...
public function Game() { // class constructor
EnemyArray = new Array();
addEventListener(Event.ENTER_FRAME,onEnterFrame);
mainRestartButton.addEventListener(MouseEvent.CLICK, RestartLevel);
...
}
public function KeyPressed(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.SPACE)
{
attack();
...
}
} // End of class
} // End of package
I also have another swf, my preloader, which has the following code in frame 1:
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.ProgressEvent;
import flash.events.Event;
var myLoader:Loader = new Loader();
myLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoading);
var myURL:URLRequest = new URLRequest("Game.swf");
myLoader.load(myURL);
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
function onLoading(event:ProgressEvent):void {
var loaded:Number = event.bytesLoaded / event.bytesTotal;
percent_txt.text = "Loading: " + (loaded*100).toFixed(0) + "%";
}
function onComplete(event:Event):void {
myLoader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, onLoading);
myLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onComplete);
this.addChild(myLoader);
}
I've been through the gamut of solutions online and none of them seem to work with the way that my code is set up, such as: How to create Preloader in AS3
I tried his option 1 by taking all the code in my Document Class other than the package and constructor and pasted it into frame 2. However it returns "Error #1009: Cannot access a property or method of a null object reference." for any references to items on the stage, such as:
mainRestartButton.addEventListener(MouseEvent.CLICK, RestartLevel);
As he mentions, "This works well if you organized your project in a way that the most of the assets (images, etc) are in the Flash IDE Library and are not loaded on the first frame (you can check that in each library item's properties)." My project is NOT organized in such a way.
What is the easiest way for me to reorganize my FLA/code so they can have a preloader in a single swf?
Thanks so much for your time and help!
I use FlashDevelop (no FLAs) so I'm not sure if it'll work for you but I use the solution described here.

Accessing variables of of loaded swf

I'm loading swf externally. I need to access it's methods and variables. This is the code I'm using:
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.display.MovieClip;
var loader:Loader;
var req:URLRequest = new URLRequest("aaa.swf");
var mc:MovieClip;
createLoader();
function createLoader():void {
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.INIT, onSWFLoad);
loader.load(req);
}
function onSWFLoad(e:Event):void {
mc = MovieClip(loader.content);
addChild(mc);
trace(loader.content)
}
EM is loaded SWF's document class. If questioned if variable gameEnded is declared publicly, the answer is yes. The game loads, but there is an error when calling the variable :
ReferenceError: Error #1069: Property gameEnded not found on EM__Preloader__ and there is no default value.
at main_fla::MainTimeline/onSWFLoad()
Check your preloader setting in the ActionScript settings panel of your game.fla - EM__Preloader__ looks to me like an auto-generated class (and not your main EM class).
Also, your EM class should implement a simple interface that you can cast your loader.content to (instead of MovieClip). This way, you can be sure that the methods you need are available, and your code is type-safe. Embed this interface into your preloader.fla instead of the EM class to prevent unnecessary bloating of your SWFs.
It turned out that I had to embed all the code in SWF (I was using some TLF in it)