AS3 doesn't recognize a variable I just declared - actionscript-3

I'm trying to load a background image, but I'm getting an error saying "Error: Access of undefined property assetLoader." What's going on here?
import flash.display.Loader;
import flash.net.URLRequest;
class Inventory {
private var assetLoader:Loader = new Loader();
assetLoader.load(new URLRequest("image.png")); //error on this line
addChild(assetLoader);
}

If you are using addChild() method you must inherits the features of DisplayObjectContainer. And if you are using your Inventory class as document class, you must extends Sprite or MovieClip.
Document class must be defined by public access specifier.
Only globally(Class property definitions) declared variables are allowed to use private and public. You are not allowed to use it locally(within functions). And Timeline also not allow you to use access specifiers.
package
{
import flash.display.Loader;
import flash.net.URLRequest;
import flash.display.MovieClip;
public class Inventory extends MovieClip
{
private var assetLoader:Loader;
public function Inventory()
{
// constructor code
assetLoader= new Loader();
assetLoader.load(new URLRequest("image.png")); //error on this line
addChild(assetLoader);
}
}
}

You need to place these two lines in the constructor code, like this:
import flash.display.Loader;
import flash.net.URLRequest;
class Inventory {
private var assetLoader:Loader = new Loader();
public function Inventory() {
assetLoader.load(new URLRequest("image.png")); //error on this line
addChild(assetLoader);
}
}

The correct answer is that even tough you can instantiate instances at declaration time like here:
private var assetLoader:Loader = new Loader();
You are not allowed to work with those objects prior to the class instance existing. Any attempt to access assetLoader properties and methods prior to creating an instance of Inventory will fail. The constructor is the first piece of code that an instance of Inventory will run so it's the first place in the class code where you can start to use the class instance objects because at this point the Inventory instance exists. Vesper code example shows it correctly.
In theory this:
private var assetLoader:Loader = new Loader();
is equivalent to this:
private var assetLoader:Loader;
public function Inventory()
{
assetLoader = new Loader();
}
but in fact the timing of the assetLoader creation differs slightly. It is always better to create those member instance in constructor.
To Benny: All classes have an access modifier that defaults to internal. The PO class is defined as internal and so has correctly an access modifier (the internal default since none is specified). The access modifier of the member variable is correctly defined and is not related to the PO problem.

Related

as3 #1009 error code provided. "Null Object reference"

