Array and EnterFrame eventlistener - actionscript-3

I have a problem that I hope you can help me resolve. I made that code:
var dates_array:Array =[y1,y2,y3];
var i= 1;
for each(var dates_sym:MovieClip in dates_array){
dates_sym.visible=false;
};
france_map.addEventListener(Event.ENTER_FRAME, fnCheckDate);
function fnCheckDate (evt:Event):void{
var i = france_map.currentFrame;
}
function fnDateSym (evt:Event):void{
dates_array[i].visible=true;
}
It is supposed to make a symbol (y1, y2 or y3 (there are more symbols, but didn't put them in the code for clarity) appear depending on what frame the main symbol is. When I compil, it shows no errors, but when I try it in my app, nothing happens.
I'm still a beginner, and I really don't see what's wrong.
If you need more context I can give it. Thanks in advance.
Jeryl

Your fnCheckDate function is called on enter frame, but that function never does anything except setting i. The other function - fnDateSym - sets the visible property based on the value of i. Which is what you want - but fnDateSym is never called anywhere in your posted code.
That may just be because you've left out some code. I'm guessing you might be calling fnDateSym from elsewhere and expect it to use the global i, as set by fnCheckDate. And yes, it will use the global i. But fnCheckDate doesn't set the global i:
var i = france_map.currentFrame;
The var keyword declares a variable within the current scope. A function creates a new scope. In other words, you're declaring a variable i local to your function and assigning the currentFrame value to that - rather than to the already existing variable i in the global scope (var i = 1). When your function exits, the local i is "lost" - and the global i hasn't changed - it will still be 1.
So the quick fix is to simply change it to:
i = france_map.currentFrame;
Now you're not declaring a new variable, but rather setting the value of your global i variable.
ETA: A bit of "teaching you how to fish rather than giving you a fish"... An easy way to debug these kinds of issues is to check the value of your variables using the trace function. For example:
function fnDateSym (evt:Event):void
{
trace("i is:", i);
dates_array[i].visible=true;
}
Now, if you don't see any traces in the output window that means your function isn't called at all. If you constantly see "i is: 1" then you know that i doesn't change and that this is the root of the problem. You could just use trace(i) - I just tend to add some kind of text to the trace - makes it easier to tell what each line in the output is, when you have more traces.
Unrelated, just a bit of code review...
Note that ENTER_FRAME is triggered on every frame refresh. I.e., it doesn't mean "when I enter a new frame on the timeline". It simply means, "when a frame is drawn in the player". In other words, it's called 24 times per second - or whatever frame rate you've chosen in Flash - no matter if currentFrame doesn't change (e.g. because you've called france_map.stop()).
This may be fine in your case - after all, setting visible to true 24 times per second doesn't actually cause any side effects. If you're doing more than that, however, it may be wasteful - or it may cause unexpected issues, since it's called more often than you really want.
One way to make something similar to a "enter timeline frame" event would be:
var previousFrame:int; // used for storing the last currentFrame we encountered
mc.addEventListener(Event.ENTER_FRAME, enterFrameListener);
function enterFrameListener(event:Event):void
{
// Are we on a different frame than last time?
if (previousFrame != mc.currentFrame)
{
currentFrameChanged();
previousFrame = mc.currentFrame;
}
}
function currentFrameChanged()
{
// Do stuff that should be done when the current frame changes
// - rather than on every frame refresh.
}
It's hard to tell exactly how you're doing things (again, because it seems a call to fnDateSym is left out) - but depending on how fnDateSym is called, mostly you wouldn't need fnCheckDate at all. Just do:
dates_array[france_map.currentFrame] = true;
Other than that, just for "niceness", you may want to declare the type for i:
var i:int = 0;

Related

AS3 extra information and properties of array included in for loop

Using Flash CC
I have the following array. The first key retrieves the string "Fish" from another array.
static public var comboType_1:Array =
[Constants.level_Data_Edible[Constants.currentLevel],"Frog"];
When I try to iterate over this array with
for(var i:String in hint)
trace(hint[i]);
I get this result:
Fish,
Frog,
function Function() {}
I debug it, it shows the array length is 2.
I googled the function Function() {} and it produces zero hits on Google.
No one has ever heard of this function Function() {} error.
There is no third index, you can see in the array. This error prevents me from iterating over the array. #1065. Variable Function function () {} is not defined.
I'm pretty sure this is yet another Flash bug, but I just want to know the workaround.
Look it is clear that you have discovered how useful static variables can be and you use them as global variables all over your app but since you do not understand when those static variables are instantiated you are running into troubles. If you prefer to blame everything on the technology itself suit yourself but that won't fix your problem and won't make you a better coder. static variables are instantiated prior to anything else in your app so for example using another static variable like that one:
Constants.currentLevel
Is likely to produce error cos whatever the currentLevel is will be ignored anyway. Anything labelled 'current' is a red flag when instantiating static variables cos when static variables are created there's nothing current going on.
The result you are getting and the code you are showing do not match and you only do that on purpose to prove your point. You could show the whole code but you won't cos you know very well that the true mistake (your own code) will be pointed out.
Stop feeling sorry for yourself, stop blaming anything but yourself and post a real question with real code so we can show you where your mistake is.

Actionscript 3 - How to access integer variable in main timeline from inside MovieClip

First, sorry if my english is bad and I'm new to Actionscript 3.
I have a movieclip, I give it an instance name "symbol1" which include a code inside it, like this :
var a: int = 2;
var b: int = 3;
var total: int = a + b;
How can I access the "total" integer variable inside that movieclip in the main timeline? I try to trace it but the result is 0. In the main timeline I wrote this code :
trace(symbol1.total);
I appreciate the help, thanks
The "problem" is the order of execution of frames. The parent is executed first.
The value is 0 and not undefined because the property does indeed exist since the creation of the object which happens in a previous separate step.
You should be able to verify that by stepping through your code with the debugger.
I've made 6 games. each game is in the MovieClip including the game functions, times, scores, variables, etc. I want the total score of each game summed outside each MoviClips, which is in the main timeline. is there a solution to that problem?
This makes your timing problem even more apparent.
You arrive at a frame, which contains a game and you immediately want to access the total score of it. It should be obvious that the game first has to be played in order to obtain a score from it.
Asking a newborn baby what his favourite moment in the first 60 years of his live was doesn't make much sense.
You have to notify the main timeline that the game was finished. The best way to do this is to dispatch an Event from the game. Frames are totally unnecessary.
Your code could look something like this:
var game:Game = new Tetris();
addChild(game);
game.addEventListener(GameEvent.FINISH, onFinish);
function onFinish(e:GameEvent):void
{
trace("finished game with score " + game.score);
}
If you want to update the exterior score sum while the game is running (to immediately reflect any change in the score, not just when the game is finished), your best bet is to create a ScoreModel for the score which you pass to the game, the Game. The Game modifies the ScoreModel, which in turn causes it to dispatch Events:
var score:ScoreModel = new ScoreModel();
var game:Game = new Tetris(score);
addChild(game);
score.addEventListener(Event.CHANGE, onScoreChange);
function onScoreChange(e:Event):void
{
trace("score changed to " + score);
}
Both examples are "what your code could look like"-type of examples. There are many questions about how to dispatch events that explain how to do this in more detail.
Something that came up in the comments from #Jezzamon:
I'm pretty sure you're accessing the variable total correctly, otherwise I would expect it to cause an error (you can test this by trying to run trace(symbol1.variableNameThatDoesntExist)).
No, there cannot be an error for accessing a variable as seen in the question. The reason for that is that the property is accessed on a MovieClip object, which is a dynamic class. As such, the compiler doesn't know if accessing a particular property is valid, because that can change at runtime. And because nothing else relies on the value to be valid, there isn't a runtime error either.
Here's some example code to illustrate this:
trace("toString: " + {}.toString); //toString: function Function() {}
trace("bananas: " + {}.bananas); //bananas: undefined
This is one of the reasons why using MovieClip can be a bad idea. In addition to that, the Flash IDE modifies the code behind the scenes. That can lead to unexpected execution of code. A purely code based workflow sure is advantageous in this regard and recommended.

how to solve variable has no type declaration warning in flex / as3

I came across this code snippet online that helps me solve a problem with a simple way to delay a piece of as3 code.
It runs fine and does the job, but I get a warning in flashbuilder / flex that says:
variable 'delayTextVisible' has no type declaration.
here is the code snippet:
var delayTextVisible = setInterval(showText,400);
function showText():void {
textgroup.visible = true; // insert delayed code here
clearInterval(delayTextVisible); // stop setInterval repeating
}
so my question is what type do I need to assign to the variable delayTextVisible for the warning to go away? I tried :String but that didnt work.
var delayTextVisible:uint = setInterval(showText,400);
setInterval return type is uint. see a documentation: setInterval
#bitmapdata.com's answer is correct.
However, in any case and for any variable, if you don't know its specific type, or if you need to declare the variable in a way that allows you to store many different types, you can always use the * placeholder:
var delayTextVisible:* = setInterval( showText, 400 );

AS3 - stop onEnterFrame Function from constantly running

Okay, I have a collisionTest function that is tied to my "onEnterFrameHandler" function.
So to simplify the way it looks:
onEnterFrameHandler(e:Event):void{
testCollision();
}
testCollision():void{
trace("always running");
if(1_MC.hitTestObject(2_MC)){
//do stuff
}
}
The thing is, it is always running. Constantly running in order to test for a collision. I have a feeling that it is what may be causing the lag on this project.
Do you know of a good way to control a function that needs to be able to check, at any time, an event, yet not run while the even is not occurring?
Usually you are always checking for collisions in a game loop. You provide a flag to indicate if something needs to be checked or not.
On a side note, consider using collision detection kit, I think you'll find it takes care of just about every scenario you can have regarding collisions.
It's hard to answer this question as it is pretty vague when you're not checking for collision. To improve the performance it's not about changing how to collision test, but when to do the check.
so you could do this by simply adding an if statement like so:
if (doCollisionTest){testCollision();}
but that doesn't solve when doCollisionTest is true or false, and that's the tricky part, that cannot be answered from the information you provided.
If you don't need to check every single frame, you can use a Timer to only check as often as you like, for instance, if you deemed it good enough to check 3 times per second, you'd set it up like this:
var timer:Timer = new Timer(333); //run 3 times a second
timer.addEventListneer(TimerEvent.TIMER, collisionTest, false, 0, true);
timer.start();
function collisionTest(e:Event = null):void {
//do you collision stuffs
}
Then, if for whatever reason you want to temporarily disable it, use timer.stop() , then timer.start() again

Access of undefined property data flex

I'm learning flex/flash and I'm lost on this one. I have used the "data" in a bunch of views and it works fine. For some reason it isn't working here.
I set a field to a string here:
function LoginLoaded (e:Event):void {
trace(e.target.data);
var ServerReturn:String;
ServerReturn = new String(e.target.data);
data.UserCommonReturnData = ServerReturn;
navigator.pushView(CommonPlaces, data);
}
and here in the common places view I try to load it back:
var CommonPlacesData:String = new String();
var CurrentSelect:String = new String();
CommonPlacesData = new String(data.UserCommonReturnData);
This gives the error "Access of undefined property data" I don't get it because calling on something like data.PickUpTime (also a string) works fine in other views.
The data begins in the first view like this:
[Bindable] public var User:ObjectProxy = new ObjectProxy();
User.ID = "2314084";
navigator.pushView(TaxiNowOrLaterView, User);
then in later views I call on it like this: (works fine)
var PickUpString:String = new String(data.ID);
Any help would be great!! Thanks!!!
There are few things about your code. First, you really should make it a habit to name the identifiers as appropriate to the language. Identifiers that start with the capital letter and subsequently use minuscule letters for the rest of the logical part of the word (system alternatively known as PascalCase) is employed to only name classes. The rest of identifiers should use camelCase (similar to PascalCase, but the first letter isn't capitalized)**. This greatly reduces the effort at understanding your code. A seasoned AS3 programmer would interpret your code as follows:
// Static constant (!) ID of the class User is assigned (?) a value of "2314084"
User.ID = "2314084";
// invoke a method pushView of a local variable navigator with arguments
// of which first is the class TaxiNowOrLater, the second is the class User
navigator.pushView(TaxiNowOrLaterView, User);
while, perhaps, you didn't mean it.
new String();
In the context of AS3 makes no sense at all. Strings are never references, are immutable and have literal syntax the majority of programmers agreed upon. The code above is identical to "". In the similar way, new String(anotherString) has exact same effect as anotherString.
Your question: event.target may be many different things, some of them may have property called "data" and some may not. The general approach to this problem is that you need to cast the value of event.currentTarget or event.target to the type you expect to dispatch the event. Suppose you are expecting an event from an instance of a Button class, then:
private function clickHandler(event:MouseEvent):void {
if (Button(event.currentTarget).enabled) // do things
}
This will not protect you from an error, if the same event was dispatched by an object, which is not a button, but will make the error reporting more conscious, because it would tell you what class was it trying to cast to what other class, when it failed.
If your program logic requires that the handler be aware of events it shouldn't handle (why?) you could then write it like this:
private function clickHandler(event:MouseEvent):void {
var button:Button = event.currentTarget as Button;
if (button && button.enabled) // do things
}
event.target vs event.currentTarget - very-very rarely you would need the event.target, most of the time you need the currentTarget. I'm not saying it is wrong, but, it looks like it might be the problem. target is the object that was the first cause of the event. Events may bubble, which means they may travel the display list hierarchy up and down, first from the parent to child, then in reverse direction. In the example below, suppose there was a label on the button, which was clicked once the event was generated - in such case, even if you added a listener to the button, event.target would be the button label, not the button. currentTarget is, on the contrary, the immediate object which dispatched the event into the handler.
Few more things: ObjectProxy is an idiotic class, you probably shouldn't use at any event. It serves no purpose and, perhaps, buggy, but very few cared to discover its bugs so far. In a nutshell, what it does is as follows: it creates an object, which "watches" dynamic creation, assignment and removal of its properties and dispatches events when these events happen. This behavior is prone to a lot of errors and implicit bugs. For example, is foo.bar = "baz"; foo.bar = "baz"; a reassignment of the same property or not? Is foo.bar.baz = "fizzbuzz"; a modification of foo.bar? What if property name is not a sting? And so on.
Why you shouldn't use it: there is always a better way to treat your data. A more transparent, easier to debug, more efficient. This class is a prototype, which had never really worked. Besides having the behavior described above, it is huge in terms of lines of code that were used to write it. Debugging the errors that happen inside of it requires a lot of time and patience, which are certainly not worth it.
If you need an object to represent a user, define a class, with properties you expect the user to have and just use that class - this will make debugging and understanding your code much easier.
[Bindable] metadata is evil. I can't tell you you should avoid it, because it is used too often, but, I will. You should avoid it as much as possible. I didn't yet encounter an instance of when the use of this meta would be justified. Much in the similar spirit as ObjectProxy it is a prototype, something designed for lazy programmers w/o much consideration for either performance or corner cases. This is, again, a source of a lot of implicit bugs, typically difficult to spot due to the code generated around this meta "swallowing" the errors. The alternative to this meta is plain addEventListener(...) code with custom events.
Unfortunately, a lot of tutorial will use this kind of code to have you quickly started with the language + framework...
** there are some exceptions to this rule: constants are all upper-case and namespace names use underscores to separate the logical part of the word, but never use uppercase letters.