您的位置:首页 > 其它

What About Flash? Can We Really Make Games With It?

2009-03-01 11:09 399 查看
Scott Bilas

Oberon Media, Inc.



Abstract

We’ve heard this story before: big-game developer gets
tired of big-game team size, pressure, and politics, and switches to making
small games. New companies filled with people escaping the retail AAA industry,
developing these “casual” games, are popping up all the time. These aren’t the
silly little things that get forwarded to us in email and hold our attention
for 30 seconds. These are games that make money, and hearken back to the days
of yore when a couple geeks in a garage could put together a hot shareware
title in a few months and get rich quick. The big difference today is in the
tools. We can build bigger, better, prettier, more advanced games with fewer
people in less time and for less money than ever before!
One of the most respected (and reviled) tools for making
interactive content is Flash. Well, what about Flash as a game development
platform? It has grown in power considerably over the years. The casual games
we build today are equivalent in production quality to the AAA games that were
shipping around 10 years ago. Can we do it in Flash instead? And why would we
want to?
This paper is the story of the Oberon development team’s
experiences with building games in Flash. All of us came from big games where
we built our own tech (the author was a C++ game systems engineer for nearly
ten years), so why did we choose Flash as our development platform instead of building
our own casual games platform? What was so hot about Flash, and what caused us
headaches? And, most importantly, when should we avoid using Flash entirely?

Casual Games

Before we get started, we should first talk about what
exactly a “casual” game is. Most of the time, this term is referring to a game
that…
…is between 3 and 10 megabytes
in size (56K modem users usually won’t be able or willing to download anything
bigger).
…sells for around $20 in the
impulse buy zone. About the same as a CD, or a cheap date.
…works on ancient computers with
equally ancient operating systems.
…is exclusively distributed
online through channels like MSN or RealArcade.
…has a vastly different audience
than retail PC/console games.
…is developed for a fraction of
the price and resources as a big retail game.
Also, casual games will frequently have a web-hosted
“teaser” that players can play forever for free, with a more full-featured
“deluxe” version that is downloadable. The deluxe version is almost always copy
protected by the distribution channels, and limited in some way until purchased
(often a simple 60 minute timeout). And in many cases, the old shareware model
still works, nagging the user with guilt screens to pay.
That’s a lot of constraints. Most of the time, we’re
ruling out requiring a 3D card. If there’s 40 hours of gameplay, it better
reuse a lot of art, because it just won’t fit into 5 megs. 8000 lines of
voice-overs are out of the question. And forget about using an expensive middleware
solution – while dropping $50K on a physics engine in a $10 million Xbox title
may be no big deal, it will instantly destroy the budget of a casual game.

The Development Platform

In order to meet our constraints, we have the following
requirements for our theoretical casual games development platform:
·
The executable code must be small. After we subtract the space
needed for the installer and DRM wrapper (sadly, this can be a megabyte or more),
the audio, and the art, we don’t have much left. Forget about bloated C++
template libraries and big third-party DLL’s. It’s even worse on the Mac due to
the fatter PPC instruction set (fortunately, Mac users are on broadband more
often than Windows users).
·
The content must be small. We can’t get away with PNG’s
and BMP’s and WAV’s. We’ve got to store our content in JPG’s or JP2’s and MP3’s
or OGG’s.
·
We’ve got to grab players’ attention. We want to be able
to build and integrate visuals that “pop” without having a programmer get
involved, sequencing complicated animations by hand.
·
The engine needs to avoid fancy API’s that probably don’t
exist on the client machines. Nobody is going to have DirectX 9 installed,
or the .NET Framework, or the right GDI+, or know how/want to download and install
them. We’ll be lucky if they have a recent version of shfolder.dll. They’ll
have ancient hardware drivers. And don’t even think of dropping support for
Win98! (Win95 is apparently ok to drop, though, according to our stats.)
·
Performance is a huge concern. Many of our players’
systems will have old CPU’s and minimal memory. They’ll be riddled with spyware
and viruses, which makes the CPU and memory problem even worse. This engine
must be tight, efficient, and fast.
·
The toolset needs to support rapid iteration. Wasting a
day of time could be one or two percent of the entire production schedule! So
we’ll need a scripting language, a good layout and animation tool, a flexible
object model, and try to data-drive it all.
·
We’re going to want to make a web version of the game as a teaser.
So we need to have a route to the web that doesn’t involve contracting out an
expensive rewrite in Java or Flash.
So what about Flash? Can we really make games with it?

What is Flash?

Flash has come a long way since the days of Punch the
Monkey and Win advertisements. Flash 7 (known as MX 2004 at retail) is a modern
interactive platform, with a powerful design and animation authoring tool, an
object-oriented type-safe dynamic scripting engine, bitmap rendering with
antialiasing and subpixel precision, and advanced video and audio playback
features. “Flash” is actually three components: the player, the file format,
and the authoring tool/IDE.

The Player