hi I'm relatively new to as3 (this year) and I'm getting this error
typer error #1009 cannot access a property or method of a null object
reference. at FoodObject/collisionTest()
i was hoping anyone could help
package {
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.events.*
import flash.utils.*
import flash.display.Stage;
public class GameScene1 extends Scene {
//public variables
//character & scenery
public var mainChar: Character;
public var testFood: FoodObject;
//constructor is used to create all necessary objects for this scene and display them
public function GameScene1(gm_: Manager) {
//constructor
super(gm_);
trace("GameScene 1 constructor");
//character
mainChar = new Character;
addChild(mainChar);
mainChar.x = 200;
mainChar.y = 200;
testFood = new FoodObject;
addChild(testFood)
testFood.x = 50
testFood.y = 200
the food object class is here.
package {
import GameScene1
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
public class FoodObject extends MovieClip {
public var Game1:GameScene1;
public function FoodObject() {
//constructor code
this.addEventListener(Event.ENTER_FRAME, collisionTest)
}
public function collisionTest(e:Event)
{
if (this.hitTestObject(Game1.mainChar))
{
trace("it works")
}
}
}
}
game manager here:
package {
import flash.display.MovieClip;
public class Manager extends MovieClip {
//stores which scene is currently loaded
public var curScene:Scene=null;
public function Manager() {
//constructor
trace("Manager Construct")
GoToScene("menu");
}
public function GoToScene(name:String)
{
if (curScene) //there was a scene already
{
curScene.OnLeaveScene(); //call its OnLeaveScene function to remove all objects
removeChild(curScene);
}
if(name=="menu") curScene = new MenuScene(this);
if(name=="select") curScene = new SelectScene(this);
if(name=="game1") curScene = new GameScene1(this);
if(name=="game2") curScene = new GameScene2(this);
if(name=="game3") curScene = new GameScene3(this);
if(name=="credit") curScene = new CreditScene(this);
addChild(curScene);
}
}
Your problem is that the concerns of your classes are not separate:
Your Scene knows both the Character and the Food object, you instantiate both classes there, nothing wrong with that.
The problem starts when you are trying to do something in the Food object, that requires knowledge of the character. The thing is: the Food object doesn't know anything about the Character.
You can solve this by simply passing the reference of Character to your Food object. In order to do this, modify the constructor like so:
private var character:Character;
public function FoodObject(character:Character) {
//constructor code
this.addEventListener(Event.ENTER_FRAME, collisionTest)
this.character = character;
}
The usage of said constructor in your Scene changes as follows:
testFood = new FoodObject(mainCharacter);
This way, Food knows the character and can do stuff with it, for example do collision tests:
public function collisionTest(e:Event)
{
if (this.hitTestObject(character)) // ==== this line changed
{
trace("it works")
}
}
However, this raises an important issue: Why should Food know the Character at all?
Sure enough, you want to do the collision test, which requires both objects.
But why do you want to do it in the Food object?
Doing the collision check in Food is cumbersome, because you have to pass a reference to Character in order to do it there.
The much preferred way of doing this is to do the collision check where both objects participating in the check are already known.
In your case, this is the Scene.
Think about how easy it is to do the check in Scene:
testFood.hitTestObject(mainCharacter);
It's that simple, because everything you need is already there.
To recap:
The collision check requires knowledge of 2 objects that you want to
check.
In order to do the check in either one, you have to pass a reference
of the other. (Character to Food as seen above or the other way
round)
It is a lot easier to do the check in some place that already knows
both objects, because no reference have to be passed around.
Your original code failed because Game1 in FoodObject is never assigned a value and therefore remains null.
Invoking methods on null causes the error you experienced.
You forgot to take the instance of GameScene1 class using new keyword.
public var Game1:GameScene1;
public function FoodObject() {
//constructor code
var _manager:Manager = new Manager();
Game1 = new GameScene1(_manager)
this.addEventListener(Event.ENTER_FRAME, collisionTest);
}
public function collisionTest(e:Event):void{
....
}

actionscript 3 - error #1009 issues calling function from another class

Im having trouble calling functions from other classes. I want to call a function in one class which updates a score display in another class. The error code for this is:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at code.functions::EnemyYellow()[code\functions\EnemyYellow.as:18]
at code::Main()[\code\Main.as:27]
Would appreciate if someone could help me out, I set up 2 basic files with the code which is causing an issue. Its normally not set up like this, I just made this for testing and so I can clearly explain the problem.
Main file:
package code {
import flash.display.MovieClip;
import flash.events.*;
import code.*;
public class Main extends MovieClip {
public var _enemy:EnemyYellow;
public var playerHP:Number;
public function Main() {
playerHP = 10;
_playerHPdisplay.text = playerHP.toString();
trace(playerHP)
_enemy = new EnemyYellow;
}
public function lowerHP ():void
{
playerHP = playerHP - 1;
_playerHPdisplay.text = playerHP.toString();
trace(playerHP)
}
}
}
Second File:
package code.functions {
import flash.display.MovieClip;
import flash.events.*;
import code.Main;
public class EnemyYellow extends MovieClip {
public var _main:Main;
public function EnemyYellow() {
_main.lowerHP();
trace ("done")
}
}
}
I also tried adding _main = new Main; in the second file but the game just loads with a blackscreen and an error about invalid data.
First of all, you surely need to "instantiate" the Main class, which means basically to create it.
public var _main:Main;
This line just declares that there will be a variable of type Main. But for now, the value of _main is null. So you are right, that you need to call:
_main = new Main();
After you've done this, the first error will disappear. But then you have things in that MovieClip that are still vague. Like _playerHPdisplay. Where's that from? Is it an instance from stage or what? You just created a brand new object, and it does not have any reference to other objects, TextFields or whatever.
So this basically answers your current question and problem, but for sure you will have more :)

How AS3 class files.as work together with FLA file?

I have two questions: Can i write app using just *.as files, and then compile them somehow in SWF? (i am making myself a webpage now)
Secondly, please look at the code, my problem is the same - I can't render text field onto stage, to be visible.
Flash say's 'undefined method addChild.' and 'Access of undefined property tekstuKaste through a reference with static type Class.'
This is a constructor type class inic which kinda serves for initialization, cos all i do is, I make an instance OF THIS class in FLA file by ActionScript, and expect, all application to work.
package {
import pacinas.visuals.*;
import pacinas.visuals.AE_kanva;
public class inic {
public function inic() {
trace("===========");
trace("inicializēt un izsaukt visu no Kanvas klases");
trace("===========");
trace(" ");
var kanvas:AE_kanva = new AE_kanva();
trace(" ");
kanvas.varis();
trace(" ");
trace("===========");
trace("inicializēt un izsaukt visu no Lauki klases");
trace("===========");
trace(" ");
var laukiTxt:BE_tekstaLaukiPrimitive = new BE_tekstaLaukiPrimitive();
trace("");
laukiTxt.simpleText();
addChild(BE_tekstaLaukiPrimitive.tekstuKaste);
}
}
}
There is another EXTERNAL CLASS By whom i hoped to place a rectangles - that does not work too. Example:
package pacinas.visuals
{
import flash.display.Sprite;
public class AE_kanva extends Sprite
{
public function AE_kanva()
{
var kvad:Shape = new Shape();
kvad.graphics.beginFill(0xFF0000);
kvad.graphics.drawRect(0, 0, 100,100);
kvad.graphics.endFill();
addChild(kvad);
trace("konstruktors - zīmē kanvu");
}
public function varis()
{
trace("te glabaas variaabljus");
var ff:int = 4;
var dd:int = 8;
}
}
}
And here is class i hoped will make text box for me (to fill it with XML later)
package pacinas.visuals
{
import flash.text.*;
import flash.display.Sprite;
public class BE_tekstaLaukiPrimitive extends Sprite
{
public var tekstuKaste:TextField = new TextField();
private var kontinents:String = new String ("XML SATURU CMON! a123");
public function BE_tekstaLaukiPrimitive():void
{
trace("teksta rāmis = konstruktora klase");
addChild(tekstuKaste); <--CAN'T GET THIS TO WORK!!!
tekstuKaste.text = kontinents;
}
public function simpleText()
{
trace("nekonstruktora f-cija no Teksta lauki");
}
}}
p.s. I do not use document Class. Ok I will if it's needed. But how?
Can I write app using just *.as files, and then compile them somehow into a SWF?
Yes - using the Flex SDK you can write pure ActionScript and compile it down into a working SWF. FlashDevelop is a good IDE that takes advantage of this.
You will however need to understand how the document class works.
Flash says undefined method addChild. and Access of undefined property tekstuKaste through a reference with static type Class.
In your code, this line is causing your issue:
addChild(BE_tekstaLaukiPrimitive.tekstuKaste);
The first error undefined method addChild is because your class inic does not extend a class that implements the method addChild(). DisplayObjectContainer defines this method, so you'll want to extend that as a minimum, like this:
public class inic extends DisplayObjectContainer
The second error is because you're attempting to access a property of the class BE_tekstaLaukiPrimitive as if it were static. I suspect what you actually wanted to do was this:
addChild(laukiTxt); // laukiTxt is the instance you created.

AS3 How to get custom class instances to access variables on timeline?

Please help me understand how to get custom class instances to access variables defined on the timeline.
I am not using a document class, because this program will be a memory experiment with multiple stages, so using the timeline works best for me. (FWIW, I'm also not using xml; just trying to keep this as simple as possible.) For now I've just made a simple one-frame fla on which I'm trying to make a vocabulary test. I have made a custom class called VocabQ, which in turn contains 4 instances of a custom class called VocabButton. Right now, clicking one of those buttons just traces the button label. But I want it to also update the value of the String variable CurrentResponse, which is declared on the timeline. If I just try to reference CurrentResponse from the VocabButton class, I get an error "1120: Access of undefined property...".
I've tried a variety of approaches based on discussions I've found across the internet, but have not yet had success and am only getting more confused. Please help! (Simple solutions would be greatly appreciated, if such exist!) See code below.
thank you, ~jason
code in timeline:
import VocabQ;
import flash.display.*;
stop();
var CurrentResponse:String="NA";
var VocabQuestion = new VocabQ("VocabWord",["answerA","answerB","answerC","answerD"]);
addChild(VocabQuestion);
VocabQ.as code:
package
{
import flash.display.*;
import flash.events.*;
import flash.net.*;
import flash.text.*;
import VocabButton;
public class VocabQ extends MovieClip{
private var _VocabWordText:String;
private var _VocabWord:TextField;
private var _ResponseOptions:Array;
public function VocabQ(VocabWordText:String,ResponseOptions:Array){
_VocabWordText=VocabWordText;
_ResponseOptions=ResponseOptions;
build();
}
private function build():void{
_VocabWord = new TextField();
_VocabWord.text=_VocabWordText;
_VocabWord.x=25;
_VocabWord.y=25;
_VocabWord.textColor = 0x000000;
addChild(_VocabWord);
for (var i:int; i < _ResponseOptions.length; i++){
var _VocabButton:VocabButton = new VocabButton(_ResponseOptions[i]);
_VocabButton.x = 25 + (_VocabWord.width) + 10 + ((_VocabButton.width + 2) * i);
_VocabButton.y = 25;
addChild(_VocabButton);
}
}
}
}
VocabButton.as code:
package
{
import flash.display.*;
import flash.text.*;
import flash.events.*;
public class VocabButton extends MovieClip{
private var _btnLabel:TextField;
public function VocabButton(labl:String){
_btnLabel = new TextField();
_btnLabel.textColor = 0x000000;
_btnLabel.text = labl;
_btnLabel.border=true;
_btnLabel.borderColor=0x000000;
_btnLabel.background=true;
_btnLabel.backgroundColor= 0xDAF4F0;
_btnLabel.mouseEnabled = false;
_btnLabel.selectable=false;
_btnLabel.width=100;
_btnLabel.height=18;
buttonMode=true;
useHandCursor=true;
addEventListener(MouseEvent.CLICK,onClick,false,0,true);
addChild(_btnLabel);
}
private function onClick(evt:MouseEvent):void{
trace(_btnLabel.text);
//CurrentResponse=_btnLabel.text; //causes error 1120: Access of undefined property...
}
}
}
This should work:
private function onClick(evt:MouseEvent):void {
trace(_btnLabel.text);
evt.currentTarget.root.CurrentResponse=_btnLabel.text;
}
See the discussion here: http://www.actionscript.org/forums/showthread.php3?t=161188
Personally, rather than trying to access the timeline like this, I would prefer to add a click listener
to your VocabQuestion on the timeline and allow the Event to Bubble Up, or, if you are going to have a number of buttons within your class, to extend EventDispatcher and create some custom events which can likewise be handled on your timeline, but for a simple test, accessing the root property should be good enough.

AS3 - Can I detect change of value of a variable using addEventListener?

Is it possible to use EventListener to Listen to a variable and detect when the value of that variable changes? Thanks.
This is quite easy to do if you wrap it all into a class. We will be using getter/setter methods. The setter method will dispatch and event whenever it is called.
(Note: Setters and Getters are treated like properties). You merely assign a value, as opposed to calling a method (e.g someVar = 5 instead of someVar(5); Even though setters / getters are functions/methods, they are treated like properties.
//The document class
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
public Class TestDocClass extends Sprite
{
private var _model:Model;
public function TestDocClass():void
{
_model = new Model();
_model.addEventListener(Model.VALUE_CHANGED, onModelChanged);
}
private function onModelChanged(e:Event):void
{
trace('The value changed');
}
}
}
//The model that holds the data (variables, etc) and dispatches events. Save in same folder as DOC Class;
package
{
import flash.events.Event;
import flash.events.EventDispatcher;
public class Model extends EventDispatcher
{
public static const VALUE_CHANGED:String = 'value_changed';
private var _someVar:someVarType;
public function Model():void
{
trace('The model was instantiated.');
}
public function set someVariable(newVal:someVarType):void
{
_someVar = newVal;
this.dispatchEvent(new Event(Model.VALUE_CHANGED));
}
}
}
#BrianHodge: How do you actually use your example? How do you call the set function? How do you refer to it? Where do pass the variable to be changed..?
Let's say if I want to change the wrapped variable with a button click, for example.
I have to confess that I tried some other codes and example (getter/setter) type, with dispatchEvent or without,and I can't get over it! But your example seems to be exactly what I need, just can't make it work.
I get the The model was instantiated when I set the function as document class. That's all.
I found out, at last, for people like me who are loosing time with this dispatch thing!
In my case the _someVar variable has to be data typed as a String (same thing for fornewVal).
OnceTestDocClass is set as your document class; you refer to the Model instantiated like this:
_model.someVariable="new stuff";
I was trying to change the value like this:
_model.someVariable("new stuff");
You can add some trace actions in the Model class to have a clear demo in the output panel:
package
{
import flash.events.Event;
import flash.events.EventDispatcher;
public class Model extends EventDispatcher
{
public static const VALUE_CHANGED:String = 'value_changed';
private var _someVar:String = "default";
public function Model():void
{
trace('The model was instantiated.');
}
public function set someVariable(newVal:String):void
{
trace ("before " + _someVar);
_someVar = newVal;
trace ("after " + _someVar);
this.dispatchEvent(new Event(Model.VALUE_CHANGED));
}
}
}
It's not much, but these things can cost some people a whole lot of time =)
You used to be able to do something similar in AS2 using Object.watch. I don't see a direct equivalent, but it looks like mx.binding.utils.ChangeWatcher will give you similar functionality for any variables that are bindable.
I don't know of a way to do it in AS3 for non-bindable variables, but if the variable you want to watch is bindable (or if you can modify it to be binadable) then ChangeWatcher might give you what you want.