Action Script: Call corresponding functions on button click - actionscript-3

I have been trying to add buttons dynamically and then assign event listeners to them. For which my code is,
var i=0;
var step=50;
for each (var child:XML in courseXML.footer.tray.elements())
{
var thumbClip:thumb = new thumb();
//set name
thumbClip.name = "mc_thumb" + (i + 1);
trace("thumbClipname:: "+thumbClip.name);
//set the x and y values
thumbClip.x = 620 + (i * step);
thumbClip.y = 560;
//attach the newly created instance to the container
addChild(thumbClip);
trace("thumbClip:: "+thumbClip);
//attach icon image from xml path
thumbClip.thumbLoader.source = child.icon;
trace("thumbClip.thumbLoader.source: "+thumbClip.thumbLoader.source);
//add listeners
trace("Node name "+ child.localName());
if(child.localName().toLowerCase() == "feedback");
{ trace("gotoFeedback..");
thumbClip.addEventListener(MouseEvent.CLICK, gotoFeedback);
}
if(child.localName().toLowerCase() == "resources");
{ trace("gotoResources..");
thumbClip.addEventListener(MouseEvent.CLICK, gotoResources);
}
if(child.localName().toLowerCase() == "glossary");
{ trace("gotoGlossary..");
thumbClip.addEventListener(MouseEvent.CLICK, gotoGlossary);
}
if(child.localName().toLowerCase() == "discussion");
{ trace("gotoDiscussion..");
thumbClip.addEventListener(MouseEvent.CLICK, gotoDiscussion);
}
thumbClip.buttonMode = true;
i++;
}
So, Finally 4 buttons are displayed on stage and when I click on any button all the four functions gotofeedback, gotoResources, gotoGlossary, gotoDiscussion are called. How do I call corresponding functions on button click? Thanks!
The four functions are:
function gotoFeedback(e: MouseEvent):void
{
trace("gotofeedback fn called..");
}
function gotoResources(e: MouseEvent):void
{
trace("gotoResources fn called..");
}
function gotoGlossary(e: MouseEvent):void
{
trace("gotoGlossary fn called..");
}
function gotoDiscussion(e: MouseEvent):void
{
trace("gotoDiscussion fn called..");
}

You need to add the event listeners to the child buttons, rather than to thumbClip. The way you have your code now, whenever the mouse is clicked anywhere inside thumbClip all the the listeners are called (which is what you are seeing).

Related

Flash CS4 How do you set variable to the Object Dragging Collison?

I am doing a game for my computer science class and I am working on inventory, dragging an item into it. I do not know how to set the item as whatever the user clicked to drag.
At the moment I hard coded it to the item they are dragging, but in the future I want more items, so a variable set to the item they are dragging would make it work perfectly, but I don't know what it's called to do that.
Here is my code for inventory item dragging
function dragItem (event:MouseEvent):void
{
knife_loot.startDrag();
}
function dropItem (event:MouseEvent):void
{
knife_loot.stopDrag();
if ((knife_loot.hitTestObject(inv_game)) && (inv_game.visible == true))
{
trace("Item dropped in inventory")
trace("")
knife_loot.x = 80
knife_loot.y = 120
}
}
// end of dragging and dropping items
You can start with:
// List the items you want to drag.
var aList:Array = [knife_loot, spoon_loot, fork_loot];
// InteractiveObject is superclass for SimpleButton, Sprite and MovieClip.
// If you're sure what they all are then just use their class instead.
for each (var anItem:InteractiveObject in aList)
{
// Subscribe them all for dragging.
anItem.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
}
public var draggedItem:InteractiveObject;
function onDrag(e:MouseEvent):void
{
// Use e.currentTarget because original MouseEvent e.target
// could be something from deep inside of top object e.currentTarget.
draggedItem = e.currentTarget as InteractiveObject;
draggedItem.startDrag();
// Let's hook drop events.
stage.addEventListener(Event.MOUSE_LEAVE, onDrop);
stage.addEventListener(MouseEvent.MOUSE_UP, onDrop);
}
function onDrop(e:Event):void
{
// Unhook drop events.
stage.removeEventListener(Event.MOUSE_LEAVE, onDrop);
stage.removeEventListener(MouseEvent.MOUSE_UP, onDrop);
// Drop the item.
draggedItem.stopDrag();
if ((draggedItem.hitTestObject(inv_game)) && (inv_game.visible == true))
{
trace("Item", draggedItem.name, "was dropped to inventory.");
trace("");
draggedItem.x = 80;
draggedItem.y = 120;
}
// Forget the item.
draggedItem = null;
}

Hiding a menu on click outside

