Jon Williams (jon)

Website: http://shovemedia.com


 

Posts by Jon Williams (jon):


FDT trace w/o Debug Revisited

My last post on this subject outlined a pretty good solution to this problem. I had one minor annoyance, and the further I chased it, the further from my original solution I drifted. Tail-ing the Flash debug log works great. It's fast, simple, easy to set up -- but I wasn't quite satisfied. I wanted to clear the log at compile so that Eclipse's console window would only contain text from the current run. Clearing the log file is easy enough, but getting Eclipse's console window to refresh turned out to be next to impossible -- at least via an Ant workflow (comments very welcome).

I dropped a note on the FDT message board, and one of the moderators pointed me to SosMax -- their free XML-based logging server. I was immediately resistant. That's just way way too much overhead for something as simple as trace output. But I gave it a chance, and am I ever glad I did. After struggling with the initial setup (as I always do with these packages), I quickly became a convert. SosMax really is a sweet little system, and after a bit of hackery, I was able to get it incorporated into my project without converting all my trace statements to myLogger.debug calls.

In addition to the great filtering, color-coding, etc features you'd expect with a custom logger, SosMax will also pull the trace log file, and it has an option for clearing the console automatically when a new connection is established. Ah ha!

Rather than write a log connector class from scratch, I downloaded one from Sönke Rohde . His class was almost perfect for my needs: by default, he only connects to the logging server if there's a message to be sent (ie, the first time you attempt to send a message). I only wanted to connect for the purpose of clearing the console, so I moved the connection logic into its own public method. Then, in my Main class:


import com.soenkerohde.logging.SOSLoggingTarget; 

import mx.logging.Log;
import mx.logging.ILogger;
import mx.logging.LogEventLevel;

public class Main {

private static const logger:ILogger = Log.getLogger("Main");

public function Main()
  {

   var sosLoggerTarget = new SOSLoggingTarget();
   //sosLoggerTarget.includeCategory = true;
    sosLoggerTarget.includeLevel = true;

   Log.addTarget(sosLoggerTarget) 
    sosLoggerTarget.connect()

 }
}

Trace in FDT without Debug Perspective

I recently switched to OS X, so I can't use my beloved FlashDevelop. FDT is really the most viable option despite the price tag. It takes awhile to get used to Eclipse and get all the settings dialed in, but it's worth it.

The only last major issue I had was getting trace output from the debug player to appear in the Eclipse console without launching a Debug task (way too much additional overhead just to see trace messages).

