I'm trying to make a file that is easy for a non-flash user to use/reuse to easily display content. The key here is that this file is to be a template for a novice user to just copy/paste some very minimal code to create different "flash card" type swf files.
The file I am creating has multiple buttons on the main timeline which when clicked, attaches a movie clip which will display a dynamic text area with content specific for the button that was clicked. The content for the text area will be loaded from a separate text file.
For the sake of this example, I'm just going to refer to one button...
So, on the main timeline, in frame 1, I have a variable definition:
var myFilename1:String = "mySampleFile2.txt";
When the button on the main timeline, in frame 1 is pressed, a movie clip is loaded which contains a text area. The content for the text area is located in that file: mySampleFile2.txt.
If I hard-code the file name, it works like a dream:
myTextLoader.load(new URLRequest("mySampleFile2.txt"));
But I don't want to hard code the file name. I want to refer the variable in the main timeline. In AS 2, it would have been
myTextLoader.load(new URLRequest(_root.myFilename1));
In AS3 I thought it would be either:
myTextLoader.load(new URLRequest(root.myFilename1));
OR
myTextLoader.load(new URLRequest(MovieClip(this.parent.root).myFilename1));
When I run the code I get the following error and when I run a trace I get the file name is NULL.
TypeError: Error #2007: Parameter url must be non-null.
How to I access the file name stored in the variable on the main timeline?
*************************** UPDATE! *************************
So I just discovered that the issue is related to a button on the screen. The button is one from the buttons library. If I remove the button, everything works great. But as soon as that button is on the main timeline, it makes it to I cannot access the variables using MovieClip(root).variable_name;. Unfortunately I want that button to trigger the events within the MovieClip. Any thoughts?
Not a good idea
You are not able to achieve your goals with this bad practice approach.
to use/reuse
The code you want to provide is not very reusable. It heavily relies on one variable existing in a certain place. Therefore it cannot be use twice in a project.
But I don't want to hard code the file name.
And now you are hard coding the variable and its location. If you considered hard coding the file name to be a bad things, consider this a bad thing, too.
What the problem is
Basically speaking, the problem is that your component is reaching out to grab this variable from somewhere within your project. But it is not the concern of the component to find the content it should display. It is not well encapsulated.
Learning from existing things
You want to display text. Let's take a look at the TextField class to see how it displays text.
var tf:TextField = new TextField();
tf.text = "hello";
addChild(tf);
As you can see, the text that it should display is passed to the TextField object. There is not some arbitrary variable one has to set in order to modify the text, as you are planning to do:
var tf:TextField = new TextField();
var someArbitraryVariableThatModifiesATextField = "hello";
addChild(tf);
There is no obvious connection to the TextField object and if there's a second TextField, this doesn't work at all.
Applying that to the problem at hand
Just like the TextField, your "flash card" should receive the file as a parameter. Either pass it to the constructor as seen in the example below, or create a method that takes it as a parameter.
var card:Card = new Card("mySampleFile2.txt");
addChild(card);
Additional thoughts
Create additional methods to set the values individually. There's nothing worse than some code that does exactly what one wants, but only operates on files and one doesn't have a file. The goal is again, to make it easy to reuse the code
Use the [Inspectable] meta tag to allow the user of your code to modify the properties at author time. This can be used to the extend of modifying properties belonging to a physics engine, now this is what I would call easy to use for a novice user.
Instead of writing code and thus requiring to recompile the file again, take the information (either the path to the file or it content) from the flashars that are passed to the .swf file when it is embedded into an html page. This makes the single .swf file truely reusable and easiest to use, because there's no As3 coding required whatsoever.
I haven't tested this but I believe the "root"-stage would be:
this.parent
In the child swf.
check out this question: as3 access variable from parent swf
Good luck!
Accessing variables or movieclips at main timeline is as following:
AS2:
_root.variable_name;
AS3:
MovieClip(root).variable_name;
Related
I'm attempting to set up a saving and loading system for a flash game I am creating. At the moment I decided to attempt to get the Save File Selection part of my new game menu to work before I proceeded any further with it. I drew up the 'DifficultySelect' screen (which contains save file selection as well as a few other things) in flash, then converted it into a symbol. I made 10 save file symbols inside of this, and created base actionscript files for them. The entire 'DifficultySelect' becomes a child of my 'Main.as' once you proceed through the title screen. I am trying to have my save file data inside of my Main.as, such as levels, health, progress, etc, as well as which save file is currently in use. However, I am unable to create a way for my Main.as to access a MouseClick function for the save file, as I can't simply have a Savefile0.MouseEvent.CLICK event in my Main.as file, as I am not creating a variable to add it to the stage.
I suppose the tl;dr question version of my situation is: How can I get my Main.as to activate one of its functions when SaveFile0 has been clicked? Also, how do I refer to a child from a parent class?
You ask how to refer to a child from parent, but since the child usually "knows" its parent, I suggest following solution:
Your child (SaveFile) should listen for the event (MouseEvent). Once the event is dispatched, you have two options. Either you can dispatch a custom event on parent or directly invoke a public function of the parent.
This is assuming your SaveFile is a MovieClip added to Main:
Inside SaveFile:
var _parentMC:MovieClip = this.parent as MovieClip;
_parentMC.functionToCall();
The best practice, however is to dispatch a custom event in SaveFile, and listen for it in main:
Inside SaveFile:
var customEvent:Event = new Event("customEvent");
this.dispatchEvent(customEvent);
Inside Main:
saveFile.addEventListener("customEvent",functionToCall();
functionToCall(e:Event):void{
}
and i am having problem, switching from Timeline code to OOP/Document Class. I managed to build the Fla with AS3 on timeline with no problem. But totally clueless when on OOP.
I had been told that Scenes are no good and i should stick to saving my scenes as Movieclips.
My situation is as such:
I have 8 pages of PSD files, and i imported each PSD into Flash Pro, and each PSD has a few buttons and textinput. First page is Login page, second page is register page etc.
My questions are:
1.) How should i save the PSD? Do i save them as nested Animation,(Giving each item on PSD a symbol? Buttons and textinput?) Then saving that PSD as 1 movieclip(Nested Animation?)
I already tried importing the PSD with Flash Layers onto Stage,then giving each buttons and Textinput their Properties then savin them as Nested Animation, but do i call that Movieclip from the Class document? Or do i link All Movieclips in the Document Class(Main.as)?
2.) How do i access the Movieclip from Class file, I tried var login:Login = New Login, then addChild(login). That adds the movieclip but none of the functionality works, and errors saying Access of Undefined Properties for every single button's Name.
3.) And if 1 button is clicked and that links to another page(PSD) do i do the Below?
h.addEventListener(MouseEvent.CLICK, fl_ClickToGohome);
function fl_ClickToGohome(event:MouseEvent):void
{
gotoAndStop("register.as");
Thanks for your time
Programming in .as files apart from the timeline isn't too different. If you're using the document class (found in Actionscript Settings panel), you may be feeling the abrupt change in class specific programming a bit too daunting. For a smoother transition, you can simply dump your current timeline code into a new code.as file (as-is), and simply drop the following line in your timeline:
include "code.as";
This effectively just copy/pastes the code and runs it, except now you can use a proper code editor (such as Sublime Text). Furthermore, as it's not a new class, the code you write there has the same scope as your timeline.
2). Functions only have access to the namespace their created in (this is probably why your document class was throwing "Access of Undefined Properties" errors). You can always pass a reference to an object (and by extension, its namespace) through function arguments.
1). To answer your first question, you can create your movieclips, and nest them as deeply as your want, in any order you want. The important thing is to be aware of how to navigate to that object. Take for example the following stage heiarchy:
root:MainTimeline ¬
0: PSD_one:MovieClip ¬
0: backgroundImage:Bitmap
1: button:Sprite
2: txt:TextField
1: PSD_two:MovieClip
2: PSD_three:MovieClip
The timeline has 3 objects, each with a zero-based index. The first PSD is a MovieClip DisplayObjectContainer with 3 child elements, each with name properties that we can use to address the objects. In Flash IDE we label these "instances", and they automatically become properties on the parent object due to internal magic the IDE has enabled in the Actionscript Settings panel labeled "Automatically declare stage instances".
This means, to change the text on txt, we can write PSD_one.txt.text = "foo". Without this setting, you'll need to use container methods like root.getChildByName("PSD_one").getChildAt(2). Outright calling txt.text = "foo" will never work because there is no property on the current scope called that (ie., this.txt is implied).
3). gotoAndStop is a MovieClip method that controls timeline frames. If you're really going to make a clean break from the old way of doing things, you should drop your use of frames.
There are two ways you could approach displaying these PSDs.
Method 1:
You instance your PSDs on the stage with the Flash IDE and give each one a unique name that you can then reference in your code. Assuming the layout above, you may simply move each PSD offscreen (such as with PSD_two.x = this.loaderInfo.width), and swap them to the center of the screen when you want to "go" to the next "frame".
Method 2:
You've imported your PSDs into your library as you're accustomed to, but do not instance them. Instead, you jump straight into your code and when someone clicks on button h to go to fl_ClickToGohome, your function picks the library object and manually instances it, and parents it to the stage with addChild().
function fl_ClickToGohome(e:MouseEvent):void {
var psd:PSD_one = new PSD_one();
addChild(psd);
}
This sort of approach would be preferable if you're going to start getting into dynamic loading of assets. Of course, rather than having an already created PSD_one class in your library, you'll simply use URLLoader() or Loader(), and you'll want to save out compressed images, not full-blown PSDs.
I hope this helps. I know I haven't answered your questions directly, but sometimes the issue stems from manner of implementation, not specific code.
-Cheers
To answer your questions...
1: Pathing to Objects
If you're not sure what the path is to your objects, try this function. It's a trimmed down version of the one I use in my own work.
function listLayers(obj = null, indent:String = ""):void {
// If no object was provided, start with the MainTimeline
if (obj == null) { obj = root; }
for (var i:int = 0; i < obj.numChildren; i++) {
// Make a pointer to the object at this index
var item = obj.getChildAt(i);
// Get the item type
var type:String = flash.utils.getQualifiedClassName(item);
if (type.lastIndexOf("::") != -1) {type = type.split("::")[1];}
var msg:String = indent + i + ": " + item.name + ":" + type;
if (type != "TLFTextField" && item.hasOwnProperty("numChildren") && item.numChildren > 0) {
trace(msg + " ¬");
listLayers(item, indent + " ");
} else {
trace(msg);
}
}
}
This will print out the structure of your stage in much the same format as you saw above (with the PSDs). You can then use getChildByName from the root to the child (the full path must be provided, much like navigating folders on your hard drive).
2: Public/Private Namespaces
These are only to be used in dedicated classes. If you're using the include method I mentioned, you omit these as you would in your timeline code. They denote whether a property/method is accessible from "the outside" of the class. If you're just starting out, leave everything Public. You can worry about memory optimizations later when you're ready to tackle it.
3: How does the class access the buttons?
The easiest way to think of the DisplayList is as a folder structure.
You might write
C:/Users/Me
Which in the DisplayList would look more like
C.Users.Me
Of course, we don't have a root location called C, and your objects are probably called PSD_one and myButton, so we can rewrite it as follows...
root.PSD_one.myButton
This is assuming you actually have those properties pre-defined on the objects, which does not happen when dynamically creating objects. In those cases, you'd string together your commands, as follows:
root.getChildByName("PSD_one").getChildByName("myButton")
When you write a Class, it's like creating a new computer on your network. There is no direct relationship between that Class and your MainTimeline. You need to connect them.
If you instance a DisplayListObject (such as a Sprite) and add it to the stage, the object automatically gains a few properties like stage, root, and parent which until it was parented were in fact null. These are properties that the class can reference from inside itself to connect to the MainTimeline and access objects on it.
Conversely, if you wanted to you could pass a reference to the stage to the class from the constructor arguments, as follows:
var foo:MySprite = new MySprite(stage);
So I've been following this tutorial on AS3 and Flash. Its been going well until, note I have tried to contact the writer of the tutorial and had no reply. Here's what it tells me to do;
Right-click PlayScreen in the library, select Properties, and check Export for ActionScript. This time, instead of accepting the default value, enter the name of your document class. Click OK.
So it pops up an error, first we’ll have to make a new document class, since no two different objects can share the same class. Cancel the Properties box.
Hit File > New and select ActionScript File. Enter the (by now familiar) code.
Save this in the Classes directory as DocumentClass.as. (There’ll be no confusing the purpose of this file!) Now, back in your FLA, change the document class to DocumentClass.
Check everything’s fine by clicking that pencil icon — if it’s all OK, that should bring up the AS file that you just created.
// So this bits all fine, its the next that i'm stuck with:
Now you can set the PlayScreen‘s class to AvoiderGame. So do so!
// So I go ahead into the properties and change the name but then it pops up with the same error as before: 'Please enter a unique class name that is not associated with other library symbols'
What does this mean!? How do I resolve this!?
Full tutorial here:Flash Tutorial
Its hard to tell what you are trying to accomplish without knowing what all the parts you are referring to actually do, which are objects in the library and which are classes, but maybe this can help:
First of all, document class in AS3 typically refers to the project's main set of code that initializes the app. This class can be called anything but is often called Main, and is entered in the property panel that is displayed when you click the projects main stage in the field called class.
Now, when linking a class to an object in the library, its a little different. In the library object's property panel, tick the box for Export for Actionscript, and put a unique name in the top box. This is what you reference in your code to call it, like new somethingOrOther() or using the pic below as an exaample, new Ball(). The second box is the base class, pathed to where it lives in your code base. This is the class you will write that actually controls the object you've linked the class to. Giving a linked object a base class and a unique identifier allows you to use the same base class for multiple linked objects.
Note that when you do this approach, Flash will warn you that there is no class associated with Ball and one will be created for you. Don't worry, this is normal behavior. If you set this up properly, your object will still be controlled by its base class.
i am working with several nested movieclip objects in a project. but i get into trouble with the buttons i created and implemented in the nested movieclips:
to describe it in a simple way:
I have a main movieclip with five frames, including two buttons with listeners to browse between the frames. Then inside of one Frame I have another movieclip with its own buttons. i instanciated it by hand not through code and gave it a specific name like "nestedMc".
Now I dont want to build the Listeners for those buttons inside the class of the nested movieclip class but in its parent class, which works fine until i then goto another frame in the main movieclips timeline and come back.
obviously every time flash enters a frame its contents get created anew (and therefore get new instance names). I could now try solve this through filling the frames via code.
But maybe there is another way to make sure the frame contains the same instance everytime i enter?
Timeline scripting is a dirty business, and really, a carry-over compatibility layer for Actionscript 2 projects. Whenever possible, I highly recommend not doing it, and simply keeping all of your code in your document class. As you're experiencing, timeline code causes headaches.
Consider instead just creating both states of your Stage (it sounds like that's what your two buttons are jumping between) and simply hiding them offstage or setting their alpha to zero and their mouseEnabled state to false. Furthermore, if the purpose of your frames is to play animation (a tween), consider instead switching to a much more powerful suite such as TweenLite. Moving an object over a hundred pixels (smoothly) can be as easy as:
TweenLite.to(redBall, 3, {x:100});
Now, if you're manually adding these items to the stage, as long as the object is a dynamic one, you can assign an instance name to it which will be saved between frame loads. Be aware the object name is not the same as the instanced name. For example:
var redBall:Ball = new Ball();
redBall.name = "bubbles";
The object's name is Ball, but it's represented as a variable called redBall. Its actual DisplayList name will likely be ambiguous (such as "Instance71"), and I can manually define it as "bubbles". 3 different names for the same object, all very different and necessary.
Even if you give the object a displayList name, you may not be able to reference it through code unless you enable Automatically declare stage instances, which basically creates on each object a pointer to the displayList object.
That said, you can always fetch the object by other means. Obviously, your buttons are always appearing, but you're trying to find a very specific object on the stage. At this point, we can use getChildByName() or getChildAt().
Hope that helps.
-Cheers
I have a flash assignment that I need help getting started, any advice would be greatly appreciated. The assignment is to create an application for playing a card game, I have to create an MXML component that has two variables, one variable stores the image of the back of a playing card, the other variable has t store all 52 options of a front facing card (the second variable will store over 50 images).
I've written the variable for the back of the card image like this:
public var backOfCard:Image = new Image();
backofCard.source = 'asset/backImage';
However I get an undefined variable error (1120: Access of undefined propery variable img1), I feel like there's something small that I'm missing here, but I was wondering if anyone could spot it.
I'd also like to know if I should use the same method for each jpg image for the front of the cards, it seems like it would be a lot of repetitive code aside from the change in filename for the front of the card images.
Here's a snippet of the homework assignment, again I just need help getting this part correct, I really appreciate any help with this.
Your job is to supply the custom component named Card. Create the
component by using File → New → MXML Component. In the popup dialog
box
leave the Package blank
Name the component Card
Base Card on spark.components.Image
What goes into the Card component?
For each card, we'll want to be able to show the front face of the
card, or its back face. That means each card should have a place to
store information about what file to show as its front face, and what
file to show as its back face.
To do this, create two variables in the Card component to store the
file names. You might call these variables backImage and frontImage.
Your access modifier is what's bothering me.
If you're creating these definitions in your class file, then the first statement works:
public var backOfCard:Image = new Image();
But if you're in one of the methods, usually the constructor (sometimes called the ctor), or any other method of the application, you could use the 2nd statement:
backofCard.source = 'asset/backImage';
But the combination of both is what I think is confusing. Because the "access modifier" (i.e. public, private, internal, protected) is what you use to define variables and methods within a class. And since you're putting both side-by-side (a definition and an assignment statement), I think you're mixing when to declare them.