Accessing Variables in another class? - actionscript-3

First off I don't understand classes, how to "call" or "initiate" them. I'm class ignorant.
I have two .fla files. One of my .fla files consist of 15+ .as files; we'll call this one XML editor. The other .fla file consists of 10+ .as files; we'll call it the interface.
The xmleditor.swf loads the interface.swf.
Within the xmleditor.swf, a login screen appears and the enduser logs in as either a "user" or an "admin". The "user" or "admin" is stored in a public variable called "userType". The userType variable is created in one of the many xmleditor.fla .as files called Login.as.
Once logged in, xmleditor loads the interface.swf. interface.fla uses 10+ .as files. one is called nodeNames.as I need an if statement in nodeNames.as that is something like this:
if (Login.userType == "user"){
trace("do something");
}
I have the following FlashVars.as file but I have no idea what the steps are to make it work.
package extras.utils {
import flash.display.Sprite;
import flash.display.LoaderInfo;
/* In AS3, we need to have a display object on the stage to access FlashVars
* this class can be used once, and then referenced from anywhere as
* FlashVars.data.variableName
*/
public class FlashVars extends Sprite {
public static var data:Object;
public function FlashVars() { }
public function load():void { //Only needs to be called once
data = this.root.loaderInfo.parameters;
}
}
}
Should I use this FlashVars? and if so, how?
Or is there an easier way to access the variable?

well, from what i understand, you Login.as is a class. Then you have two ways of accessing the Login.userType variable : if you want to be able to call it with
Login.userType, you'll need it to be static in your class
public static var userType:String
it is then accessible using Login.userType from anywhere in your application, as long as you import Login.
But it is often considered bad practice to have too many static vars in your app, especially from different classes. so you may want to have an instance of your login class stored in a variable somewhere in your app, along with anything you need
var myLogin = new Login();
myLogin.userType = 'value';
But be aware that this way, every new Login() will carry it's own different userType, so you will want to pass along myLogin to any object needing it.
Object programming can be confusing, but is very powerful, i suggest you read about it (in books or on the web) since the whole thing can't be explained here.
Have fun!

Related

Access to protected function in external swf

I've bought an external component composed by the MXP component and two external swf.
Obviously I haven't any source or fla file.
I've imported the component in my own project and it works fine (combined with the two external swf). Now I've debugged and decompiled one of this two external swf whith a stand alone program (SWF Decompailer) in order to find two functions I wanto to manage.
I've found their name [forceNextImage() and forcePrevImage()] and the class where they are declared.
The problem is that those functions are protected and I've the necessity to call them inside my project (the project where I've imported the components, of course). There's a way to do that? And how?
I hope I've been understandable even with my lacking english, but if not don't esitate to ask me..
Thanks in advance.
Fabrizio
Can you subclass it, and then call it from the subclass?
protected methods are callable from subclasses, so you can extend the component and expose them:
public class YourComponent extends Component
{
public function nextImage():void
{
forceNextImage();
}
public function prevImage():void
{
forcePrevImage();
}
}

AS3: Create static variables in registry from external list

