Monthly Archives: August 2010

Flash CS5 exports weird FXG

FXG is cool. I’m using it extensively in skins for Logicly, the Flex 4 app I’ve been building recently. However, there are some oddities, mainly around Adobe’s tooling support for it. Honestly, the output I get when I export FXG for a FLA in Flash CS5 feels downright messy. It’s all valid, of course, but there doesn’t seem to be much intelligence in the exporter. Let me show you an example to explain.

Here’s the FXG gets exported for a rectangle I drew using the Rectangle Primitive Tool in Flash CS5:

<Path x="-272" y="-108" data="M315 109 315 151 273 151 273 109 315 109">
    <fill>
        <SolidColor color="#FFFFFF"/>
    </fill>
</Path>
<Path x="-272" y="-108" data="M315 109 315 151 273 151 273 109 315 109">
    <stroke>
        <SolidColorStroke weight="2"/>
    </stroke>
</Path>

Here’s what bothers me about the output:

  • There are separate Path elements, one with fill and one with stroke, but the position and data of those paths are exactly the same. You can define both fill and stroke on the same Path element, so why litter my code with extra stuff?

  • Speaking of Paths, why is it that anything I export becomes a Path? It doesn’t matter if I drew a rectangle or an ellipse (both of which are supported by FXG), I always get a path. Actually, I think Flash can add things to objects drawn with the primitive tools that FXG may not support, like the line style (solid, dashed, dotted, etc.) or an inner radius on an ellipse, so it kind of makes sense. However, it would be cool if the exporter could detect that <Rect/> or <Ellipse/> would be okay in some cases. Isn’t human readability the point of XML?

  • Notice the coordinates. This path gets positioned at -272, -108. Then, drawing starts at 315, 109. Nowhere in the FXG do we see the point 0, 0. Why doesn’t this get normalized? I can’t imagine anyone picking arbitrary points like that. I’d either set x=”0″ y=”0″ or I’d include that position somewhere in the path’s drawing coordinates.

That said, it’s important to note that I’m still using the exported FXG mostly as-is in my Flex skins. I remove some of the Groups created for layers and do some binding here and there, but the path data and positions stay exactly the same. It’s not like normalizing them manually would change the way they look, so I just don’t do it. With that in mind, I guess the things I wish were different aren’t that important, but I still can’t stop myself from frowning at the generated FXG every time I have to look at it.

Flash Player for Android fullscreen mode, and why I'm frustrated by it

When you view content in Flash Player on Android, there are some special mobile-only features available. For instance, when you longtap a running SWF, a little overlay appears. It has a fullscreen icon that will work on any SWF. Similarly, there’s a new parameter, named fullscreenOnSelection that goes into your HTML/JS embed code. This one will automatically put the SWF into fullscreen mode as soon as the user interacts with it (basically, skipping the overlay). Both are great ideas for games and other app-like SWFs, except I’m not happy with the way they’re implemented.

The right way

When I have my own custom fullscreen button on the display list, Flash Player on Android will properly preserve my scaling preferences. So when I use stage.scaleMode = StageScaleMode.NO_SCALE and stage.align = StageAlign.TOP_LEFT, I can run my layout code again after entering fullscreen mode to make my content fill the screen entirely. That’s what I want under any possible condition where my SWF enters fullscreen mode. Instead, it only works part of the time.

Screenshot of Android phone with proper fullscreen scaling.

The wrong way

With those two new fullscreen features I mentioned earlier, things work differently than my custom fullscreen button. You press the fullscreen icon in the overlay, and my SWF grows to fit the screen. However, the stage size as I see it from ActionScript maintains aspect ratio based on the embed width and height, rather than giving me the new dimensions based on the screen resolution.

Screenshot of Android phone with incorrect fullscreen scaling.

I could live with this behavior, except for the fact that some of my content that should be hidden may now become visible to the user. When my custom fullscreen button is used, and when the SWF is embedded in the page, I control the entire area of my displayed SWF. Since I don’t control part of the screen now (anything outside the bounds of the stage, as I see it from ActionScript), there’s not much I can do to fix it. Maybe I could mask (or set a scrollRect for) the entire stage to hide the overflow, but that affects performance. On a mobile device, that’s unacceptable.

Uh oh… it gets worse

If the user doesn’t use the overlay fullscreen button, and only uses my custom fullscreen button, everything works fine. Yay! If the user goes into fullscreen mode using the overlay, exits fullscreen mode, and then they discover my custom button, fullscreen continues to act as if they used the overlay. In short, Flash Player on Android is being very inconsistent here. At least from my point of view as a developer, maybe not for the user. Regardless, it ruins the experience I’m trying to provide because I have trouble detecting that this broken fullscreen mode has been entered.

