Frustration w/ my first AS3 project - outside/inside/where am I?

So – I’m working on my first AS3 project, and it’s frustrating me to death. I’m not an OOP programmer, but I’ve been working on AS2 projects exclusively for 2 years. Just never did my work in classes up until now. Sadly, this changeover to AS3’s straight up OOP way of doing things has made me technically a week late on a project. But I’m trying to get it right.

I think I’m NOT doing the “outside looking in” thing that Senocular talks about right – the whole encapsulation angle.

I’ve built a project that I can’t post here (it’s work stuff, so I can’t really post a generic sample) where I have a document class (Shell.as) that loads a navigation sprite class (Navigation.as) that uses a nav button tab sprite class (NavTab.as) to build 3-tab horizontal navigation for the widget in question. I’ve placed the MouseEvents on the instances of NavTab.as, and now I’m finding I’m going to have duplicate those at the Navigation.as level and then pass them again to the Shell.as level so that the Shell.as functions for loading a particular tab’s content will work.

I feel like I’m outside, looking in, like Senocular recommends, but then I’m bringing everything that I found inside and bringing it back to the outside (the Shell.as document class).

Any suggestions? If needed, I’ll post a sample here, but it’ll take me time to strip the proprietary stuff out of it.

Thanks,
IronChefMorimoto

It sounds like what you need is to dispatch an event all the way back up to Shell.as. The code is something like this:


//On the NavTab click function
dispatchEvent(new Event("myEvent", true)); //that 'true' causes the event to bubble, this is important

//then in Shell.as
stage.addEventListener("myEvent", myFunction);

That should work as long as the NavTab is part of the display list so that it will bubble up to the stage eventually.

Anogar – thank you for your reply. Lemme explain a little further, and you tell me if I have this right based on what you just said.

The Shell.as document class’ role, in my mind, is to load the high level stuff (configuration XML for the widget) along with visual class instances (Background.as – which loads up 3 bitmaps, Navigation.as – which loads up instances of the little NavTab.as button sprite class I mentioned already, and the various custom classes for the tab content – 3 different ones so far, as they each render different content).

What I’m having to wrap my brain around is, well, figuring out where to send all the events that matter to the user. If the user is waiting on something to load, do I send XML complete/progress events from TeamInfo.as (a tab content class) all the way back up to Shell.as listeners so I can do something with a Shell.as level preloader? Or do I drop a preloader down into TeamInfo.as, which means I have to do it 2 more times for the other tab classes.

With the navigation (tabbed – 3 tabs total) for the widget, I’m confused about how to best structure the Navigation.as class itself (the 3 tabs total) and the reusable NavTab.as button sprites. Do I put MOUSE_OVER and MOUSE_OUT events into the NavTab.as class? They don’t really carry any navigation information (i.e. where the user wanted to go) at that level, so does doing the bubbling thing you mentioned work? Or should I let them be strictly sprites with graphics that I’ve dynamically drawn and THEN use the Navigation.as class to render the 3 NavTab.as instances out and apply event listeners for MOUSE_OVER, MOUSE_OUT, and CLICK events? It’s 1 level closer, in my mind, to Shell.as, but it seems less reusable this way.

Thank you for chiming in – I have never been so frustrated with what I do for a living as I have this past week. AS3 just boggles the mind if you don’t really have a firm grasp of OOP – I understand how it works, but getting my brain into the who mindset of structuring what I hope is a clean, sensible OOP project just doesn’t seem to be happening.

That, and tracing Objects from my Output window show me 2.3 billion instances (exaggerating) of things that I’ve done so far.

Regards,
IronChefMorimoto

Just to put this project in perspective, I wrote on my cubicle white board:

“I HATE THIS PROJECT ON SO MANY LEVELS IT MAKES BUNNIES BLEED OUT THEIR EYES.”

I drew a crude Matt Groening-esque rabbit with empty eye sockets and eyeballs in his hands to make my point. I’m a developer too, so it’s a crap drawing, but it had enough emotion in it to impress my rather prudish design manager boss. He laughed. That alone gave me perspective on this AS3 stuff.