I have an application which will be using large numbers of assets. In order to better handle that I chose to use a registry to hold all the assets so they are accessible across the entire application:
package
{
public class SpriteRegistry
{
public static var SPRITENAME = "link to image file";
public function SpriteRegistry()
{
}
}
}
What I would like to do is create an XML document and list off the file name and link so that when the application starts, this registry creates its variables which are freely accessible from that list without me needing to hard code any content directly into it.
Specifically what I need to know is how to get the "public static" effect or how to get an equivalent effect for variables that I CAN dynamically produce.
More info:
I am using a function that loads a sprite texture into a sprite object based on a string variable called mouseAttribute:
loadGraphic(SpriteRegistry[currentAttribute+"Texture"]);
Basically it's like a painting program but for a level editor for a video game.
The problem is that I'm eventually going to have 100+ sprites that I need to application to load and then I need the loadGraphic function to still be able to point effectively to the target sprite.
The library I'm using also needs me to embed the source into a class before I can pull it into the sprite object:
[Embed(source = "/Images/GridTile.png")]
public static var gridTileTexture:Class;
The reason I'm trying to avoid an array is because it means that I will have to search through an array of 100+ objects to find one sprite every time I click a single grid on the editor. That is going to chug.
It's very simple - just use a static function, which will return the XML. So you will need to load the XML file somehow (you decide where, but your registry class should have reference to it). Something similar to this:
private static var _xml:XML;
public static function initialize(xml:XML):void {
_xml = xml;
}
public static function getXML():XML {
return _xml;
}
So you will use it like that:
SpriteRegistry.initialize(loadedXML); // done only once when you initialize your app
trace(SpriteRegistry.getXML().someValue); // someValue is directly from the XML
It's a common used strategy and most of the times you would have something like an app initializer - something to load and instantiate all the things, then pass them to some registries that keep them stored for faster and global usage.
Edit:
After reading your further comments, I can't see any big change - everything would be ok with this resolution.
If you are worried about the 'need to search through array' - just do it as an object! This way you will be able to directly access the proper one using a key exactly like you pointed:
private static var _registry:Object;
public static function initialize(xml:XML):void {
// loop through xml and insert items
_registry[key] = resource;
}
public static function getResource(id):Object {
return _registry[id];
}
This way you can use it like:
SpriteRegistry.getResource(currentAttribute+"Texture");
My personal opinion is that you should avoid statics wherever possible. Instead, you should just create a single instance and provide it through dependency injection where needed.
If you were to go with that approach, you could do something like:
public function getSprite(spriteName:String):Class{
return this[spriteName];
}
or
public function getSprite(spriteName:String):Class{
return yourDictionaryOrObject[spriteName];//I'd implement it this way
}
Otherwise you could go with something like:
public static function getSprite(spriteName):Class{
return ThisHonkingBigUnnchangeableClassname[spriteName];
}
What I would not do is create a Dictionary in a static-only Class, because you're almost inevitably going to wind up with global mutable state.
Discussion, per request
Why would you want to create an instance and pass it, rather than hard-code a reference to a specific Class? A lot of the answers are covered in the global mutable state link above, but here are some that are specific to this kind of problem:
Flexibility. Say you build everything with the idea that you'd only have one set of resources being used in parallel, then you discover you need more than one--for example you might need one for color blind users, or multiple languages, or thumbnails vs. full-sized. If you hard-code to a static, then you'll have to go in every place that was hard-coded and make some sort of change to use a different set, whereas if you use DI, you just supply a different instance loaded with different resources, and done.
Testability. This is actually covered in the link, but I think it bears pulling out. If you want to run a quick test on something that needs a resource, you have to have that static "thing" and you can't change anything about it. It then becomes very difficult to know if the thing you're actually testing is working or if it just appears to be working based on the current implementation of the "thing."
Resource use: everything about an all-static Class exists from the time the swf loads to the time it unloads. Instances only exist from when you instantiate them until they are garbage collected. This can be especially important with resource files that contain embedded assets.
I think the important thing about Frameworks is to realize how they work. The major ones used in ActionScript work the same way, which is they have a central event dispatcher (event bus) that anything loaded to the framework can get a reference to by declaring an interest in it by asking for it to be injected. Additionally, they watch the stage for an event that says that something has been added (in RL it's ADDED_TO_STAGE, whereas in Mate it's the Flex event CREATION_COMPLETE). Once you understand these principles, you can actually apply them yourself with a very light hand without necessarily needing everything that comes along with a framework.
TL;DR
I usually try to avoid answering questions that weren't asked, but in this case I think it would be helpful to discuss an entirely different approach to this problem. At root, the solution comes down not to injecting an entire resource instance, but instead just injecting the resource that's needed.
I don't know what the OP's code is like, but this solution should be general enough that it would work to pass named BitmapDatas to anything that implements our Interface that is capable of dispatching against whatever IEventDispatcher we set as the eventBus (this could be the stage, a particular DisplayObject, or an EventDispatcher that is created just for the purpose.
Note that this code is strikingly similar to code I have in production ;).
public class ResourceManager {
//this can be loaded dynamically, or you can create subclasses that fill the registry
//with embedded Classes in the constructor
protected var registry:Dictionary = new Dictionary();
protected var _eventBus:IeventDispatcher;
public function registerResource(resourceName:String, resourceClass:Class):void {
var bitmap:BitmapData = new resourceClass as BitmapData;
if (resourceClass) {
registry[resourceName] = bitmap;
} else {
trace('Class didn\'t make a BitmapData');
}
}
public function getResource(resourceName:String):BitmapData {
var resource:BitmapData = registry[resourceName];
if (!resource) trace('there was no resource registered for', resourceName);
}
public function get eventBus():IEventDispatcher {
return _eventBus;
}
public function set eventBus(value:IEventDispatcher):void {
if (value != _eventBus){
if (_eventBus) {
_eventBus.removeEventListener(YourCustomEvent.GET_RESOURCE, provideResource);
}
_eventBus = value;
if (_eventBus) {
_eventBus.addEventListener(YourCustomEvent.GET_RESOURCE, provideResource);
}
}
}
protected function provideResource(e:YourCustomEvent):void {
var client:IBitmapResourceClient = e.target as IBitmapResourceClient;
if (client) {
client.resource = getResource(e.resourceName);//your custom event has a resourceName property that you populated when you dispatched the event.
}
}
}
Note that I didn't provide the Interface or the custom event or an example implementation of the Interface due to the fact I am on my lunch break, but if anyone needs that to understand the code please post back and I'll fill that in.

