I am pretty new to as3 and tried searching around for an answer to my question but it seems nothing works. I have an xml loaded file where when the user clicks the correct option (of 4) they get a point scored. I'm trying to disable the button after it has been clicked once but this is not happening. Any help would be greatly appreciated.
Here is the section I have.
function setupButtons():void {
for (var obj:Object in buttons)
{
buttons[obj].addEventListener(MouseEvent.CLICK, checkAnswer);
}
buttons[obj].addEventListener(MouseEvent.MOUSE_UP,disableBtns);
}
function disableBtns(evt:MouseEvent):void {
for (var obj:Object in buttons)
evt.currentTarget.removeEventListener(MouseEvent.MOUSE_UP,disableBtns);
buttons[obj].enabled = false;
}
Here are some comments next to your original code to help explain what is likely happening:
function setupButtons():void {
//you're adding a click listener for every object in `buttons`
for (var obj:Object in buttons)
{
buttons[obj].addEventListener(MouseEvent.CLICK, checkAnswer);
}
//this next line seems out of place,
//it is NOT a part of your for loop above so it will only run once,
//The value of obj will be the LAST item in the for loop above
buttons[obj].addEventListener(MouseEvent.MOUSE_UP,disableBtns);
}
function disableBtns(evt:MouseEvent):void {
//you don't have curly braces on this next for loop line
//this means it's only going to run the line immediately following the loop as part of the loop.
for (var obj:Object in buttons)
//your attempting to remove the same listener over and over again (since this line is in a loop)
evt.currentTarget.removeEventListener(MouseEvent.MOUSE_UP,disableBtns);
//this next line is not part of the loop above.
//I imagine you only want to disable the button that was clicked (evt.currentTarget)
//This will only disable whatever the last value of obj was in the loop above
buttons[obj].enabled = false;
}
Now, here is a simple code refactoring that may help:
//first, just have one click listener for each button, forget the mouse up listener
function setupButtons():void {
for (var obj:Object in buttons){
buttons[obj].addEventListener(MouseEvent.CLICK, btnClick);
}
}
function btnClick(evt:MouseEvent):void {
//If buttons are of the SimpleButton class, you can just disable them
evt.currentTarget.enabled = false;
//OR, if the buttons are not of the SimpleButton class
evt.currentTarget.mouseChildren = false;
evt.currentTarget.mouseEnabled = false;
//OR, just remove the click listener
evt.currentTarget.removeEventListener(MouseEvent.CLICK, btnClick);
//run the checkAnswer function
checkAnswer(evt);
}
To disable all buttons when any 1 is clicked, you could do this:
function btnClick(evt:MouseEvent):void {
for (var obj:Object in buttons){
buttons[obj].removeEventListener(MouseEvent.CLICK, btnClick);
}
//run the checkAnswer function
checkAnswer(evt);
}
Related
I am looking to have a single function that removes listeners based on the switch/case button that was clicked. I have 2 MCs on the stage named "btn01" and "btn02" and have an array with matching names.
I want btnRemove() to be able to removeListener to btn01 if it was click, or if btn02 was clicked. How do I accomplish this? Thanks.
var buttons = new Array(btn01, btn02);
for (var a=0; a<buttons.length; a++){
buttons[a].buttonMode=true;
buttons[a].addEventListener(MouseEvent.CLICK,buttonClick);
}
function btnRemove() {
e.currentTarget.removeEventListener(MouseEvent.CLICK,buttonClick); //1120: Access of undefined property e
}
function buttonClick(e:Event):void{
switch(e.currentTarget.name){
case "btn01":
btnRemove(); //remove btn01 listener
break;
case "btn02":
btnRemove(); //remove btn02 listener
break;
}}
event.currentTarget is an object who calls listener so it would be your button, you can remove listener with a help of currentTarget, see next code:
btn01.addEventListener(MouseEvent.CLICK, OnClickBtn);
btn02.addEventListener(MouseEvent.CLICK, OnClickBtn);
function OnClickBtn(e:Event):void
{
if ( e.currentTarget.hasEventListener(MouseEvent.CLICK) )
{
e.currentTarget.removeEventListener(MouseEvent.CLICK, OnClickBtn);
}
}
I am creating a puzzle in which the player have to click on the buttons on the right order or sequence to go to the next level (Scene 2 for example). I don't know how to do it. If any one have any idea to how to achieve this in Action Script.
Thank you
Scene 1:
enter image description here
each number is a button. Now the player has to click in the right order or sequence (1 2 3 4 5 6 7 8) to open the next level (Scene 2)
var checkString:String = "";
//Create event listeners and their functions.
btn1.addEventListener(Mouse.CLICK, oneClick);
btn2.addEventListener(Mouse.CLICK, twoClick);
btn3.addEventListener(Mouse.CLICK, threeClick);
btn4.addEventListener(Mouse.CLICK, fourClick);
btn5.addEventListener(Mouse.CLICK, fiveClick);
btn6.addEventListener(Mouse.CLICK, sixClick);
btn7.addEventListener(Mouse.CLICK, sevenClick);
btn8.addEventListener(Mouse.CLICK, eightClick);
function oneClick(evt:Event):void
{
//In each event listener function, add a letter or
//string to the checkString variable.
checkString += "on";
//Then, see if the string matches or not.
check();
}
function twoClick(evt:Event):void
{
checkString += "tw";
check();
}
function threeClick(evt:Event):void
{
checkString += "th";
check();
}
function fourClick(evt:Event):void
{
checkString += "fo";
check();
}
function fiveClick(evt:Event):void
{
checkString += "fi";
check();
}
function sixClick(evt:Event):void
{
checkString += "si";
check();
}
function sevenClick(evt:Event):void
{
checkString += "se";
check();
}
function eightClick(evt:Event):void
{
checkString += "ei";
check();
}
//If the proper sequence is one, two, three, four, five, six, seven, eight the string would read "ontwthfofisiseei".
function check():void
{
if(checkString == "ontwthfofisiseei")
{
//Clear the checkString for convenience before going on.
clearString();
//CODE TO GO TO NEW FRAME
gotoAndPlay(1, "Scene 3");
}
}
function clearString():void
{
//You will want to have a function for clearing the string.
//This is especially useful if you have a button for "start over."
checkString = "";
}
this the code i used before but it show error in the listener and it doesn't. work
To answer your updated question:
Your error is likely that Mouse.CLICK should be MouseEvent.CLICK.
Your other error is telling you that there is no scene called "Scene 3"
Let's assume you have 8 MovieClips (or buttons) that are on a timeline in Flash/Animate.
One (of many) ways to accomplish this would be the following:
Give each of those buttons an instance name. To make for less code, lets give them the name btn + their respective correct order number - so btn1, btn2, btn3 etc.
You'll need to add a click listener to each button, so they can have something happen when they are clicked.
You could do this 8 times (one for each button): btn1.addEventListener(MouseEvent.CLICK, buttonClick); but to make things simpler, you can just iterate through all the objects on the timeline and add the listener to each object whose name starts with "btn":
var totalBtns:int = 0; //create a var to store how many buttons there are
//loop through each child of the current timeline
var i:int = numChildren;
while(i--){
//if the child's name starts with 'btn'
if(getChildAt(i).name.indexOf("btn") == 0){
//add the click listener
getChildAt(i).addEventListener(MouseEvent.CLICK, buttonClick,false,0,true);
totalBtns++; //increase the total buttons variable by 1
}
}
This also means less work later if you add/remove buttons
You need a way to track when a button was clicked. To accomplish this, we'll use an array.
var clickArray:Array = []; //this creates a new array
//When a button is clicked, you add it to this array
lets create the function that is called when a button is clicked:
function buttonClick(e:Event):void {
//add the item that was just clicked (represented by the event's currentTarget property) to the array
//so if btn1 was just clicked, btn1 would be e.currentTarget
clickArray.push(e.currentTarget);
//now disable the button so it can't be clicked anymore
SimpleButton(e.currentTarget).enabled = false;
//check if all button have been clicked
if(clickArray.length == totalBtns){
//lets go through every item in the array, and see if it's in the right order
var ctr:int = 0; //a counter to keep track of the expected next number var i:int = 0; //iterator for the for loops
for(i=0;i<clickArray.length;i++){
//lets convert everything after the 3rd character of the name to a number - so for btn1, that would be 1
if(parseInt(clickArray[i].name.substring(3)) == ctr + 1){
ctr++; //increment the counter to the next expected number
}else{
break; //leave the for loop early since a click was out of place
}
}
//if the correct order was achieved
if(ctr == totalBtns){
nextScene(); //or however you continue
}else{
//the correct order was NOT acheived
//make all the buttons clickable again
for(i=0;i<clickArray.length;i++){
SimpleButton(clickArray[i]).enabled = true;
}
//reset the array
clickArray = [];
//probably want to tell the user to try again
}
}
}
Lets say I have 30 objects created in for loop, added to a container.
Objects stop on frame 1. I have added event listeners to the objects as you can see below, and when I click any object inside container, it goes to frame 2 and play.
for (var i:int=0; i < 30; i++)
{
var object = new Object1();
object.gotoAndStop(1);
object.addEventListener(MouseEvent.CLICK, myFunction);
container.addChild(object);
}
private function myFunction(e:MouseEvent):void
{
e.currentTarget.gotoAndPlay(2);
}
So I have to click each object to send it on frame 2,
I also tried ROLL_OVER, everything is same but CLICK is changed to ROLL_OVER inside for loop.
What I want is to click, and then mouse over object so they go to frame 2 and play.
The problem is that I need to use MOUSE_DOWN event, I have tried to set MOUSE_DOWN instead of CLICK or ROLL_OVER, but it does not work. If I want to send objects to frame 2 (using MOUSE_DOWN), I need to click each of them, there is no difference between MOUSE_DOWN and CLICK in this case.
As someone who does not know much about mouse events, I'm wondering why roll over and click works, but mouse_down does not?
I think I see what you're trying to do... you want to press the mouse to start drawing over a bunch of sprites, each one goes to frame two when you mouse over it, but only if the mouse button is pressed, right?
try something like this
container.addEventListener(MouseEvent.MOUSE_DOWN, setMouseDown);
container.addEventListener(MouseEvent.MOUSE_UP, setMouseUp);
private var mouseIsDown:Boolean = false;
private var currentSprite:Sprite;
for (var i:int=0; i < 30; i++)
{
var object = new Object1();
object.gotoAndStop(1);
object.addEventListener(MouseEvent.MOUSE_OVER, myFunction);
object.mouseChildren = false;
container.addChild(object);
}
private function setMouseDown(e:MouseEvent){
mouseIsDown = true;
setActive(currentSprite);
}
private function setMouseUp(e:MouseEvent){
mouseIsDown = false;
}
private function myFunction(e:MouseEvent){
currentSprite = e.target;
if(mouseIsDown){
setActive(currentSprite);
}
}
private function setActive(target:Sprite){
target.gotoAndPlay(2);
}
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;
}
}
I'm fairly new to ActionScript 3 (so I’m sorry if this is a naïve question) and I'm working on an existing project that uses a "Tree" menu. Each node in the tree represents a section in the application. Unfortunately, some of the section names (which are what's displayed in the node’s display value) are fairly long and requires the text to be truncated. As a result, there are times where the section names are cut off. To get around this, we want to give users the ability to see the entire title by moving their mouse cursor over the node for “X” seconds in which case a small pop-up renders the node's label.
Example
public var menuTree:Tree;
public function DoSomething(){
menuTree.addEventListener(ListEvent.ITEM_ROLL_OVER, onListItemRollover, false, 100);
}
private function onListItemRollover(event:ListEvent):void {
//IF MOUSE CURSOR IS STILL OVER NODE FOR "X" SECONDS DISPLAY NODE'S LABEL IN POP-UP
}
Thanks all in advance!
Without knowing more about your setup, I would probably setup something like this:
var timer:Timer;
var currentItem:*
for each (var node:* in menuTree) {
node.addEventListener(MouseEvent.MOUSE_OVER, overHandler);
node.addEventListener(MouseEvent.MOUSE_OUT, outHandler);
}
function overHandler(event:MouseEvent):void {
stopTimer();
currentItem = event.currentTarget;
timer = new Timer(2000, 1);
timer.addEventListener(TimerEvent.TIMER, showPopup);
timer.start();
}
function outHandler(event:MouseEvent):void {
stopTimer();
}
function showPopup(timerEvent:TimerEvent):void {
stopTimer();
//show popup code here
//use currentItem
}
function stopTimer():void {
if (timer) {
timer.stop();
timer.removeEventListener(TimerEvent.TIMER, showPopup);
}
}
So instead of adding the event listener to the menuTree you're going to loop though each item in the tree and add a listener to that item. Then when the user rolls over any given item it starts a timer that after 2 seconds will run a function to show the popup.