I have a menu that pops up and at the same time is hidden on a mouse click event on a button but I would like to be able to hide said menu by clicking outside the menu movieclip and its button. Is it possible to accomplish that in as3?
So far this is the solution I found, adapted and have being trying to work with but still not getting anywhere.
switchbd_btn.addEventListener(MouseEvent.CLICK, onClickHandler);
stage.addEventListener(MouseEvent.CLICK, onClickHandler);
function onClickHandler(event : MouseEvent) : void {
switch(event.target)
{
case switchbd_btn:
switchbd.gotoAndStop(2);
switchbdIN.start();
switchbd_btn.filters = [ONf];
break;
case stage:
switchbdOUT.start();
switchbd.gotoAndStop(3);
switchbd_btn.filters = [OFf];
break;
}
}
My original working code :-
//////////////////////SWITCH BOARD\\\\\\\\\\\\\\\\\\\\\\\\\\\\
switchbd_btn.addEventListener(MouseEvent.MOUSE_DOWN, ShowswitchBD);
var switchbdIN:Tween = new Tween (switchbd, "x", Strong.easeOut, 1089.05, 277.85, 1, true);
var switchbdOUT:Tween = new Tween (switchbd, "x", Strong.easeOut, 277.85, 1089.05, 1, true);
var ONf:DropShadowFilter = new DropShadowFilter (-1,26,0xCCCCCC,1,2,2,1,3,false,false,false);
var OFf:DropShadowFilter = new DropShadowFilter (6,26,0x000000,1,2,2,1,3,false,false,false);
function ShowswitchBD(e:MouseEvent):void {
if (switchbd.currentFrame != 2)
{
switchbd.gotoAndStop(2);
switchbdIN.start();
switchbd_btn.filters = [ONf];
}
else {
switchbdOUT.start();
switchbd.gotoAndStop(3);
switchbd_btn.filters = [OFf];
}
}
switchbd is the menu movieclip, and switchbd_btn is the button.
Here is a pattern to accomplish what you're asking. This assumes your menu movieClip is called: switchbd and you show/hide it with the button: switchbd_btn.
First, add a click listener to your button and create the handler function:
switchbd_btn.addEventListener(MouseEvent.CLICK, toggleMenu);
function toggleMenu(e:Event):void {
//the x position should be 277.85 when visible
if(switchbd.x <= 278){
hideMenu();
}else{
showMenu();
}
}
Now create the show and hide menu functions:
function showMenu():void {
switchbd.gotoAndStop(2); //or however you 'show' it
switchbdIN.start();
switchbd_btn.filters = [ONf];
//since the menu is visible, listen for global mouse clicks to hide it
stage.addEventListener(MouseEvent.CLICK, hideMenuGlobalClick);
}
function hideMenu():void {
switchbd.gotoAndStop(3);
switchbdOUT.start();
switchbd_btn.filters = [OFf];
//stop listening for global mouse clicks since the menu is hidden now
stage.removeEventListener(MouseEvent.CLICK, hideMenuGlobalClick);
}
function hideMenuGlobalClick(e:Event):void {
var target:DisplayObject = e.target as DisplayObject;
//crawl up the display tree from the item click until there is no parent (stage)
while(target && target.parent){
//if the target is the menu or button, exit this function
if(target == switchbd || target == switcbd_btn){
return;
}
//move on to the next item up the chain
target = target.parent;
}
//if you made it this far, it wasn't the menu that was clicked
hideMenu();
}

ActionScript 3 after seven buttons clicked go to next scene

