addEventListener adding again and again - actionscript-3

My pictures gallery has 8 frames. There are a few lines of AS3 on the AS3 layer in the first frame:
stop();
var picsArrayYouthVillage:Array = new Array(pic1,pic2,pic3,pic4,pic5,pic6,pic7,pic8);
for each (var pic in picsArrayYouthVillage)
{
pic.buttonMode = true;
}
for(var i = 0; i<8; i++)
{
trace("hi");
picsArrayYouthVillage[i].addEventListener(MouseEvent.CLICK, jumpToFrame);
}
function jumpToFrame(m:MouseEvent):void{
gotoAndStop(m.target.name + "_frame");
}
On the Pictures layer there are 8 frames containing pictures and thumbnail buttons (pic1,...pic8)
The problem is when I navigate using the thumbs, every time I click the first button and jumping to frame 1, the event listeners are added again.
Any ideas? Thank you all in advance.

You may check the object has the event listener or not before add event listener to it
for(var i = 0; i<8; i++) {
if (!picsArrayYouthVillage[i].hasEventListener(MouseEvent.CLICK)) {
trace("hi");
picsArrayYouthVillage[i].addEventListener(MouseEvent.CLICK, jumpToFrame);
}
}
EDIT
After I tried the code, I have found the problem,change this code too
var picsArrayYouthVillage:Array = new Array(pic1,pic2,pic3,pic4,pic5,pic6,pic7,pic8);
to
var picsArrayYouthVillage:Array;
if (picsArrayYouthVillage == null) {
picsArrayYouthVillage = new Array(pic1,pic2,pic3,pic4,pic5,pic6,pic7,pic8);
}
Remember to trace hi in the if condition. If it works, it should eight hi and only one time.

Related

Flash AS3 AddEventListener with Parameter using loop

I have 34 buttons in my scene, if I click any of them a MovieClip will be visible and jump (gotoAndStop) to a frame based on which button I pressed.
import flash.events.Event;
import flash.events.MouseEvent;
stop();
MC.visible = false;
var btns:Array = new Array(
prov1, prov2, prov3, prov4, prov5, prov6, prov7, prov8, prov9, prov10,
prov11, prov12, prov13, prov14, prov15, prov16, prov17, prov18, prov19, prov20,
prov21, prov22, prov23, prov24, prov25, prov26, prov27, prov28, prov29, prov30,
prov31, prov32, prov33, prov34
);
for(var i:int = 0; i < 34; i++)
{
btns[i].addEventListener(MouseEvent.CLICK, function(e:Event):void{OpenDetail(i+1)});
trace(i);
}
function OpenDetail(frame:int)
{
MC.visible = true;
MC.gotoAndPlay(1);
MC.MSC.gotoAndStop(frame);
}
In the code above it should be that if I click prov1 it will open MC.MSC and goto frame 1, if I click prov2 it will open MC.MSC goto frame 2, etc.
But what really happened is when I click any of my buttons above, MC.MSC is opened but goes to frame 34.
Where did I do wrong? Any help would be very appreciated. Thanks.
Your mistake is not understanding what closure (an unnamed unbound function) is and how it works. The thing is, your i iterator goes to 34 and all the closures you create read i value from variable reference rather than use i value of the moment they were created.
Instead, you should do the following:
for (var i:int = 0; i < 34; i++)
{
btns[i].addEventListener(MouseEvent.CLICK, onClick);
}
function onClick(e:MouseEvent):void
{
// Get reference to the clicked button.
var aBut:DisplayObject = e.currentTarget as DisplayObject;
// Option 1: figure its index within the list.
var anIndex:int = btns.indexOf(aBut) + 1;
// Option 2: figure its index from the button's name.
var anIndex:int = int(aBut.name.substr(4));
// Go to the relevant frame.
OpenDetail(anIndex);
}

Remove function from the elements of an array in as3

I am building a hangman game. I have some alphabet letters that are the wrong letters and I built an array with them.When a wrong letter is been clicked my movie clip Kremmala is moving a frame showing the hangman and the wrong letter becomes alpha = .5. The problem is that i want after the seventh click my movie clip Kremmala to stop at frame 8 and the elements of the array not to be clickable anymore. I have trouble building the code. Every help is appreciated.
I only have this code until now:
var wrongletters:Array = [a2,a3,a4,a5,a6,a8,a9,a10,a11,a12,a13,a14,a15,a16,a19,a20,a21,a22,a23]
for (var i:int= 0; i< wrongletters.length; i++) {
wrongletters[i].buttonMode = true;
wrongletters[i].isClicked = false;
wrongletters[i].addEventListener(MouseEvent.CLICK, kanoklick);
function kanoklick(event:MouseEvent):void
{
kremmala.nextFrame();
event.target.alpha = 0.5;
if(event.currentTarget.isClicked == false){
clickCount ++;
event.currentTarget.isClicked = true;
}
if(clickCount == 7){
kremmala.stop();
trace("All buttons have been clicked");
}
}
}
I can think of two ways:
1) Disabling the control (list) that holds the array with all the letters. I assume there is a visible list with id="list1" that has the wrongletters:Array as it's dataprovider.
list1.enabled = false;
or 2) Removing the event listener.
for (var i:int= 0; i< wrongletters.length; i++)
{
wrongletters[i].removeEventListener(MouseEvent.CLICK, kanoklick);
}

