How to detect if a specific button has been clicked? - actionscript-3

I have various colour buttons that change the colour of a movieclip on click but I want to write code that says like if btnRed has been clicked, apply red ColorTransform. This is because I have multiple buttons and I don't want to have to write methods that are almost identical just with different RGB multiplier values. Is there a way of doing it so that the event listener for each button calls the same method but then within that method it basically says if redBtn is clicked, change color to red, if blueBtn is clicked, change color to blue etc.

As M4tchB0X3r indicated, use a Dictionary to store a lookup of button object to color transform. Here is working code, assuming your button names are btnRed, btnGreen, and btnBlue, and that you have some kind of named object on the stage called box1.
They key points here are that the Dictionary can use object references as keys (not just integers and strings as with the simple Object type), and that the target property of an Event object holds a reference to the thing that raised the event--in this case a button. In fact it's probably safer to use currentTarget, because sometimes target is a parent or child display object, due to the way events can bubble up and down the tree.
import flash.utils.Dictionary;
import flash.geom.ColorTransform;
var buttonToTransform:Dictionary = new Dictionary();
buttonToTransform[btnRed] = new ColorTransform(1.0, 0.2, 0.2);
buttonToTransform[btnGreen] = new ColorTransform(0.2, 1.0, 0.2);
buttonToTransform[btnBlue] = new ColorTransform(0.2, 0.2, 1.0);
// Note: for..in iterates over the keys of an object
// (vs. for each, which iterates over the values)
for(var btn:* in buttonToTransform) {
btn.addEventListener(MouseEvent.CLICK, onTransform);
}
function onTransform(e:MouseEvent):void {
this.box1.transform.colorTransform = buttonToTransform[e.currentTarget];
}

Hold all your Buttons in an Array, in the CLICK Event determin which one was pressed with buttonArray.indexOf(event.target);
then get the according color value from a map like a Dictionary or an Object.
You could also keep your Buttons in the Dictionary itself and loop through it to find your color.

Related

Turn image array images to buttons AS3

I'm creating an app with a search function. I display the images by loading from the array the one's which match the search criteria. All the images are loaded from the library. I want to be able to click on an image as though it were a button. Once I click I want to goto frame 3 and change a variable integer to say which image was clicked on so that I can display the information about the photo in frame 3. Can I do this using an event listener say
imagesArray[i].addEventListener(MouseEvent.CLICK, imageClick);
function imageClick(event:MouseEvent):void
{
gotoAndStop(3);
current = i;
}
or similar,
Thanks
Yes, but it won't be as easy. First, Bitmaps do not process events, so you can't assign a listener directly to a Bitmap object. Next, there is no "i" available in such a construction, you have to determine that "i" by yourself. To do that, you parse event.target property, which is the object that's been clicked. You wrap each Bitmap object into a separate Sprite object, assign listeners to these sprites, then you parse event.target to get the relevant object reference out of it, grab the index via indexOf() call, and assign it to global current variable.
for (i=0;i<imageArray.length;i++) {
var sp:Sprite=new Sprite();
sp.addChild(imageArray[i]);
// position "sp" correctly here
addChild(sp);
sp.addEventListener(MouseEvent.CLICK, imageClick);
}
function imageClick(e:Event):void {
var content=e.target.getChildAt(0); // the object that was wrapped
var i:int=imageArray.indexOf(content);
if (i==-1) return; // OW, out of array
current=i;
gotoAndStop(3);
}
I'm not so sure that setting "current" to "i" would work as the function wouldn't be running at the same time as the for loop.
I'm assuming that because you're using the [i] that you've added the event listeners in a for loop?
What you could do is:
for (var i:int = 0; i < (howeverManyTimesToRun); i++)
{
imagesArray[i].addEventListener(MouseEvent.CLICK, imageClick);
imagesArray[i].myIndex = i;
}
And then in your function (outside of the for loop)
function imageClick (e:MouseEvent) {
gotoAndStop(3);
current = e.currentTarget.myIndex;
}
Also in your for loop you might want to add
imagesArray[i].buttonMode = true;
To change the mouse cursor to a hand when their mouse goes over your image.

AS3 Vector remove display list

I have an app which is using a vector object to create and display multiple dynamic items on the stage.
When I quit the game and then return to the inGame screen the objects are still visible. I have tried a number of ways to remove but nothing has worked.
I have null'ed the vectors but the objects still remain on the stage.
Basically I just need to clear the stage when the game is quit.
I am using:
var item = new Vector.<Item>();
to create.
The user quits the game by hitting the pause button and then a 'back to menu' button.
Any guidance is appreciated.
Once you perform an addChild() on something, that something receives another link to it, namely from display list. So you have to manually call removeChild() on each of your dynamic objects you store in your Vector, before actually dropping the vector.
var item:Vector.<Item>;
for (var i:int=item.length-1;i>=0;i--)
item[i].parent.removeChild(item[i]);
item=null;
If all of your DisplayObject's are in the item Vector and Item is an ancestor of DisplayObject then following loop executed when you are going to the main screen will remove them from it's container.
var child:Item;
while(item.length)
{
child = item.shift();
if(child)
{
//perform some cleaning functionality e.g. child.destroy();//if there is destroy method for disposing Item class
//
if(child.parent)
{
child.parent.removeChild(child);
}
child = null;
}
}
//
item = null;

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.