Everyone knows what the Flash Player is. Nearly every
computer on the internet has Flash – according to NPD, its penetration is
higher than Internet Explorer’s, at 96%. We load Flash in our browsers every
time we visit web sites with irritating advertisements. For the version 7 Player,
it’s a 1 MB ActiveX control (OCX) that compresses to 560K, usually installed in
C:/windows/system32/Macromed/Flash.
The player consists of:
·
A virtual machine. This interprets and executes bytecode
for ActionScript, Flash’s scripting language. As with any managed environment,
the system uses a garbage collected memory manager. The VM’s execution engine can
be fairly slow – more on how to work around this later in the paper.
·
A hierarchical frame-advancing visual object model. Flash maintains
a hierarchy of MovieClip objects (and Graphic and Button, but those are less
useful) in a layered display list, where each object has its own
frame-subdivided timeline, and layers map onto z-order. The clips can be laid
out in the IDE, or created and rearranged from code based on exported symbols
in the library. Each has a parent, which eventually goes out to _root. MovieClips
can also be loaded dynamically from external SWF’s into anywhere in the
hierarchy.
·
A set of media decoders. Flash can decode and play back
multiple streams of compressed audio and video simultaneously. It has decoders
for ADPCM, MP3, and NellyMoser (for voice). For video it supports Sorenson
H.263 and Sorenson Spark. Because of the ubiquity of Flash on the web, and the
quality of Spark, many sites such as Amazon are starting to use Flash for video
playback instead of the traditional Real, Windows Media, or QuickTime players.
·
Rendering algorithms. Flash has a set of fairly advanced
algorithms for rendering vector graphics, including lines, splines, gradients,
and antialiased, filtered bitmap fills. Flash is a vector engine, but its
support of bitmap fills means it’s also a bitmap engine – when a bitmap is
dragged onto the stage, Flash actually creates a four-sided shape then attaches
a bitmap fill with an identity texture transform matrix. Each shape fill can
have a texture transform as well as a simple shader for playing with the color
and alpha of texels as they are rasterized. There are many examples online
using Flash to render simple 3D objects in this way.
·
A framework library. Much of this is just the standard
library we would expect from any JavaScript implementation – basic string
functions, arrays, sorting, math, etc. Flash also adds support for TCP
communications (no UDP unfortunately), asynchronous loading, XML, and more.

The File Format

The Flash file format is known as SWF (from Shockwave
Flash, pronounced “swiff”), which has gone through many revisions over the
years. SWF is a tag-based binary format designed for streaming, with zlib
compression on top to keep it small. It’s important not to confuse Flash with
SWF – while the Flash environment has a closed FLA document format (more on
this later), and the Player is closed source code, SWF as a file format is free
and open – the spec is complete, and easy to find on Macromedia’s site:
http://www.macromedia.com/software/flash/open/licensing/fileformat
Here is a more programmer-friendly version:
http://sswf.sourceforge.net/SWFalexref.html
Many apps have been created that output directly to SWF,
such as vector drawing programs, charting programs, screen capture software for
demos, presentation software, and enterprise frameworks such as Flex and
Laszlo. There is even an MSIL-to-SWF compiler by Robin Debrueil that lets us
write code in C# or VB.NET and compile into SWF.
There are a few potential alternatives to SWF that meet
some of our requirements, but not nearly enough:
·
SVG from the W3C. Scalable Vector Graphics is a standard popular
with the open source community, but not much of a competitor to SWF, primarily
because of the tools available to build SWF’s. The only SVG authoring tools
currently available are very primitive – they are today where Flash was 5 years
ago.
·
XAML from Microsoft. This hasn’t been released yet, but it
looks like a good, comprehensive system. However, until we see an authoring
tool, we can forget about it. There is at least one SVG-to-XAML converter (from
Xamlon), but that doesn’t solve the problem with the authoring tool. Not that
it matters much anyway – XAML and the composition engine to render it cannot be
considered standard on desktops in the casual audience for ten years, at least
not if the number of people running Win98 today is any indication of how people
drag their feet on upgrades. And when it’s released, it will likely have the
same problem as the .NET Framework does today (even worse, as “Avalon” requires
.NET) – the redistributable size will be in the tens or hundreds of megs,
overwhelming the download size of the game.
The Flash player is available on Windows, Mac, Linux, and PocketPC.
For mobile phones the Flash Lite player is increasingly supported, although this
player only supports relatively primitive Flash 4 level scripting.

The Authoring Tool / IDE

