OpenSpace logo

The structure of an OpenSpace map

In this tutorial we will discuss the structure of an OpenSpace isometric map, as it can be created in the OpenSpace Editor. The main "building block" of a map, the tile, will be described quite deeply, and some useful tips&tricks will be provided to make maps’ designers life easier! Operating instructions on the map creation process can be found in the OpenSpace Editor documentation.

The OpenSpace scene

Let’s start with an overview of the main map elements of the OpenSpace scene...

... where the numbered items are:

  1. the viewport limits, which match with the size of the OpenSpace component on the stage;
  2. the isometric grid, usually hidden (here displayed for clarity);
  3. the background layer;
  4. the foreground layer;
  5. an empty tile, where empty means that it doesn’t contain graphics;
  6. an avatar — more informations can be found in this overview;
  7. a tile with associated graphics (a barrel);
  8. a tile containing an oversized graphical element (an house);
  9. a tile used as an hotspot to trigger events (for example the door opens when the avatar steps on that tile).

A virtual world, especially if targeted at the Flash technology, is usually divided into “locations”, where each location is described by its own map. OpenSpace handles each map as a separate data file which is loaded and parsed by the OpenSpace Extension whenever a client requests it.
Each map is made of tiles (which can also be grouped into supertiles), usually a background and optionally a foreground. When the map is rendered on the stage, tiles are added following the sequence shown in the image below. The index number indicates the tile depth: the lower the index is, the lower the tile depth is. So, a lower index means that the tile (and everything it contains) is behind the tiles with an higher index. Of course this doesn’t respect the nature of a true 3D environment (where, for example, tile #10 would be behind tile #9), but it works pretty well for the purposes of OpenSpace.

The tiles’ indexes structure is very important and it should always be taken into account when designing a new environment and the objects it will contain, to avoid wrong behavior of map objects (for example wrong overlapping of objects that in a real 3D space would overlap correctly, or wrong overlapping of avatars when moving on the map).
We will talk more about this subject when describing how to handle large, tile-exceeding graphics in the tridimensional space, after describing tiles and their skins.

Tiles

In OpenSpace, the tile is a sort of building block (just like the Lego!) which concurs to create the map “architecture”. Each tile has a size, an elevation (the tile height in a 3D perspective), a “viewing angle” and other properties which can be fully customized. Of course size and viewing angle are common to all the tiles (in fact they are set in the OpenSpace client-side configuration file), while the elevation and the other properties can differ from tile to tile.
Thinking the tile as a building block, we can set a different elevation for both its upper side and its lower side. This leads to countless possibilities, just like the following image on the left shows:

Tiles can be stacked one above the other to create complex structures with overpasses or underpasses, combining plain tiles with tiles having a bottom elevation greater than zero. In the previous image on the right, orange tiles are stacked upon blue tiles.
Stacking more than two or three tiles is generally not recommended. Tiles composition should also be planned very carefully, to avoid unnecessary tiles to be rendered on the screen, causing performance issues. For example, if you want to place a non-walkable tile representing a tree on an existing walkable tile, instead of simply adding the new tile to the existing one it would be better to remove the previous one and substitute it with the new one (the OpenSpace Editor comes into help here, with a “smart” behavior).
Another important aspect in building maps is to carefully balance the size of tiles, the size of the map and the size of the viewport: having small tiles, a big map and a wide viewport can cause performance issues, as the number of tiles (together with their skins) on the stage at the same time could be huge.

Skins

A skin is a graphical element contained inside a tile. A skin can be a piece of floor, a tree, a wall, some grass, a greek column, etc. Everything you want to display on the map is a skin (with the exception of the background and foreground, described later, and the avatar). Most important, a skin can be an entire building too, with boundaries that exceed the tile size (more on this later).
A tile can have no skin, one skin or even more than one skin. Empty tiles (tiles without at least one skin) can be used in combination with the background graphics to simply indicate on which areas of the map avatars can walk, and on which ones they can’t.
If more than one skin is assigned to a tile, they will be stacked one above the other. In this way it is possible to create different tiles by combining different skins, just like in the following image:

The skins are movieclips or sprites contained in the Flash library of one or more external swf files (let’s call them “skins library files”) loaded by the OpenSpace Editor (at author-time) and by the OpenSpace component (at run-time); they can be also custom classes which extend those base classes (see the note below). Each skin must have a unique Class name set in its Linkage properties, while the Base Class must be flash.display.MovieClip or flash.display.Sprite. Using sprites instead of movieclips is highly recommended for performance and memory usage reasons.
In a tile, the skin’s origin is aligned to the (0,0) coordinates of the upper side of the tile; the tile’s (0,0) coordinates are shown in the image on the right. To set the proper skin alignment inside a tile, the two best ways are:

A. In Flash, give the graphics contained in the skin sprite a predefined offset with respect to the sprite’s origin, so that the skin will have the right positioning automatically.

B. Align the graphics in the skin to the sprite’s origin and drag the skin in the Skin editor preview to adjust its position with respect to the tile (alternatively, for a more precise control, you can set the hOffset and vOffset attributes in the skin properties pane manually).

The first approach is probably the best, especially when combined with the “auto-generate skins” feature of the OpenSpace Editor (see the SWFs manager section), because you don’t need to adjust the offset of each skin inside the Editor; also, the designer who creates the skin inside Flash can use a mock-up tile on a guide layer inside the skin sprite to set the correct position of the element (and maybe of other elements around it) with respect to the tile.

As a convention, the skin classes can have some optional methods defined in their timeline’s first frame (or inside the class itself in case the skin is linked to a custom class). If available, OpenSpace makes use of these methods to offer additional customization features at run-time. The conventional methods are:

NOTE
If you create a custom class defined in an external as file and attach it to the skin symbol in the Flash library, it must extend flash.display.MovieClip or flash.display.Sprite. The custom class must also be declared as dynamic, because OpenSpace needs to write an internal property to it. If you don't want to declare your class as dynamic, you can still make it work by adding the following members in your class definition:

private var _os_id:String;
public function get os_id():String { return _os_id; }
public function set os_id(value:String):void { _os_id = value; }

Placing big 2D elements in the 3D space

What if we want to create a large 2D object, for example a building, and show it on the map? The task of creating elements that exceed the tile size is not trivial to carry out, because it largely depends on the object size (small width but big depth? or vice-versa?), its shape (convex or concave?), its placement on the map (along the map sides? near other objects?), how the avatars will interact with it (just move along the perimeter? or a more complex interaction?), etc.
This paragraph will describe a couple of ways to approach this task, discussing pro and cons and giving some general guidelines. First of all we have to explain why this task is not just as simple as adding a skin to a tile. The image on the right shows a simple country house drawn in Flash as vectors, and then placed on a background.

We place it on the isometric grid discussed previously, adjusting its alpha value to show the grid behind. In order to simulate what happens in OpenSpace, the house is used as skin of the yellow-highlighted tile.

If we imagine an avatar walking around the house, due to the way avatars are handled (they are placed inside the tile they are walking on at each instant of their movement), we will immediately see that when the avatar enter tiles 57, 47 and 37 it will be behind the house skin (which is part of tile 66), not in front of it as it should be! This is what we would get (supposed avatar is on tile 57):

If we attach the skin to tile 63 we have the same result. Instead, if we use the other two corners of the house base (corresponding to tiles 33 and 36), the avatar will overlap in the wrong way when moving behind the house on tiles > 36 and < 63, for example on tile 51:

Now let’s see how to solve this problem.

Tile-based approach

The best way to have large 2D elements on the map is... not to have them! This means that we should divide the skin among all the tiles that constitute the object base (or better, the frontal tiles). This can be done in several ways: the worst is using vertical slices of the bitmap (not recommended!); the best is to create some sort of building blocks to compose each object, taking advantage of the tile’s stacked skins feature. The following image is a rough example of the latest technique:

As the picture shows, a single skin is used as basic wall for the house, then additional skins are added to the relevant tiles to create windows, doors and so on. Adding details is the key to make the buildings differ one from the other and make their appearance less tiled (for example we could add cracks on the walls, some ivy, a balcony, have different shapes, etc.). We could even add a second floor to some buildings, by stacking tiles one above the other. Moreover, in the above example the roof is a single, non-tiled bitmap, which can be used in a tile above the front corner. This is possible because avatars height will never make them “disappear” under the roof (oppositely to what happens in the first of the images above showing the red circle). This technique has the big advantage of allowing a great reusability of each element, letting you build different objects from a reduced number of skins, thus reducing the size of the tiles library and the memory consumption. Also, this technique allows the creation of complex elements, like overpasses, bridges and underpasses. On the other hand, all this requires graphic designers to make an effort to create the building blocks properly.

Skin separation approach

In order to keep a better control over the objects’ graphics, avoiding the common defects of a tiled approach (repetitiveness, above all) you can adopt this second approach, which consists in dividing the skin into two parts, following the main isometric directions. How to divide the skin largely depends on its shape: the only suggestion is to reason on the numbered isometric grid, to understand how to make the different parts correctly overlap with surrounding objects or avatars. Here is an example, which makes use of the previous country house:

The house has been divided into two skins, assigned to different tiles (63 and 36). This solves the overlapping problems seen previously. This approach may not work properly in some cases, for example if the building’s structure contains a concavity, like in the following image on the left. In this case, dividing the skin between two tiles is not enough (try to reason on the numeric grid to see why), but you can still divide it into four parts, as if we had two distinct buildings (both convex) on which to use the described technique:

NOTE
If you use the skin separation approach with bitmap graphics containing transparencies (usually the bitmap’s bounding box is filled with transparent pixels), you may experience the following issue: the transparent part of the bitmap catches the mouse click, so you can’t make your avatar move on the tiles covered by the bounding box of that skin. In order to solve this problem, simply remove the background of the bitmaps after importing them into Flash, following this tech note from Adobe.

Whatever of the proposed techniques is used, a good approach is to “compose” the large objects by grouping the tiles they consists of (tiles 63 and 36 in the above example), so that they can be easily instantiated more than once on one or more maps. This can be achieved using the Supertile editor section of the OpenSpace Editor.

Background and foreground

OpenSpace uses separate background and foreground layers: background is placed below all the tiles, while foreground is always above. A separate layer for background let the map designers have a better control over the environment appearance, without being subject to the restrictions and defects of a tiled approach. Taking this to the extreme, an environment could be made of just a background covered with empty tiles (tiles without their skin) which simply set where an avatar can or cannot walk. Also, having a separate background allows you to fill with continuous graphics (which scroll together with the map) those parts of the scene which aren’t covered with tiles (typically the viewport corners, due to the fact that the isometric map has a diamond shape).
As it regards the foreground, if its overall size is smaller than the background overall size, a parallactic effect is applied during the map scrolling.

Both background and foreground graphics should be split into several sub-parts in order to improve the scrolling performance. In fact, whenever one of the background/foreground parts is out of sight, the OpenSpace engine removes it from the display list, therefore avoiding to render it during the scrolling. Background and foreground parts are placed on an orthogonal grid (not isometric!) in the Background editor of the OpenSpace Editor, thus each one of them must have the same size (width and height). The smaller the size is (with respect to the viewport size), the better it is. The following image shows an example of background divided into four parts:

The background / foreground parts are movieclips or sprites contained in the Flash library of one or more external swf files (let’s call them “backgrounds library files”) loaded by the OpenSpace Editor (at author-time) and by the OpenSpace component (at run-time). Each part must have a unique Class name set in its Linkage properties, while the Base Class must be flash.display.MovieClip or flash.display.Sprite. Using sprites instead of movieclips is highly recommended for performance and memory usage reasons.
At author-time, the OpenSpace Editor processes the backgrounds library SWF file to retrieve all the available parts automatically.

Operating instructions on the map creation process can be found in the OpenSpace Editor documentation.