How do you access a dynamic text field from a package / class? - actionscript-3

I tried the following line of code inside a class, but it results in an errormessage.
textbox1.text = this.attribute1;
Error description: 1120: Access of undefined property textbox1.

package yourpackage
{
public class MyClass
{
public var dynamicText:TextField;
public function MyClass(){
dynamicText = new TextField();
}
}
}
Now you can create a new instance from this class:
package yourpackage
{
public class MyOtherClass
{
public var myInstance:MyClass;
private var attribute1:int = 0;
public function MyOtherClass(){
myInstance = new MyClass(); //create new instance
myInstance.dynamicText.text = String(attribute1); //set the text of it's
//dynamicText textfield's text to the attribute you want
}
}
}
The error you get actually says that textbox1 is not a defined variable in the current context, or the access modifier is private, thus you can't access it only from within the class. You can create static variables which you can access from anywhere like this:
MyClass.dynamicText.text = "something";
The above code assumes that you declared the dynamicText as a static variable.
public static var dynamicText:TextField = new TextField();

Thanks for your help! However I managed to access and change the text of my textfield by the following two lines of code inside my clickHandler function.
var r:MovieClip = MovieClip(root);
TextField(r["textbox1"]).text = this.navn;
Even though I didn't fully understand your code, I guess it involved creating a text field for each of the objects inside my class?
I will by the way, as you recommended, continue my reading on classes. :)
Thanks again.

Related

Changing world's in flashpunk

I'm trying to make my first actual game in AS3, for this I am using flashpunk due to it's simplicity.
I have got to the point where I have a moving character and a textbox when I go infront of a door.
When I am infront of a door, two variables are changed inside the player class:
public var onDoor:Boolean = false;
public var doorType:String = ""
You can probably guess what onDoor does, doorType is the name the class. It's set like this:
public static var BedroomDoor:Door = new Door(350, 331, "ApartmentBedroom")
ApartmenBedroom being the name of the world the door leads to.
Inside the main class where flashpunk is initialised, I have this function:
public static function ChangeLevel(world:String)
{
var newWorld = getDefinitionByName(world) as Class
FP.world = new newWorld
}
But when I go to the door and press X infront of the door which calls the function, I always get this error:
[Fault] exception, information=ReferenceError: Error #1065: Variable ApartmentBedroom is not defined.
Can anyone help fix this?
In order to use getDefinitionByName() you have to include your class in the code first. Anything will do, for example simple var a:ApartmentBedroom; or more complex one like var allLevelsClasses:Array = [ApartmentBedroom, ApartmentLivingRoom];
So your Main.as code should look like this:
public static function ChangeLevel(world:String)
{
var allLevelsClasses:Array = [ApartmentBedroom, ApartmentLivingRoom]; // put everything here
var newWorld = getDefinitionByName(world) as Class
FP.world = new newWorld
}
Also you could avoid full classname confusion when creating Door. Instead of passing string with its name into Door constructor just pass world's class:
private var worldClassName:String;
public function Door(x:Number, y:Number, worldClass:Class):void
{
/// init what's necessary
this.worldClassName = getQualifiedClassName(worldClass);
}
And later just:
public static var BedroomDoor:Door = new Door(350, 331, ApartmentBedroom)

as3 - Creating common objects for all methods

I'm building an application using Flash CS6 and AS3, where there will be loads of texts. So I want to create only one text format object for all of them. I am using this code:
public class MyClass extends MovieClip {
public var formatTitle = new TextFormat();
formatTitle.size = 50; <-- ERROR HERE
public function MyClass(){
buildHome();
}
public function buildHome(){
var title:TextField = new TextField();
title.text = "HOME";
title.defaultTextFormat = formatTitle;
addChild(title);
}
}
But I'm getting the error: Access of undefined property formatTitle where it says formatTitle.size = 50. But it's here above it! What am I missing?
Thanks in advance.
You need to move formatTitle.size = 50; at the beginning of the constructor. You can't have code like this outside of a method.
public function MyClass(){
formatTitle.size = 50;
buildHome();
}

How to Make Popup window as Global in Flex?

