AS3 class : access of undefined method / property errors - actionscript-3

I have this class :
package {
import flash.net.SharedObject;
import flash.display.DisplayObject;
public class gestioneMultilingua
{
public static function settaLingua(lingua:String):void
{
var dati:SharedObject = SharedObject.getLocal("datiApp", "/");
dati.data.lingua = lingua;
dati.flush();
}
public static function applicaFiltriLingua():void
{
var dati:SharedObject = SharedObject.getLocal("datiApp", "/");
var lingua : String = dati.data.lingua;
for(var i:int = 0; i<numChildren; i++){
var e:Object = getChildAt(i);
if(e.name.indexOf("$"+lingua) >= 0){
e.visible = true;
}
else if(e.name.indexOf("$") >= 0){
e.visible = false;
}
}
}
}
}
but I got these errors :
How can I fix them ? maybe I need to import a package ?

You can use a static function without any problem when you use it correctly of course, the problem here is not that the function is static (and not using numChildren or calling getChildAt() in that static function) but it is about how you did all that.
In your case, you want to work with a DisplayObjectContainer's children, so you can simply pass that object to your applicaFiltriLingua() function like this :
public static function applicaFiltriLingua(container:DisplayObjectContainer):void
{
var dati:SharedObject = SharedObject.getLocal("datiApp","/");
var lingua:String = dati.data.lingua;
for (var i:int = 0; i < container.numChildren; i++)
{
var e:DisplayObject = container.getChildAt(i);
if (e.name.indexOf("$" + lingua) >= 0) {
e.visible = true;
} else if (e.name.indexOf("$") >= 0) {
e.visible = false;
}
}
}
then you can call your function without any problem, like this, for example :
import gestioneMultilingua;
gestioneMultilingua.applicaFiltriLingua(this);
Hope that can help.

A static method can only make calls to another static method. numChildren and getChildAt are not static methods and calling them from inside a static method can only produce errors. Even if your class was extending a DisplayObjectContainer it will still get those errors since instances of that class will have getChildAt method and numChildren property but at static level those would still not exist and would still produce errors.
Do not make your applicaFiltriLingua method static and extend a valid DisplayObjectContainer

