EDIT: I figured this problem out on my own, and have included the answer below.
I have a variable in my main timeline called characterDismissed which is a Boolean. I also have a series of nested MovieClips (MovieClips within MovieClips) which look something like: Stage > Container > List > Buttons.
In the Buttons MovieObject at the bottom of the nest I'm trying to output characterDismissed's value just to see if it can see or modify it:
trace("characterDismissed is: " + characterDismissed);
This obviously doesn't work, and I understand why it doesn't work (because characterDismissed is not a variable in the Buttons ActionScript, but rather in the main timeline's ActionScript, so it has no concept of the characterDismissed variable yet.)
How would I go about making this variable accessible to the Buttons MovieClip in AS3? I've tried root.characterDismissed, parent.characterDismissed, this.parent.characterDismissed, even parent.parent.parent.characterDismissed, etc. These always give me some flavor of this error, however:
1119: Access of possibly undefined property characterDismissed through a reference with static type flash.display:DisplayObjectContainer.
I feel like I've been reading suggestions for handling this for days, but nothing is working, and with my understanding of AS3 being limited already, I don't have a proper grasp on the vocabulary to better research it past what I've already searched, or make sense of what typically ends up being a vague response on other forums, or for similar, but not-quite-right questions/answers.
I ended up figuring out the answer on my own, here's what I came up with:
I made a new ActionScript 3.0 Class file and named it GlobalVars (though, you can name it whatever you like.) and saved it into my project directory alongside my main .FLA file. In GlobalVars I made a test variable named testVar, set it to public, and then static.
My understanding for this is that public means anything can modify it, and static means that this variable will be the same value throughout your entire program. That looks like this:
public static var testVar:Number = 1234;
Then in both my Main project AS3, and the nested object's AS3 I added:
import GlobalVars;
This adds the class I made, and any functions or variables I configured within GlobalVariables to my Main AS3 script on the timeline.
Now, I have can access or change my variables in those AS3 scripts by simply prefixing the variable with the class name, like so:
GlobalVars.testVar += 20; // Add 20 to testVar.
Now, as long as I import GlobalVars into my script, I can access, and modify these variables from anywhere.
Hope this helps anybody else out there who found themselves lacking the vocabulary to properly articulate a search on this subject. I have attempted to include as many keywords in my explanation as possible to help people with similar search queries.
Related
Evening all, and thanks in advance for your wisdom.
Bear with me if I show ignorance, but here is how my project is currently built:
-TitleScreen: first class which appears. Extends Sprite.
-Startup: class I use to call other classes. Extends Sprite.
-GameScreen: the "game engine" class. Extends AssetsHandler.
-AssetsHandler: where most of the methods to manipulate the assets are. Extends GrfAssetsStore.
-GrfAssetsStore: where all graphical assets are stored. Extends Sprite.
-Level01: first level class. Extends GameScreen.
Now: when I start everything up, all is hunky dory. So, let's say I finish level 1, and I want to restart, or go to title screen: again no problems, BUT I re-instantiate the GameScreen class -and in turn AssetsHandler, and in turn GrfAssetsStore. Mind you I have not set up any EventListeners that call them back up -indeed, I tried to make sure that once started, they would be left undisturbed- but in my ignorance I've now realised that restarting Level01 is in turn re-extending the other classes.
Understandably this is greatly undesirable, but so far I cannot overcome it. I tried just instantiating the super classes within Level01 -same issue.
The aim pretty much is having GameScreen, AssetsHandler and GrfAssetsStore running under the bonnet, so to speak, while new levels are begun and ended, but without in turn restarting the superclasses, just getting methods/variables etc. from them.
So: how do I overcome this? And no, I am not greatly experienced in AS3, so I appreciate if this is obvious to actual experts, hence why I am here.
If I need to word anything better please do not hesitate in saying such.
EDIT: the issue now I believe isn't the extending, but me not de-referencing correctly the variables etc., thanks Josh for helping me realise such. As you mentioned, it makes little sense to deny one of the major aspects of OOP: as such I should defo not consider applying that incorrect logic.
I'll attempt to better GC (and force GC if necessary) until I have removed correctly all references. If this doesn't work though...I'll post another, more detailed question.
You could set it up as a Singleton.
Basic structure:
public class ClassName {
private static var _instance:ClassName;
public function ClassName() {
// run normal constructor code here
}
public static function get instance():ClassName {
if ( !_instance ) {
_instance = new ClassName();
}
return _instance;
}
}
So instead of you ever calling new ClassName() in your code, you just call ClassName.instance to access the single instance of that class. That will return the same single instance every single time, and create it if it has not already been created. This will ensure there is never more than a single instance of the code at any given time (assuming you never call new ClassName() of course)
Note that this is not a design pattern that should be used often, if at all. It goes against basic OOP principles and is a highly debated design pattern for that reason. I think this works in this case because you do not want more than one instance of your game running at any given time, but in most cases you should write your code to avoid this pattern.
http://en.wikipedia.org/wiki/Singleton_pattern
I'm usin Flash Builder to create some actionscript code that uses SharedObjects.
First question: how can I delete my local SharedObject in Flash Builder? I am debugging my program and the SharedObject sems to persist between runs. I want to start fresh and clean with no SharedObject storing my data. How do I get rid of it?
Also, in my SharedObject, I used mySharedObject.data["mykey"] to store a Dictionary. This Dictionary will have String keys and values of MyCustomClass. The problem is that when I later try to loop over the values of this Dictionary, I get error #1034 cannot convert object to type MyCustomClass. It seems like I can put an item of type MyCustomClass into this dictionary, but I can't get the item back out as anything other than an object.
Any idea what is going wrong?
Those are essentially two questions, so should have been asked as two questions. Anyway, I'd answer them here but still prefer that you break them up in two parts (possibly leave a link to the other one here for reference sake):
Local shared object, are useful exactly for persistence across runs. And then there's SharedObject.clear() to clear the state as required.
For you second issue, Shared Object's serialize your object into AMF, so that it can be written to disk or sent over network using RTMP. Now, your custom class can't really be serialized in AMF. What actually happens is that the public properties (and dynamic ones, if the class is declared dynamic) are serialized into the structure. So, the public data is stored... but it's essentially a general Object.
To work around that, you can have a public static readFrom(object:Object):MyCustomClass type function, which would read the properties from the passed object to construct a new MyCustomClass representing that information.
There are ways to register your class with the player to be stored in SharedObject (see here)... but you need to make sure that the code that de-serializes that data is aware of the class as well.
To make a class available for conversion, in your global initialization use registerClassAlias() call with MyCustomClass and its fully qualified name as parameters. The manual. Say your custom class is foo.bar.TheClass, you write:
registerClassAlias('foo.bar.TheClass',foo.bar.TheClass);
In order to drop old SO use delete call against so.data["mykey"] and do so.flush(). Edit: SharedObject.clear() is way better.
1/ Being persistent is one of the particularity of a SharedObject. To cleanup all its content, you need to call the clear method.
var shareObject:SharedObject = SharedObject.getLocal('justatest');
shareObject.data.test = 'test';
trace(shareObject.data.test)
shareObject.clear();
trace(shareObject.data.test)
output
test
undefined
2/ To store complex data types in SO, you need to use flash.net.registerClassAlias (example here)
I've written a JTree with couple of nodes. When I launch the program, I only see the node icons like folder or file and not the names associated with them. I could expand and collapse the nodes. When I debug, I see that the nodes are set with proper data whatever I used while building the model. In this program, i've written wrappers for JTree, TreeModel, DefaultMutableTreeNode. What could be the problem? Any pointers would be of great help.
-Paul
Sorry for not posting more details/code. Anyway, I've found the problem with my code. The problem was that I had overridden the toString() method in the class that I use to set as user object for the tree node, but that was returning null. As the method was returning null, there was nothing displayed. I made it to return the string to be displayed. It is working good now.
Thanks guys..!
Just wonder if I can reference entry point object from any place in the app? Is it maybe assigned to some global object, like stage is for example?
Currently I use static methods and variables, but this breaks encapsulation.
If someObject is in display list, then you have a someObject.root reference which is what you are looking for. If you remove someObject from display list, you loose that reference.
My answer is no, there is no direct way to access entry object, and there shouldn't be: that's what incapsulation is about. Accessing something globally is pretty much AS1 way. When you access main instance by implicitly referencing MainClass, you make parts of your application tightly coupled, which is generally bad.
However, if you do need to have it, you may choose from several options.
Use static var: MainClass.instance
Use singletone-like access through MainClass.getInstance()
Create a package-level variable or a package level getter method
I would choose the latter.
package com.smth.application
{
public var mainObject:MainClass;
}
// in main app
package com.smth.application
{
public function MainClass()
{
mainObject = this;
}
}
It may look somewhat similar to static acces, but I think this way your code will retain some flexibility.
stage is a reference to the top level of your application, which you can access though any display object that is on the display tree as myDisplayObject.stage. When using a custom document class, it will be the first child (index 0) of stage, unless you manually force something else into the 0 index as Bakapii says.
I'm working on a portfolio suggestion application in Flash, which consists of two views: ask user for 3 to 4 points of information, and display recommendations based on that information.
The first view is going swimmingly, as all I need are the graphics to be created. However, I'm having trouble understanding how a AS3 variable can be seen across keyframes when it was declared and initialized on the first frame.
The only multi-view app I've done is a Restaurant Guide flash app that was described in Adobe Flash CS5 Classroom in a Book. In that example, the only AS function on four of the views
was a stop() function.
If I were to do the same in this app, and declare the variables as global in the first frame, will they be accessible throughout?
CLARIFICATION
Two comments have said that my question is unclear, so I hope this makes my question more understandable. I want to know how, if I gather all the user information on Frame 1 and then switch to a view on Frame 15, to access those variables on Frame 1.
This isn't really the way you're supposed to work in AS3. Each view should be an object in your library with an associated class. Your document should also have a class associated with it, and it is here that you would hold your common data. The document class would instantiate each view as it is required and pass in the relevant variables.
That said, if you want to work the old way you shouldn't have trouble declaring a variable on frame 1 like this:
var myVar:String = "Hello!";
and then accessing it on frame 15 of the same timeline like this:
trace(myVar);
If that's what you're doing and it's not working then you'll need to update your question with some code examples.