Actually in my Flex Application have Some Popup windows and i want take some values in this Popup Window But The Values are Comming NULL
So how to Make a PopUp Window as Global? Because we are Using the values Globally.
Please Give Suggestion...
Edit
I'm Edit with some code...
Main.mxml(Main Aplication), Demo1.mxml(PopUpWindow), Demo2.mxml(PopUpWindow)
Now in Demo1.mxml have variable like...
[Bindable]private var arrayC:ArrayCollection=new ArrayCollection();//Hear Some value their.
NOw i want Use arrayC in Demo2.mxml then ..
public var variable1:Demo1=new Demo1();
var ac:ArrayCollection = new ArrayCollection();
ac = variable1.arrayC;
But hear ac contain Null Value Why?
Then,Now i'm Thinking Demo2.mxml(PopUpWindow) is Converting To Global Scope so it's value Used in Any Where .
Null because of you are tried create new instance so that each instance having their own state.
Also i bet you can't access arrayC ArrayCollection variable declared as private so you can't acccess.
Need to follow few steps
[Bindable]public var arrayC:ArrayCollection=new ArrayCollection(); //Make public variable
Use Singleton Class for you application
package com.foo.bar {
public class Model {
private static var instance : Model;
public function Model( enforcer : SingletonEnforcer ) {}
public static function getInstance() : Model {
if (!instance) {
instance = new Model( new SingletonEnforcer() );
}
return instance;
}
public var arrayC:ArrayCollection = new ArrayCollection();
}
}
class SingletonEnforcer{}
For more details Singleton pattern
private var popup:Demo1;
popup = PopUpManager.createPopUp(this,Demo1,true) as Demo1;
popup.arrayC = Model.getInstance().arrayC; // Here set value from Model class
PopUpManager.centerPopUp(popup);
Suppose you tried to access demo1.mxml arrayC variable in Demo2.mxml
var demo1_arrayC = Model.getInstance().arrayC;
Note that you can access arrayC arraycollection anywhere in your application like Demo2.mxml,Demo3...etc.
But better we have to avoid Singleton Class (unit test diffcult ..etc).
If you are using the values Globally, then no matter what you mean by the "Make a PopUp Window as Global", I strongly suspect that you would be best served by a singleton event dispatcher.
package com.example.demo.models {
import flash.events.IEventDispatcher;
import flash.events.EventDispatcher;
[Bindable]
class MyGlobalStuff extends EventDispatcher {
public var someGlobalValue:*;
private var _instance:MyGlobalStuff;
public function MyGlobalStuff (lock:SingletonLock, target:IEventDispatcher=null) {
super(target);
if(!(lock is SingletonLock)) {
throw(new Error("MyGlobalStuff is a singleton, please do not make foreign instances of it"));
}
}
public static function getInstance():MyGlobalStuff {
if(!_instance) {
_instance = new MyGlobalStuff (new SingletonLock());
}
return _instance;
}
}
}
class SingletonLock{}
The idea is this: that you would bind in your popup to
{myStuffModel.someGlobalValue}
myStuffModel would be initialized in your mxml as:
protected var myStuffModel:MyStuffModel = MyStuffModel.getInstance();
then in any other class throughout your application you can bind to or access the EXACT same data via the singleton model.

how do I make non-document-class classes 'aware' of stage components in Flash AS3?