This is the equivalent of Visual Studio for composing
Flash content, and it’s what Flash developers spend most of their time using.
Contained within its integrated development environment are the following major
components:
·
A code editor. Don’t use it, it’s terrible. Better than
Notepad, but nowhere close to a tool like Visual Studio. At Oberon we avoid
using Flash’s built-in code editor for anything over 10 lines of code, and
instead use PrimalScript by Sapien (www.sapien.com).
PrimalScript supports standard features we’ve all become accustomed to, like
IntelliSense, unlimited undo, source control integration, etc. Despite it being
buggy and overpriced, it’s worth using. Because of the dynamic nature of JavaScript,
it’s easy to mess up and spell something wrong, or pass the wrong parameters
into a function, without the compiler catching it. The IntelliSense feature
helps to avoid these silly mistakes, which can save a lot of debugging time.
·
An animation editor. This is one of the most powerful
features of Flash. Animations are done using familiar tools like layers,
tweening, onion skin, easing in/out, etc. Most people are familiar with Flash’s
vector animation abilities, but the same system works with bitmaps as well,
which are simply treated as fills on vector shapes (i.e. textures with
transforms).
·
An editor for vector art. While most of the art is likely
going to still be bitmaps, it’s frequently useful to use the vector engine for
drawing the gradients, line art, and fills that are so common in game UI’s. And
when it comes to prototyping something quickly, it’s trivial to bang out some
decent looking programmer art in a few minutes.
·
A compiler. Flash’s scripting language is called
ActionScript 2.0, which is actually an advanced version of JavaScript based on the
ECMAScript 4 draft spec. This version takes the dynamic JavaScript language and
adds features such as static typing, classes, interfaces, and type safety.
·
A content build system. This is the compression and
packaging step, converting bitmaps and audio into JPG and MP3. Code and content
are wrapped up into a SWF, which is Flash’s packaged file format. Versions
since 6 have supported zlib compression of the SWF, so the files can be very
small.
·
A debugger. This is probably one of the worst features of
Flash. The debugger supports standard features like breakpoints, watching variables,
and a call stack trace, but don’t let the feature set fool you. It is poorly
implemented, has terrible usability, and is almost criminally slow and
unreliable. When projects get over a certain size, the debugger becomes
impossible to use, and the only choice is to fall back to “printf debugging” (i.e.
debug via log analysis). Most of the time this works well enough, and the
tough-to-debug cases can be handled by copy-pasting a subset of elements into a
test file and debugging from there (more on this later).
·
A help system. Flash stores all its help in HTML files, but
the interface to it from the IDE is pretty awful compared to a viewer like the MSDN
Library uses. Some tools such as PrimalScript can index this content and
provide a better viewer for it, but only slightly. It’s good for
context-sensitive F1 style help, but that’s about it. Fortunately there’s a
great workaround: the Flash Resource Manager, which is a free tool that
integrates help from Flash with a decent interface, but also will search a
variety of online resources such as the amazing FlashCoders mailing list,
Macromedia Tech Notes, Fullasagoog, and many others. It can be found at http://www.markme.com/mesh/archives/004700.cfm.
·
A content manager. Flash has a good system for managing
content. It will import art and audio stored in most major formats into its
“library”, which is organized as a tree structure. This is convenient for
developers – artists and composers can store their assets in version control in
whatever folder structure they like, and engineers integrating it can organize
it in the library in a format that is more convenient for them.
The IDE manages FLA files, which are the source for
creating SWF’s. All art and audio used by a FLA are stored directly inside of
it in a lossless format. The FLA also maintains a reference to the original
file on disk, so when the asset changes on disk, it can be updated in the FLA.
The disadvantage of this is that assets must be updated manually (although this
can be automated as part of a scripted build process). Artists working on bare
PNG’s can’t simply check in new art and expect to see it, unless they tell an
engineer to update it in the FLA. Artists working on FLA’s directly will need
to remember to update their libraries to get the art they just changed in. But
on the other hand, the advantage of this process is that assets can be updated
only when the engineer is ready for it. There are no problems with someone
checking in new assets that accidentally break the build, because the
integrating engineer will have to know about every change that is made.
“Publishing” the FLA initiates the build process, and will
result in a SWF, usually with graphics compressed to JPG and audio compressed
to MP3. The type and level of compression are configurable on a per-asset
basis, as well as with global defaults.
Flash’s IDE is scriptable via a language called JSFL,
which is JavaScript plus a DOM for the environment. The library for JSFL can be
extended with DLL’s written in C. Nearly every feature of the IDE can be used
from JSFL. In fact, any command the user performs is recorded in a history
buffer for undo/redo, and most commands have a JSFL equivalent. It’s trivial to
drag-select a set of commands in the history and save them as a JSFL function.
This is a convenient way to learn JSFL coding – just do the operations
manually, then save the code and make adjustments from there.
Panels and custom tools can be created in the IDE that
look and operate just like the UI that ships with the IDE. The UI for these is
(unsurprisingly) implemented as SWF’s configured with an XML language.
Flash MX 2004 Pro costs $700, which is on par with most
IDE’s. It uses a product activation system that permits two installations per
copy, which is convenient for working on Flash at work on the workstation or at
home on the notebook. It’s available on Windows and Mac – the interface is
nearly identical on both versions, and the FLA format is the same, so files can
be interchanged. In the few places where a path can be stored in a FLA (such as
for publish settings), each platform will accept path separators from the other
platform.

Advantages of Flash