Custom AS3 Class not Updating

I've had a similar issue to this, but the means that I solved the last one are not working here.
I have a custom class that consists of 12 separate .as modules. They're declared in the document class as follows:
import trailcrest.v1.s3.averta;
import trailcrest.v1.s3.chronos;
import trailcrest.v1.s3.eripio;
import trailcrest.v1.s3.fabrilla;
import trailcrest.v1.s3.gradua;
import trailcrest.v1.s3.lingua;
import trailcrest.v1.s3.navigare;
import trailcrest.v1.s3.pedem;
import trailcrest.v1.s3.praeferre;
import trailcrest.v1.s3.scriba;
import trailcrest.v1.s3.securos;
import trailcrest.v1.s3.sonus;
public static var Averta:averta = new averta();
public static var Chronos:chronos = new chronos();
public static var Eripio:eripio = new eripio();
public static var Fabrilla:fabrilla = new fabrilla();
public static var Gradua:gradua = new gradua();
public static var Lingua:lingua = new lingua();
public static var Navigare:navigare = new navigare();
public static var Pedem:pedem = new pedem();
public static var Praeferre:praeferre = new praeferre();
public static var Scriba:scriba = new scriba();
public static var Securos:securos = new securos();
public static var Sonus:sonus = new sonus();
This is a new version of the code. I am able to successfully refer to all of these classes and the public variables and functions inside in the "osr.as" document class. I can also SEE one module from another (i.e. Sonus can see Scriba using "osr.Scriba."
Where I'm having trouble is that, while the various modules used to be able to access all of each other's public functions and variables perfectly, after I added some new modules and variables and removed some old ones, Flash Professional is still literally USING the old version. Inside of any module, the code hints are showing all of the old public functions and variables, and none of the new ones.
I am guessing that this has something to do with some sort of temporary file that I can't get to. I absolutely need this working this week!
My .fla is "Tester.fla," and the document class is "osr.as." They're both in the same directory. Also in the same directory is the folder structure "/trailcrest/v1/s3/" which contains all of the Trailcrest modules.
Help??
EDIT: Whenever I try to reference one Trailcrest class from another Trailcrest class (i.e. osr.Sonus.foo), I get...
TypeError: Error #1009: Cannot access a property or method of a null
object reference.
I have confirmed beyond a shadow of a doubt all references.
This is the age old problem of what ultimately boils down to is the Verify Error. It happens when you embed "Class A" in one or more applications, modules, swfs, etc. Ultimately every output swf that uses "Class A" must be recompiled when "Class A" is changed. Otherwise you end up with a situation where 1 module has the newer implementation but others don't. This problem is compounded by the fact that the application domain is defined as a "first in wins" when it encounters a Class of the same name / package - meaning if the old one is referenced first, the newer one loaded later gets ignored.
The more permanent solution is to use class promotion to an RSL that ultimately allows the RSL to control the actual "Class A" reference in which it also implements an "IClassAImpl" interface that all modules use. This allows the compiler to cross link the reference with a signature it knows about without actually embedding the actual class itself.
Well, I finally figured it out. Here's the skinny on what was happening:
#1: Flash was apparently pulling an old version of the Trailcrest modules. To remedy this, I backed up everything and then removed all old instances of Trailcrest from my entire computer. Then, I put only the new modules back. That fixed the problem with Code Hints showing the old modules and variables.
#2: I had been experiencing Error #1009 whenever one Trailcrest class tried to access any component of another Trailcrest class, even though the references were all correct.
The cause was that I was calling functions on the various modules directly from the document class osr.as, outside of a function. This, of course, executes on the program start.
However, all the code within one Trailcrest class that called another Trailcrest class (i.e. osr.Sonus.foo) would not be able to access "foo" because osr.as for some reason or another hadn't finished initializing the classes before it ran the code that called them. This occurred, even though the problem code was well below the code that initialized the classes (see my question).
To fix this, I simply had to wrap the problem code into a public static function in the document class, and then call it from the Timeline. That ensured that all the classes were initialized before they tried referencing each other.
Needless to say, everything is running like a well-oiled machine now. How weird.
I'd welcome any explanation as to WHY this fixed the problem.

AS3 OOP common practices examples?

I am trying to better understand the AS3 OOP structure and organization, but I am having some problems wrapping my head around it. I want to create multiple class files and it seems that best practice is not to and to put all classes in one file? I have searched for hours on the web and came up with little for good examples. Maybe seperate files is not the way to go while using AS3, but to me it only makes sense for modularzation. The files I have been playing with are:
Main.fla
Main.as (document class)
TestOne.as
TestTwo.as
TestThree.as
TestFour.as
TestFive.as
I have created a folder called classes to house all class files except the Main.as which resides with the FLA.
All five Test classes are the same code except the file name and class name.
Here is how I am importing the files:
Main.as
package classes
{
import flash.display.MovieClip;
import classes.TestOne;
import classes.TestTwo;
import classes.TestThree;
import classes.TestFour;
import classes.TestFive;
public class Init extends MovieClip
{
trace("This is Main Class");
var testOne : TestOne = new TestOne;
}
}
TestOne.as
package classes
{
import flash.display.MovieClip;
public class TestOne extends MovieClip
{
trace("This is TestOne");
public function testing():String
{
return "This is the testing method";
}
}
}
Are the above examples I created good AS3 OOP practices? I understand these are real basic classes, but I think it should get the point arossed.
I am using CS3
Might be good to look at the Flex SDK coding conventions and best practices. It is a point by point rundown of how you should be using ActionScript 3. There is quite a bit of OOP stuff scattered throughout, so take a good skim through it. I think it is worth any new or experienced AS3 devs to have a read, because there is a lot of useful information there.
OOP is a big subject but here is a good primer.
ActionScript 3 design patterns will be also useful for you.
As Nathan said, big subject.
The thing about having all classes in one file is related to the topic "visibility of a class" and "access modifiers".
The modifier is that what is written before the class keyword. It can be public or internal. Internal means, that only code that is placed in the same directory (package) of the internal class can create an object of it. Public means, any code can create an instance of the class. Random link via google: http://flexmaster.blog.co.in/2010/05/20/action-script-use-access-modifiers-with-classes-and-class-members/
You are allowed to have multiple classes in one file. But then only one can have the modifier public. All others need to be internal. If you leave out the modifier, a class is by default internally visible. An internal class in a multiple classes file can be accessed only from within this file.
There are two more modifiers: protected and private. Both are applicable only to properties or methods. As an advanced developer you can even define you own modifier by using namespaces.
The rules of OOP still apply to AS3
1) Encapsulation.
2) Inheritance.
3) Abstraction.
4) Polymorphism.
Apply them or not is your choice but it is good practice.
And don't forget the most important rule "KISS" (keep it simple stupid)
I also want to point out your code has an error
package classes
{
import flash.display.MovieClip;
public class TestOne extends MovieClip
{
trace("This is TestOne");// this line is not inside a function and will most undoubtly error out your app.
public function testing():String
{
return "This is the testing method";
}
}
}
I think you either did something wrong when you copied the code into SO or you're not placing the trace statements correctly. You need to place the trace("This is TestOne"); inside a constructor in TestOne.as, like this:
public function TestOne() {
trace("This is TestOne");
}
The same goes for the code inside the Init class, which now reads:
trace("This is Main Class");
var testOne : TestOne = new TestOne;
but should be(note the bracers after new TestOne):
public function Init() {
trace("This is Main Class");
var testOne : TestOne = new TestOne();
}
What happens when you run your SWF, is that the constructor of the class Init will:
1) Trace "This is Main Class" to your console.
2) It will construct a new object(thus the name constructor) by calling the constructor of the class TestOne.
If you were to add this line to the end of the constructor in the class Init:
testOne.testing();
you should see this in the console: "This is the testing method".
If you would now comment out the line: var testOne : TestOne = new TestOne(); and run the SWF again, you'll get an error telling you something is null. This is because you attempt to call the method testing on an object that does not exist.
I do realize this is primarily fixing some coding errors of yours, and not so much helping you understand OOP. But hopefully you can pick up some help regarding object construction. I see some answers already mention key OOP principle that you really should look into.
Edit:
Remember that duplicating code is never a good thing, so if you find that all of the classes TestOne - TestFive contain the same code, except for some minor detail. You should probably change them into one class.
In your case you could for example change TestOne so that the constructor accepts a String, and then in your testing function you could just trace that String. By changing your TestOne class into the following you effectively get rid of 4 other classes. You also encapsulate a String inside of the class TestOne.
package classes {
import flash.display.MovieClip;
public class TestOne extends MovieClip {
private var message : String;
public function TestOne(myMessage:String) {
message = myMessage;
trace("This is TestOne");
}
public function testing() : String {
return message;
}
}
}

In actionscript, why is my static class member variable not the same when accessed from different parts of my app?

I have an actionscript class with a static member variable defined.
public class A
{
public static var x:int;
}
When I try to access it from different parts in my code I don't get the same value in each spot.
A.x
I am accessing the variable in different modules that are loaded, so they are all in their own separate .swf file. Could this by why?
Seems like an application domain problem. The main swf and the modules seem to be accessing their own copies of the A class. You should probably change the way you load your modules.
Check this out:
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/system/LoaderContext.html#applicationDomain
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/system/ApplicationDomain.html