I'm on OS X which has 'tail' -- if you're on windows (why aren't you using FlashDevelop?), you'll have to use cygwin or get fancy with the batch scripting. There's also something called tail.exe from MS...

Found this: http://flash-focus.blogspot.com/2007/06/creating-bare-bones-output-window-in.html which outlines how to configure the Debug Player to drop trace messages into a log file.

First, I followed those instructions ... then in Eclipse added an External tool configuration:

Run >> External Tools >> External Tools Configurations
New Program
Location: /usr/bin/tail
Arguments: -f "/Users/MYUSER/Library/Preferences/Macromedia/Flash Player/Logs/flashlog.txt"

I wasn't able to point to the user Library via ~/Library -- maybe that's an Eclipse shortcoming...

Launch that, and it appears as one of the running console logs, then you can run your build normally, ANT or what-have-you, and you'll still get the trace output without all the debug perspective stuff, and it's about a zillion times faster. Yay!

Seems like there ought to be console level configuration somewhere, but I'm no Eclipse expert.

Hope this helps someone else.

I decided I'd try an FLA-less project using embedded library assets from swfs, but that proved contrary to my workflow. If I'm going to use the IDE for layout, then I've got a good handful of layers. Not just a graphic or three. I want several things to align, you know visually, so I used a visual layout tool to configure my layout. Smart, huh? But you can't pull in an entire timeline worth of assets and then provide the class and still expect to get the whole thing wired up. Flex compiler's gotta be all one child asset at a time within the class.

Despite reading more than once that you could somehow:

[Embed (src="library.swf", symbol="layout"]
public class layoutClass extends Sprite
{
// rest of class here
}

I never got it to work. I only got the directive to work for class property members, not the class definition itself.

You could use composition to pull an entire layout's worth of assets in. But then you've got this magic asset container property that's different from the local "this" context. No, I wanted all the assets linked to the class in one place, like I was used to with the IDE in the first place.

I decided it was worth it to reparent all the assets out of a temporary holder, and reconstruct the layer stack in the new parent.

I knew the code for this wasn't hard or long, but it isn't exactly obvious:

//Layout is a class that can be populated via
//embed directive or by having a 'skin' swc in your classpath. 

var layout:Sprite = new Layout()

var len = layout.numChildren
for (var i=0; i<len ; i++) {
  //move the child into this
  var c = addChild (layout.getChildAt(0))
  //link the property name of the class to the asset
  this[c.name] = c
}

Merry WhateverDecemberweenNewYear.

Weird note of the day. If you place a multiline input Textfield on the stage (as opposed to creating it with the class constructor), it will contain a newline by default rather than the expected null. Simply reset it to proceed normally:
myTextField.text = ""

AS3 package names vs property names

Tattoo it on your arm, whatever it takes to remember:

Package names can't match property names in your classes. Try to plan accordingly. If you accidentally create a conflict, the compiler might not be as helpful as you'd hope.

Let this be a warning to you.

AS3 scrollRect vs height & getBounds()

The new scrollRect property in AS3 DisplayObjects is pretty cool. If you haven't run into it yet, it's a fairly simple way to set a rectangular window on a larger piece of content without the hassle of drawing a rectangle and using a mask and inverse positioning the content... For the most common masking operations it comes in really handy.

And then reality sets in. You want to check the height of your content so you can set up boundary conditions for the scrolling behavior. But! When you get the height property, it's been modified to reflect the fact that the content is now masked. You don't get the "native" height anymore. What's even worse, this update to the property doesn't take effect until the next frame (following a change to scrollRect -- and you'll need another frame if you're doing this the first frame the asset is on the stage -- YMMV), so you've got to add (and remove) a temporary enterframe event listener ... it's a total mess. Thinking about using getBounds instead? Save yourself the trip. It works (as in "doesn't work") the same way.

Now suppose you suck it up and decide to deal with waiting a frame after your content fires onResize. You can handle a little add/remove listener juggling. No biggie. Alas, you've got no way to get access to your original height once a scrollRect has been set. You could temporarily remove the scrollRect, but that change won't take effect until the next frame. Gah!

So, I went digging through the docs to find an alternative. The only thing that looked even remotely promising was the transform property. I went through my code and replaced references to content.height with content.transform.pixelBounds.height and I was in business. As far as I can tell, this property responds appropriately to scale, rotation, etc while omitting any scaleRect clipping. However, if you were to grab content.parent.transform.pixelBounds.height, it would take the clipping into account.

Hopes this helps someone else out there...

-- UPDATE --

You know what's awesome? If the DisplayObject isn't on the stage, pixelBounds values are the "native" x, y, width, and height you'd expect looking at the Flash IDE property inspector. Times 5. Don't look at me like that. Try it. You'll get values five times bigger than you ought to. Maybe it's something to do with twips...

The whole idea of this exercise was to find a way to grab the height of a DisplayObject without a bunch of if/else hassle. But if you've got to sniff for a stage object, you might as well sniff for the scrollRect object itself -- and the value you read won't be subject to the frame delay. That's only a problem when reading it via the height property. Hope that clears up any confusion.

, , , ,

PNG sequence to SWF

I needed to stitch a stack of PNG images into a SWF using a server process. There are quite a few tools and methods for doing this interactively, but it gets painful if you want an unattended process.

I found SWFTools (includes PNG2SWF.EXE), which handles the awful, complex bit of ... building a SWF from a bunch of PNGs, but then I needed to figure out how to get it to auto-magically use all the PNGs in a specific folder. Essentially, I found a tool that does the hard part, but I needed to cobble together the actual command it should use. Wince if you want to, but I'm a masochist and I hacked together this batch file (like it's 1988, baby):

@echo OFF
SET LIST=

REM Build a list of PNGs
for /f "delims=" %%a in ('dir /b /a-d %1*.png 2^>NUL') do call :process %%a %1

@echo ON
REM now make a SWF!
CALL png2swf -r 20 -o %2 %LIST%

SET LIST=
goto :eof

:process
REM append the next file to the LIST variable
if not "%LIST%"=="" set LIST=%LIST%
set LIST=%LIST%%~2%~1

example usage -- test.bat c:\path\pngFolder c:\path\resulting.swf

I'm sure this is dead easy in linux (you can get swftools in linux flavors too, including source), and I'll send cookies to whoever posts the first working script in the comments.

Note: I'm not sure why this is, but the resulting SWF can't be imported into Flash CS3 as one would expect. If you were going to do that, you could've imported the initial sequence in the first place.

(see the original Mangled Kerning post)

We decided when we started this blog it wasn't going to be a bunch of whine, whine, whine such-and-such doesn't work. If we couldn't find a workaround of some sort, then we were just polluting the search space with more of the same "anyone else have an answer?" You may have dug through some of that to get here. There's value in seeing you're not the only one out there, but it's so limited we decided to avoid it if at all possible.

So. You've got an autosized textfield. You want to use Anti-alias for readability. But you've noticed strange spacing problems around HTML anchors. You've got a few options. I've come back to edit this post several times after seeing opportunities to achieve the same fix with less effort, but I'm preserving some of the more complex work-arounds because the bug is so quirky, someone might have need to try one of the uglier approaches.

1) After setting the htmlText, access the height property of the field, then it's safe to turn off autoSize which will allow correct kerning behavior:

