Objects within Objects - actionscript-3

I have an object in my Library called Bottle. Bottle is made up of "Glass" and "Cap" instances. There are two more symbols in my library called Cap, and Glass.
When I click on the cap of Bottle, it says that this object is of class Cap, and when I click on the glass, it says it is of type Glass. Each one of these objects has base class flash.display.MovieClip.
However, in my code when I do:
var bottleOnStage:Bottle = new Bottle();
addChild(bottleOnStage);
var newColor:uint = 0x00ff00;
var newColorTransform:ColorTransform = new ColorTransform();
newColorTransform.color = newColor;
bottleOnStage.Glass.transform.colorTransform = newColorTransform;
I get this error:
TypeError: Error #1010: A term is undefined and has no properties. at MethodInfo-1()
Am I accessing the Glass property wrong? Is it because I haven't created an instance of Glass? I am confused on how objects within objects work in Flash.
EDIT
var cap:Cap;
var glass:Glass;
Above is what is in my Bottle.as file. In my Main.as file I have:
var bottleOnStage:Bottle = new Bottle();
bottleOnStage.cap = new Cap();
bottleOnStage.glass = new Glass();
addChild(bottleOnStage);
var newColor:uint = 0x00ff00;
var newColorTransform:ColorTransform = new ColorTransform();
newColorTransform.color = newColor;
bottleOnStage.glass.transform.colorTransform = newColorTransform;
When I run this code, no changes occur to the "glass" portion of the bottle. Why is this? I know that it is this line; I have traced and debugged all of the other lines, and the colors I am tracing are correct, etc. When I add "cap" and "bottle" to "bottleOnStage" using addChild, I get a duplicate of these two symbols, so this is apparently not the way. Basically, how do I modify "cap" and "glass" on stage?

It looks like your are confusing Classes with instances. Instance names cannot have the same name as a Class name (in the same scope).
Glass is your class. If you have variable with the name of "Glass" inside your bottle class, you need to rename it so it isn't ambiguous with your class name Glass.
bottleOnStage.glassInstanceName.transform.colorTransform = newColorTransform;
As a tip, to avoid this situation best practice is always make your instance names begin with a lower case letter, and always make your Class names begin with an upper case letter. (That also helps with code highlighting in most coding applications as well as here in Stack Overflow - notice how your uppercase items are hightlighted?)
As far as your error goes, you likely don't have an actual object in your variable yet.
Doing the following:
var myGlass:Glass;
Doesn't actually make an object (the value is null), it's just defining a placeholder for one. You need to instantiate using the new keyword in order to create an actual object.
var myGlass:Glass = new Glass();
Now you'll have an object in that variable.
EDIT
To address your edit, sounds like your probably want to something like this:
package {
public class Bottle extends Sprite {
public var cap:Cap;
public var glass:Glass;
//this is a constructor function (same name as the class), it gets run when you instantiate with the new keyword. so calling `new Bottle()` will run this method:
public function Bottle():void {
cap = new Cap();
glass = new Glass();
addChild(cap); //you want these to be children of this bottle, not Main
addChild(glass);
}
}
}
This keeps everything encapsulated and adds the cap and glass as children of the bottle. So bottle is a child of main, and cap and glass are children or bottle.

Whats is the name of the Glass attribute in the bottle?
if you have for example:
public class Bottle {
public var glass : Glass;
}
You can access the glass with:
var bottle : Bottle = new Bottle();
bottle.glass = new Glass();
Glass is the class. bottle.glass is the attribute "glass" of the class Bottle.
Hope it helps.

Related

AS3 MovieClip name ambiguity