Conclusion

I sincerely hope that I will get more control over fullscreen behavior in a future build of Flash Player for Android (and other mobile platforms, as they’re added). At the very least, if I have to settle for something that isn’t ideal, I want be comfortable knowing that my SWF won’t be showing content or anything outside the known bounds of the stage. If I’m forced to guess if there’s content displayed that should be hidden, mobile Flash Player is doing something wrong.

Logicly is back. Shiny new Flex 4 version is simulating now!

Remember my logic gate simulator, Logicly? Well, after two years of interest from students, educators, computer architecture geeks, and a whole lot of people visiting from Hacker News, Reddit, and StumbleUpon (among many other smaller sources), I’ve decided this app has a proper audience. I’ve been working hard the last month or so rewriting it in Flex 4. Yes, working for oneself has advantages, like being able to convince your “boss” more easily when a rewrite is necessary. Of course, when budget time comes around (read that as “when I have to do some freelance work to pay the bills”), I might grumble that I didn’t get as much done as I hoped, but I still think breaking apart that prototype code and doing it right will be totally worth it. Without further ado, check out Logicly!

Screenshot of Logicly

Since @troygilbert asked nicely, I thought I’d do a little informal writeup on how I have things set up for this project. It’ll probably be kind of high level, with a few mini-dives, if I think something might be particularly interesting.

The Basics

Logicly is built with Flex 4. Everything is a Spark component with an MXML-based skin, except for the flexwires part which seemed a pain to rewrite. This is my first time properly building custom Flex 4 components, and I enjoyed the process quite a bit. I especially enjoyed being able to export FXG from Creative Suite applications to use in skins. The learning curve for me, an experienced Flex 3 developer, was mostly non-existent. I don’t remember anything tripping me up.

My current framework of choice is RobotLegs. The dependency injection is a joy to have around, and I like that it felt like PureMVC, except, you know, properly made for Flash. I still don’t know when I’d be likely to port my app to another language and want to use the “same” framework, but to each his or her own.

In the process of building Logicly, I realized that the RobotLegs Flex examples all use the main application as the contextView for detecting when components are created and stuff. The problem is that when you create something on the PopUpManager, you don’t automatically get a mediator because the PopUpManager is attached to something higher up the display list than the application. Instead, I passed in a reference to systemManager, and everything worked awesomely. A quick tweet about it got some attention, and a variety of shout-outs from the community. Sometimes it’s fun to shake things up a little.

Multiple Projects

Logicly is made up of several Flash Builder projects. There are two main Flex projects. One for the web version of Logicly and one for the desktop version. Then, there are a variety of Library projects where all the real magic happens. From a technical perspective, I’m not sure if I actually needed to do so much separation, but I think it definitely helped me to keep things loosely coupled in some places, which is a win in my book.