So what is so hot about Flash? Briefly, the main
advantages are:
·
A great authoring tool for interactive content. Integrates most
features needed for making a game.
·
Flash is everywhere. For the web version of a game, 96% of the
audience won’t need to download anything except the game. More importantly,
many people won’t be able to install arbitrary ActiveX controls, or use a Java
plugin, whereas Flash is preinstalled with Windows on corporate machines.
·
Near trivial porting to Macintosh. Open up another 5% of the
market to an audience desperate for decent games.
·
Easy conversion from a full game to a web version, or if going
the other way, a natural path to take from web version to full downloadable game.
·
Cost is essentially free – there is a small cost for the Flash IDE,
but it’s nearly free to distribute (just some minor licensing things to worry
about that don’t cost anything). Royalty-free licenses for decoders such as MP3
and Sorensen Spark are included.
·
Ease of finding artists. There is a huge talent pool to draw from
for creating art or animations for Flash, either on staff or contract.
·
Embed your game in PowerPoint when giving a GDC presentation!
·
A gigantic community and secondary market. There are thousands of
Flash related web sites with tutorials, articles, and discussions. There are
hundreds of Flash add-ons or components for sale.
·
Easy copy-paste to test things out. Flash permits drag-and-drop
or copy-paste from one FLA to another, and it automatically brings along any
dependent objects into the new library. This can make it incredibly easy to try
out quick ideas outside of the main game, and is the one case where it’s worth
using the debugger.
The main advantage of using Flash, though, is that it’s
simply well-suited to the task of making games. An entire gameplay mechanic can
be prototyped in a few hours, with decent art, in an easily packaged form that
runs on a PC, Mac, or Linux, through a web browser or
standalone...royalty-free. If we want to scale up to larger games, i.e. go from
prototype into downloadable casual games, then there are some tricks to use to
make it work, but nothing too awful (there’s more on this later in the paper).
The hierarchical visual object model in Flash is the main
reason for this fast prototyping ability. It’s difficult to describe how
powerful it is without showing a demo, but here’s an attempt. Take for example
any graphical object that can have multiple states, such as:
·
A toolbar that, based on mouse proximity, may slide on or off the
screen, or alpha in and out.
·
A player avatar that can have many different skins, and within
each skin are several different poses, each of which is animated.
·
A checkbox that has states for hover, down, up, and disabled.
·
An object that, if the player destroys it, breaks into fragments
and explodes with an effect.
·
Room decorations that can be added to a scene, such as a clock,
nightlight, potted plant, candle, or spider web. Each of which may have
multiple states, such as ticking, not ticking, lit, not lit, alive, and dead.
Each of those states may be animated, and there may be animated transitions
from one state to another.
In all of these cases, the results can be accomplished
with a small amount of visual programming. Let’s focus on how we would
implement the toolbar:
1. Create
a movie clip “Toolbar” that contains all of the screen elements on the toolbar
such as a background, buttons, text, etc.
2. Create
a new clip “ToolbarAnim” that contains just one instance of the Toolbar.
3. It
starts out with one frame. Give it an extra frame, and name the two frames “On”
and “Off”.
4. Go
to the second frame, and drag the Toolbar instance so it is off-screen.
5. Now
add a new object, say a vector rectangle that spans both frames. Convert it to
a movie clip called “ToolbarHotSpot” then keyframe it, and in each frame, size
it for where the mouse can be to keep the toolbar open. Convert this rectangle
to a movie clip, and set its alpha to 0. Name it to “_hotspot” in both frames.
6. In
frame “On” have _hotspot respond to onRollOut with gotoAndStop( “Off”
). And in frame “Off” have _hotspot respond to onRollOver with gotoAndStop(
“On” ).
Now we have an auto-hiding toolbar, and it took just a
couple minutes to create. Actually, it took longer to write about than it did
to create. That’s a fun trick, but the power of nested clips really starts to
show if we were to decide to make the toolbar animate off-screen as it is
hiding. To do this, we’d throw a bunch of frames after Off, tween the off-screen
motion with some ease-out selected, and change the gotoAndStop( “Off” )
to gotoAndPlay( “Off” ) with a stop() in the last frame. That
takes about 30 seconds to do.
Every single one of the multiple-state graphic examples
described previously can be done in this way. In Flash, a state machine for a
graphical object can be represented by a named frame in a MovieClip. And a
hierarchical state machine is simply a set of nested MovieClips. If we want
animated transitions between states, we can simply insert frames that do the
effect we’re looking for, followed by a stop() somewhere at the end
(plus maybe some additional code, such as an event callback to notify the game
that it’s done). If we want more complicated behaviors, we can create a class
that extends MovieClip, and associate it with one of our clips.
Let’s go through one more example. Say we need to
represent a game level in Flash, with decorations like furniture, plants, wall
outlets, etc. We would create an object called Decoration and export it so the
code can create it and place it in the level based on the XML level data.
Inside of the Decoration we’d make one frame per different object, and name each
frame according to its contents. The code can switch among them using gotoAndStop()
on the Decoration to go to the correct frame that shows the object we want
(again, based on XML data at level load time). Now let’s say we wanted to add
states – a candle can be lit or extinguished. We would go to the object on the
Candle frame within the Decoration object, convert it to a movie clip, create
frames inside it for the Lit and Extinguished states, and then out in our game
code, now we can use gotoAndStop() to switch between these states. Now,
say we want to go even further, and show a fireplace that can be lit or
extinguished, but we want to show it starting to burn, or start to go out. We
can add more frames and insert a bitmap sequence (or other animated effect) and
switch to gotoAndPlay() instead to show a transition.
This simple method of visually sequencing behaviors is
the most powerful concept in Flash. Objects can be made deeper, more
complex, more interactive, in a clear and intuitive way, without breaking any
code that was working with a higher level of hierarchy. In the previous
example, the fact that the candle can be lit or extinguished doesn’t affect the
level load logic, which only knows that the object is a Candle. Artists can go
into an assets file in this way and add effects or animations to objects
without requiring an engineer, and without breaking the game.

What is a Flash Game?

Say we decide to use Flash. We now have a bunch of MP3,
SWF, and XML files. What’s next? We need to be able to play these back somehow,
which means using the Flash Player. But it’s missing features such as
fullscreen mode, support for right-click, and reading and writing save games.
Plus our SWF’s, being an open format, are easily reversible, so we’d like to
protect our intellectual property with some encryption or at least obfuscation.
Macromedia has a program to license source to the Player, which
would let us add the features we need, but this is meant more for hardware
manufacturers looking to port Flash to their platforms (cell phones, set-top
boxes, kiosks, etc.). It’s not a very game developer-friendly program – they
want about $150,000 for the source, and royalties on top of that. This is
ridiculous compared to what that would buy us in the 3D commercial engine
space. So we can forget about licensing Flash’s source.
There have been several efforts to clean-room engineer a
Flash Player, but nearly all have fizzled out. One that continues to see
regular updates is gameswf, contained in Thatcher Ulrich’s public domain
tu-testbed project over at SourceForge. Unfortunately, while gameswf looks
extremely promising, it is OpenGL-based, and this won’t work for us.
So we’re stuck with the Flash OCX. We have a couple
options here. Either build a host application in C++ that adds in the features
that are missing, or buy one off the shelf. Putting together a host for Flash
is not a trivial amount of work. We created one at Oberon using C++ and ATL 7
that adds fullscreen mode, right click handling, crash detection and reporting,
support for JPEG2000 graphics, OGG and OXM playback through the FMOD library,
encryption, save game reading/writing, splash screens, Flash embedding, and a
bunch of other features, in a very small package. Flash can communicate with
its host using async COM events in one direction, and in the other direction,
perform direct variable setting/getting or function calls. This can be used to
add support for any operation that Flash doesn’t support natively. For example,
the OCX host application would subscribe to the fscommand event, and
respond to fscommand( “fullscreen”, “true” ) to do its resolution
changing. Macromedia has documentation on this available here:
http://www.macromedia.com/cfusion/knowledgebase/index.cfm?id=tn_12059
COM events are async, which means the SWF will not be able
to call a function like fscommand( “getComputerName” ) and expect to
wait for a response. Flash will continue executing, and the request will not
get posted to the hosting application until after some time has passed. To deal
with this, we must use a sequence where the SWF makes a request, then goes
about its business until the host app has a chance to receive and process the
request, and then set a variable in the SWF with the results. The SWF will have
to notice this independently (probably by a “watch” on the variable – a great
ActionScript feature), and be able to handle the time in between. This can be
annoying, but Flash developers should be accustomed to programming
asynchronously – everything from loading a SWF to a JPEG to getting data from a
TCP socket is all done asynchronously.
There are also some off-the-shelf packages available, such
as SWF Studio from Northcode, and mProjector from ScreenTime (Google for “SWF
to EXE” to find all of them). These have varying sets of features, and may
include scripting and the ability to make plugins in C++ to extend the system
further. As they are general purpose tools, they tend to add a lot to the size
of the EXE. They will usually package the SWF’s and other support files in with
the EXE, along with the Flash OCX itself, to help prevent reverse engineering.
Recently these types of tools have also been adding save-as-Mac EXE support.
And at least one of them has managed to fix the async COM event problem, where
the Flash app really can call out synchronously to its host to get information.
These tools are always royalty-free and so cheap that they’re essentially free,
and worth checking out.
So here are the pieces in our game: the “projector” EXE,
the Flash Player OCX, and the content in SWF’s, XML files, and other resource
formats. This can be distributed royalty-free – Macromedia basically only requires
some minor logo placement when we use their Player. Be sure to check the
license agreement for all the details.