I have seven buttons (btn_one, btn_two, btn_three, ...) and when all of them were clicked (not in a row, just random) I want go to the first frame in the next scene. What does my code should look like?
Thank you!
const buttons:Array = [btn_one, btn_two, btn_three, btn_four, btn_five, btn_six, btn_seven];
// dictionary to keep clicks state
const clicked:Dictionary = new Dictionary();
function buttonClickHandler(event:Event):void {
// record specific button's click to a dictionary
clicked[event.currentTarget] = true;
// true, if all the dict keys have true values
const allButtonsClicked:Boolean = buttons.every(
function(button:Object, ...rest):Boolean {
return clicked[button];
});
if (allButtonsClicked) {
// remove all listeners
for each (var button:DisplayObject in buttons) {
button.removeEventListener(MouseEvent.CLICK, buttonClickHandler);
}
//do whatever action you need. For example:
gotoAndStop(/*neededFrame*/);
}
}
// initialize dictionary values, and add listeners
for each (var button:DisplayObject in buttons) {
clicked[button] = false;
button.addEventListener(MouseEvent.CLICK, buttonClickHandler);
}
haven't tested, it but should work. Anyway, the scheme should be valid.
stop();
const buttons:Array = [btn_one, btn_two, btn_three, btn_four, btn_five, btn_six, btn_seven];
// dictionary to keep clicks state
const clicked:Dictionary = new Dictionary();
function buttonClickHandler(event:Event):void {
// record specific button's click to a dictionary
clicked[event.currentTarget] = true;
// true, if all the dict keys have true values
const allButtonsClicked:Boolean = buttons.every(
function(button:Object, ...rest):Boolean {
return clicked[button];
});
if (allButtonsClicked) {
// remove all listeners
for each (var button:DisplayObject in buttons) {
button.removeEventListener(MouseEvent.CLICK, buttonClickHandler);
}
//do whatever action you need. For example:
gotoAndStop(2);
}
}
// initialize dictionary values, and add listeners
for (var button:DisplayObject in buttons) {
clicked[button] = false;
btn_one.addEventListener(MouseEvent.CLICK, buttonClickHandler);
btn_two.addEventListener(MouseEvent.CLICK, buttonClickHandler);
btn_three.addEventListener(MouseEvent.CLICK, buttonClickHandler);
btn_four.addEventListener(MouseEvent.CLICK, buttonClickHandler);
btn_five.addEventListener(MouseEvent.CLICK, buttonClickHandler);
btn_six.addEventListener(MouseEvent.CLICK, buttonClickHandler);
btn_seven.addEventListener(MouseEvent.CLICK, buttonClickHandler);
}
I tested the code of leetwinski and added the eventlisteners for my buttons, but it doesn't work. I get the error "1067: Implicit coercion of a value of type Class to an unrelated type flash.display:DisplayObject" What did I do wrong?

Adding multiple instances of the same object to the stage