Let’s take a look at the various projects:

  • CommonLibraries contains the code that I reuse among all the other projects. My own personal library of utility functions is in there (math and drawing stuff mostly), along with the open source projects I use in Logicly, in either source and SWC form. For the SWCs, I just put them in a folder and use MXMLC’s include-libraries compiler argument to compile in everything from that folder.

  • Simulation handles signal propagatation among circuits. There is absolutely nothing visual in this project. It’s purely a model of the running circuit. In the prototype, the data was passed around through connections made in flexwires. That was a little too complex to maintain, in my opinion, and I like the fact that I could potentially reuse this library to view the simulation a different way in the future, or maybe to run sub-circuits in separate simulations.

    Rather than using Events, I use Robert Penner’s as3-signals to pass signal changes throughout the simulation. It’s mainly for performance reasons. I’ve seen some crazy stuff built with Logicly’s prototype and the signal propagation could definitely become a bottleneck in the right hands. I do not use signals anywhere else. I was tempted to use signals to communicate within RobotLegs, but it didn’t feel very important at the time, so I just stuck with the default events.

  • CircuitViews has all the Flex components I built for various types of circuits you can drag into the editor, plus their skins. I mainly separated this one from the next project, Editor, to keep compile times speedy. I’m not sure if it actually has any real impact of compile time, though. Honestly, it just seemed like a good idea at the time. At the very least, since Editor is a pretty big project on it’s own, it’s nice to pull some stuff out to make it easier to navigate that source tree.

  • Editor is the powerhouse of Logicly. This is the biggest project, and it contains the majority of the Flex UI along with the related RobotLegs code. Basically, it’s everything that is shared among the desktop and web versions of the app.

    I tried to find as much common ground as possible to avoid duplicate code. This led to some interesting things like a service in the web app that rather than saving or loading files, displays modal windows on Flex’s PopUpManager (to tell the user that these features are disabled and to ask them to sign up for updates about the desktop app). There are other ways to do this. For instance, I could respond to the save event in the desktop app with the same Command I have now, but have a different Command respond in the web app that opens the pop ups directly, but I liked the idea of implementing an interface to create a fake service and piggy-backing the mapSingletonOf() dependency injection often used for services.

    Yeah, sometimes I make weird architecture choices on a whim. Don’t be so serious all the time.

  • LogiclyDesktop is the currently-unreleased desktop app. It has a subclass of the RobotLegs Context I created, but didn’t instantiate, in the Editor project. It mainly handles some desktop-specific events and views. Currently, the plan is to allow LogiclyDesktop to support multiple documents in separate windows, each with its own RobotLegs Context (so that I can reuse all the same code without changes that would probably require major refactoring). There will be some minor communication among documents, but mainly only for window management (to figure out when the app should close, for example).

  • LogiclyWeb is, obviously, the web app. Like LogiclyDesktop, it has a subclassed Context with some customizations for differing behavior. I’m also using some monkey-patching in this project to override some views I created in the Editor project.

    Since you cannot save a document in the web app, closing an edited document works a bit differently. In the desktop app, it asks you to Save, Discard Changes, or Cancel. To avoid confusion, the web app only asks to Discard or Cancel. I suppose I could have modified the component to add a boolean that omits the Save button, but the message changes too, and I didn’t want to write the invalidation and commitProperties() stuff. Actually, no, I think I chose monkey-patching because I wanted to see how RobotLegs handled it. The result worked, so I left it there.

Spark Skins

Since this is my first real project using Flex 4, it was also my first time getting down and dirty with the new skinning system. I love it. Everything is so customizable, and I was able to spend much less time on certain parts of the UI. In Flex 3, I probably would have needed to build a whole new component for some Panels because I wanted a wildly different layout. Not so in Flex 4, thanks to the Spark skinning architecture.

Right now, most of the skins I made are variations on the default Spark skins. I plan to make more interesting tweaks down the road to make Logicly have a more unique look and feel, but that wasn’t a priority yet. For now, I mainly just cared about the colors and fixing a couple things in Spark that I think are horribly ugly (like those increment and decrement buttons on scrollbars… yikes!).

By the way, I really don’t mind the copy-paste nature of skins in Flex 4. I know you hardcore developers get an uncontrollable twitch when you can’t inherit or reuse something, but it all felt pretty natural to me. Skins aren’t code… even if they are. For the Creative Suite exported FXG, I didn’t even feel the need to clean it up all that much. Well, except for the million and a half extra namespaces each CS application throws in there. What’s up with that useless garbage?

Source Control

Git works great for me. I’m not a big branch user, so all those features aren’t too special to me, but nothing beats the ease of typing in git init and starting a local repo. For Logicly, everything is still local on my machine, but I do use Github for flexwires, a related open source project I built along with Logicly. Eventually, I might upgrade my plan to put Logicly in a private repo on Github in order to have an offsite backup of the repo.

Testing

Yeah, about that…. I don’t really do unit testing. I know, that means I’m a horrible person. However, I’m inching closer and closer. My code today is much more testable than it was a year ago, and I actively try to make sure the right stuff can be tested on that magical day when I decide to write some tests.

Build Process

I use an Ant script to build Logicly. It’s a pretty standard Ant script. Although I do actually use <exec/> with the executables rather than using the Flex Ant tasks. That’s just the way I’ve always done it. I think I ran into some trouble early on (as in a few years ago) with the Ant tasks and gave up. The only magic in there is the fact that I increment a build number and use a filter token to inject the version string into the source code (it is displayed in the context menu).

Most of my development is from Flash Builder, so I don’t run the build script all that often. I could improve it, but that’s another case where the importance of doing so is rather low, so what’s there now is good enough.

Conclusion

So that’s my mostly unedited stream of consciousness explanation of Logicly’s project structure, code, and other stuff, with some thoughts on Flex 4 thrown in, since it was new to me. If I were working on Logicly full-time, it would have taken about a month to build. I switched to other projects over the course of development, and I generally took it easy throughout. My work on Logicly is a break from game development. I needed to recharge those batteries a little. My upcoming plans for Logicly include at least one more preview build, and then the release of the AIR app. Then it’s something game-related again, unless I decide to pick up some freelance projects.