Developing with Flash

What’s different about developing for Flash than a roll-our-own
engine? For artists, it’s about the same. Make art in Photoshop and check it
into source control – Flash can import a variety of formats, including PSD. For
audio, hand off MP3’s to Flash, or give it WAV’s and let Flash do the
compression itself. Of course, Flash is much more flexible in that it’s easy to
find artists with Flash animation experience for contract or full time work. We
can simply have them make SWF’s and integrate that directly into the game via loadMovie()
or dragging and dropping the SWF onto the stage or into a symbol. Or they can
edit our FLA’s directly, if they’re careful. Audio engineers can do the same
thing, if sequencing audio into animations.
The real difference with using Flash comes with assembling
the game – the work our content engineers will do.

Setting Up for Debugging

Flash is an extremely tolerant platform. It will
accept and silently ignore any error. This understandably sounds harsh to C++
or C# programmers accustomed to crashes or exceptions, but we’ve all been to
web sites that have put up annoying modal JavaScript errors, or other problems
resulting from bad programming. Macromedia understood that not everyone coding
Flash tests their work thoroughly, and that most of the problems that result can
be ignored to avoid ruining the user experience. So they only permitted two
types of errors to throw up a system dialog: an infinite recursion (greater
than x levels of call stack), or a code hang (greater than x seconds of code
execution without returning to the system). In either case, Flash will put up a
dialog. In all other cases, whether a function call is spelled wrong, or a
member is accessed on an object instance that doesn’t exist, Flash ignores
it. This is great for the web experience, but is horrible for development.
Important exception: the compiler will catch it, but only when using classes
and strongly typed variables – more on this in a little bit.
To help work around this, we need to configure the system
to use the debug Player. This involves the following steps:
1. Exit
all browsers and the Flash IDE.
2. Download
the uninstaller at:

http://www.macromedia.com/cfusion/knowledgebase/index.cfm?id=tn_14157

…and run it.
3. Install
the Debug Player found at C:/Program Files/Macromedia/Flash MX
2004/Players/Debug. This can be verified by going to any site with Flash on it
(such as the banner on the top of www.macromedia.com)
and right-clicking on it. If there is a “Debugger” grayed out in the menu, then
the debug version is installed. This menu selection doesn’t do anything except
show that the Debug version is installed (i.e. it’s always grayed out).
4. Create
a file mm.cfg in C:/Documents and Settings/(username) containing:

TraceOutputFileEnable=1

ErrorReportingEnable=1

MaxWarnings=0
Now, when any errors occur that are caused by accessing
runtime members that don’t exist, or if a trace() is called, Flash will
output to the flashlog.txt file in C:/Documents and Settings/(username).
This can be watched during development with a tail program. If using MX
components, it’s best to filter tail through a grep that removes
all the errors that the components cause (those components are not exactly
“clean”).
Next, we’ll need to add the development tools that any game
engine would require – a console, logging features, error reporting, and
assertions. Note: Flash has no concept of a modal dialog that is callable from
code, so asserts that stop the game are not possible. The trick to work around
this (assuming we really want to make sure the game stops executing when
something bad happens) is to just go into an infinite recursion. Flash will
instantly put up a dialog that testers can catch, and the game screen will
still be in the state it was at the time of the failure, for a screen shot.
Finally, when we code, we need to make sure to do
everything in classes using private access protection when necessary, and use
ActionScript 2.0 with strongly typed variables, parameters, and return types on
methods. Without classes and strongly typed variables, we don't get any type
safety at all – Flash reverts to ActionScript 1.0 mode which will
tolerate pretty much anything it tries to compile. But when using them, the
compiler will catch almost all of the errors for us. In practice, it’s really
only necessary to tail flashlog.txt when something bizarre is happening
in the code that makes no sense. More often than not, it’s a typo.
In order for the strong typing to really work, we need to
modify the factory-installed Flash class stubs. The type safety feature of
ActionScript 2.0 is disabled on a per-class basis by the “dynamic” tag attached
to the class. Macromedia apparently did this in Flash MX 2004 for backwards
compatibility. So in order to maximize our chances at finding errors, we need
to go through every one of the .as files shipped with Flash and remove the “dynamic”
keyword, then fix all the errors that come up from that (as mentioned before,
Flash ships with unclean classes). These classes are found in an obscure
location – deep breath –
C:/Documents and Settings/(username)/Local
Settings/Application Data/Macromedia/Flash MX 2004/en/Configuration/Classes
It’s best to take this whole folder (minus the ‘aso’
subfolder, which is for intermediate object files), check it into version
control in a standard location, and delete it from its original goofy location.
Then update Flash’s global classpath settings to point to the location
mapped by version control for these files. This is similar to what we would do
with Visual Studio for include or lib paths. Then go through the
.as files one by one, removing “dynamic” from each, except for the Function
class, which really needs to keep its dynamic tag otherwise many things in
Flash will break.
Note: many of the MX components will throw up a lot of
compile errors if used with this classpath. At Oberon, we don’t use components
except for prototyping, because they are so heavyweight, slow, and difficult to
skin how we like. So in our projects that use the components that throw errors,
we simply set the classpath for each project to point at an unmodified classes
folder. It’s not the best solution, but then again, MX components are evil.