I'm making a "spit" card game and I'm trying to be able to have 3 cards on the stage at once to be able to drag to the pile. So my question is how do I have multiple instances of the same object on the stage, but be able to assign each card different frames, etc. Here is the code to understand the context of it.
"cardArray" has 53 frames, 52 of which have a card face, 53rd is a "deck" picture.
//variables, constants
var cardDeck:Array = new Array();
var timer:Timer = new Timer(2000);
var j:int = 0;
var card:MovieClip = new CardArray();
var cardInDeck:Boolean;
const deckSize:int = 52;
//events:
card.addEventListener(MouseEvent.MOUSE_DOWN,fDown);
card.addEventListener(MouseEvent.MOUSE_UP,fUp);
startRandomise();
//This is where the unshuffled "deck" is created - values loaded into the array.
function createDeck():void
{
var i:int;
for(i =0; i<deckSize; i++)
{
cardDeck[i] = i+1;
}
}
function randomizeDeck( a : *, b : * ):int
{
return (Math.random()>.5) ? 1 : -1;
}
//Grab the value from the (presumably) current frame of the card
function convertCard(cardNo:int):int
{
var deckPos:int;
if (cardNo <= deckSize/4)
{
deckPos = cardNo;
}
else if (cardNo > deckSize/4 && cardNo <= deckSize/2)
{
deckPos = cardNo -13;
}
else if (cardNo > deckSize/2 && cardNo <=deckSize*3/4)
{
deckPos = cardNo -deckSize/2;
}
else if (cardNo >39)
{
deckPos = cardNo -39;
}
return deckPos;
}
btn.addEventListener(MouseEvent.MOUSE_UP,showArray);
function showArray(event:MouseEvent):void
{
if(j<deckSize /2)
{
addChild(card);
card.gotoAndStop(cardDeck[j]);
trace(cardDeck[j]+","+deckCompare[j]);
j++;
}
if(cardInDeck)
{
card.x = 200;
card.y = 200;
cardInDeck+false;
}
}
function fDown(evt:MouseEvent)
{
card.startDrag();
}
function fUp(evt:MouseEvent)
{
stopDrag();
if(card.hitTestObject(deck))
{
trace("deck: "+convertCard(deck.currentFrame));
trace("card: "+convertCard(card.currentFrame));
if(convertCard(card.currentFrame) == convertCard(deck.currentFrame)+1 || convertCard(card.currentFrame) == convertCard(deck.currentFrame)-1 || convertCard(card.currentFrame) == 13 && convertCard(deck.currentFrame) == 1 || convertCard(card.currentFrame) == 1 && convertCard(deck.currentFrame) == 13 || convertCard(deck.currentFrame) == 14)
{
deck.gotoAndStop(card.currentFrame);
removeChild(card);
cardInDeck=true;
}
else
{
card.x = 200;
card.y = 200;
}
}
else
{
card.x = 200;
card.y = 200;
}
}
function startRandomise():void
{
createDeck();
cardDeck.sort(randomizeDeck);
cardDeck.sort(randomizeDeck);
trace("random: "+cardDeck);
trace("deckCompare: "+deckCompare);
card.x = 200;
card.y = 200;
deck.gotoAndStop(53);
}
To have multiple cards, you need to instantiate more than one card. I don't know anything about the card game spit and don't understand the purpose of many of your functions, but you'll want to do something along these lines:
Create a function that generates (instantiates) a new card:
function createCard(faceFrame):MovieClip {
var tmpCard:MovieClip = new CardArray(); //this creates a new instance of a card
tmpCard.addEventListener(MouseEvent.MOUSE_DOWN, cardMouseDown); //make the card call the mouse down function when that event is triggered
tmpCard.gotoAndStop(faceFrame); //assign the card it's face (frame)
addChild(tmpCard); //add the card to the screen
return tmpCard;
}
Then, in your mouse down handler (I renamed it to be more clear what is is), you can do the following to card that was mouse downed:
function cardMouseDown(evt:MouseEvent) {
//the events currentTarget property is reference to the item that you attached the listener to, so in this case the card who triggered the mouse down
card = evt.currentTarget as MovieClip; //assign the current clicked card to the global card variable (so we can access it in the mouse up function)
card.startDrag();
//add the mouse up listener on the stage, since there are cases where you can drag so fast that the mouse isn't over the item it's dragging (and then if you were to release the mouse at that moment it wouldn't dispatch the event)
stage.addEventListener(MouseEvent.MOUSE_UP, stageMouseUp);
}
Then your mouse up function would look something like this:
function stageMouseUp(evt:MouseEvent) {
//remove the mouse up listener from the stage
stage.removeEventListener(MouseEvent.MOUSE_UP, stageMouseUp);
card.stopDrag();
if(card.hitTestObject(deck))
{
......//rest if the code
Seems like you would want to generate a new card in the showArray function you have? So something like this:
function showArray(event:MouseEvent):void
{
var newCard:MovieClip = createCard(cardDeck[j]);
j++
newCard.y = newCard.x = 200;
trace(cardDeck[j]+","+deckCompare[j]);
}
As an aside, you should consider calling your Card object something more sensible, like Card instead of CardArray, as it's not an array...

ENTER_FRAME event idle occurrence or was gotoAndPlay called?

I have an MC with frame labels that are jumped through. Currently, I can detect when it starts a new label, but I also want to be able to restart the actions should the current label get called with gotoAndPlay() without ENTER_FRAME calling it 30 times per second. Any idea how to filter that out?
private function onNewFrame(e:Event) {
if(e.target.currentLabel != _currentLabel) {
// started new label (working)
trace("New label: "+ e.target.currentLabel);
}else if(e.target.currentFrame == _currentFrame && e.target.isPlaying) {
// repeated frame (doesn't work)
trace("Repeated label: "+ e.target.currentFrame);
}
_currentFrame = e.target.currentFrame;
_currentLabel = e.target.currentLabel;
}
As far as I understand, you need to know next two things:
1). When movieclip advances to next frame with the new frame label;
2). When the next frame has the same label as the previous.
First of all MovieClip doesn't has "isPlaying" property. It sounds unrealistic, but there is no built-in method to check whether MC is playing. So e.target.isPlaying will always return false; therefore your second "if" statement will also always return false.
Also you don't need that "isPlaying" check at all because MovieClip dispatches Event.ENTER_FRAME only when it plays.
So this will work:
var testMc:TestMC = new TestMC();
testMc.addEventListener(Event.ENTER_FRAME, onNewFrame);
testMc.play();
private function onNewFrame(e:Event):void
{
if (e.target.currentLabel != _currentLabel)
{
// started new label (working)
trace("New label: " + e.target.currentLabel);
}
else if (e.target.currentFrame !== _currentFrame)
{
// started frame with the same label
trace("New frame with same label: " + e.target.currentFrame);
}
_currentFrame = e.target.currentFrame;
_currentLabel = e.target.currentLabel;
}
But maybe I didn't understand your question?
I ended up solving this problem by manually storing frame label indices in the class constructor. The MovieClip property currentFrameLabel should take care of this, however my tests show that it is always undefined.
public class DynamicMC extends MovieClip {
private var _currentLabel:String;
private var _currentFrame:int;
private var _labels:Object = {};
public function DynamicPlanComparison() {
super();
findLabels();
}
private function findLabels():void {
for(var i:uint = 0; i < currentLabels.length; i++) {
var l:FrameLabel = currentLabels[i];
_labels[l.name] = l;
}
}
private function onNewFrame(e:Event) {
if(e.target.currentLabel != _currentLabel) {
// started new label
trace("New label: "+ e.target.currentLabel);
}else if(_labels[e.target.currentLabel].frame == e.target.currentFrame) {
// repeated label
trace("Repeated label: "+ e.target.currentLabel);
}
_currentFrame = e.target.currentFrame;
_currentLabel = e.target.currentLabel;
}
}