How to add a keyboard navigation to a Flash AS3 based app?

I would like to make my Flash AS3 based app more accessible with a keyboard navigation.
What's the best way to add to every MovieClip with a MouseEvent.CLICK the ability to get selected through the TAB and clicked/fired through ENTER?
Some basic example of my code:
nav.btna.addEventListener(MouseEvent.CLICK, openSection);
dialog.btnx.addEventListener(MouseEvent.CLICK, closeDialog);
function openSection(event:Event=null):void
{
trace("nav.btna")
}
function closeDialog(event:Event=null):void
{
trace("dialog.btnx")
}
I remember that there was a AS3 function that enabled that every MovieClip with a MouseEvent could be fire through ENTER if the MovieClip was selected with TAB. I can't remeber the function though.
I think the problem may be that you are attempting this with a MovieClip instead of a button (Button or SimpleButton).
I made a simple test by creating buttons instead of MovieClips in my library and this worked as expected:
// I have 4 buttons (button1, button2, etc) on the stage
for(var i:int = 1; i <= 4; i++)
{
var mc = getChildByName("button" + (i+1));
mc.tabIndex = i;
mc.addEventListener(MouseEvent.CLICK, onClicked);
}
function onClicked(e:MouseEvent):void
{
trace(e.currentTarget + " clicked");
}
stage.focus = stage;
I initially ran this test with MovieClip instances, and while they would show that the tab was working (a yellow border shows up), the MouseEvent.CLICK was never firing. Once I switched to actual buttons (SimpleButton in this case), it worked with both the Enter and Space keys.
EDIT:
To answer the question posed in the comments, this is a quick-and-dirty way to "convert" MovieClips to SimpleButtons at runtime:
// I have 4 MovieClips (button1, button2, etc) on the stage
for(var i:int = 1; i <= 4; i++)
{
var mc:MovieClip = getChildByName("button" + i) as MovieClip;
var button:SimpleButton = convertMovieClipToButton(mc);
button.tabIndex = i;
button.addEventListener(MouseEvent.CLICK, onClicked);
}
function convertMovieClipToButton(mc:MovieClip):SimpleButton
{
var className:Class = getDefinitionByName(getQualifiedClassName(mc)) as Class;
var button:SimpleButton = new SimpleButton(new className(), new className(), new className(), new className());
button.name = mc.name;
button.x = mc.x;
button.y = mc.y;
mc.parent.addChildAt(button, getChildIndex(mc));
mc.parent.removeChild(mc);
return button;
}

Creating a vector array of movie clips AS3

I have several movie clips on the stage of my main .fla named btn1-btn7 which will act as buttons. I have a class file named Functions.as where an event listener is created when a button is clicked. onButtonClicked is just going to a frame on the timeline.
obj.addEventListener(MouseEvent.CLICK, onButtonClicked);
I would like the ability to set the buttonMode, visibility, etc. of all of the buttons simultaneously. I have been looking into this for a few hours and am not able to find any solutions. I am now looking into adding them to a vector (which is a new concept for me), but I am not sure how to go about executing this properly. This is what I have so far.
public var buttons:Vector.<MovieClip > = new Vector.<MovieClip > ();
function addButtons()
{
buttons.push(btn1,btn2,btn3,btn4,btn5,btn6,btn7);
for (var i:int; i<buttons.length; i++)
{
trace(buttons[i].name);
}
}
How would I go about, for example, adding the event listener to all of the objects? I will also be setting the buttonMode to true, and making them all invisible simultaneously. I don't even know if it's possible to accomplish this. Thank you in advance for any suggestions.
I'm going to asume that you use timeline code, and have instances of the buttons already placed on the stage. So, first, create the vector:
var _btns:Vector.<MovieClip> = new Vector.<MovieClip>;
_btns.push(btn1,btn2,btn43....) //add all the buttons
Than, you can init the properties of all the buttons:
var _mc:MovieClip;//helper var
for(var i:int=0,i<_btns.length;i++)
{
_mc = _btns[i];
_mc.visible = false;
_mc.buttonMode = true;
_mc.addEventListener(MouseEvent.CLICK, onClick);
}
Then, the event handler:
function onClick(e:MouseEvent):void
{
for(var i:int=0,i<_btns.length;i++)//reset all the buttons
{
_btns[i].visible = false;
}
_mc = MovieClip(e.eventTarget);
_mc.visible = true; //make visible the clicked one
}
You just need to do what you are doing with the .name property in your example code. You need to loop thru every single button in your array (or vector, if you prefer). Here is an example how to set the property of buttonMode:
function setButtonMode(b:Boolean):void {
for(var i:int=0; i<buttons.length; i++) {
var btn:MovieClip = buttons[i]; //store the current reference in a var for faster access
btn.buttonMode = b;
btn.mouseChildren = !b;
}
}

