AS3 Passing Variable Parameters to a generic Function Menu / SubItems - actionscript-3

I'm no code genius, but a fan of action script.
Can you help me on this:
I have a function that depending on the object selected, will call event listeners to a set of 'sub-items' that are already on stage (I want to reuse this subitems with changed parameters upon click, instead of creating several instances and several code).
So for each selected 'case' I have to pass diferent variables to those 'sub-items', like this:
function fooMenu(event:MouseEvent):void {
switch (event.currentTarget.name)
{
case "btUa1" :
trace(event.currentTarget.name);
// a bunch of code goes here
//(just cleaned to easy the view)
/*
HELP HERE <--
here is a way to pass the variables to those subitems
*/
break;
}
}
function fooSub(event:MouseEvent):void
{
trace(event.target.data);
trace(event.currentTarget.name);
// HELP PLEASE <-> How can I access the variables that I need here ?
}
btUa1.addEventListener(MouseEvent.CLICK, fooMenu);
btUa2.addEventListener(MouseEvent.CLICK, fooMenu);
btTextos.addEventListener(MouseEvent.CLICK, fooSub);
btLegislacao.addEventListener(MouseEvent.CLICK, fooSub);
Anyone to help me please?
Thank very much in advance. :)

(I'm not sure I got your question right, and I haven't developed in AS3 for a while.)
If you want to simply create function with parameters which will be called upon a click (or other event) you can simply use this:
btUa1.addEventListener(MouseEvent.CLICK, function() {
fooMenu(parameters);
});
btUa2.addEventListener(MouseEvent.CLICK, function() {
fooMenu(other_parameters)
}):
public function fooMenu(...rest):void {
for(var i:uint = 0; i < rest.length; i++)
{
// creating elements
}
}
If you want to call event listeners assigned to something else you can use DispatchEvent
btnTextos.dispatchEvent(new MouseEvent(MouseEvent.CLICK))
Remember, you can't use btTextos.addEventListener(MouseEvent.CLICK, carregaConteudo("jocasta")); because the 2nd parameter you pass while adding Eventlistener will be considered as function itself - there are two proper ways to use addEventListener:
1:
function doSomething(event:MouseEvent):void
{
// function code
}
element.addEventListener(MouseEvent.CLICK, doSomething); //notice no brackets
2:
element.addEventListener(MouseEvent.CLICK, function() { // function code });
So:
function fooSub(event:MouseEvent, bla:String):void
{
trace(event.currentTarget.name+" - "+bla);
// bla would be a clip name.
}
codebtTextos.addEventListener(MouseEvent.CLICK, function(e:MouseEvent) { fooSub(e, "jocasta") } );
Or try something like this if you want content to be dynamically generated:
btUa1.addEventListener(MouseEvent.CLICK, function() {
createMenu(1);
});
btUa2.addEventListener(MouseEvent.CLICK, function() {
createMenu(2);
});
function createMenu(id):void
{
// Switching submenu elements
switch (id)
{
case 1:
createSubmenu([myFunc1, myFunc2, myFunc3]); // dynamically creating submenus in case you need more of them than u already have
break;
case 2:
createSubmenu([myFunc4, myFunc5, myFunc6, myFunc7]);
break;
default:
[ and so on ..]
}
}
function createSubmenu(...rest):void {
for (var i:uint = 0; i < rest.length; i++)
{
var mc:SubItem = new SubItem(); // Subitem should be an MovieClip in library exported for ActionScript
mc.addEventListener(MouseEvent.CLICK, rest[i] as function)
mc.x = i * 100;
mc.y = 0;
this.addChild(mc);
}
}

Your question is rather vague; what "variables" do you want to "pass"? And what do you mean by "passing the variable to a sub item"? Usually "passing" means invoking a function.
If you can be more specific on what exactly your trying to do that would be helpful. In the meantime, here are three things that may get at what you want:
You can get any member of any object using bracket notation.
var mc:MovieClip = someMovieClip;
var xVal:Number = mc.x; // The obvious way
xVal = mc["x"]; // This works too
var propName:String = "x";
xVal = mc[propName] ; // So does this.
You can refer to functions using variables
function echo(message:String):void {
trace(message);
}
echo("Hello"); // The normal way
var f:Function = echo;
f("Hello"); // This also works
You can call a function with all the arguments in an array using function.apply
// Extending the above example...
var fArgs:Array = ["Hello"];
f.apply(fArgs); // This does the same thing
Between these three things (and the rest parameter noted by another poster) you can write some very flexible code. Dynamic code comes at a performance cost for sure, but as long as the frequency of calls is a few hundred times per second or less you'll never notice the difference.

Related

ActionSctipt 3.0 Error:

I'm having real trouble trying to access the symbol dynamically, I have 9 buttons that all call this method, and they pass in their location (tl, t, tr, etc.) I've tried this method before on another program and it works without a problem, but in this program it fails.
I am attempting to access a symbol call s_tl (example location), but all I'm getting is undefined (see results).
function turn(btn : String):Function {
return function(e:MouseEvent) {
var players_turn : int;
var chosen : String = "s_" + btn;
trace(this);
trace(this[chosen]);
trace(chosen);
trace(this[chosen]);
// if crosses turn 0 else 1
if (s_c.currentFrame == 1) {
players_turn = 0;
} else {
players_turn = 1;
}
// check who's turn it is if it's been pressed before
if (players_turn == 0 && this[chosen].visible == false) {
this[chosen].gotoAndStop(1);
this[chosen].visible = true;
} else {
this[chosen].gotoAndStop(2);
this[chosen].visible = true;
}
};
}
Results:
[object global]
undefined
s_br
undefined
TypeError: Error #1010: A term is undefined and has no properties.
at MethodInfo-6()
Your problem is the bad code style. You define unnamed unbind function inside function turn() and that's where the root of your problem is. Unbind function exist, as your trace shows, in global addressing context and, unlike function turn(), is not bind to any specific display object. Your buttons probably exist on the same addressing context with turn(). Argument btn is available inside unnamed function because ECMA standard instructs so (if function A creates function B then local variables, including arguments, of A are available as local variables in B), but it is a very very very bad practice that makes code messy and induce headaches.
Please explain what you tried to achieve with that code so we could untangle it and rewrite in not-so-twisted way.
Okey, I basically figured you're doing Tic Tac Toe. Now, guideline. A cell must contain 3 frames: 1st frame for the button graphics, 2nd and 3rd for X and O. Name them your way: s_1, s_2, etc.
for (var i:int = 1; i < 10; i++)
{
var aCell:MovieClip = getChildByName("s_" + i) as MovieClip;
aCell.addEventListener(MouseEvent.CLICK, onTic);
}
function onTic(e:MouseEvent):void
{
var playersTurn:int = s_c.currentFrame;
var aCell:MovieClip = e.currentTarget as MovieClip;
trace(aCell.name);
// Now, the magic.
aCell.gotoAndStop(playersTurn + 1);
aCell.removeEventListener(MouseEvent.CLICK, onTic);
}

Create a set of anonymous functions with parameters defined at definiton time

I'm attempting to gradually refactor existing code. I have a set of functions that are defined, and only differ by one of the internal arguments:
function loadGame1():void
{
loadGame("save1");
}
function loadGame2():void
{
loadGame("save2");
}
function loadGame3():void
{
loadGame("save3");
}
//... snip many, many lines
// Note- I cannot pass function arguments at this time!
picker(loadGame1, loadGame2, loadGame3 ...);
I'm trying to refactor at least part of this (I can't completely replace the whole thing yet, too many interdependencies).
Basically, I want to be able to generate a big set of functions with the difference between the functions being a internal parameter:
var fNames:Array = new Array("save1", "save2", "save3");
var funcs:Array = new Array();
for (var i = 0; i < fNames.length; i += 1)
{
trace("Creating function with indice = ", i);
funcs.push(
function() : void
{
saveGame(fNames[i]);
}
)
}
picker(funcs[0], funcs[1], funcs[2] ...);
However, as I understand it, closure is causing the state of i to be maintained beyond the scope of the for loop, and any attempt to call any of the generated functions is failing with an out-of-bounds error, which is what you would expect given that i will reach fNames.size + 1 before i < fNames.size evaluates to false.
So, basically, given that I need to generate functions that are passed as arguments to a pre-existing function that I cannot change currently. How can I dynamically generate these functions?
Try to use IIFE:
for (var i = 0; i < fNames.length; i += 1)
{
(function(i){
trace("Creating function with indice = ", i);
funcs.push(
function() : void
{
saveGame(fNames[i]);
}
)
})(i);
}

requestAnimationFrame type error in object

hi i'm trying to use requestAnimationFrame for my game and I actually use this code below, but as you can see ".bind()" create every loop a new function that slow down my game... I'm looking for a "efficient" solution for the best perfomance, thank you in advance :D
function myClass() {
this.loop = function() {
window.requestAnimationFrame(this.loop.bind(this));
/* here myGameLoop */
}
this.loop();
}
above code works but is slow.. instead this "standard" code give me "Type error":
window.requestAnimationFrame(this);
I have also found e tried this Q&A: requestAnimationFrame attached to App object not Window works just ONE time then give the same "Type error" :(
try if you don't believe me: http://jsfiddle.net/ygree/1 :'(
Without knowing the whole story of your object (what else is in there); you could simplify life by just doing this:
function myClass() {
var iHavAccessToThis = 1;
function loop() {
iHavAccessToThis++;
/* here myGameLoop */
requestAnimationFrame(loop);
}
loop();
//if you need a method to start externally use this instead of the above line
this.start = function() { loop() }
//...
return this;
}
Now you don't need to bind anything and you access local scope which is fast.
And then call:
var class1 = new myClass();
class1.start();

How to Getting the Variable from Function in as3 without using get ,set method?

Hai am Getting trouble to retrive the values from function(addText).i Called from another function onFullScreen().I dont know how Can i do this,Kindly Help me?Here i attach my Code
private function addText()
{
nc = new NetConnection();
nc.addEventListener(NetStatusEvent.NET_STATUS, ncOnStatus);
function ncOnStatus(infoObject:NetStatusEvent)
{
trace("nc: "+infoObject.info.code+" ("+infoObject.info.description+")");
if (infoObject.info.code == "NetConnection.Connect.Success")
{
initSharedObject(chatSharedObjectName);
}
}
function formatMessage(chatData:Object)
{
trace("room"+chatData.message);
number = chatData.txtalign;//i want to retrive the value of number
number.toString();
return number;
}
function syncEventHandler(ev:SyncEvent)
{
var infoObj:Object = ev.changeList;
// if first time only show last 4 messages in the list
if (lastChatId == 0)
{
lastChatId = Number(textchat_so.data["lastChatId"]) - 1;
if (lastChatId < 0)
lastChatId = 0;
}
}
function connectSharedObject(soName:String)
{
textchat_so = SharedObject.getRemote(soName, nc.uri)
// add new message to the chat box as they come in
textchat_so.addEventListener(SyncEvent.SYNC, syncEventHandler)
textchat_so.connect(nc)
}
function connectSharedObjectRes(soName:String)
{
connectSharedObject(soName)
trace(soName)
}
function initSharedObject(soName:String)
{
// initialize the shared object server side
nc.call("initSharedObject", new Responder(connectSharedObjectRes), soName)
}
}
i using the variable in another function ,but I cannot retrive the Value.
private function onFullScreen(event:FullScreenEvent):void
{
mediaContainer.addMediaElement(alert);
alert.alert("Error",number);// if i cannot retrive the value hnumber here
}
The addText() method is asynchronous, meaning that you can't simply call it , you need to wait for the event listener to return a value.
I'm not sure why you would feel the need to enclose all these functions, it's not very legible and I doubt it's necessary. You're also missing quite a few semi colons...
In any case , I couldn't see where the formatMessage() method was called, it seems that's the only place where the "number" variable gets defined.
You could create a variable outside the scope of the functions.
private var num:int;
Then in your addText function, assign a value to the variable:
num = infoObject.info.code;
Then in your onFullScreen function, access the num variable:
alert.alert("Error", num);

JSLint writing constructors that reference static variables

I'm writing a display class in Javascript (using jQuery) which may be instantiated before a web page has loaded. If the page isn't ready when the constructor is called, the instance is added to a static instances field for the class, which is iterated over when the page has loaded:
function MemDisplay(ready_callback) {
this.readyCallback = ready_callback;
if (MemDisplay.ready) {
this.linkToPage();
} else {
MemDislay.instances.push(this);
}
}
//this makes sure that the ready callback can be sent when the page has loaded
MemDisplay.ready = false;
MemDisplay.instances = [];
$(document).ready(function () {
var i;
MemDisplay.ready = true;
for (i = 0; i < MemDisplay.instances.length; i += 1) {
MemDisplay.instances[i].linkToPage();
} });
//example truncated for brevity
When I run this through JSLint, I get this error:
Problem at line 25 character 9:
'MemDislay' is not defined.
MemDislay.instances.push(this);
I need to reference MemDisplay.instances in the constructor, but the constructor is where MemDisplay is defined, so I'm puzzled about how to make this work while fitting within JSLint's guidelines. Is there a better way to do this? Should I just ignore JSLint in this instance?
JSLint here is actually highlighting a broader issue with the code without saying so.
You are referencing a class (MemDisplay) but never instantiating it as an object. I.e. you are treating the class like an already-instantiated object.
I've created a very simple equivalent to what you are trying to achieve (also at this JSFiddle)
function MyClass(p1, p2){
this.param1 = p1; //class member/property - use this to access internally.
if (this.param1 === 1){ //you might want to consider doing this as part of some setter method
alert("test");
}
this.MyMethod = function(){ //class method/function
alert("MyMethod Called");
};
}
var myObj = new MyClass(1,2); //instantiate
alert(myObj.param1); //get value of object member (you can set as well)
myObj.MyMethod(); //call a method
It'll take a bit of reorgansiation, but by declaring the values up front, you can get make JSLint happy.
My brain must have figured this out while I slept: the trick is to attach the field to the prototype, which seems pretty obvious now that I've thought of it, since that's what you have to do to define class methods.
The following checks out in JSLint, and demonstrates the sharing of a field between all instances of MyClass (or see this code on jsfiddle):
/*global alert */
function MyClass(name) {
this.name = name;
MyClass.prototype.field += 1;
}
MyClass.prototype.field = 0;
MyClass.prototype.myMethod = function () {
alert(this.name + "'s class's field is " + MyClass.prototype.field);
};
var myObj = new MyClass("first");
myObj.myMethod();
var myOtherObj = new MyClass("second");
myObj.myMethod();
myOtherObj.myMethod();
I'm not sure if there's a prettier way to do it, as having 'prototype' all over the place feels a bit excessive, on the other hand it could be a good thing because it makes it clear that prototype.field does not belong to the instance.