I can't seem to access automatically named objects (instance##) placed on the stage in AS3, am I missing something?

I have a movieclip in the library that is added to the stage dynamically in the document class's actionscript. This movieclip contains many many child images that were imported directly from photoshop at their original positions (which must be preserved).
I do not want to manually name every single image instance, as there are dozens upon dozens.
I have already gone through and manually converted the images to symbols, as apparently flash won't recognize the "bitmap" objects as children of a parent movieclip in AS3 (numChildren doesn't see the bitmaps, but it sees the symbols).
I have an array filled with references to the dozens of children, and I loop through it, checking if each one is under the mouse when clicked. However, somehow, it is not detecting when I click over the items unless I manually name the child symbols (I tested by manually naming a few of them -- those ones became click-sensitive.)
I have already done trace() debugging all throughout the code, verifying that my array is full of data, that the data is, in fact, the names of the instances (automatically named, IE instance45, instance46, instance47, etc.), verifying that the function is running on click, verifying that the code works properly if I manually name the symbols.
Can any one see what's going wrong, or what aspect of flash I am failing to understand?
Here is the code:
//check each animal to see if it was clicked on
private function check_animal_hits():void
{
var i:int = 0;
var animal:Object = this.animal_container;
for (i=0; i<animal.mussels.length; i++)
{
if (this.instance_under_cursor(animal.mussels[i].name))
{
var animal_data = new Object();
animal_data.animal = "mussel";
this.send_data(animal_data);
}
}
}
Here is the code for the instance_under_cursor() method:
// Used for finding out if a certain instance is underneath the cursor the instance name is a string
private function instance_under_cursor(instance_name)
{
var i:Number;
var pt:Point = new Point(mouseX,mouseY);
var objects:Array = stage.getObjectsUnderPoint(pt);
var buttons:Array = new Array ;
var o:DisplayObject;
var myMovieClip:MovieClip;
// add items under mouseclick to an array
for (i = 0; i < objects.length; i++)
{
o = objects[i];
while (! o.parent is MovieClip)
{
o = o.parent;
}
myMovieClip = o.parent as MovieClip;
buttons.push(myMovieClip.name);
}
if (buttons.indexOf(instance_name) >= 0)
{
return true;
}
return false;
}
Update:
I believe I have narrowed it down to a problem with getObjectsUnderPoint() not detecting the objects unless they are named manually.
That is the most bizarre way to find objects under mouse pointer... There is a built-in function that does exactly that. But, that aside, you shouldn't probably rely on instance names as they are irrelevant / can be changed / kept solely for historical reasons. The code that makes use of this property is a subject to refactoring.
However, what you have observed might be this: when you put images on the scene in Flash CS, Flash will try to optimize it by reducing them all to a shape with a bitmap fill. Once you convert them to symbols, it won't be able to do it (as it assumes you want to use them later), but it will create Bitmpas instead - Bitmap is not an interactive object - i.e. it doesn't register mouse events - no point in adding it into what's returned from getObjectsUnderPoint(). Obviously, what you want to do, is to make them something interactive - like Sprite for example. Thus, your testing for parent being a MovieClip misses the point - as the parent needs not be MovieClip (could be Sprite or SimpleButton or Loader).
But, if you could explain what did you need the instance_under_cursor function for, there may be a better way to do what it was meant to do.

Take glow from a DisplayObject and put it in another

I have a grid of DisplayObjects that when I put a glow on any of them, the glow overlap the other objects.
I was wondering if I could take the glow created by a DisplayObject and put it another, so I can attach it to a container that's behind all the objects? If someone can suggest a better idea, that would be much appreciated too.
Kodiak has the right idea here but it sounds like once you add the glow to the object it stays there and you don't remove it. (For example you don't do somethings like on mouse hover -> glow, on mouse out -> no glow) You want something like Once I hover over the object it glows and the glow itself is always behind the other display objects.
This seems odd to me but what you could is create a duplicate of the grid and place it underneath of the top level ones and then do somethings like...
public function test() {
// constructor code
primaryDisObj:Array() = new Array(primaryDO1, primaryDO2);// an array of the instances of the Display Objects on top
secondaryDisObj:Array() = new Array(secondDO1, secondDO2);// an array of the instances of the Display Objects underneath the originals
for(var i:uint = 0; i < primaryDisObj.length; i++){
primaryDisObj[i].name = i;
primaryDisObj[i].addEventListener(MouseEvent.MOUSE_OVER, overPrimary);
}
}
private function overPrimary(e:MouseEvent):void{
secondaryDisObj[e.target.name as uint).filters = [new GlowFilter(0xFF6699, .75, 25, 25, 2, 2, false, false)];//Or however you want you filer to look
}
Without seeing you code it's kind of hard to figure out what you're going for but this is the simplest way I can think of to do this.
Can't you just change the index of the glowing object to put it in the back?
myItem.parent.setChildIndex(myItem, 0);