Organization

Here are some tricks to help keep Flash projects
organized, under control, source control friendly, and team friendly.
·
Use .as (AS2 class) and .asi (#include from FLA) files as
much as possible. Keep all code out of the FLA files, other than the one- or
two-liners. Because FLA files are binary, they end up getting exclusive-locked
in source control, plus they cannot be diff’d for changes. Developers will end
up fighting over who gets to keep the FLA checked out when only code changes
are required. If the code is #include’d, or stored in classes (.as
files), then this problem is avoided.
·
Ok, well avoid using .asi files too. They are a necessary evil in
just a few cases where classes can’t be attached to objects (such as startup
code for the root timeline). Flash compiles them as AS1 code, so they will not
be typesafe and can have easy errors creep in. It might even be better to take
all that code and store it in a class as a static function, then call that
function from where the #include would normally be.
·
Use externally shared FLA’s for “content” art, broken down by
content type (game board pieces and animations, cut scenes, etc.). This will
permit art integrators, or perhaps artists, to work on FLA’s without affecting
code, layout, or running into exclusive-lock problems with other developers. It
also helps with keeping large FLA’s under control. Whether or not this is
necessary really depends on the project size and team dynamics.
·
Keep everything off the main timeline in the core FLA, and work
exclusively in symbols. Symbols are the most powerful concept in Flash.
·
Keep data in external XML files. Audio can go in external MP3
files, if it’s more convenient that way (it certainly speeds publishing up).

Flash Performance

In this paper so far we’ve covered many disadvantages of the
Flash platform, nearly all of which are fairly minor and can be worked around.
Flash is like any platform, with its own list of weird quirks and annoying
features and bugs. However, there is one major problem that deserves its own
section: performance.
ActionScript can be very slow. Bytecode execution is ok, probably
on par with other scripting languages, but there is a significant problem with
entry points. Setting up the execution context to call into the virtual machine
and tearing it down again after a function exits is extremely expensive. Less
expensive, but still significant, is a script-to-script function call.
Optimizing ActionScript is straightforward:
·
Minimize entry points into the code. For example, use a
traditional game main loop rather than a lot of onEnterFrames attached
to MovieClip-derived classes for every game object on the screen.
·
Profile, profile, profile. Nothing shows what’s slow like ASProf
(see Flash Resources at the end of this paper).
·
Manually inline functions when necessary. When in inner loops, use
local variables, which are specifically optimized in “registers”, instead of
global variables.
·
Publish for Flash 7, which is much faster than Flash 6 (mostly
due to the “registers”).
·
Scan the blogs and mailing list archives for tips on optimizing
ActionScript performance. There are many tricks out there, too many to cover
here, but this site gathers a lot of analysis and links in one place:

http://www.oddhammer.com/actionscriptperformance/old_index.htm

Note that many of these may be out of date due to Flash 7 and need re-testing.
Worse than scripting performance is graphics performance.
Flash is basically a 2D rasterizer in software with zero caching other than on
the primary surface. Each bitmap being rendered is actually a textured fill of
a four-sided shape, rendered through a generic rasterizer. It’s very pretty,
but can be very slow. Little work is apparently done inside the Player to
optimize for bitmaps on integral coordinates with an identity texture
transform. There is a dirty rectangle system that works fairly well, but it is
spoiled by a final step in the renderer that unions all the dirty rectangles
together for the final update area. This means that on a screen with a lot of
detail, a flashing icon in one corner of the screen, with the gameplay action
in the other corner, causes the entire screen to be redrawn each time the icon
changes. There is also overhead in maintaining each graphical object on the
screen, and managing it as part of the display list.
Optimizing graphics is also straightforward, although it
may not be very appealing:
·
Avoid making action games where the whole screen is scrolling.
Feeding Frenzy is a great example of something not to attempt in Flash.
·
Minimize the number of objects onscreen at once.
·
Avoid UI designs that have animated indicators at the edge of the
screen. These will expand the final union size for dirty rectangle rendering,
increasing the update cost.
·
Avoid large full-screen effects unless the screen is very simple
(such as on a rewards screen). If possible, downshift the quality temporarily
while a large full-screen effect is playing.
·
Target frame rates for 16 or 20 fps. A consistent frame rate
feels much better than a high frame rate, and it reduces the per-frame overhead
that Flash incurs from maintaining its objects.
·
Use lower resolutions – the graphics problem only really kicks in
at higher resolutions. For web resolutions, we can get away with pretty much anything.
At 800x600 though, the pixel throughput of Flash really starts to hurt.
·
If an animated object needs to be hidden, remove it from the
screen instead of setting its _visible member to false. An
invisible animating object still (inexplicably) dirties the screen.
There’s really no way around it. Flash is not designed for
fast paced full-screen animated graphics of any complexity, but with careful
optimization and some modifications to the game design we can still make it
work for us.

Odds and Ends

This section is for whatever didn’t fit anywhere else in
the paper. (I always seem to have one of these.)

Tricks

