victorkhugo
victorkhugo

Reputation: 131

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?

Upvotes: 3

Views: 38202

Answers (4)

victorkhugo
victorkhugo

Reputation: 131

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);
}

Upvotes: 1

pho
pho

Reputation: 25500

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.

Upvotes: 12

Taurayi
Taurayi

Reputation: 3207

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.

Upvotes: 2

Chunky Chunk
Chunky Chunk

Reputation: 17237

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;
        }
    }
}

Upvotes: 0

Related Questions