1. Manual (start here)

In this manual I will explain how to work with the FFilmation engine. As we progress through the process of building a FFilmation application and its assets, I will also be explaining how does the engine work internally. You don’t need to know all the insides, but having an idea of the decisions that were made while building the engine and the reasons behind them is good: it will help plan you own application better.

Glossary

These are some words that will be used often and a brief description of each.

Engine: The engine is the top-most class in your ffilmation application. You will be using one single engine all the way long. The engine provides methods for creating scenes and switching between scenes. Only one scene is shown at the time. This doesn’t limit the amount of active scenes you can have at the same time, but only one will be displayed.

Scene: An scene is an isometric space of arbitrary size. The scene is the object you will be working the most. The engine renders one scene at a time. Scenes are independent: there’s no interface to communicate scenes or to move elements from one to another. Multi-scene logic has to be programmed outside the engine (we’ll see how later in this manual). Scenes are loaded/generated from XML definitions. Once created they also provide and interface to add/remove elements.

Element: Anything in you scene is an element. Cameras, lights and non-physical stuff are elements as well as walls, floors, and characters. Talking OOP, everything in your scene inherits from the Element class.

RenderableElement: A renderable element is an element that becomes a graphic symbol when the scene ins rendered. Lights are not considered renderable elements, instead they alter how renderable elements are shown.

Plane: Floors and walls are planes. Planes have an special treatment in the ffilmation engine because they define the basic structure of a scene and other elements are restricted to this basic structure. The basic structure of a scene can’t be altered once created. Why ? Because this structure is very important to zSorting, collision and other key algorithms that need to execute really fast, and some precalculations and assumptions are needed to achieve that.

Object: An Object is a graphic element that is part of the the environment and, opposed to planes, is not projected in any way. The library item is attached to the scene as is. Objects cast and receive shadows. Trees, statues and furniture are typical examples of objects. Objects can be rotated, if you define a set of sprites that represent this object in different angles. Objects can’t be moved.

Character: A character is simply an object that can be moved around the scene. It is a different class so some optimizations can be applied to static objects. People are the most common usage of Characters.

Working with the FFilmation Engine

Creating a new isometric application can be split in the following processes.

Outside application

  • Step 1: Create the definitions that you will be using in your scenes
  • Step 2: Create your scenes as XML, using the above definitions

Inside application

  • Step 3: Load an scene into your engine (from XML)
  • Step 4: Display scene
  • Step 5: Manipulate scene

Definition files

Definition files are XML files that define resources that will be used to build ffilmation scenes. Loading an scene involves loading all its referenced definition files, and all external swfs defined in those definition files that have not yet been loaded. This is transparent to you, you only see an “scene loading” process. There is no limit to the amount of definitions you can have in a single XML, but it is a good practice to group similar elements in a single file, such as trees.xml, stonewalls.xml or furniture.xml.

There are a number of reasons to have definitions separated from the scenes themselves, which become more evident with bigger applications.

  • You can share element definitions between scenes. You can change the diffuse map of one material and the change applies to all scenes that use that material. The engine is clever enough to identify previously loaded resources and definitions so you don’t have to worry about duplicates.
  • You can balance loading times. In a big application, it becomes impossible to have everything loaded from start. Imagine a game with 10 levels. Do you need to load the elements and enemies of level 10 for a user that never gets past level 1 ? Certainly not. If you group wisely your definitions, and every scene references only the definitions it needs, and every definition file references only the SWFs it needs, your load times become optimal.

You may be tempted to include some common elements (classes) of your application in your main swf because they are used all over the place, in all scenes. A typical case would be your game’s hero. However, if you create an scene that uses resources not specifically referenced in that scene’s XML, you won’t be able to load that scene in other ffilmation applications other than yours. The FFilmation editor, for example, will fail: it will try to create an instance of a Bitmap or a Class that will not be there, and will give an error.

Also, definitions can be nested. If you are building a definition file and want to use a definition in another file, simply reference the second file. You don’t need to duplicate its contents: the engine will handle the references.

Creating definitions to use in a FFilmation scene