Useful random tricks:
·
ActionScript 2 and JScript.NET are 99% the same. The Oberon
multiplayer platform (one of its installations is at http://arcade.icq.com/multi.htm) has
a feature on the server that lets it use JScript.NET or C# for the server
script. So we can take a common rule set that needs to be implemented on both
the client and the server (say a chess game, which has complicated rules), put
it in a common class, and have both the FLA and the server both reference the
class. JScript.NET even has some nice features to let us /*@if ( XYZ ) */ out code
so Flash doesn't see some code, but the server does, or the other way around. For
a complicated piece of code that is difficult to debug in Flash (perhaps a
level generator, or pathfinder), we could throw together a quick JScript.NET
front end to it, get it debugged and working via Visual Studio, then switch
back to Flash, which can use it immediately.
·
It is possible, although it can be messy, to diff a FLA by
publishing the old and new versions to SWF’s, then using KineticFusion (see
Flash Resources at the end of this paper) to convert the SWF’s to XML, and
diffing the XML files. This can be useful when trying to figure out exactly
what changed in a FLA from one version to another, such as when that weird bug
was introduced a couple weeks ago in version #27 that just got discovered, and the
engineer who checked it in (who will surely be punished) used “made some fixes”
in the check-in notes. The “fixes” could be anywhere. With standalone .as files
it’s simple to diff the history, but with binary FLA files it’s impossible. The
FLA-to-XML conversion makes it possible.
·
Flash renders at a variable frame rate if streaming sound is not
playing. Every single frame in an animation sequence is guaranteed to be
played. This means that if the system gets bogged down with a lot of script or
expensive graphics, the game will appear to slow down as well. For gameplay
controlled by code, this won’t be a problem, because the code will be
time-based rather than frame-based. However, it will affect animations created
using the Flash IDE. The solution to this is to write a “frame advancer” that
takes over responsibility of advancing frames from Flash. It will simply check
what time it is, and decide which frame to gotoAndStop() to based on the
delta since the last check (divided into the target frame rate). When using a
frame advancer, be careful not to skip past frames that have code attached to
them that needs to run.
·
Any object placed in the Flash authoring tool receives a negative
depth. When Flash goes to another frame, it will only destroy objects that do
not exist on the new frame, but only if they have a negative depth. This means
that objects created in code will stay around forever unless also removed by
the code. It also means that in order to destroy objects that were placed in
the authoring tool, it must be moved to a positive depth first.

Traps

Here are some things to watch out for during development:
·
When odd compile or runtime errors are coming up that make no
sense, before spending an hour debugging it, try deleting the ASO cache files.
These are to .as files what .obj files are to .cpp files – temporary object
files that Flash creates in the process of compiling. Unfortunately, they
apparently only perform a basic greater-than test on file timestamps, so reverting
an .as file in source control will not get noticed by Flash, and not get
recompiled, which can result in results that turn hair gray. The solution is to
just delete all the ASO’s. Mike Chambers makes this easy with his “Clear ASO
Cache” command, available here:

http://www.markme.com/mesh/archives/005686.cfm
·
Classes have a limit of 32,000 bytes, because of the way
Macromedia had to shoehorn AS2 into an AS1 bytecode Player. Avoid making
gigantic, monolithic classes – keeping them under 1500 lines should be safe. At
Oberon we’ve run into this problem when creating our “Constants” classes, which
we use to store fake enums etc. – we usually just divide the constants down
into multiple classes to deal with this.
·
Fonts in Flash are rendered very poorly at small sizes (under 12
points or so) and can look fuzzy or jagged. If using a font that is pretty much
guaranteed to be installed on the system (such as Arial) then it’s possible to
cheat by not embedding the font glyphs, and instead rendering the text as a
“device font”. This lets the operating system render the font instead, and has
the advantage of using the OS’s antialiasing (in Windows’ case, that may mean
ClearType).
·
There is a 12-layer alpha limit – after 12 images are overlapping
with alpha channels, Flash stops rendering the layers underneath. This is
enough objects on top of each other that it usually shouldn’t be a problem, but
it did come up in our testing and is a known issue.
·
Flash renders the edges of images it imports very poorly sometimes.
A thorough explanation of the problem and its very simple workaround is
detailed here:

http://www.fatorcaos.com.br/flashimagebug/
·
It’s easy to get collisions between classes (which are installed
into the global namespace), global variables, and instances on the timeline. It
saves a lot of debugging time to simply name things with a convention based on
scope. At Oberon our standard is to prefix class names with a ‘C’, and member
variables or instances on the timeline with an underscore. That’s been enough
to prevent collisions so far. It also avoids problems when publishing as Flash
6. For example, this code, while fine in Flash 7, can wreak havoc in 6:

var myClass :MyClass = new MyClass();
·
Long-running scripts can cause the dreaded “A script is running
slowly” dialog to pop up. This is incredibly unprofessional in a game, and if
the user hits “Yes” on the dialog, it will break the game, because it kills all
scripts from then on. For the downloadable version, it’s possible to set the
timeout before this dialog comes up by hacking the SWF. Better still, though,
is to simply make sure that any functions that could run long are iterative. A
level generation function will need to return back to the system every once in
a while so Flash doesn’t think that it has hung. Remember that there are
machines of all kinds out there – have such a function return to Flash no later
than half a second per increment, just to be safe.
·
Avoid MX Components. They are tempting to use, because they can
just be dropped right in and we can start working right away, but unfortunately
they have a lot of problems: they are enormous in bytecode size, extremely slow
to render, cause focus issues, and do other odd things like install “managers”
at high numbered depths on _root. Plus they’re very difficult to skin. Instead,
make a simple button class, an edit box, etc. – it’s takes five minutes to do
in Flash.
Finally, here is a special note to people intending to use
Flash on a console: you may be able to get what you need from gameswf, but
forget about writing your own Player from scratch that can process SWF’s. It’s
an enormous task – a lot more complicated than just drawing some
triangles or interpreting some bytecode. Look into using GameFace from Anark
instead. This product is currently in beta testing but looks to be a great
Flash-in-3D.

Flash in the Future

There is a new version of Flash that Macromedia has been
demonstrating at user group meetings, and at their conferences, supposedly
entering beta soon (as of this writing). The new version is Flash 8, and it
looks like it could really solve a lot of the performance problems mentioned in
this paper, in addition to adding a lot of impressive new features.
On the performance front, supposedly the new ActionScript
interpreter is much faster. But more importantly, they have added “bitmap
caching”, which should solve many of the graphics related performance issues
we’ve run into. Normally, Flash does a full render of anything on the screen
that has changed, clipped to the dirty rectangle. With bitmap caching, we can
have Flash cache a render for a MovieClip into a bitmap, rather than
re-rendering the same pixels over and over.
As for new features, they are adding advanced pixel shaders
(although still rendered in software) like glow, shadow, and blur. And they are
fixing the font rendering problem, adding ClearType quality font rendering called
“Saffron” that also includes hinting for rendering small fonts properly.

Conclusion

Let’s see how Flash stacks up to our original
requirements:
·
The executable code must be small. The Oberon host
application plus Flash’s OCX adds up to about 1.1 megs, compressing down to
829K. Not great, but not bad, considering all the toys in there. Grade: B.
·
The content must be small. Flash supports JPG and MP3, and
its bytecode is tight enough to be negligible in comparison to the bitmaps and
audio. We’re good to go. Our Oberon Flash host application adds support for
JPEG2000, OGG, and OXM (Ogg-compressed .xm format), all of which are even
smaller. Grade: A.
·
We’ve got to grab players’ attention. Flash is an
excellent animation tool. With the right talent we can really grab people,
although we need to be very careful about doing large full screen effects. Grade:
B+.
·
The engine needs to avoid fancy API’s that probably don’t
exist on the client machines. Flash runs on a default install of Win95, so
it’s up to the host application to limit its API use, which isn’t difficult.
Grade: A.
·
Performance is a huge concern. This is the worst problem
with Flash, and it gets a C here. Although while we can’t bet on Flash 8’s
release date, it looks like we may be able to bump this up to a B in a few
months.
·
The toolset needs to support rapid iteration. This is
perhaps the most powerful ability Flash gives us. Grade: A+.
·
We’re going to want to make a web version of the game as a
teaser. The route to a web game from a deluxe game (or the other way
around) is clear and direct in Flash. Grade: A.
At Oberon in Seattle, we’ve developed and shipped two
successful downloadable Flash games (Betrapped! and A Series of
Unfortunate Events) plus online web versions, a multi-thousand-user real-time
multiplayer system that uses Flash and UDP on the client, and are working on
additional Flash-based downloadable and web games to ship this year.
Flash has been a great experience for us. As described in
this paper, it has a number of pro’s and con’s. We’ve worked around nearly all
of the disadvantages, which have turned out to be minor in practice, and we
would expect similar issues with any other platform we were to choose. The
biggest disadvantage with Flash is of course CPU usage, which is a challenge,
but we still think it’s worth fighting through. At the moment we’re betting on
Flash 8 to give us the performance boost we need, but if that doesn’t work out,
we may have to consider alternatives such as Torque 2D for our more action
style fast paced games, and continue to use Flash for the slower paced games.
And even if we weren’t using Flash as our primary development platform, we’ll
still use it as a rapid prototyping tool to get us through the first couple
stages of preproduction. Nothing beats being able to create an entire game
prototype in a few days.

Flash Resources

Flash has an enormous community, with people of all skill
levels, from many backgrounds. These aren’t just amateur web designers messing
around with a few buttons and animations for a silly menu navigation bar. The
heavy hitters in the community tend to be involved in “rich” client enterprise
applications, and frequently have backgrounds in C# or Java.
Here are key resources for any Flash developer:
·
Fullasagoog’s RSS feed. Available at http://www.fullasagoog.com/feeds.cfm,
this is an aggregator for all of the best Flash related blogs out there, and has
valuable information popping up daily. This is the One True RSS Feed that
everyone should subscribe to.
·
Any book by Colin Moock. His latest is Essential
ActionScript 2.0 – anyone coding with Flash must stop what they are doing,
and buy this book.
·
Extending Macromedia Flash MX 2004 by Keith Peters and
Todd Yard. Writing JSFL? Automating common Flash tasks? Building custom
panels and extending the IDE? This is the book to buy.
·
The FlashCoders mailing list. Every question about Flash
has been asked here, and answered here, many many times. All known bugs have
been analyzed, discussed, and worked around. The mailing list carries extremely
heavy traffic, but that’s what the archive search is for. It’s available at http://chattyfig.figleaf.com/mailman/listinfo/flashcoders.
This archive contains or links to everything ever written on Flash that
matters.
At Oberon, the tools we use that really speed up
development are:
·
PrimalScript by Sapien (www.sapien.com).
The text editor that does IntelliSense with ActionScript, mentioned previously
in this paper.
·
ActionScript Viewer by Burak Kalayci (http://www.buraks.com/asv/). There
are probably ten great decompilers for SWF’s out there right now, but this is
the one we use at Oberon. It can reverse engineer all classes used in a SWF,
and does a pretty decent job of naming variables. This tool is really useful
for figuring out “how did they do that?” when visiting a site that shows off
some interesting effect in Flash.
·
Flash Resource Manager by Mike Chambers (http://www.markme.com/mesh/archives/004700.cfm).
Already mentioned earlier in this paper, this is a critical tool.
·
KineticFusion by Kinesis Software (http://www.kinesissoftware.com/index.php).
This tool can roundtrip a SWF to/from XML, which can really aid in automation
during the build process, or for making tweaks to a SWF after it’s made without
needing to recompile (such as to change its frame rate, or alter some code).
·
AdminTool by AcmeWebWorks (http://acmewebworks.typepad.com/admintool/).
This is a remote debugging tool for Flash in two parts – the admin interface (a
standalone program), and a component that goes onto the stage in the SWF for
communication with the admin interface. This tool can walk the object
hierarchy, take snapshots for inspection, execute code in the SWF, control
objects in the SWF, gather traces, and much more. Nobody should develop for Flash
without this tool.
·
ASProf by David Chang (http://www.nochump.com/asprof/).
This is a real-time profiling library that can dynamically hook different parts
of the code and collect execution times, delivering the results in a table
format. Required for optimizing ActionScript.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: