use class to handle mutiple nested movieclips and their specific events - actionscript-3

I have a menu with five buttons. Menu is visible all the time. there is click event for each menu item. which slides corresponding movie clip from left to right. each movie clip has different nature events and respective animation and activity. for example tab 1 brings the video page. and within that movie clip I have video events like play pause volume and on complete etc. events and code. tab 2 has button group for Time and another button group Features. depending on user selection code will calculate and show value on a animated counter. tab 3 has button group for Time and button group Source. as per the user selection it will calculate and show the values as animated graph. and so on.
Right now I have all the individual tab movie clip has its own time line code for its own events. and some crossover variables and references with other tabs. Everything is working as expected. No problem. I know time line code is not the best way to do any complex project.
So, I would like to get the entire coding as one class or more classes if that is the correct way.
I am beginner as far as class logic. I have already created Main as document class and could control the general navigation of tabs and their initial look. But stuck at tab specific button events and other such unique events for the specific tab.
Any help is greatly appreciated. Thanks in advance.
any similar example or suggestions.
First of all, thanks a lot for a prompt response. It seems like I am not even a beginner. I need to read a lot and probalbly grasp all fundamental concepts thoroughly. I have gone through both the links suggested in your comments. I am trying to digest the stuff slowly. I do not have any formal informal education regarding OOP or any sort of programming. To be honest, I have hard time understanding the code you have suggeted. Not because of your code but because of my level of caliber. I will have to spend some time to make myself clearer regarding events and sequence etc. different tab contents are as movieclips to main timeline and already placed on stage. It comes and goes to its corresponding tab button click event. I am not marking your answer as yes because I still need to my own homework based on your suggestion. Thanks a lot once again. I am sure I will ask few more questions later.