My Actionsript is Skipping Frame 3 and Going Straight to Frame 4

I'm trying to make a primitive game in Flash. I'm using AS3 to build it. So far everything I have coded is working fine. Until now, I've only had 3 frames. However, I am ready to move on so I added a fourth frame. But, when I test the animation, it skips from frame 2 to frame 4. I put a trace in Frame 3 to see if Flash was even running it, and the trace executes the trace so I know Flash isn't completely ignoring Frame 3. But, I have a stop(); at the end of frame 3 and I have a stop(); on Frame 4. So, I'm not sure why Frame 3 is being skipped. The game doesn't have any tweens or actual animations so it shouldn't be anything of that sort. The only interaction is clicking on dots. I've put the code for all 4 of my frames below (I'm not sure if this is frowned upon. If it is, please tell me and I'll remove it but I'm putting it because it seems like it may be helpful). I'm also uploading a link to my .FLA file in case someone wants to see the whole thing.
Frame 1:
import flash.events.MouseEvent;
var dotList = new Array(); var level:int = 10; var invisoDotList = new Array();
var loop:int;
for(loop = 0; loop < level; loop++)
{
var dot:Dot = new Dot();
var invisoDot:InvisoDot = new InvisoDot();
var tester:Boolean = true;
var xval:int = Math.floor(Math.random()*(1+520))+14;
var looper:int = 0;
while(looper < dotList.length)
{
if(Math.abs(xval - dotList[looper].x) > 30)//minimum spacing
{
looper++;
}
else
{
looper = 0;
xval = Math.floor(Math.random()*(1+520))+14;
}
}
dot.x = xval;
dot.y = 187;
invisoDot.x = xval;
invisoDot.y = 187;
invisoDot.alpha = 0;
dotList[loop] = dot;
invisoDotList[loop] = invisoDot;
addChild(invisoDot);
addChild(dot);
}
//trace(dotList); test to ensure that dots are added to the array
button.addEventListener(MouseEvent.CLICK, hideDots);
function hideDots(e:MouseEvent)
{
for(var loop:int = 0; loop < dotList.length; loop++)
{
dotList[loop].alpha = 0;//make dots disappear
}
nextFrame();
}
stop();
Frame 2:
import flash.events.MouseEvent;
button.addEventListener(MouseEvent.CLICK, next);
function next(e:MouseEvent)
{
nextFrame();
}
stop();
Frame 3:
import flash.events.MouseEvent;
removeChild(button);
var clicks:int = -1;
//trace(dotList.length);
stage.addEventListener(MouseEvent.CLICK, clickCount);
for(var loopvar:int = 0; loopvar < dotList.length; loopvar++)
{
//trace("loop");
dot = dotList[loopvar];
invisoDot = invisoDotList[loopvar];
dot.addEventListener(MouseEvent.CLICK, onClick);
invisoDot.addEventListener(MouseEvent.CLICK, onClick);
//trace("event");
}
//trace(dotList.length);
function onClick(e:MouseEvent)
{
//e.currentTarget.alpha = .5;
for(var hitcheck:int = 0; hitcheck < dotList.length; hitcheck++)
{
if(dotList[hitcheck].x == e.currentTarget.x)
{
dotList[hitcheck].alpha = 1;
}
}
//trace("check");
}
function clickCount(e:MouseEvent)
{
clicks++;
//trace(clicks);
var numChanged:int = 0;
for(var index:int = 0; index < dotList.length; index++)//check whether the user has gotten all the dots
{
if(dotList[index].alpha == 1)
{
numChanged++;
}
}
if(numChanged == level)//if the user has gotten all the dots
{
trace("next screen for sucess");
trace(clicks);
}
else if((clicks - numChanged) >= 2)//this ends the session as soon as 2 mistakes are made
{
trace("next screen for failed number of clicks");
trace(clicks);
}
/*else if((clicks - level) >= 2)//if the user has made too many mistakes. This ends the session after the maximum number of tries have been used
{
trace("next screen too many clicks");
trace(clicks);
}*/
}
trace("end");
stop();
Frame 4:
stop();
Link to the .FLA file: https://www.dropbox.com/s/x1vim49tnz227id/Game.fla
If any of the conventions I've used in this question are wrong or frowned upon, please let me know and I'll correct them. It's been over a year since I've last posted on StackOverflow.
Does the same button instance exist on both frame 1 and 2?
If so you will end up with two click event handlers on the button on frame 2 (hideDots() and next()). If you click on the button then they both call nextFrame() which would skip frame 3.
Possible solutions:
Remove the first event listener before moving to the next frame:
button.addEventListener(MouseEvent.CLICK, hideDots);
function hideDots(e:MouseEvent)
{
for(var loop:int = 0; loop < dotList.length; loop++)
{
dotList[loop].alpha = 0;//make dots disappear
}
// Remove the event listener here:
button.removeEventListener(MouseEvent.CLICK, hideDots);
nextFrame();
}
OR
Have different instances of the button on frame 1 and 2.
You can do this by having a keyframe for the button on frame 1 and 2 - Flash will create a new instance of the button when it hits that frame.