I'm new to AS3. Learning how to create classes. Is comp = new HouseObjects creating a new class? Is comp creating an instance of the HouseObjects? I realize that this is inside public class TreeHouse. I'm thinking that HouseObjects, how I set it up is not a class...not sure what the correct way to set up classes and properties.
Also I noticed, that when I tried to link another movieclip using the same linkage name HouseObjects--it asked to enter a unique class. I'm trying to create multiple instances from the same class called HouseObjects.
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
public class TreeHouse extends MovieClip
{
private var comp:MovieClip;
var powerData:int; // stores user data (of selected data)
//var currentPower:int; // stores current power
public function TreeHouse()
{
comp = new HouseObjects; // linkage in library
comp.power = 2; // amount of power
comp.name = "comp";
comp.buttonMode = true;
comp.bstate = 0; // button state
//add event listeners -- listens to functions that are called
comp.addEventListener(MouseEvent.MOUSE_OVER, rolloverToggle);
comp.addEventListener(MouseEvent.MOUSE_OUT, rolloutToggle);
comp.addEventListener(MouseEvent.CLICK, toggleClick);
comp.addEventListener(MouseEvent.CLICK, toggleClick);
stage.addChild(comp); // add computer to stage -----------------------------------
trace("tracing...");
comp.x = 100;
comp.y = 100;
}
// function rollOver --------------------------------------------------------------
function rolloverToggle(e:MouseEvent) {
if (e.currentTarget.currentFrame == 1)
e.currentTarget.gotoAndStop(2);
if (e.currentTarget.currentFrame == 3)
e.currentTarget.gotoAndStop(4);
}
// function rollOut-- --------------------------------------------------------------
function rolloutToggle(e:MouseEvent) {
if (e.currentTarget.currentFrame == 2)
e.currentTarget.gotoAndStop(1);
if (e.currentTarget.currentFrame == 4)
e.currentTarget.gotoAndStop(3);
}
// function toggleClick-------------------------------------------------------------
function toggleClick(e:MouseEvent) {
// On MouseEvent gotoAndStop(Frame Number)
if (e.currentTarget.currentFrame == 2)
{
e.currentTarget.gotoAndStop(3);
e.currentTarget.bstate = 1;
}
if (e.currentTarget.currentFrame == 4)
{
e.currentTarget.gotoAndStop(1);
e.currentTarget.bstate = 0;
}
//var powerData:int = HouseObjects[e.currentTarget.power]; // set power value
// Find out which object selected-------------------------------------------------
//trace("movieClip Instance Name = " + e.currentTarget); // [object Comp]
//trace(houseArray[e.currentTarget.name]); // comp
trace("using currentTarget: " + e.currentTarget.name); // comp
//trace("powerData: " + powerData); // power of user data
//trace("houseArray: " + houseArray[0]); // the 0 index of house array
trace(e.currentTarget.power); // currentTarget's power************
}
} //end of class
} // end of package
I am not quite sure if I understood your question correctly. comp = new HouseObjects creates a new instance (object) of the type HouseObjects. (A little research on OOP basics would probably make life easier for you.)
Regarding the »Please enter a unique class name« error: You cannot assign the same class to two library symbols because the symbol is hooked up to the class internally so that if you create a new instance (var x = new HouseObjects; addChild(x);), the content from the linked symbol is also added to the display list. If there were multiple library symbols linked to the same class, how would the Flash compiler know which one to choose?
Your question is pretty broad and , as klickverbot suggests, it would be better if you took a little time to understand basic OOP concepts.
There are a lot of resources available to get you started with AS3, check this for instance
http://tv.adobe.com/watch/colin-moocks-lost-actionscript-weekend/course-1-introduction
Colin Moock's tutorial is very easy to follow and will give you most of the tools you need to get started.
If you are new to AS3, and OOP in particular, you should check out Moock's Essential Actionscript 3 which is beyond fantastic for a step by step education in OOP in AS3.
HouseObjects appears to be a class and you are creating a new instance of it for the variable comp
You've got a duplicate definition. It appears that you are trying to use Flash Pro to extend HouseObjects for the lightbulb. It doesn't work like this in Flash Pro. You are creating a MovieClip symbol and giving it a class definition. It has to extend MovieClip and you cannot change this in this case. You could likely extend HouseObjects in an AS3 file and make use of it in your application.
Personally think that if you want to really get your head around OOP with AS3 you should get the book and get out of Flash Pro. Use an IDE like Flash Builder, FDT, Flash Develop, or IntelliJ IDEA. It is a lot easier to understand when you get away from the dialogs and other complications of the Flash Pro IDE :>
Related
I have created a new Symbol in the Flash IDE, I set it to Export for Actionscript and it has a class name of itemCoin
My stage has now 3 movieclips of that class, how can I:
count how many of itemCoin are on the stage
manipulate them, set and get their x, y individually etc. I tried itemCoin[0].x [1] [2]...etc but it throws an error
remove them from stage when needed
add an event listener that executes a function whenever a itemCoin is removed?
Instance name is used for referencing instances of objects.
For example, if you had a symbol of type ItemCoin (note that naming convention for a type usually starts with a capital letter):
When you place instances on the stage, you give them an instance name to reference them by (note that naming convention for an instance is usually camel case):
Now, properties may be accessed by referencing the instance name from code:
itemCoin1.x = 50;
itemCoin1.y = 25;
Remove it form stage:
removeChild(itemCoin1);
Add an event listener to the itemCoin1 instance for when it is removed:
import flash.events.Event;
itemCoin1.addEventListener(Event.REMOVED, removedHandler);
function removedHandler(event:Event):void {
trace("itemCoin1 was removed");
}
removeChild(itemCoin1);
Although generally a poor practice, you can iterate all children to identify instances. For example, to count the number of ItemCoins:
import flash.display.DisplayObject;
var count:uint = 0;
for (var i:uint = 0; i < numChildren; i++) {
var obj:DisplayObject = getChildAt(i);
if (obj is ItemCoin) {
trace("Found " + ++count + " item coins so far.");
}
}
To comprehensively search the display list, you'd have to traverse children of all display objects.
If knowing the total number of instances on the stage was that important, it might be a better idea to define some ActionScript inside the component or within a Factory class to reference count when added to stage and removed from stage.
My current project is in as3, but this is something I am curious about for other languages as well.
I'm attempting to use a factory object to create the appropriate object dynamically. My LevelFactory has a static method that returns a new instance of the level number provided to the method. In the code calling that method, I am able to dynamically create the buttons to call the levels like so:
for (var i:int = 1; i < 4; i++) {
var tempbutton:Sprite = createButton("Level " + i, 25, 25 +(60 * i), start(i));
_buttons.push(button);
}
This code just creates a simple button with the given arguments (ButtonText, x, y, function). It's working fine. The buttons are created, and clicking on one of them calls this method with the appropriate argument
private function start(level:int):Function {
return function(e:MouseEvent):void {
disableButtons();
newLevel = LevelFactory.createLevel(level);
addChild(newLevel);
}
}
This is all working fine; I'm just providing it for background context. The question I have is this: Is it possible to dynamically choose the type of object that my static function returns? Currently, I have am doing it as follows
public static function createLevel(level:int):Level {
var result:Level;
switch(level) {
case 1: result = new Level1(); break;
case 2: result = new Level2(); break;
//etc
}
return result;
}
I should note that all of these Level1, Level2, etc. classes extend my base level class. (Yay polymorphism!) What I would like to do is be able to do something along the lines of
public static function createLevel(level:int):Level {
var result:Level;
var levelType:String = "Level" + level;
return new levelType();
}
Obviously it's not going to work with a string like that, but is there any way to accomplish this in as3? What about other languages, such as Java or Python? Can you dynamically choose what type of child class to instantiate?
Update:
import Levels.*;
import flash.events.*;
import flash.utils.*;
public class LevelFactory
{
public static function createLevel(level:int):Level {
var ref:Class = getDefinitionByName('Levels.' + 'Level' + level) as Class;
var result:Level = new ref();
return result;
}
}
Update/Edit: getDefinitionByName seems to be what I'm looking for, but it has a problem. It seems that the compiler will strip unused imports, which means that unless I declare each subclass in the code ahead of time, this method will get a reference error. How can I get around the need to declare each class separately (which defeats the purpose of dynamic instantiation)?
Yes, you sure can, and it's very similar to the string thing that you've provided. The only thing that you are missing is the getDefinitionByName method: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/package.html#getDefinitionByName()
You can generate whatever class name you want, and what this method does is that it searches for that class in it's namespace, and if it finds it - it returns it as a class:
var ClassReference:Class = getDefinitionByName("flash.display.Sprite") as Class;
var instance:Object = new ClassReference();
This piece of code will instantiate a Sprite. This way you can instantiate your classes without all those switches and cases, especially when you have to make a hundred levels :)
Hope that helps! Cheers!
Edit:
In your case, the code should be:
var ref:Class = getDefinitionByName('com.path.Level' + index) as Class;
var level:Level = new ref(); // it will actually be Level1 Class
Since Andrey didn't quite finish helping me out, I am writing up a more complete answer to the question after much research.
getDefinitionByName definitely has the use I am looking for. However, unlike its use in Java, you HAVE to have a hard reference to the class you want instantiated somewhere in your code. Merely imported the class is not enough; the reason for this is that the compiler will strip the reference from any unused import to save space. So if you import the package of classes you want to choose dynamically but don't have a hard reference to them, the compiler will de-reference them. This will lead to a run-time error when the program cannot find the appropriate reference to your class.
Note that you don't actually have to do anything with the reference. You just have to declare a reference so that it can be found at run-time. So the following code will work to eliminate the switch-case statement and allow me to dynamically declare which class I am using at run-time.
{
import Levels.*;
import flash.events.*;
import flash.utils.*;
/**
*
* Returns the requested level using the createLevel class
* ...
* #author Joshua Zollinger
*/
public class LevelFactory
{
Level1, Level2, Level3, Level4, Level5, Level6, Level7;
public static function createLevel(level:int):Level {
var ref:Class = getDefinitionByName('Levels.Level' + level) as Class;
var result:Level = new ref(); // it will actually be the correct class
return result;
}}}
The obvious downside to this is that you still have to have a hard-coded reference to every class that can be instantiated like this. In this case, if I try to create a Level8 instance, it will through a run-time error because Level8 is not referenced. So every time I create a new level, I still have to go add a reference to it; I can't just use the reference dynamically.
There are supposedly ways around this that I have not tested yet, such as putting the code for the classes in a separate SWF and importing the SWF at run-time or using outside libraries that will have different functionality. If anyone has a solid way to get a truly dynamic reference that doesn't require a hard coded reference anywhere, I would love to hear about it.
Of course, it's still a lot cleaner this way; I don't have a extensive switch case statement to pack all the levels. And it's easier and faster to add a reference to the list than creating a new case in a switch. Plus it is closer to dynamic programming, which is usually a good thing.
Can variables be created dynamically without declaration when we write as Document class in AS3?
For example, from a library I'm importing sound files. Some 20 sound files.
If the code is in fla itself, we can assign in for loop like:
this["SOUND"+increasingNumber]
But in documentClass this is not working , since this refers the class here not the stage.
Any method to create variables?
When imported into your library, right click the sound file and go to its properties. Click the actionscript tab and check 'export for actionscript'. Give it a class name which you can then use in your document class to instantiate that sound.
If you named it Sound1:
var sound:Sound = new Sound1();
sound.play();
more detailed info here
[Edit to loxxy's reply] above shows how to create the variables in the document class.
To dynamically create all the sound variables, I'd recommend using an array, like so:
Suppose you named all your sounds in your library Sound1 to Sound20
import flash.utils.getDefinitionByName;
var sounds:Array = [];
var soundClass:Class;
for(var i:int = 1; i<21; i++){
soundClass = getDefinitionByName("Sound" + i) as Class;
sounds.push(new soundClass());
}
In fla when you add code, you add it into a framescript.
A framescript is a block of code repeated at a regular interval (framerate).
You can achieve that using addFrameScript like this.
However a better approach would be to not mix up framescript & the regular class methods.
You can access the 'stage' from the code but only after the added_to_stage event to be sure.
addEventListener(Event.ADDED_TO_STAGE, init);
function init(e:Event):void{
// Access 'stage' here
}
Okay, so I am making a small game where the user picks randomly spawned flowers. When a flower is picked, it disappears and the user gets points.
Here is some of my code:
import flash.events.MouseEvent;
function makeFlower() {
var flower:Flower = new Flower();
addChild(flower);
flower.x = Math.random() * 500;
flower.y = Math.random() * 400;
}
function removeFlower(event:MouseEvent):void {
flower.pick();
}
setInterval(makeFlower, 2500);
addEventListener(MouseEvent.CLICK, removeFlower);
So in the above code, flower.pick() doesn't work because it's out of scope (how would I get it in-scope, by the way?)... that is one problem. But this problem got me questioning where the creation of the flower should happen. Would it be better to put addChild() in my constructor method?
And then the destruction part... the event listener which detects the flower being clicked... should this be separate (like how I have it) or should it be put into the Flower class? I am new to ActionScript and would like to know where things should be put.
Thanks!
try:
import flash.events.MouseEvent;
var flower:Flower;
function makeFlower() {
flower = new Flower();
addChild(flower);
flower.x = Math.random() * 500;
flower.y = Math.random() * 400;
flower.addEventListener(MouseEvent.CLICK, removeFlower);
}
function removeFlower(event:MouseEvent):void {
event.target.pick();
//removeChild(event.target); // active this to remove the clicked flower
}
setInterval(makeFlower, 2500);
Where you should handle things depends on quite a few factors, number one on my list would be if you're using the Flex framework or not, number two would be what is best for a given application. For your case it appears you're just using Flash IDE.
You'll want to have a collection of the flower objects your adding to the display tree. Then on click you'll want to use the target of the click to know which "flower" they picked, instead of arbitrarily removing some flower.
The other good thing about having a collection of the flowers is that you can actually just toggle the visibility (this also toggles the ability for a touch/click to interact with an object). Then you can have the Flower objects all created at once or at least re-used instead of having to be garbage collected and making a ton more objects (as pointed out by Daniel below the term is object pooling).
import flash.events.MouseEvent;
var allFlowers:Array = [];
var oldFlowers:Array = [];
function makeFlower() {
var flower:Flower;
if(oldFlowers.length>0) //if there's stale ones, already created but since picked
{
flower = oldFlowers.pop();//grab the last one from the list
flower.visible=true;//show it, update to position below should happen fast enough so you won't see it move
}
else
flower = new Flower();
allFlowers.push(flower);
addChild(flower);
flower.addEventListener(MouseEvent.CLICK, removeFlower); //Adding the listener directly to the Flower object, assuming it's a Sprite/MovieClip/InteractiveObject of some sort
flower.x = Math.random() * 500;
flower.y = Math.random() * 400;
}
function removeFlower(event:MouseEvent):void {
var clickedFlower:Flower = (event.target as Flower); //this is a local reference
clickedFlower.pick(); //assuming this toggles the visibility
oldFlowers.push(allFlowers.splice(clickedFlower,1)); //removing it from the "active array" putting it in the "stale array"
}
setInterval(makeFlower, 2500);
Ideally this would all be wrapped up in a class, really scoping variables just makes way more sense to me in the context of a class than just dangling in some block of code somewhere.
Since in your original code you declared that flower was a var and gave it the type of object stored at that var (Flower), it's scope is limited to the opening and closing curly braces for that function. In the case of the variables I defined they should be available so long as the object that contains the code is available.
There are three primary "scope modifiers" you can use when declaring variables or functions in a class in AS3 (namely public, protected, or private). Using public means the property/method (member) is accessible within the class definition (generally the file, something.as) as well as by anything else, if you make a variable public it can be modified by anything that uses the code, this can lead to un-predictable behavior of your application if change from the outside is unintended. Using protected means anything that inherits from or extends a class can access/use the protected member, but nothing that just has an instance of the object can access these members (hence the term access modifier). The third level is private which means only code within that class (across all methods) can access the member but no inheriting/sub-classes of the class can access the member. This is essentially an implementation of the concept generally termed encapsulation in computer science. There's a lot more detail, but really it's already getting too long for a decent SO post.
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.