Since your function is a STATIC you can never instantiate one and non-static fields of all types are not allowed. Instance constructors are also not allowed and the class is automatically sealed.
Make method non-static and instantiate the class "gestioneMultilingua"
var multilingua:gestioneMultilingua = new gestioneMultilingua();
than you can access it like that multilingua.applicaFiltriLingua(//reference to stage)
and
do
public function applicaFiltriLingua(stage_ref:MovieClip):void
{
var dati:SharedObject = SharedObject.getLocal("datiApp", "/");
var lingua : String = dati.data.lingua;
for(var i:int = 0; i<numChildren; i++){
var e:Object = stage_ref.getChildAt(i);
if(e.name.indexOf("$"+lingua) >= 0){
e.visible = true;
}
else if(e.name.indexOf("$") >= 0){
e.visible = false;
}
}
}

Related

Removing an Object when it hits another object AS3

Beginner here. I have a symbol on the timeline with an instance name of 'island', so basically I want to remove the cells that hits the 'island'
if (cell.hitTestObject (island)) {
if(stage.contains(cell))
removeChild (cell);
}
I tried this one under the moveCell function but it only removes one cell instead of every cell that hits the island. Thanks everyone!
Here's my code so far:
package {
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Main extends MovieClip {
public var cell:Cell;
public var group:Array;
public var gameTimer:Timer;
public function Main() {
cell = new Cell (400, -15);
addChild (cell);
group = new Array();
var newCell = new Cell (100, -15);
group.push ( newCell);
addChild(newCell);
gameTimer = new Timer (25);
gameTimer.addEventListener(TimerEvent.TIMER,moveCell);
gameTimer.start();
}
public function moveCell (timerEvent:TimerEvent):void {
if (Math.random() < 0.01) {
var randomX:Number = Math.random() * 700;
var newCell:Cell = new Cell (randomX, -15);
group.push (newCell);
addChild(newCell);
}
for each(var i:MovieClip in group) {
if (i.hitTestObject(island)) {
i.visible = false;
//i.parent.removeChild(i);
var score:int = 0;
score ++;
scoreOutPut.text = score.toString();
}
}
}
}
}`
You got the "Cannot access a property or method of a null object reference" because you've removed the Cell object from the DisplayObjectContainer (its parent) but not from the group array, so in the next iteration of your for loop, that object didn't exist anymore and that error will be fired.
To avoid that you can do like this :
for(var i:int = 0; i < group.length; i++)
{
var cell:Cell = Cell(group[i]);
if (cell.hitTestObject(island))
{
cell.parent.removeChild(cell);
group.splice(i, 1);
score++;
}
}
For the score, it should be a global property for all your class to get updated every time.
Also, for your code to be more organised and clearer, it's better to put every task in a single method.
For example, for creating cells, you can use a createCell() method :
// 0 is the default value of __x and -15 is the default one of __y
private function createCell(__x:Number = 0, __y:Number = -15): void
{
var cell:Cell = new Cell(__x, __y);
group.push(cell);
addChild(cell);
}
Then you can use it in any place in your code, for example, for your two first cells that you create in the constructor :
public function Main()
{
// ..
createCell(400);
createCell(100);
// ...
}
Or inside the moveCell() method :
if (Math.random() < 0.01)
{
var randomX:Number = Math.random() * 700;
createCell(randomX);
}
Also, if you don't really need that a property or a method to be public, don't put it as public.
...
Hope that can help.

1120: Access of undefined property shuffledArray

Please can you help me out I am new to as3 and I am trying to create a shuffled deck using the Fisher-Yates Algorithm. When I run the code with ctrl-enter it compiles with no errors but when I try to output it with trace(); it comes back with:
Scene 1, Layer 'actions', Frame 1, Line 6 1120: Access of undefined property shuffledArray.
Like I said I am new to this and it will be me doing something very stupid but all the same i'm stuck.
Here is the code
package src.CardDeck
{
public class CardDeck
{
public var allCards:Array = [];
public var cardNames:Array;
public var cardValues:Array;
public var gameType:String;
public var drawnCards:uint = 0;
public function CardDeck(game:String)
{
gameType = game;
cardNames = ["Ace","Two","Three",
"Four","Five","Six",
"Seven","Eight","Nine",
"Ten","Jack","Queen","King"];
if(gameType == "texasholdem")
{
cardValues = [1,2,3,4,5,6,7,8,9,10,10,10,10];
}
makeSuit("Spade");
makeSuit("Heart");
makeSuit("Diamond");
makeSuit("Club");
}
function makeSuit(suitString:String):void
{
var card:Object;
for(var i:uint = 0; i < cardNames.length; i++)
{
card = {};
card.cardType = suitString;
card.cardName = cardNames[i];
card.cardValue = cardValues[i];
card.isDrawn = false;
allCards.push(card);
}
}
public function shuffleFisherYates():Array
{
var shuffledArray:Array = [];
var randomCardIndex: int;
do
{
randomCardIndex = Math.floor(Math.random()* allCards.length);
shuffledArray.push(allCards[randomCardIndex]); // add to mix
allCards.splice(randomCardIndex,1); // remove from deck
}while(allCards.length); // Meaning while allCards.length != 0
return shuffledArray;
}
}
}
and here is the .fla actions layer
import src.CardDeck.CardDeck;
var deck:CardDeck = new CardDeck("texasholdem");
trace(shuffledArray);
I know its probably something silly but i'm struggling.
Thanks in advance!
Paul
var deck:CardDeck = new CardDeck("texasholdem");
trace(shuffledArray);
This doesn't work because shuffledArray isn't defined there.
Try :
var deck:CardDeck = new CardDeck("texasholdem");
var array:Array = deck.shuffleFisherYates();
for(var i:int=0; i<array.length; i++)
{
trace(array[i].cardName);
trace(array[i].cardType);
trace(array[i].cardValue);
trace(array[i].isDrawn);
}
"shuffledArray" is a property inside of your CardDeck object. To access public methods and properties within it, you need to use the dot syntax:
trace(deck.shuffleFisherYates());
However, depending on what you are doing, you may not need to really be accessing the array directly, if your CardDeck object is meant to control the entire deck.

Actionscript 3 compare two MovieClips

I dynamically add MovieClips to an DisplayObjectContainer. Some of these MovieClips loop through all children of DisplayObjectContainer to check gravitation and collision. Though, when I check if the current child is not equal to the caller MovieClip it seems to check the type only.
So basically, when I check MovieClip equality it seems to check the type only.
Main.as:
var planet:Planet = new Planet(holder);
planet.x = 0;
planet.y = 0;
planet.spawn();
var planet2:Planet = new Planet(holder);
planet2.x = 50;
planet2.y = 50;
planet2.spawn();
Planet.as:
public class Planet {
public var x:Number = 0;
public var y:Number = 0;
private var _holder:DisplayObjectContainer;
private var _mc:MovieClip;
public function Planet(holder:DisplayObjectContainer) {
_holder = holder;
_mc = new PlanetMovieClip();
_mc.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
public function spawn():void {
_holder.addChild(_mc);
}
private function enterFrameHandler(evt:Event):void {
for(var i:int = 0; i < _holder.numChildren; i++) {
var child:MovieClip = _holder.getChildAt(i) as MovieClip;
// the other planet never passes this check
if(child !== _mc) {
trace('child is not the same');
}
}
}
}
So am I doing something wrong, should I approach an other method or should I just add an property that generates a random token used for identification?
you should remove as MovieClip; in _holder.getChildAt(i);
I would change !== with !=
The rest of your code seems ok.
First of all you have error in the code you have given to create Planet movieclip.
It should be
var planet:Planet = new Planet(holder);
planet.x = 0;
planet.y = 0;
planet.spawn();
var planet2:Planet = new Planet(holder)
planet2.x = 50;
planet2.y = 50;
planet2.spawn();
Did you check for null in Planet.as ?
if(child!=null) {
if(child !== _mc)
trace('child is not the same');
else
trace("child same");
}
And ofcourse you can always assign some unique name to the movieclips, and use it for comparing.

AS3 Creating an array of objects

I would like to add a bunch of cars to the stage, and store them in an array as objects. The problem is I hate using external AS files and would like to keep it as simple as possible.
I tried doing :
var car:Object = {carcolor:String,carscale:Number,carpower:Number};
var test:Array = new Array()
for (var i:Number=0; i<10; i++) {
test.push(car)
}
The problem is if I try to set a value of one object in the like
test[1].carscale = 5
Every object in the array gets their attribute carscale set to 5.
Is there any way I can do this without using external class files?
While you should use external AS files (its a good practice), here's the reason why you are having the issue, and I'm going to explain line-by-line
var car:Object = {carcolor:String,carscale:Number,carpower:Number};
//This creates an object called car. Suppose it saves it in memory at "location" 0x12345
var test:Array = new Array();
//This creates an empty array
for (var i:Number=0; i<10; i++) {
test.push(car);
//This adds the object "car" to the array
//Since Object is a reference type, its memory location is actually added to the array
//This means you added 0x12345 to the array (10 times over the loop)
}
//The array now contains
[0x12345, 0x12345, 0x12345, .......];
//So now
test[1]; //returns the object at 0x12345
test[1].carscale=5; //sets the carscale property of the object at 0x12345
Since all objects in the array point to the same location, getting any of them will actually return the same object. This means that all of them will show carscale as 5
A solution to this would be:
var test:Array = new Array();
for (var i:Number=0; i<10; i++) {
var car:Object = {carcolor:String,carscale:Number,carpower:Number};
test.push(car);
}
A better, REAL Object oriented solution would be to create a class called Car and then instead of doing
var car:Object = {carcolor:String,carscale:Number,carpower:Number};
you use
var car:Car = new Car();
The Car.as class would be like this:
public class Car {
public function Car() {
//this is the constructor, initialize the object here
//Suppose the default values of the car are as follows:
carcolor="red";
carscale=5;
carpower=1000;
}
public var carcolor:String;
public var carscale:Number, carpower:Number;
}
In fact, you could even use another constructor that automatically sets the properties based on arguments:
public function Car(_color:String, _scale:Number, _power:Number) {
carcolor=_color;
carscale=_scale;
carpower=_power;
}
and call it as
var car:Car=new Car("red", 5, 1000);
In fact, the car before carcolor, carscale and carpower is not even necessary because it is obvious when you put them in a class called Car.
Like TheDarkIn1978 said you're pushing a reference of your car instance into your array. When you change the value of one instance's property the same happens for each reference.
The simple answer is to create a new object upon each interation of your for loop like in the following:
var test:Array = [];
for (var i:Number = 0; i < 10; i++)
{
var car:Object = {carcolor:String, carscale:Number, carpower:Number};
test.push(car);
}// end for
[UPDATE]
I know you said that you didn't want to use "external classes" but there are advantages to using a custom class object to store values as opposed to a Object object. Here is an example:
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}// end function
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
var cars:Vector.<Car> = new Vector.<Car>();
cars.push(new Car("red", 1, 1));
cars.push(new Car("blue", 2, 2));
cars.push(new Car("green", 3, 3));
trace(cars[2].color); // output: green
}// end function
}// class
}// end package
internal class Car
{
private var _color:String;
private var _scale:Number;
private var _power:Number;
public function get color():String { return color; }
public function get scale():String { return scale; }
public function get power():String { return power; }
public function Car(color:String, scale:Number, power:Number)
{
_color = color;
_scale = scale;
_power = power;
}// end function
}// end class
This is a good example of creating an object for the sole purpose of storing values that never change by only allowing the object's properties to be set upon initiation and using getter methods to make the values read only.
I feel dumb, I found the answer here :
http://board.flashkit.com/board/showthread.php?t=792345
You're pushing the Object reference to the array, not a unique Object each time. You have to do something like:
for(var temp=0;temp<100;temp++){
var roomData:Object=new Object;
roomData.first_time=true;
rooms.push(roomData);
}
you're adding the same object to the array multiple times. you need to create new instances of your car object.
EDIT:
although it would be a best practice to create your own "Car" class and create new instances of it, even if it's only a small object with 3 properties, here's a quick example that should get you started.
package
{
//Imports
import flash.display.Sprite;
//Class
public class Main extends Sprite
{
//Constants
private static const DEFAULT_CAR_COLOR:Number = 0x000000;
private static const DEFAULT_CAR_SCALE:Number = 1.0;
private static const DEFAULT_CAR_POWER:int = 50;
//Properties
private var carsArray:Array;
//Constructor
public function Main():void
{
init();
outputCarColors();
}
//Initialize
private function init():void
{
carsArray = new Array();
for (var i:int = 0; i < 10; i++)
{
carsArray.push(CreateCar(Math.random() * 0xFFFFFF));
}
}
//Output Car Colors
private function outputCarColors():void
{
for (var i:int = 0; i < carsArray.length; i++)
{
trace("Color of car " + i + " : " + carsArray[i].carColor);
}
}
//Create Car Object
private function CreateCar(carColor:Number = DEFAULT_CAR_COLOR, carScale:Number = DEFAULT_CAR_SCALE, carPower:int = DEFAULT_CAR_POWER):Object
{
var result:Object = new Object();
result.carColor = carColor;
result.carScale = carScale;
result.carPower = carPower;
return result;
}
}
}

Actionscript 3.0: display object walker in strict mode

This is a document class for a display object walker. Make sure to turn off the strict mode (howto here) when testing the class. Also put some stuff on the stage. When the strict mode is turned off the object walker works just fine. However, I want to make it work in strict mode too. I have tried changing the problematic parts, and addig (dispObj as DisplayObject), with no luck.
package {
import flash.display.MovieClip;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
public class DisplayWalker extends MovieClip {
public function DisplayWalker() {
showChildren(stage, 0);
}
private function padIndent(indents:int):String {
var indent:String = "";
for (var i:uint = 0; i < indents; i++) {
indent += " ";
}
return indent;
}
private function showChildren(dispObj:DisplayObject, indentLevel:Number):void {
for (var i:uint = 0; i < dispObj.numChildren; i++) {
var obj:DisplayObject = dispObj.getChildAt(i);
if (obj is DisplayObjectContainer) {
trace(padIndent(indentLevel), obj, obj.name);
showChildren(obj, indentLevel + 1);
} else {
trace(padIndent(indentLevel), obj);
}
}
}
}
}
Your class will generate compile time errors in Strict mode because you're trying to access the numChildren and getChildAt methods, which aren't available on the DisplayObject class, but first on one of it's subclasses, DisplayObjectContainer.
The reason it is working in non-Strict mode is that, at runtime, you're effectively passing in subclasses of DisplayObjectContainer (Stage, Sprite, etc).
Just replace DisplayObject with DisplayObjectContainer as the type for dispObj in your showChildren method. DisplayObjects cannot have children and are always leafs in the display object tree, something your showChildren method will have to account for.
Stiggler is on the right track, but properly didn't see that you already check for DisplayObjectContainers.
You just need to modify your code slightly. I didn't test the code, but in any case you should be able to figure it out ;)
private function showChildren(dispObj:DisplayObject, indentLevel:Number):void
{
var dOC:DisplayObjectContainer = dispObj as DisplayObjectContainer;
if(dOC == null)
{
trace(padIndent(indentLevel),obj);
}
else
{
trace(padIndent(indentLevel), obj, obj.name);
var obj:DisplayObject = null;
for (var i:uint = 0; i < dispObj.numChildren; i++)
{
obj = dOC.getChildAt(i);
showChildren(obj, indentLevel + 1);
}
}
}