Summary: I create instances of various MovieClips via AS3, using MovieClip class objects that are defined in the library.
As each MC is instantiated, I push it into an array for later reference.
Finally I create an XML file that contains data related to each MC, including its name. This is the problematic part – the name has to be able to identify the respective MC when the XML is read back in. I don’t want “instance17” etc, which I assume will be meaningless in another session.
Background: I am not a career OO programmer and this is a temporary assignment, forming only a very small part of my long-term interests. It will probably be a couple of years before my next Flash project.
Create instance
Library object
Type: MovieClip, linkage _brakepipe
Instantiation
var brakepipe: _brakepipe = new _brakepipe();
shapes.push(brakepipe);
Then later
var clip: MovieClip = shapes(i);
Trace (clip);
This yields
[object _breakpipe]
So it is giving me the class name, not the MC instance name. What property or method of MC would yield “breakpipe”? (Or even "_breakpipe" - without the "object" prefix?)
You can use an associative array. It could look like this:
var shapes:Array = new Array();
and then
shapes.push({item:_brakepipe,_name:"brakepipe"};
Essentially the curly brackets create an Object instance and the name before the colon (:) is the name you create that you want associated with the value after the colon.
so now you can do this in a loop
trace(shapes[i]._name+"\n"+shapes[i].item);
// output:
// brakepipe
// [object _brakepipe]
The nice thing about this method is you can extend it for any number of properties you want to associate with your array element, like this:
shapes.push({item:_brakepipe,_name:"brakepipe",urlLink:"http://www.sierra.com",_status:"used",_flagged:"false"};
and now
shapes[i]._status
would return the string "used". And you could change that value at runtime to "new" by doing
shapes[i]._status = "new";
The Instantiation / Then later / This yields... Seems to be unclear for me, but you may try this and change the code...
Because I'm not sure not sure about the instance name you want to store...
In your loop you may do this if clip is a MovieClip! :
var clip: MovieClip = shapes(i);
clip.name = "breakpipe_" + i
trace (clip.name);
// will output : breakpipe_1 - > breakpipe_n...
You may deal with the clip.name later by removing the extra "_number" if you want.
If i == 13
var clip: MovieClip = new MovieClip();
clip.name = "breakpipe_" + 13
trace(clip.name);
// output breakpipe_13
var pattern:RegExp = /_\d*/g;
trace(clip.name.replace(pattern,""));
//output :
//breakpipe
So here, you may push your Array or Vector with the instance name.
Am I wrong?

How can I make a function to make a child of an object in the library based on the variables supplied?

I'm trying to do a little project for my class and though I know how to do it the long way I'd prefer to do it in a more intuitive way so that I can avoid having to copy and paste a load of essentially the same code. The idea is to have a function which will create an instance of a class object with it's own unique name, set it's position/size/etc, and then add that child to the stage. Looking at this (what I have now) might help out a little bit.
//Set up variables for all deco pieces
var decoGreen:GreenBall;
var decoRed:RedBall;
var decoStar:Star;
var decoFlower:Flower1;
var decoYellow:YellowBall;
var decoBlue:BlueBall;
//Functions to allow easier object placement
function makeDeco(posX:Number, posY:Number, decoName:String, rootClass:Object):void
{
decoName = new (rootClass)();
decoName.x = posX;
decoName.y = posY;
addChild((decoName));
}
makeDeco(90,320,"greenBall",GreenBall)
Now obviously this code doesn't work and it's pretty rough right now but I think it's sufficient to understand what I'm trying to accomplish here. Thanks for any and all who attempt to decipher my mess! :D
You are pretty close from what I can tell and if I understand your question, it would simply be using the getDefinitionByName class
function makeDeco(posX:Number, posY:Number, decoName:String):void
{
var DecoClass:Class = getDefinitionByName(decoName) as Class;
var deco:DisplayObject = new DecoClass();
deco.x = posX;
deco.y = posY;
addChild((deco));
}
makeDeco(90,320,"greenBall")
You don't need to define the variables initially like you did, granted they've all set to "Export as actionscript" in the library. For example calling a string of "greenBall" would mean you have a movie clip in the library with a class name of greenBall

Declaring variable in different class not working as3

I have a public var called monster number in my monster class.
public var monsterNumber:int;
And in my document class, I want to give monsterNumber a number, lets say 5.
It's still tracing monsterNumber as 0 in my monster class, but 5 in my document class. Is there any way to change this var in my document class?
Here's an example of how you can create a instance of Monster and modify it's property monsterNumber :
// in your document class
var monster:Monster = new Monster();
monster.monsterNumber = 1;
You can define your variable as a static variable so you can change its value from anywhere you want.

How can I give flash stage instances unique properties in Flash Professional to pass to AS3 script?

I've started building a rough game engine framework in Flash Professional and I'm curious how I can create objects in the Flash library that I'm able to drag onto the stage and assign properties that are accessible from AS3.
Example:
I want to create a switch object (e.g. a light switch), so that when the player interactes with it, it triggers something specific in code such as a light in the room turns on.
I understand that Flash has built in UI components that you can define properties within the Flash Professional environment (see image below), and I'm wondering if there's a way to create my own custom style components so that I can essentially have my level file open in flash (.fla) and then drag a switch component from my library, and type in some information such as what light it is controlling, and any other information I want.
(above is an example of the type of parameter control I'm looking for)
I've read a bit about extending the flash UIComponent class but I feel that that's not the right approach because it's overkill for what I want. All I want is to pass some basic parameters from a library stage instance into AS3. I do not want to pass data via the instance name because this seems very messy if I want to have more complex interaction.
Thanks!
I would create a "switch" movie clip and export it to actionscrip, same with a "light" movie clip. The in the main class .as file I would inset them into the stage, using addChild (clips) and then add a click listener to the "switch" movie clip to control the "light".
This can be easily done.
Component(s) are wrong approach in my opinion.
Firstly you would want to setup Actionscript linkage / label your Library item.
In Library Panel.
- Right Click on "yourMC" >> click "Properties".
- In Properties dialog Tick "Export for Action Script"
- Then Name your Class eg "yourMC_Class"
now MC is ready to be referenced in your code.
next you would want to Dynamically add your "yourMC" from library to stage.
which can be done like such.
// first reference library item
var yourMC_ref:yourMC_Class = new yourMC_Class();
// Then load dynamic mc item into var
var your_MC_OBJ = yourMC_ref;
// then add your MC to stage.
this.addChild(your_MC_OBJ);
your_MC_OBJ.x = 200;
your_MC_OBJ.y = 100;
in a nutshell that's how I add library items to stage.
Obviously thats the basic function / code.
In a project I would have all code in an external class, in which case you would just set vars as public vars
public var yourMC_ref:yourMC_Class = new yourMC_Class();
public var your_MC_OBJ = yourMC_ref;
and the last 3 lines of code into a public function
public function ADD_First_MC()
{
this.addChild(your_MC_OBJ);
your_MC_OBJ.x = 200;
your_MC_OBJ.y = 100;
}
Now 'your_MC_OBJ' can be used in more complex ways.
eg. to create a light switch there are many options depending on how you need to approch functionality.
eg. Apply a different MC library item to "your_MC_OBJ"
play specific frame within MCs.
However If it was me I would just use mouse function to switch light on or off using addChild removeChild.
eg.
public var LightON = 0;
public var yourMC_ref:yourMC_Class = new yourMC_Class();
public var your_MC_OBJ = yourMC_ref;
then create a public function that handles on / off events
public function LightON_OFF()
{
if(LightON == 1)
{
this.addChild(your_MC_OBJ);
your_MC_OBJ.x = 200;
your_MC_OBJ.y = 100;
}
if(LightON == 0)
{
this.removeChild(your_MC_OBJ);
}
}
Hope this helps.
So, for what you want, while it may not be the best way to do what you want, I understand it's your experience you are constructing.
Use components, yes...in the following way (the most simple one):
Create a Movie Clip
Right-click it in library
Click on "Component Definitions"
Add a property, set a name, a variable name (var test, for this matter) and a default value
Click OK
Open your movie clip
Open code for the first frame and declare the variable without an initial value (var test:String;)
Trace it's value ( trace( test ); )
Go back to the stage root
Drag and drop the item from library to stage
Test it (Cmd/Ctrl + Enter) (maybe it will print null, dunno why, it ignores the default value sometimes)
Select your component on stage
Open the properties panel (Windows > Properties)
Go to Component Parameters on this panel and change the property value
You should see the value traced on console
And, I think, like this you can use properties from components for what you want, like using a String and getting the controlled mc by its name.
Good luck
I think what people are trying to say is that you can have the whole thing is data driven, and so you can combine the IDE with the data to come up with your final game.
But consider this ... it might be what you want.
If you have, for instance, a BaseSwitch Class:
public Class BaseSwitch extends MovieClip {
private var _lightName:String;
private var _light:Light;
public function get lightName():String {
return lightName;
}
public function set lightName(value:String):void {
if (value != _lightName) {
_lightnName = value;
//Note I don't advocate having children reach into their parents like this,
//but you sound like you don't want the parent involved in the process, so
//this is one way you could do it.
if (parent.hasOwnProperty(lightName) && parent[lightName] is Light) {
_light = parent[lightName];
} else {
trace('Could not find light', _lightName);
}
}
}
//other code to listen for gestures and operate the light
}
Now, when you want a switch to operate a specific light name, create a library instance and set its base class to BaseSwitch. When you close the dialog where you set the base Class, you'll notice that it gives you a dialogue that it couldn't find the Class in the Class path and one will be generated. You're going to replace it with a Class that sets the lightName. Create a new AS3 Class in the root directory with the same name as your library instance. It should look something like this:
public class SpecificSwitch {
public function SpecificSwitch() {
super();
lightName = 'theSwitch';
}
}
Other possible choices involve having the parent Class match up instances of switch with instances of light based on name, so if it finds a light1 and a light1Switch, it either gives a reference to the light to the switch or it simply sets up a mapping in its own event listening system.

AS3 Multiple instance names in one MC

I apologize for how confusing this question is.
I have a Movie Clip that is a car. In the car movie clip there are four different angles to the car. (e.g. left, right, front back). I dynamically change the body color of the car. In each angle of the car, the body of the car has an instance name "body." I change the color with the code :
var tempcar = "car_mc" + i;
var myNewTransform = new ColorTransform();
myNewTransform.color = 0x000000 //in real life this is a random value
this[tempcar].body.transform.colorTransform = myNewTransform;
Everything works fine, until I tell the car movie clip to gotoAndPlay the frame "front," where we see the front side of the car, and I try and apply the color change again to the body of the front of the car. I get the error :
TypeError: Error #1009: Cannot access a property or method of a null object reference.
Is there a better way to do what I am trying to do?
That's the old ActionScript 2 way of handling things. In ActionScript the container is not always a MovieClip, which would except the hash to access a dynamic field. Also, if you'd added it to the display list via addChild, the result would be different as well, since it is not the case in ActionScript 3, that could address the child automatically.
You should use an Array to store and access dynamically created instances.
// clazz would be the symbol
function createInstance(container:DisplayObjectContainer, clazz:Class, list:Array):Sprite
{
const child:MovieClip = new clazz() as MovieClip;
if (!child) throw new ArgumentError("Wrong type given");
return list[list.length] = container.addChild(child);
}
function getInstanceAt(index:int, list:Array):Sprite
{
return list[index] as Sprite;
}