IronChefMorimoto

A standard way to look at this is the Model / View / Controller (MVC) pattern. It’s an important design pattern (or architectural pattern, depending on who you ask) and it can be helpful for getting your head around encapsulation and this sort of thing.

Alright, so the MVC pattern has three subsystems (I imagine that’s clear by the name). Lemme just briefly go over what each of them does:

The Model:

The model is your data. It stores it, protects it, and dispatches it. The model doesn’t know about your view or controller, it is ideally strictly encapsulated and totally independent. This way you can use this model with many different views and/or controllers without rewriting it, which is one of the main goals of OOP. The model should broadcast changes then they occur, it should not directly access any other class.

The View:

This is your interface, so in your example, the navigation and such. The big thing here is making sure that the view does nothing but handle visual components and the model data that it needs. (Nav names pulled from XML or something, for example.) It doesn’t edit that data, it just knows how to read the data when it’s given to it.

The Controller:

This is the “Shell”, in your example. It takes input and updates the model and the view as required, and passes information around in a useful fashion. If, for example, someone clicks on something in your View, and the Model must change, the Controller should relay that information.

Now, the model has to be totally independent, and can’t know about the view and the controller. The view knows about the model, because it listens for updates and it takes data from it, and the controller also knows about the model, because it has to make updates. Often you can even have your controller and your view be one and the same, that’s totally fine.

So, to answer your specific question, your XML Data events should occur in your model, then be dispatched to your controller / view. No direct interaction should occur in your model, it needs to just dispatch an event.

Does that help at all?

Navigation.as should probably be where your interaction is - the NavTab should just be the graphics.

[QUOTE=Anogar;2338329]Does that help at all?[/QUOTE]

This sounds familiar to the Friends of Ed description in their AS3 book – the section on multimedia.

Structurally, I have this sort of setup going on – I’ve highlighted what I think are the pieces of your structure – correct me if I’m wrong:

[LIST]
[*]Shell.as CONTROLLER? - Loads parameters from Flashvars in embed to determine file name/path to custom configuration XML file. Based on said parameters, loads XML file using a custom XML parser class that I developed (extends EventDispatcher) based on 1-2 threads here on Kirupa (with URLVariables functionality added on) - XML controls only high-level parameters, such as background image path, logo path, and sub-XML configuration file paths (there are 3 others – so everything isn’t in one large XML file). XML configuration also includes path to CSS for all text styles used in deeper classes. This CSS is loaded using a custom CSS parser (same sort of thing) and prepared at the document class level for passing on to other classes. Finally, Shell.as loads, through various private methods, the following:

[LIST]
[]Background.as VIEW (PARTIAL) - Receives logo/background image path parameters and loads them using BulkLoader class from Google Code (very handy).
[LIST][
]BulkLoader.as - Using this to load multiple bitmap images collectively and then reporting the readiness of the Background.as instance back to Shell.as.[/LIST]
[*]Navigation.as VIEW (PARTIAL) - Receives parameters for tab colors and labels and then dynamically loads/lays out instances of NavTab.as button sprite class:

[LIST]
[*]NavTab.as VIEW (PARTIAL) - Receives parameters from Navigation.as to render 2 sprite backgrounds (on/off states) and a textfield tab label. Also contains MOUSE_OVER, MOUSE_OUT, and CLICK event handlers, which I think is bad because I don’t want to pass navigation information that deeply down from Shell.as.
[/LIST]

[]GameDayTab.as VIEW (PARTIAL - 1 of 3 THAT CAN BE LOADED) - Shell.as passes configuration XML path to this class, and config XML for this tab content instance ONLY is loaded, including: 1 “schedule” XML feed for rendering 2/3 of the content in the tab; 1 “weather” XML feed for rendering the other 1/3 of the tab. There’s some dynamic content based on what the 2 feeds bring in, but nothing interactive here.
[list][
]BulkLoader.as - Going to use this here to load the 1 configuration XML file, 2 XML feeds, and up to 7 related thumbnail images.[/list]