This is how I would design it:
I'd have a Menu Class, which only contains the buttons and "converts" clicks on them into more specific events. That might look something like this:
public Class Menu extends Sprite {
protected var buttons:Vector. = new Vector.();
public function Menu() {
super();
var loops:int = numChildren;
for (var i:int=0; i<loops; i++) {
var button:SimpleButton = getChildAt(i) as SimpleButton;
if (button) {
buttons[buttons.length] = button;
button.addEventListener(MouseEvent.CLICK, broadcastMenuEvent);
}
}
}
public function broadcastMenuEvent(e:Event):void {
var button:DisplayObject = e.currentTarget as DisplayObject;
dispatchEvent(new Event(button.name, true));//bubbling, can catch at any level
}
}
The way this is built, you can change the events that are being dispatched simply by changing the name you give the instance of the button on stage. Note that you need to apply Menu as the Base Class and not the Class for this to work if you have "declare instances automatically" unchecked, because doing it that way allows the compiler to generate those instance names for you in a way your base Class doesn't have to know about.
At this point, you can then deal with those events in another place--whether it's your main document Class or whether you have a separate Controller.
I would define each of the Views you described as a separate Class as well. If you have objects coming and going on the stage, you can use one of the techniques described here to handle that. Otherwise, it's fairly straightforward to address your timeline instances from the base Class instead of timeline code. Again, you can listen for those events in the main document Class or a dedicated Controller--the main point is to make sure your Views are not making any important decisions and usually they should not be editing data.
You can choose to have your Main Document orchestrate how the tabs get added and removed (I'm a big fan of using the timeline with goToAndStop, but not everyone shares this preference), or, again, you can separate this logic out to a dedicated Controller. I would suggest that if it's possible to generalize how your Views work to have them implement a single Interface. That way, you can give them a single instance name and manage them all with the same getter/setter pair (assuming you go the timeline route).
Note the Flash compiler isn't terribly sophisticated in this regard, so if you do this and your Views extend different parent Classes, you'll get compiler warnings. Just ignore these--they don't mean anything.
The thing you shoud try to root out of your code completely is the part where Views are referencing each other. The only time it's acceptable for one View to know about another is when it's a parent knowing about its child. Even then, try to have as little specific knowledge as possible. Notice in the Menu View I wrote as an example, the parent only knows there may be some SimpleButtons, but it has no specific knowledge of where they are on stage, what, specifically, is in them, or even what there instance names are.
Instead of having your Views know about one another, have a third party (which, again, you can choose to use the main Document Class for or not) that transfers requests for state changes (in the form of events) from one to another.

Related

as3 how can i prevent that a new instance is created by entering a frame?

i am working with several nested movieclip objects in a project. but i get into trouble with the buttons i created and implemented in the nested movieclips:
to describe it in a simple way:
I have a main movieclip with five frames, including two buttons with listeners to browse between the frames. Then inside of one Frame I have another movieclip with its own buttons. i instanciated it by hand not through code and gave it a specific name like "nestedMc".
Now I dont want to build the Listeners for those buttons inside the class of the nested movieclip class but in its parent class, which works fine until i then goto another frame in the main movieclips timeline and come back.
obviously every time flash enters a frame its contents get created anew (and therefore get new instance names). I could now try solve this through filling the frames via code.
But maybe there is another way to make sure the frame contains the same instance everytime i enter?
Timeline scripting is a dirty business, and really, a carry-over compatibility layer for Actionscript 2 projects. Whenever possible, I highly recommend not doing it, and simply keeping all of your code in your document class. As you're experiencing, timeline code causes headaches.
Consider instead just creating both states of your Stage (it sounds like that's what your two buttons are jumping between) and simply hiding them offstage or setting their alpha to zero and their mouseEnabled state to false. Furthermore, if the purpose of your frames is to play animation (a tween), consider instead switching to a much more powerful suite such as TweenLite. Moving an object over a hundred pixels (smoothly) can be as easy as:
TweenLite.to(redBall, 3, {x:100});
Now, if you're manually adding these items to the stage, as long as the object is a dynamic one, you can assign an instance name to it which will be saved between frame loads. Be aware the object name is not the same as the instanced name. For example:
var redBall:Ball = new Ball();
redBall.name = "bubbles";
The object's name is Ball, but it's represented as a variable called redBall. Its actual DisplayList name will likely be ambiguous (such as "Instance71"), and I can manually define it as "bubbles". 3 different names for the same object, all very different and necessary.
Even if you give the object a displayList name, you may not be able to reference it through code unless you enable Automatically declare stage instances, which basically creates on each object a pointer to the displayList object.
That said, you can always fetch the object by other means. Obviously, your buttons are always appearing, but you're trying to find a very specific object on the stage. At this point, we can use getChildByName() or getChildAt().
Hope that helps.
-Cheers

AS3 How to communicate between frames

I have been writing a game in timeline code. I want the different frames (rooms) in the game to be able to share information between each other. Of course, timeline code is limited to the frame it is written in.
After doing quite a bit of reading ("Foundation Game Design with Flash" and a number of articles, tutorials, forums etc) I decided to employ a document class. This did not work either. It seems it only works for frame one but not the rest of the frames (I have four).
How can I have frame four respond to something that happpened in frame one? For example, if the player achieves something in frame one, I want a movie clip in frame four to be visible.
If You are writing your code on the timeline, My suggestion would be to create two layers in the timeline, one for 'frame-actions' - in this layer you insert the code specific to a single frame (will work when the movieclip is stopped on that particular frame).. And also create one more layer called global-actions (for the entire timeline). Only the first frame will be a key frame and there should be empty frames till the end of the timeline.
In this layer actions write the code that you want to access from any keyframe in the same timeline.
If you define a variable in the actions which are written for the whole timeline (global-actions) then that will be available on all the frames.
Now if you want to go to a different frame based on some action, just write some functions in the layer which contains global actions and call that particular function through the frame actions. To go to a different frame use the 'gotoAndStop(frameNumber)' function of flash.
I want to tell you that while it will work, I would not recommend using it in this way.
HTH.
You can use static variables - these are variables which are linked to a class, rather than an instance of it.
Suppose your document class was called Document.as, and you wanted a variable, playerLives, to be visible from any part of the program.
Declare it inside Document.as:
public static var playerLives:int = 3;
You can then reference this directly from anywhere else in your code with:
Document.playerLives
(note that the variable is a member of the class itself, not an instance of it).
You could use a dedicated Statics class to hold these variables if you want to keep your document neat, or attach them to the relevant classes (eg Player.lives)
I've not used timeline/frames for some years but I believe this is how I used to do it!
NB Statics will be fine for your purposes but they are, in some ways, an equivalent to the _global variable in AS2 (at least, they can be used in the same manner) - many would not approve of their use, or over-use, as they are freely accessible from anywhere in your program (thus anathema to the OO concept of encapsulation), but personally I try not to worry about it in small cases - the most important thing to know about the rules of any design pattern is when they can be broken!
They are also slightly slower to access than instance members, but you won't notice this unless you are constantly accessing/changing them (making things like player velocity, which will need to be referenced/changed every frame, static, is not a good idea).
Hope this helps.
You may find the simplest way to link everything with the document class is to move your four frames into a movieclip together and have that on the first frame, then interact with that movieclip.
E.g. in the document class, where the movieclip instance on the timeline is called 'game'.
game.gotoAndStop(4);
game.objectToDisplay.visible = true;
If you encounter reference errors in the IDE then you can avoid these by using [] notation to refer to the properties of game, e.g. game["objectToDisplay"].visible = true;
Note that it's not really best practice to do this, but it will at least help you to finish that first game which is really more important at this stage in your learning. Afterwards, if you want to learn more then I'd recommend "The Essential Guide to Flash Games" by Jeff Fulton from 8bitrocket.com - it will teach you how to use the document class effectively.

Can two buttons with the same class instance act differently in Flash?

Say I have this specific button class in Flash called cont_button and it's supposed to be used to break out of a loop, but I want to use the class more than once. Is there a way to give every instance of this class some kind of parameter so that it knows which frame it nees to go to?
Example:
I have an instance of cont_button on frame 200 and there's a loop between 200 and 210. This cont_button executes a gotoAndPlay(211). But later on I have another instance of the button on frame 315 and a loop between 315 and 325. Is there a way to make it so each instance knows which frame it specifically needs to go to via the use of a variable? Or am I going to have to make an actionscript file for each individual one?
Pretty new to ActionScript so I appreciate the help and if there are good coding references to AS3 you guys recommend, I'll gladly look those over.
Sure, this is possible. One way you can do this is make the frame numbers class variables and when the button is clicked, they reference whatever value is stored in them, rather then hardcoded numbers. To get a better idea, can you post the relevant parts of your button class?
As you say, you need to pass a parameter to each instance of the button. There are lots of different ways you could do this, but I'd be tempted to just do it via the instance names.
You could name each button loopBreakTo211, loopBreakTo326 and so on, then in your button's class have:
var breakFrame:Number = Number(name.replace("loopBreakTo", ""));
(parent as MovieClip).gotoAndPlay(breakFrame);
Admittedly that's not a very robust way of doing it (for example, it will break if a button is named incorrectly and breakFrame ends up as NaN, so you might want to add a check for that), but it keeps the parameter together with the instance instead of in the timeline somewhere.

How to updating JLayeredPane while the JFrame is running ? java

Having read many tutorials, articles and questions, I am still have confusions about updating the GUI. Plus there are numerous related questions here on this website and still no luck - even though I think my problem is very simple.
Basically, I have a JFrame that has a JLayeredPane as its root container. And I have some layers of JPanels inside it.
The main issue is with updating a particular JPanel in this JLayeredPane. And for this particular Panel, I have implemented an update method that changes the contents inside it.
updatePanel(int para)
//doesn't remove this panel
//removes some existing labels and replaces it with new ones
Once I create the whole Frame, obviously just calling this method won't show any change displayed the frame.
private void static main (String[] args){
WindowFrame frame = new WindowFrame()//WindowFrame extends JFrame
frame.updatePanel(2);
.....
.....
}
And that's where I am stuck. I want to update the contents as the frame is displayed.
I saw these methods mentioned by people but due to nature of problems, I couldn't fully grasped the concepts. Plus the documentation on these methods isn't really helping - at least to me.
revalidate()
validate()
repaint()
How/when should these methods should be called? Or is this not the right way of what I should be doing, given these methods and the problem I am trying to solve?
Thank you for your time.
Basically you need two methods:
revalidate()
This method does the same as invalidate() but in AWT event dispatching thread (i will just call it Swing thread later on)). It updates container and all of its ancestors (parent containers in which this one is placed) layouting.
Basically if you either move something inside this container or place/remove components inside of it you should call this method (or invalidate in case you are performing it in Swing thread, for example inside any Mouse/Action listener body or just inside).
repaint()
This method forces component, all its sub-components (if it has them) and parent container (basically if this component is NOT opaque) to update what they are "painting".
Usually you don't need this method since all standard Swing components know when to repaint themselves and they do it on their own (that ofcourse depends on components UIs and some other things). This method might be useful in case you have your own specific components with some unique painting-way (for e.g. some custom selection over the components) and in some rare problematic cases with standard components.
Also the way this method acts depends on the components placement (due to some Swing painting optimizations) - if you have some massive repaints rolling you'd better optimize them to repaint only those parts (rects) that you actually need to repaint. For example if you change the component bounds inside any container the best choice is either to repaint its old bounds rect and new bounds rect OR repaint rect that contains both of those bounds, but not the whole container to avoid repainting uninvolved in the action components.
So, basically in your case after some changes with panels you should call revalidate on their container (or invalidate) followed by repaint (in case revalidate leaves some visual artefacts) again for the container.
Guess i didn't miss anything and i hope that now you know the basic meaning of those methods.
revalidate at the end of your update method like so .
updatePanel(int para){
.....
.....
this.revalidate(); //of course this refer to the panel
parent.revalidate(); // parent refer to the window
}

symbols placed on the timeline become undefined if stepping backwards

I am using the frames in the timeline of a .swf as pages in a flash app. The user can advance to the next page by clicking a button that takes her to the next frame. Similarly, it is possible to navigate to the previous frame/page as well.
Most of the content is placed on the stage (i.e. created by dragging an instance of a library symbol to the stage) but properties of those instances, such as .visible might be changed via actionscript. Also, some objects are loaded from external flash files and displayed programmatically with addChild / addChildAt.
The problem is, if I am on Frame N+1 and there is an object displayed on the stage programmatically (i.e. with addChild, not by having it placed on the stage) and navigate to Frame N where there is an object that is placed on the stage (i.e. dragged from the library),
then the instance of that object is undefined/null and throws an error if I try to set its properties (like .visible).
The error does not occur if I am moving to the NEXT frame, only if I am moving to the PREVIOUS one. Therefore I assume that some kind of initialization is not getting called while going one frame back.
I was also thinking that the objects would just not "live" to the next timeframe, that is, their value would be lost and re-initialized because of scope, but if there is no dynamically created object on the stage, I can navigate back and forth just fine.
Is there a way to ensure that the objects created on the stage do not disappear while navigating back to the previous frame?
The first, and more useful, part of the answer is this: timeline keyframes and scripts can give conflicting information about display objects - whether they should exist, where they should be, and so on. For example, when you add an item by playing into its frame, and then delete it with script, and then play into its frame again. When this happens, there's no unambiguously correct thing for Flash to do, so it tends to be unpredictable. I believe what generally happens is that once you fiddle with a given object via script, it's considered to no longer pay attention to the timeline - but your mileage will vary.
Having said that, the reason things are different when you play backwards is the second and more arcane part of the answer. Internally Flash functions differently when seeking forward and backwards on the timeline. Flash internally treats keyframes as changes to be applied in the forward direction, so as you play forward, it applies those changes in sequence. When you move backwards, however, from frame N+X to frame N, it doesn't scan through the intervening X frames reversing those changes - it jumps back to frame 1 and fast-forwards along to frame N. Normally, it amounts to the same thing and you don't need to worry about it, but when you get into the twitchy area where scripts and the timeline have a different idea of what should be on the stage, you're liable to see things behave differently depending on which way you jump (as you are now).
The super-short version is, for things to work predictably, try to ensure that any given object gets added, updated, and removed the same way - either all via script, or all via the timeline. When that seems impossible, fiddle with your content structure - usually, the best solution is to change your object into two nested ones, so that the things you want to do with script occur one level higher or lower than the things you want to do with the timeline.
I'm not sure I got your question right, but as3 does not instantiate elements on the timeline as soon as you gotoAndSomething, but later that frame.
That is, you can't
this.gotoAndPlay(10)
this.elementOnTimelineFrame10.DoSomething()
without errors.
I remember using this chunk of code in the past to work around this problem. It uses the Stage.Invalidate() function to wait for an Event.RENDER before trying to access and children, more info (although vague as hell) is here
private function init():void
{
stage.addEventListener(Event.RENDER, stage_renderHandler);
}
private function stage_renderHandler(evt:Event):void
{
// Run your code here
updateChildren();
}
private function enterFrameHandler(evt:Event):void
{
// triggers the RENDER event
stage.invalidate();
}
This also might me very costly (performance wise). I would strongly advise against dynamically adding/removing objects to an existing timeline, is there any way in which you can place an empty Sprite above the timeline animation and use that for all your dynamic content?
Hope this helps