<temp>
Hopefully one day when the editor is complete you will create definition files within the editor and you won’t have to bother with its XML structure. In the meantime these files still need to be created by hand. Follow this link for an example and TAG description (http://www.ffilmation.org/website/documentation/2-usage/xml-how-to/)
</temp>

Definition files contain media references, material definitions and object definitions.

Media references are paths to resources that need to be loaded to work with the definitions in this file (external SWFs with the referenced classes, movieclips or bitmaps).

Object definitions provide common info for types of objects, such as graphic resources they use and size. You can instantiate multiple instances of these definitions in your scenes, and each instance will share this common definition. The base attributes for the object definition are:

  • name: Used when instanstiating objects to refer to this definition
  • solid: Solid objects collide with things, non solid objects don’t.
  • receiveLights: Is this objects affected by light ?
  • castShadows: Cast shadows upon other renderable elements
  • receiveShadows: Receives shadows from other renderable elements

All of the above properties ( except name ) can be overwritten for each instance ( both in the instance’s XML node or at runtime via the FFilmation API ), but you can provide default values in the object definition.

An object definition contains a display model, a collision model and a shadow model. The display model is formed of one of more sprites, each associated to an angle. When the object is oriented ( from 0 to 360 degrease ) the engine will automatically show the sprite than represents an angle closest to the desired one. Attributes for the sprite are:

  • angle: which angle represents this sprite
  • src: library symbol for this sprite
  • shadowsrc: library symbol that represents the shadow of this sprite, in case you want to use another and not the same sprite.

Please follow this link for details on how to create assets to use in your object definitions.

The collision model defines the geometry that will be used to calculate collisions for this type of object. As the engine can’t extrapolate a valid collision geometry from an Sprite ( think of a tree ), you have to define it. Currently 2 collision models are supported: the cylinder collision model and the box collision model.

Attributes for the cylinder collision model

  • radius: The radius in pixels of an imaginary cylinder enclosing the object.
  • height: The height in pixels of an imaginary cylinder enclosing the object.

Attributes for the box collision model

  • width, depth, height size along x,y and z axis of the box enclosing the object

The shadow model only supports the Sprite type for now, but someday you will be able to use boxes and cylinders to define more accurate shadowing.

Material definitions are used in walls and floors. Think of them as the materials in any 3d package. The engine includes several standard material types.
Follow this link to find out which material types are currently supported and their XML syntax.

If the provided materials are not enough for you, you can write your own. A material ends up being a class. To use custom classes there’s a “procedural” material type that takes any class that implements the fEngineMaterial interface as a material. Refer to the engine’s API for details on how to implement a new material class.

Scene files

The engine uses XML to define an scene. In the default behaviour, the engine will load this XML from an external file, but you could write a class that generates a random scene and returns the XML to the engine. For now let’s stick to the most common usage. An scene XML can be roughly split in three parts: defining some common parameters for this scene, including references to the definition files we will need and place instances of these definitions at specific coordinates.

With the FFilmation editor, you don’t need to fully know the syntax for the XML, as you will be creating your scene visually, dragging things around. Not every tag is available to use in the editor yet, so please refer to this page for a full XML specification.

When you create an scene the first thing you will do is decide the size of the grid for that scene. Although it can be changed anytime, it has lots of implications in how the scene behaves, so you’d better think of it before doing anything else. Let me elaborate a bit about the grid: Each scene is internally represented as a 3d grid. Imagine your typical isometric engine, made of small squares, as a chessboard, but in three dimensions. Structural elements ( the walls and floors in the scene ) are forced to be along the axis of this grid, leaving the cells in between. That is, a wall is either left of a cell or right of a cell, but never crosses one. When you attach walls and floors to your scene, their positions and sizes are corrected to fit the grid. For example: you have a 50px grid and you add a wall 140px long. It will be scaled to be 150px, so it occupies 3 cells. This applies to the height as well. The editor automatically snaps things to the grid.

The grid is used internally in a number of algorithms and calculations. The main 3 uses are as follow:

  • Lighting: Rendering a light consists of two steps: 1. Decide which elements are within reach of the light and which other elements are casting shadows over them. 2. Project and draw the lights and shadows. Step A takes more CPU than step B, therefore we want to reduce it as much as possible. Using the grid, we can assume that the result of the A step for any light source inside a cell is the same. Therefore, those calculations are performed the very first time needed for each cell and then cached internally.
  • Collisions:, every cell in the grid stores the walls and objects that roughly touch it. Then when a character moves into that cell we test against those elements only instead of testing against all elements in the scene.
  • zSorting: when the scene is processed all walls, floors and cells are zSorted and every cell is given a zIndex. When an object enters a cell it is given the zIndex of that cell to avoid complex calculations. This means that all objects in the same cell share the same zIndex an thus you may experience small imperfections if two objects are in the same cell.

This means that some things in the engine have cell-precision instead of pixel-precision. Smaller grid sizes mean more resources and cells too big will cause some calculations to fail. Usually a good size is one that roughly encloses one character inside one cell. Default size is 64px.

Loading a scene into the engine

Once your scene is done you can create your FFilmation application and load the scene into it. The first thing you need to do is create an instance of the fEngine class. I’ll be using the most common syntax for all constructors and methods. Please refer to the API reference for extended functionality.

this.container = new Sprite()
myTimeline.addChild(this.container)
this.engine = new fEngine(this.container)

We have now created an engine associated to a given Sprite. Everything FFilmation will be drawn into this container. You are free to add it anywhere on your display list. Now let’s load an scene into it.

var loader:fSceneLoader = new fSceneLoader("scene.xml")
this.scene = this.engine.createScene(loader,800,600)
this.scene.addEventListener(fScene.LOADPROGRESS, this.loadProgressHandler)
this.scene.addEventListener(fScene.LOADCOMPLETE, this.loadCompleteHandler)

The engine’s createScene method received the object that is to provide the xml ( in our default case, a class that loads the external XML ) and the window size for this scene (contents that scroll outside are clipped ). When the scene is created, it starts loading and initializing itself. You can’t do anything with the scene until it has been initialized. We use the fScene.LOADCOMPLETE event to notify this. Also, you can use the fScene.LOADPROGRESS event to display a progress bar for this scene.

Displaying the scene

When the scene is ready (you have received the fScene.LOADCOMPLETE event) usually you will want to show the scene. Before you show an scene, you need to define a camera for it. The camera of an scene allows you to specify which portion of the scene is shown.

this.cameras = this.scene.createCamera()
this.scene.setCamera(this.camera)
this.camera.moveTo(300,300,10)

Notice that the camera has 3 axis of movement because it moves in 3d. The coordinates of the camera are internally translated into 2d values that will in turn be translated into the appropriate scrollRect value for the scene’s container. You can define several cameras for one scene ( simply call scene.createCamera() more than once ) and switch between them at anytime.

And finally:

this.engine.showScene(this.scene)

This will display your scene. The engine only shows one scene at a time, so if another one was shown at the time it would have been hidden. You can manually hide an scene using the engine.hideScene()

There’s one important concept here that I’d like to introduce: showing / hiding scenes only affects the DisplayObjects used by the scene, but has no effect on the scene itself and the elements within. You can manipulate elements ( move people, add or remove lights ) in an scene regardless of it being displayed or not. The scene keeps its status and when the scene is shown again the changes that were made while it was hidden are properly applied.

On the other hand, the DisplayObjects used to display an scene are destroyed when the scene is hidden and created again if it is shown again. This is done to reduce resource usage and allow much bigger applications with multiple scenes. Internally the scene takes care of everything, but you will need to be aware of it too. For example, if you add a mouse Event listener to the display object for an specific element, and then hide the scene, the displayobject is destroyed and therefore the eventlistener is lost. If you show the scene again you will need to define the event listener again as the same element will get assigned a new DisplayObject.

Manipulating the scene

You scene is now onscreen. You can see the area corresponding to the position of your active camera. Let’s start manipulating the elements in it. Typically the first thing you will do is create some references to the elements in the engine so you can call methods into them. If you now the id for your element (the one assigned within the editor) you can do:

var myObject:fObject = this.scene.all["objectID"]
var myWall:fWall = this.scene.all["wallID"]
var myLight:fOmniLight = this.scene.all["lightID"]

You now have access to all methods in the API for every element type. You can also create and remove elements dynamically. Not every element type can be added and removed from the scene. You can’t add/remove walls and floors for example. This is a limitation, I know, but it has a reason. Walls and floors define the basic geometry of the scene and are the basis of the lighting and zSort algorithm. Most of the optimizations in the engine rely on precalculating some relationships that are assumed not to change. Therefore walls and floors can’t be created and destroyed ( but you can always show/hide them which will do the trick 95% of the time ).

The dynamic elements in the engine are lights and characters. Lights are self-explanatory. Characters are basically objects that can be moved, created and destroyed. I made the distinction so static objects can else be optimized a bit. The fCharacter class extends the fObject class. Let’s create a light and a character:

var myLight:fOmniLight = this.scene.createOmniLight("lightId",x,y,z,...)
var myCharacter:fCharacter = this.scene.createCharacter("characterId",x,y,z,...)

Now we have access to all elements in our scene, both the ones that are already in its definition and the dynamically created elements. The first thing you will want to do is moving them:

myCharacter.moveTo(newx,newy,newz)

And the character updates its position. For objects and characters, you can also change its orientation. When the object is oriented ( from 0 to 360 degrease ) the engine will automatically show the sprite than represents an angle closest to the desired one. Rememeber that the available sprites for one element are defined in the definition file for the object’s type.

myCharacter.orientation = 180

Moving a character can cause it to collide against other elements in the scene. The engine will handle the collision ( canceling the movement ) but you may want to do something about it yourself also. To do it, you can listen to the fCharacter.COLLIDE event.

myCharacter.addEventListener(fCharacter.COLLIDE, this.collision)
public function collision(evt:couldn't):void {
  if(evt.victim is fWall) {
    trace("Ohh Bloody wall !!!")
  }
  if(evt.victim is fObject) {
    trace("Ohh Bloody object !!!")
  }
}

All elements have a solid Boolean property that makes them collision-enabled. You can change its value at any time. When you move a non-solid character, it doesn’t collide against anything. But when a solid character touches a non-solid element, although the movement is not stopped, another event is generated. This is the WALKOVER event and it is useful to pick-up items as you walk, for example.

myCharacter.addEventListener(fCharacter.WALKOVER, this.walkOverListener)
public function walkOverListener(evt:fWalkoverEvent):void {
  if(evt.victim is fObject) {
     var victim:fObject = evt.victim as fObject
     // When you walk on a money Bag, you collect it
     if(victim.definitionID=="MNIP_MoneyBag") {
       victim.hide()
       this.money++
     }
   }
}

Animating your objects

In a typical application you will have some characters walking around your scene. Walking around means two things: the character updates its position and you see some sort of walking animation. Whne the engine was designed it was important that designers and could work on any project without knowing any actionscript nor how the engine works. So it was important that simple animation cycles could be animated directly on the flash timeline. Assuming this, characters have access to its timeline so you can play through it. Easy:

myCharacter.gotoAndPlay("WalkLoop")

this will send your character’s timeline to the desired frame and play from there. Make no mistake: The fCharacter class is not a MovieClip, but the method name is the same to make it easier to understand. When you call the gotoAndPLay method of the fCharacter, the class calls the real gotoAndPlay method the real movieClip that is nested somewhere in the engine display list ( and so does to the shadows, to mantain synchronisation ).

The engine assumes that all sprites for an object have the same number of frames representing the same animations. Why ? Imagine a character running. Its rotation has caused Sprite 0 to be used. This sprite is currently at frame 32 ( somewhere in your walk loop ). Now you change the object’s rotation to another, and a new Sprite is needed ( say Sprite 3 ). The engine stores 32 as current frame, removes Sprite 0 form the Stage, adds Sprite 3 and gotoAndPlays Sprite 3 to frame 32, assuming it will represent the same frame with another rotation.

So now we know how to move the character and how to send it to the desired animation loop. Still there’s some extra logic needed in order to have him walk its way around. We’ll see how to approach the issue in a later in the advanced manual.

Holes

Planes in the FFilmation engine support holes. A hole is, well, a hole: you can see thought it, light goes thought it and you can get shot through it. Typically you will be using holes to create doors and windows. Currently the engine only supports rectangle-shaped holes, but more complex geometry is being worked on.

A decision was made so the holes of a plane are defines by its material. I know this may be controversial, a hole is more of an structural thing rather than an appearance thing. However, I am very obsessed with allowing designers to use the engine, and to me being able to “draw” a window directly into the material and having the engine recognise the hole is an important feature.

If you use the “MovieClip” material, read here to understand how to add define a hole. If you use other material types that ship with the engine, holes will already be created when you apply the material. Some holes can be opened and closed. For a hole to be “closeable” it must provide a hole block. A hole block is simply a displayObject that will be displayed when the hole is closed. Typically, a door. If you want to write your own material types, write a class that implements the fEngienMaterial interface and provides the necessary hole blocks when asked.

Closeable holes default as closed, all the others are open. Let’s see an example. Out scene contains a wall with id wallWithDoor. We know that there’s a door in there, so the wall will have one hole which represent the door:

var myWall:fWall = this.scene.all["wallWithDoor"]
var door:fHole = myWall.holes[0]
door.open()

This will open the door. You will see the door disappear ( the hole block is removed from the display list ). You will be able to walk and shoot through it. Lights and shadows will be affected as well.

Bullets

Bullets are treated as a separate renderable element because there’s two special things about them: they can be considered massless and they move very fast. This means than collision detection is more about trajectory calculations than position calculations. Also, you can’t draw a bullet as an Sprite because this is too limited: a bullet’s speed and direction will affect its visual representation. Maybe there’s trails involved, or the bullet is shown as a ray, etc etc

FFilmation provides the fBullet class to deal with bullets. Also, there are bullet renderers. Bullets and their render are handled by different classes for greater flexibility. The engine provides two default bullet renderers ( line and point ). A bullet rendered is to be shared by all bullets that look the same. You can write you own bullets if you implement the fBulletRenderer interface.

This is our renderer for the example:

var renderer:fLineBulletRenderer = new fLineBulletRenderer(0xFFFFFF,2,0.5,"Ricochet","Blood","Ricochet")

The first three parameters are line color, size and alpha. The other three are for ricochets. Automatic ricochets, how about that ? The renderer takes three optional parameters which are class definitions for plane ricochets, character ricochets and object ricochets. When a bullet hits something, the bullet dies and the appropriate ricochet is displayed. The engine assumes that in you class, the ricochet starts at (0,0) and animates upward. The clip will be transformed appropriately to fit the angle of the impact.

Our renderer is ready. Let’s create one bullet that goes from our character to some destiny point:

var destiny:Point = whereEverWeArePointing
var angle:Number = mathUtils.getAngle(this.character.x,this.character.y,destiny.x,destiny.y)
var dx:Number = destiny.x-this.character.x
var dy:Number = destiny.y-this.character.y
var dtotal:Number = Math.abs(dx)+Math.abs(dy)+Math.abs(dz)
dx/=dtotal
dy/=dtotal
var b:fBullet = this.createBullet(this.character.x+60*dx,this.character.y+60*dy,this.character.z,
                                  bulletSpeed*dx,bulletSpeed*dy,0,this.bulletRenderer)

I didn’t want to burden programmers with bullet control, so bullets are assigned an origin point and speed along the three available axis, and work automatically from there. How do we detect collisions between bullets and other elements in the scene ? Instead of listening to the COLLIDE event, we listen to the SHOT event.

b.addEventListener(fBullet.SHOT,this.shotListener)
private function shotListener(evt:fShotEvent):void {
   evt.bullet.removeEventListener(fBullet.SHOT,this.shotListener)
   trace("Ouch !!")
}

Both the bullet and the victim dispatch the shot event, so you can choose where to process those events. When a bullet hits something, events are dispatched, a ricochet is shown and THE BULLET IS DESTROYED. So if you had some variable pointing to that bullet, it is now pointing to garbage. The idea is that you don’t keep track of bullets yourself: you create them when needed and are handled by the engine.

Controllers

We have covered the basics of manipulating our ffilmation application. However the idea is to build something on top of this, so we need a more high-level control of our scene. To achieve this you can use controllers. Controllers are classes that are associated to either any element in the scene or a whole scene, and provide specific behaviors for what is being controlled. Examples:

An element controller class listeners to keyboard events and animated the main character accordingly.
An scene controller class updates lighting for the scene to simulate dawn or has a train arrive and leave periodically at your train station.

Controllers are very abstract classes that simply need to implement either the fEngineController interface or the fElementController interface. But why would you want to use controllers anyway instead of simply writing a class that manages the game ? Because the engine supports enabling/disabling of your controllers. You can enable/disable an element or an scene. Disabling an scene disables all of its controllers. This comes in handy with complex applications because otherwise you end up managing tons of listeners. If you use controllers you can do something like:

function pauseGame():void {
   this.currentScene.disable()
   this.pausedText.visible = true
}
function unpauseGame():void {
   this.currentScene.enable()
   this.pausedText.visible = false
}

Which I though would be quite convenient. To assign a controller to something simply assign the controller property ( or nullify it to remove the controller )

Please note than enabling/disabling an scene has nothing to do with showing/hiding it. You can hide an scene which is enabled and events, collisions and all logic will continue to execute, only the results won’t display oncreen, and vice versa.

Final words

Writing manuals is always a difficult task. I have tried to cover what I consider the basics of working with the engine. There’s a lot of functionality provided that has not been covered ( pathfinding for example ). I hope to write an “advanced usage” manual someday that covers what has been left here. In the meantime, please refer to the API and the example files available for download from the FFilmation website.