Unity App Structure from a Flash Perspective
Unity apps are structured very strangely. They’re a lot different than Flash or standalone apps and definitely take some time to get used to. Today’s article is an introduction to how a Unity app’s code is structured from the perspective of a Flash developer. It should give a basic understanding of where your code goes and how the basic architecture of a Unity app looks.
To recap, a Flash app starts with a Stage
. It may also have one or more Stage3D
and StageVideo
in more recent versions, but the Stage
is always there as a good basis for comparison. On that Stage
is a “root” Sprite
. If you’re compiling from pure code, this is the .as
file that you pass to mxmlc
:
mxmlc MyApp.as
That command will yield MyApp.swf
with a root Sprite
that is an instance of the MyApp
class found in MyApp.as
:
package { import flash.display.Sprite; public class MyApp extends Sprite { public function MyApp() { } } }
The constructor of the MyApp
class is called when the root Sprite
is created and added to the Stage
. This class then controls all of the app from its constructor and any events it chooses to listen to. These typically include Event.ENTER_FRAME
and TimerEvent.TIMER
but may include others like Event.VIDEO_FRAME
or Event.RENDER
.
The app’s “main loop” is typically formed by successive calls to the function handling Event.ENTER_FRAME
or TimerEvent.TIMER
events. A mass of code is called from these event handlers to handle all of the app’s logic. In the case of a game, this may include input handling, display rendering, sound playback, network communications, file I/O, and so forth.
If the app isn’t compiled from a single .as
file but rather built by Flash Professional, a “document class” will serve the same purpose as the “root” Sprite
. The app’s logic may be much more spread out though. This is because ActionScript may be attached directly to entities on the timeline. For example, a small script may be added to stop an animation from looping by adding a simple stop();
on the last frame of the timeline.
In this latter case, there’s no need to set up a “main loop” based on Event.ENTER_FRAME
or TimerEvent.TIMER
since Flash Professional allows a more graphical, timeline-based approach to writing the app’s code. Some find this approach to programming extremely intuitive while others find it repulsive. Whatever your opinion, it’s a very common way that Flash apps are built.
With that overview of Flash architecture in mind, let’s discuss Unity. Apps that are built on Unity always use the Unity Editor. This is the graphical tool that allows us to build what Unity calls “scenes”. Each scene primarily consists of a hierarchy of GameObject
instances. Each GameObject
has Component
instances attached to it. Unity’s scenes are somewhat like Flash’s stage and Unity’s GameObject
is somewhat like Flash’s DisplayObject
. There isn’t a real equivalent to Unity’s Component
in Flash.
One of the biggest differences between Flash and Unity programming is that Unity has no concept that is like a “root” Sprite
or “document class”. All of your code is attached directly to a GameObject
in the scene. The way this is done is via a class called MonoBehaviour
. When you want to write code that attaches to a GameObject
, you don’t extend GameObject
like you would extend DisplayObject
in Flash. Instead, you extend MonoBehaviour
which in turn extends Component
. This allows your class to be instantiated and then attached to the GameObject
. Here’s a trivial MonoBehaviour
:
using UnityEngine; public class MyScript : MonoBehaviour { }
Instead of events like Event.ENTER_FRAME
and TimerEvent.TIMER
driving the “main loop” of a whole application, each MonoBehaviour
listens to its own events. Instead of Flash’s EventDispatcher
system, “magic” function naming is used. Here are just a couple of them:
using UnityEngine; public class MyScript : MonoBehaviour { public void Start() { // ... script started } public void Update() { // ... every frame } }
I won’t go into the full litany of events available to MonoBehaviour
classes in this article, but they’ll be discussed in upcoming articles. In the meantime, the Unity docs cover them pretty well.
This lack of a “root” Sprite
or “document class” has a very large impact on application structure. Instead of a single “root” that “holds” all of the main components or engines of the game, the system is decentralized. Each MonoBehaviour
is a peer of each other MonoBehaviour
with none in a “master” role. Think of the system more like a graph than a tree.
When faced with this unusual architecture, many developers are tempted to—or even implement—a system where there is only a single GameObject
with a single MonoBehaviour
attached to it. It’s usually called Main.cs
, Root.cs
, App.cs
, or Game.cs
and serves just like the MyApp.as
above. This is a valid way to architect a Unity app, but has plenty of drawbacks of its own. For example, the Unity event system’s “magic” functions don’t allow for easy listening to events on another GameObject
.
If you choose to use a system with many decentralized MonoBehaviour
instances rather than the “root” GameObject
approach, you’ll find a variety of other challenges to contend with. Among these are difficulties in Update
and Start
event ordering and poor support for RAII. This is not to say that all Unity apps are necessarily “unclean” or a “hack”, but rather that they, like Flash, feature their own unique challenges which must be overcome by clever, well thought out application architecture.
This has been just a high-level overview of both platform’s app structures and how they compare. There are many details (e.g. scenes in Flash, C++ code in Unity) that haven’t been covered here, but these basics should cover most apps at least until the point where they start using advanced functionality like Flash ANEs or Unity’s platform-specific plugins.
To recap, here’s a handy table showing the rough equivalences between Flash and Unity app architectures:
Concept | Flash | Unity |
---|---|---|
App Container | Stage |
Scene |
Main Building Block | DisplayObject |
GameObject |
Main App Controller | “root” Sprite /”document class” |
n/a |
Script Attachments | Timeline scripts in Flash Pro | MonoBehaviour |
Spot a bug? Have a question or suggestion? Post a comment!
#1 by henke37 on December 29th, 2014
You painted a misleading picture of flash with respect to the timeline in Flash. You should have mentioned that symbols are timelines too and that all timelines can have a class attached to them. And I am curious if Unity has something equivalent.
It’s been said a lot before, but the framescripts in flash are secretly converted into methods on the timeline class.
#2 by jackson on December 29th, 2014
You’re right that Flash supports nesting timelines inside timelines like this. Unity, as a mostly-3D game engine, doesn’t have such a first-class timeline as Flash does. Flash’s history as a 2D vector graphics animation package before it was ever a programming platform leads to such a design.
Unity does have 2D (and 3D) animation support via timelines, but they’re not as prominent as in Flash. Most Unity apps will never care about fixed-duration frames but rather do everything on variable time steps. For example,
Time.deltaTime
(time since the last frame) is an extremely common sight in Unity code whileTime.frameCount
(frame index) is almost never seen.#3 by Shapevoid on March 16th, 2015
When I first started using unity after many many years in AS land I found the setup to be a throwback to the old as2 days with scripts all over the place, but the benefits of the system are clear within the scope of unity. It isn’t perfect but what is. his tutorial popped p recently and gives a nice overview of how to setup a project and covers a wide variety of topics. http://unity3d.com/learn/tutorials/projects/stealth