var temp1 = (field.height)
field.autoSize = TextFieldAutoSize.NONE

You won't have to wait additional frames or anything like that. Just remember to turn autoSize back on before changing the text.

2) Set the antiAliasType property of the TextField to flash.text.AntiAliasType.ADVANCED after the field has already been on the stage for at least two (count 'em: 2) frames. That's frame 3 if you're following along at home and your TextField was present on frame 1. Use the visible property to avoid epileptic seizures.

3) It would appear that only authoring-tool-placed TextFields require the extra 2 frames. Create a TextField from code, and you can set the antiAliasType property of the TextField to flash.text.AntiAliasType.ADVANCED in the next frame. Again, use the visible property to hide the layout jump:

var field = new TextField( 20, 20, 500, 1)
addChild(field)

field.embedFonts = true
field.multiline = true
field.wordWrap = true
field.autoSize = TextFieldAutoSize.LEFT

var styles = new StyleSheet();
styles.setStyle("p", {fontFamily: "HelveticaNeueLT Std Med Cn", fontSize: "18", kerning: false, letterSpacing: 0, color: '#CCCCCC'})
styles.setStyle("a", {textDecoration: 'underline', kerning: false, letterSpacing: 0, color: '#FFFFFF'} );
field.styleSheet = styles

field.htmlText = "<p>This top line is necessary to push the content down because that matters somehow in this simple example of <a href=\"http://nowhere.com\">Quirky</a> text in Flash.</p>"

//NEXT FRAME:
field.antiAliasType = flash.text.AntiAliasType.ADVANCED

4) If you must be a sadist, use a hybrid approach to replace authoring tool-placed TextFields with runtime-created TextFields while preserving position, dimensions, autoSizing, styles, etc. And after you've gone to all the trouble, don't forget to set the antiAliasType to advanced. If you're willing to let the original field handle the autoSizing, you can turn off autoSize on the dynamic field, size it according to the first field, and avoid having to wait a frame to set the antiAliasType as in #2. Just remember that if you need to change the field's contents, you'll have to turn autoSize back on. NOTE: Your mileage may vary, but I found that wordwrap was uneffected by this bug, so even though the kerning sometimes jumps around aggressively, I didn't find any changes in wordwrapping, thus no changes in sizing to worry about ... so far.

Mangled Kerning in Flash HTML Text

Work long enough with Flash and dynamic textfields, and you'll probably run into this one—words that appear to have an extra and/or missing space preceding or following them, often when a link is introduced via the <A> tag. It doesn't happen with every font (I was using Helvetica Condensed—other condensed fonts seemed faulty as well), it doesn't happen with every link (certain letter combinations have a high degree of reproducability, others no problem).

I spent half a day narrowing it down. Since my text was originating from XML, it first masqueraded as some sort of entity or character encoding problem. I messed with TextFormat and StyleSheet (mutually exclusive by-the-way). A later wild goose test-case showed that flipping the autosize flag off made the issue disappear. Fine, but I need autosizing.

When Andreas Heim pointed out the solution, I remembered I'd run into this before: "Do you happen to be using 'Anti-alias for readability?'" Sure enough, flip it to "Anti-alias for animation" and all's well with the world.

I can only hope that the Flash 10 player addresses this bug. With all the work that's gone into its type rendering features in this revision, I'd certainly assume so. I'll post some test cases / screenshots in the next update.

Download example FLA & SWF

Update: Screenshot of effected swf. Verified broken in Flash 10 beta player. :(

, , ,