[]TeamInfoTab.as VIEW (PARTIAL - 2 of 3 THAT CAN BE LOADED) - Shell.as passes configuration XML path to this class, same as before. This is the only data loaded, part of which is an image path that I drop into an HTML text field to be rendered in the tab content area.
[list][
]XMLParser.as - Single file XMLParser (not BulkLoader) that I wrote loads XML for this class – the configuration XML file only.[/list]

[*]NewsTab.as VIEW (PARTIAL - 2 of 3 THAT CAN BE LOADED) - Shell.as passes configuration XML path to this class, same as before. Based on this configuration XML file, an external RSS feed is loaded and rendered as text links, along with the rest of the configuration XML data.

[list][*]XMLParser.as - Single file XMLParser (not BulkLoader) that I wrote loads XML for this class – loads the configuration XML and then an RSS feed based on that.[/list]
[/LIST]

[/LIST]

So…did I completely BLOW that model you mentioned?

IronChefMorimoto

Your encapsulation might not be totally right, but it should work fine. Which part are you having issues with?

I think my “model” – the data side – is not all in one place. In each of the tab classes, I load tab-specific data for processing and rendering.

Biggest conceptual issue - where to send events up to the Shell (the controller) for things like loading different instances of tabs based on a selection from Navigation.as, progress/complete events from Background.as, tab classes loaded XML, Navigation.as firing off click events.

You tell me – is it BAD to have these “view” classes like Navigation.as, tab classes, and Background.as “bubbling up”, as it were, dispatched events to handlers at the Shell.as level? To me, that seems like I’m going backwards – getting NavTab.as to send a CLICK event to Navigation.as which is then passed up to Shell.as to determine which tab to load. Before you recommended that Navigation.as handle buttons (and NavTab.as just handle the graphic rendering), that’s what I was going to do, begrudgingly.

If my XMLParser.as class that I re-use a few times in the 3 types of tab classes passes up COMPLETE and PROGRESS information, is it inefficient for GameDayTab.as to then hand-off the exact same information up to Shell.as so I can facilitate an app-wide Preloader.as or Error.as? To handle app-wide loading and error issues?

If that’s standard practice, then I’ll do it. My point being – I want to do this first project right and break my brain of the chains of uncertainty (even if just a little) about how to be “outside looking in” and thinking in the right AS3 frame of mind.

Thanks, dude. You’ve been a great help so far. Hope others are benefiting from this discussion.

Regards,
IronChefMorimoto

I can see how that would be a little confusing. The whole “outside looking in” thing (encapsulation) is not broken by event listeners. That’s the nice thing about them - they’re a way for your navigation class to say to your shell class, “Hey, the user just clicked”. It doesn’t dictate what the shell does it with, it doesn’t even dictate that anything at all happens, it just sends the event out, and other classes can choose to listen or not listen for that event - nothing is forced.

Your nav doesn’t care what is done with the event, see? The shell is still independent, it does whatever it wants with that event, thus maintaining the encapsulation. An example of bad encapsulation would be if your Navigation class called a specific method in your Shell class. That makes it inflexible, and it breaks the encapsulation.

Thank you for clearing up the listener issue. I will move the MOUSE_OVER, MOUSE_OUT and CLICK events up to the Navigation.as class and let NavTab.as just be a visual class for rendering the tab navigation assets. This way, I also won’t have to use the bubbling trick you mentioned earlier to get CLICK events from a NavTab instance all the way back up to the Shell.as “controller.”

IronChefMorimoto

Sorry to butt in, are you talking about a senocular tutorial or just what sen says on the forum?

I’m making the transition to AS3 too, and I’m having trouble thinking in terms of OOP.

There’s a thread (either in the “tip of the week” thread or one where Senocular replies directly) where he talks about the whole encapsulation thing (“outside looking in”). I’m pretty sure it’s in the tip of the week sticky here on the forums.

IronChefMorimoto