I am working on a text adventure game which will have at least a few components (a text area for narrative and text input for user input) on the stage at all times. Therefore, I have created those components statically through Flash's WYSIWYG design environment. I gave them instance names "myTA" and "myTI" respectively. I was able to get my main class (the document class for the stage) to interact with them (dynamically adding text one character at a time like a typewriter at runtime), but other classes in the same package don't seem able to recognize the stage components. Below is the relevant code:
Case A, in which everything happens within the Main class:
package {
public class Main extends MovieClip {
public var myTA:TextArea;
var displayedChar:String = new String();
var textToWrite:String = new String();
var i:int = 0; var intervalId:uint;
var done:int = 0;
public function Main {
setUpTA();
}
public function setUpTA(){
myTA.text = "" + playAtInterval("Hello Player!");
}
public function writeCharsSlowly(){
textToWrite = arguments[0];
displayedChar=textToWrite.substring(i,i+1);
myTA.appendText(displayedChar);
i++;
if (i == textToWrite.length) {
done = 1;
clearInterval(intervalId);
}
}
public function playAtInterval(theText:String) {
i = 0;
intervalId = setInterval(writeCharsSlowly, 100, theText);
}
}
}
Case B, where Main calls on a second class 'TypeWriter' to handle the typewriter-printing:
Main:
package {
public class Main extends MovieClip {
public var myTA:TextArea;
public var myTI:TextInput;
var str:String = new String();
public function Main{
testTypeWriter();
}
public function testTypeWriter(){
typeW.playAtInterval("Hello Player");
typeW.addEventListener(MouseEvent.CLICK,testTypeWriter2);
typeW.addEventListener(KeyboardEvent.KEY_DOWN,inputEngine2)
addChild(typeW);
}
public function testTypeWriter2(event:MouseEvent){
if (myTI.text == "a") {
typeW.playAtInterval("yo");
} else {
typeW.playAtInterval("Greetings, I am a test...");
}
addChild(typeW);
}
public function inputEngine2(event:KeyboardEvent){
str = String.fromCharCode(event.charCode);
myTI.appendText(str);
}
TypeWriter:
package {
public class TypeWriter extends MovieClip {
public var myTI:TextInput;
public var myTA:TextArea;
var i:int = 0;
var done:int = 0;
var intervalId:uint;
var displayedChar:String = new String();
var textToWrite:String = new String();
public function TypeWriter(){
///nothing here
}
public function writeCharsSlowly(){
textToWrite = arguments[0];
displayedChar = textToWrite.substring(i,i+1);
myTA.appendText(displayedChar);
i++;
if (i == textToWrite.length) {
done = 1;
clearInterval(intervalId);
}
}
public function playAtInterval(theText:String) {
i = 0;
intervalId = setInterval(writeCharsSlowly, 100, theText);
}
}
}
Case A works, but in case B Flash is giving me the error "Error #1009: Cannot access a property or method of a null object reference" and notes the first line in TypeWriter where I try to operate on myTA as the problem.
how can I make other classes besides the document class 'aware' of existing stage components?
Thanks,
CCJ
I would recommend the Service Locator Pattern for this. The most naive approach would be to create a resource class which contains public static variables. Then in your document class you assign the stage instances to the corresponding static variable in the resource class. Then you can simply access these stage components anywhere.
var someTextArea = Resource.TA; //probably should rename to something more meaningful
For something a little more ingenious you should read the article I linked to.
I think this is better than the dependency injection as constructor injection could lead to huge parameter list as you might add more items to the stage, and I am not so fond on setter injection as it is easy to forget to set them.
EDIT:
Just to make it a bit more clear I thought I would add some code :)
Resource class
package
{
//TODO imports
public class Resource
{
public static var TA:TextArea;
public static var TI:TextInput;
}
}
Document class
//....setup function
Resource.TA = myTA; //myTA is the name of the instance on stage
Resource.TI = myTI;
Foo class
Resource.TA.x = 100;
//or
_myClassMemberVariable = Resource.TA;
_myClassMemberVariable.x = 100;
I think some dependency injection will solve this problem. When you instantiate your Typewriter class, pass references to myTA and myTI. ex:
public function Main{
testTypeWriter(this.myTA, this.myTI);
}
Then your Typewriter constructor should look like this:
public function TypeWriter(ta:TextArea, ti:TextArea){
this.myTA = ta;
this.myTI = ti;
}
This also has the benefit of making your application less tightly coupled, so for example you can reuse your Typewriter class with a different text area and text input.
Edit
Some extra info that may help you in the future: you can access stage elements through the root object. But this only works with objects that have been added to the display list. Let's say that Typewriter represents an object in the display list, you could then access myTA like this:
MovieClip(root).myTA
(Change MovieClip to Sprite if that's what your document class extends).
However, since it seems that Typewriter does not get added to the display list, I recommend using my first suggestion of dependancy injection.
Also check out this page, it dicusses using CasaLib to access the stage from any object. I personally haven't tried it, so that's why it's at the end here ;-)
Are myTA and myTI actually on the stage at author time or are the added dynamically?
In the first case, just add an instance name to each. Then add a variable to each class
var main_mc : Main = root as Main;
You can then access the instances via main_mc.myTA and main_mc.myTI (assuming those are the instances names you chose) and everything should be type-safe.
In the dynamic case, just make sure you save off references in the main class to each as you add them.
Another option is to have classes for myTA and myTI send an event in their constructor to announce their existence. The main class can then listen for these and register the references.
To be honest, though, you are mixing up your display with your logic. Read up on MVC and PureMVC in particular. With a good design, everything can be handled by messages, and the instances don't need direct references to each other. IIRC, Moock's AS3 book has a chapter on MVC (but it could be his AS2 book).
The fact that they will be on stage at all times shouldn't stop you from creating specific classes for them.
Depending on your game structure, you could either create a MovieClip with your TextFields and link them to the Typewriter class, or simply create a class for the TextFields and use Events to modify the text content.
You're using external classes so there are no reason to keep any kind of logic inside Flash CS.
Just to be clear. When you are writing stage you really mean the document class for your flash document. Stage is a class that every instance that has been added to the displaylist Have access to.
I would pass the textfields into the classes that needs to update them.
var tw : Typewriter = new Typewriter();
tw.inputField = myTI;
tw.textArea = myTA;
Or
var tw : Typewriter = new Typewriter(myTI, myTA);

I Want Access To a Public Static Const in my Actionscript Without Instantiating an Object... Is That Possible?

I've got a static property I would like to access by importing it's class without instantiating an object of that class. Is this possible?
Essentially I'm writing a bunch of styleSheet Objects over and over. I figure If I have a class called CSS and like this:
package com
{
import flash.text.*;
public class CSS
{
public static var STYLE_SHEET:StyleSheet = new StyleSheet();
and assign all of it's properties in the constructor like:
public function CSS
{
//NAV BUTTON
var navButtonBlock:Object = new Object();
navButtonBlock.color = "#000000";
navButtonBlock.fontSize = "25";
navButtonBlock.fontFamily = "Arial";
navButtonBlock.marginLeft = "5";
navButtonBlock.kerning = "true";
navButtonBlock.fontWeight = "bold";
//TITLE
var titleBlock:Object = new Object();
titleBlock.color = "#CCCCCC";
titleBlock.fontSize = "25";
titleBlock.fontFamily = "Arial";
titleBlock.marginLeft = "5";
titleBlock.kerning = "true";
titleBlock.fontWeight = "bold";
STYLE_SHEET.setStyle("code", titleBlock);
STYLE_SHEET.setStyle("navButton", navButtonBlock);
}
If I import the class into the class I wish to make use of it like:
package{
import com.CSS;
and inside my class use the variable like:
textField.styleSheet = CSS.STYLE_SHEET;
I can save some headaches.
The thing I find weird is that I have create an instance of that class to access it's const. So in the class header I have to write:
private var css:CSS = new CSS();
even though I never end up making use of this object...
Does this make sense? Am I going about this the wrong way?
-J
p.s. Who wishes the tab key worked in this question editor window?
You can write static init() function, which you will have call only once or you can use "static initializers":
package com
{
import flash.text.*;
public class CSS
{
public static var STYLE_SHEET:StyleSheet = new StyleSheet();
// Static init block
// This block is run once when the class is first accessed
{
var navButtonBlock:Object = new Object();
/*...*/
var titleBlock:Object = new Object();
/*...*/
STYLE_SHEET.setStyle("code", titleBlock);
STYLE_SHEET.setStyle("navButton", navButtonBlock);
}
}
}
Now import class and just use static var STYLE_SHEET
import com.CSS;
...
textField.styleSheet = CSS.STYLE_SHEET;
You don't have to make an instance of the class to ACCESS its static members, but you are initiating your static variable inside the classes constructor.
This mean that at the time you access the static variable like this:
textField.styleSheet = CSS.STYLE_SHEET;
The STYLE_SHEET property is not set yet!
Usually the way to get around this kind of thing is to have an "init" static method.
CSS.init();
The init method would set STYLE_SHEET, like you have done in your constructor.
This does mean that in you application you will have to call CSS.init() once before you use STYLE_SHEET anywhere else.
ALSO:
What you refer to as a "const", is not a const at all. It is just a static. Const means the value is constant (never changes).
Thanks to both ivann and TandemAdam for leading me down the right path. Ultimately I figured out that first, the reason I had to instantiate an instance of my class is because I was defining my variables properties in the constructor function. So I built a static constructor function which eliminated the need to instantiate, but I still had to call the function (rather than just import).
Then, ivann pointed out, I don't need to call the function at all If I just build a static init() function. Awesome idea except missing one bit of information. You cannot declare variables in a static initializer. So, the ultimate solution was to call my private static function that CAN declare variables from my static initilaizer function.
example:
package com.atJascha
{
import flash.text.*;
public class CSS
{
public static var STYLE_SHEET:StyleSheet = new StyleSheet();
{
init();
}
private static function init()
{
//NAV BUTTON
var navButtonBlock:Object = new Object();
navButtonBlock.color = "#FFFFFF";
//TITLE
var titleBlock:Object = new Object();
titleBlock.color = "#00FFFF";
STYLE_SHEET.setStyle("navButton", navButtonBlock);
STYLE_SHEET.setStyle("title", titleBlock);
}
}
}