Opal Reference Manual

1.0

Introduction

The Opal Library consists of two parts: A level editing tool for creating maps using polygons and sprites, and a set of C++ classes designed to work alongside Haaf's Game Engine (HGE) providing a means to render & create games using the maps created within the level editor software.

This page contains the guide to configuring & using the editor to create game levels, and for creating C++ code to make use of your creations. It assumes that you are familiar with C++, and Haafs Game Engine (http://hge.relishgames.com/).



The Level Editor

editor1.jpg

The Editor.

The level editor can be found within the /editor/ folder of the Opal distribution.


Configuring the editor

The editors config is contained in the editor.cfg file. The file is divided into three main sections. All of the options are commented in the config file that comes with the editor but I will give a brief description of them here.

The first section is "editor options". These options can customize some of the colors in the editor, like the background and grid color. They also specify the directories for various filetypes, like maps, textures, border textures, etc. Your game will likely reference the same data as the level editor so this is where you can customise the directory structure of your project. The default values are:

editor options
{
    //////////////////////////////////////////////////////////////////////////
    // Editor Options

    // Editor Window Title
    window_title = "Opal Level Editor";

    // Background Color
    background = 0xFF444444;

    //////////////////////////////////////////////////////////////////////////
    // File+Directory Options

    // Base Maps directory
    map_base = "maps";

    // Base Prefabs Directory
    prefab_base = "maps/prefabs";

    // Base Texture directory - subfolders of this directory are listed
    tex_base = "data/textures";

    // Border textures directory
    tex_border = "data/border";

    // Shadow textures directory
    tex_border_shadow = "data/border/shadow";

    //////////////////////////////////////////////////////////////////////////
    // Interface Options

    // Invert middle mouse pan control
    invert_pan = 0;

    // Grid Options
    grid_color = 0x11FFFFFF;
    grid_scale = 64.0;
}


The second section is point entitys. This is where you can define the various elements that will make up your game that will need placing into levels by a level designer. Point entitys are a polygon with only a single vertex and have a sprite file associated with them rather than a textured shape. Below is an example point entity:

 point Turret
 {
   sprite = "data/ents/turret.png";
   shoot_rate = 1.0;
   bullet_speed = 200;
 }


The point definition lets the editor know this is a point entity type, and the next word - Turret is the classname of the entity. You must pick a unique classname for your entitys. The next section is the definition of the properties that a Turret entity will posess. You can specify as many properties as you like here with or without default values specified. You can set or alter values on individual entitys when they are placed in the editor, and the specified values can later be read by your C++ code. The editor takes special note of the "sprite" property for point entitys. It will render the specified sprite when you create this entity within the editor.

editor4.jpg

The Turret entity from within the editor.

The final section of the config is for polygon entitys. Polygon entitys work much the same way as point entitys, except they represent a polygonal shape instead of a point & sprite. You can specify a default texture for polgon entitys to use with:
texture="path/to/texture.png"
The texture used must exist within the configured base textures folder.


Using the editor

The editor uses the mouse for the most part, with common click & drag features you should be used to from other software. The mouses standard function is to select & drag polygons. To create a polygon, hold the spacebar and click on the map area. A vertex will appear with a line leading to the mouse.

editor2.jpg

Creating a polygon.

You can now release the spacebar and keep clicking to add more points to the shape. When you are done adding points, right click with the mouse to close the shape.

editor3.jpg

Right click to close the shape.

The texture bar

The texture bar allows you to manipulate the visual style of a selected polygon, and its entity class & properties. You can click the white arrow on the upper left of the screen, or press Q to toggle the texture bar on or off.
The bar consists of 3 tabs.

editor5.jpg

The three texture bar modes

Layering

The right click menu appears when you right click on a selected polygon. It allows you to adjust the layer and position within a layer, of a polygon. The level editor stores polygons in 3 distinct layers - the Background, Middle and Foreground layers. You can move polygons into one of these distinct layers by clicking the layers name in the menu. These distinct layers become useful in game development when you may want a whole layer of polygons that go in the background purely for decoration and do not collide with anything - and the SDK takes advantage of this.
You can also adjust a polygons position within its distinct layer using the remaining options in the menu.

The toggle layer visibility buttons are located on the bottom right ahnd side of the GUI. Pressing a button will cause it to turn yellow & to hide any polygons in that layer from the view. Press the button again to toggle the layer to visible again.

rcmenu.jpg

The right click menu and layer visibility buttons

Controls + Keyboard Shortcuts

There are various other controls & keyboard shortcuts the for the level editor. They are detailled below:


The SDK

The SDK consists of a set of C++ classes for handling polygons & the polygon map as a whole. The hgePolygonMap class is the core of the SDK and provides all the functionality you need to create a game without having to write an engine yourself. You can concentrate on writing the classes that make up the game, and just link them to entitys you defined in the editor where nececarry.

The SDK is designed to work alongside HGE, and the classes and functions defined in the SDK retain HGE naming conventions to promote ease of use & integration.

Installing the SDK

The Polygon SDK is installed in the same way as HGE. First, you need to extact the SDK to a sensible directory, something like:
C:\Programming\Libs\Opal


Next, you must add the include directory folder to visual studio's list.

vc1.jpg

Adding the include directory to visual studio

Creating a project.

Now you are ready to create a project that uses the SDK. Your project needs to reference PolygonSDK.lib or DebugPolygonSDK.lib for the debug configuration, alongside hge.lib, hgehelp.lib and whatever else your project may use. You should use the /MT or /MTd flag in the c++ code generation options page. If you are having trouble with your project configuration, there is a .sln project in the /example directory that is set up correctly and can serve as a base to build your own project off.

vc2.jpg

Set the /MTd flag if in debug configuration, or /MT for release.


Loading a map.

Below is the code from the example included in the SDK.

    // Initialize Map
    map = new hgePolygonMap ( hgeVector(SCREEN_WIDTH, SCREEN_HEIGHT) );

    // Register Entitys
    map->RegisterEntityClass("Player", new entPlayer() );
    map->RegisterEntityClass("Turret", new entTurret() );

    // Load File
    map->LoadFile("maps/level1.map");


The first line of code initializes the hgePolygonMap object and supplies it with a hgeVector that defines the viewport size for the map. Basicly, the area it will draw to when you call hgePolygonMap::Render(). In most cases this value will match the size of the window.
The last line will load the map from disk and prepare it for rendering.

Registering entitys.

The hgePolygonMap::RegisterEntityClass() lines above are very important lines for the game. They link a class which derives from hgeEntity - in this case entPlayer and entTurret - to an entity classname which you have defined in the editors config file. RegisterEntityClass() must be called before hgePolygonMap::LoadFile() in the map because when LoadFile() is called, the map will load polygons out of the map file and compare their entity classnames to ones that you have registered with the map. If a match is found, a copy of your custom entity class is created and it inherits the polygon instance that was loaded from the map file. In this way, you can easily write C++ code for entitys that you have defined in the editor config, and placed and configured in the level editor.

Entity layering

Entitys can exist on 4 possible layers, between the 3 map layers. This is illustrated below:

layers.jpg

Ordered diagram of possible rendering layers.

The entity layers are defined in the hgeEntityLayers enum.

 enum hgeEntityLayers
 {
     HEL_BACK = 0,
     HEL_MIDDLE1,
     HEL_MIDDLE2,
     HEL_FRONT
 };
 

Static vs Dynamic entitys.

Entitys must specify wether they are static or dynamic upon creation.

Creating an entity class.

Now you understand entitys, we will write a class that is compatible with the hgePolygonMap::RegisterEntityClass() function so that we can link our entity class code to an entity classname defined in the editor.

To do this, the class that we create must inherit from hgeEntity - which in turn inherits from hgePolygon. Below is an illustration of how the skeleton of our class will look:

    class entBall : public hgeEntity
    {
        public:

        entBall() : hgeEntity(HEL_FRONT, false) {}
        entBall *Spawn() { return new entBall(); }

        void Initialize()
        {
        }

        void Update(float dt)
        {
        }

        void Render()
        {
        }
    };

There are a few important things to note here. First are the parameters passed to the hgeEntity::hgeEntity() constructor. The first parameter is the entitys render layer, the second parameter determines if the entity will behave as a static entity.
Next is the Spawn() function. Your class must have this function, and it must return a pointer to a copy of your class. It is used by hgePolygonMap to create instances of your class when it needs to.

Finally, the Initialize(), Update() and Render() routines are optional and I have drawn them in here just to illustrate where they go. Initialize() is called after all polygons & entitys have been loaded from the map. Update is called every frame, just before Render() is called.

Next we will look at the complete code to make our bouncing ball entity react to collisions with the map. In our example code we won't need to make use of Initialize() or Render() since the default implementations will suffice.

// Bouncing Ball Entity 
class entBall : public hgeEntity
{
protected:

    hgeVector velocity;

public:

    entBall() : hgeEntity(HEL_FRONT, false) {}
    entBall *Spawn() { return new entBall(); }

    void Update(float dt)
    {
        // Check we're visible
        if (!map->TestVisibility(this, 100.0f)) return;

        // Apply Gravity
        velocity += hgeVector(0, 500 * dt);

        // Test Collide
        hgeCircle c = hgeCircle( GetPosition(), 20 );
        hgeIntersect test = map->Test( &c, velocity * dt, NULL, COLLIDE_STATIC + COLLIDE_MULTI);

        // Adjust velocity
        if (test.collides)
            test.SetResponseVector( &velocity );

        // Move
        SetPosition( GetPosition() + velocity * dt  );
    }
};

First we call hgePolygonMap::TestVisibility to check if our class is in the cameras view. We pass it a pointer to our class, and a padding value of 100 pixels around the screen edge.

Next we apply a gravity force to the velocity value member, which represents the objects speed in pixels per second. Knowing the objects current position, and its velocity we can perform a collision test to see if the object is going to collide in the next frame. We do this by creating a hgeCircle shape to represent the ball, and passing it to the hgePolygonMap::Test() routine. We pass Test() the COLLIDE_STATIC flag to collide with the map, and the COLLIDE_MULTI flag to detect multiple collisions in the test. The multiple collision test is slower to perform than a regular test, but it will produce more accurate collision results. It is useful for creating objects with realistic physics such as the bouncing ball.

The collision test will return a hgeIntersect struct with all the points of collision and the normals of the edges that were collided against. It also contains a bool, collides which determines if there was any collision at all. The test result has some useful routines for making use of the collision data. hgeIntersect::SetResponseVector() takes a pointer to a velocity value and will set the given value to the appropriate velocity change response for the collision that just occured. It works with or without the COLLIDE_MULTI flag, but produces better results when multi is set.

Finally after finding the velocity value for the next frame, we adjust the position of our entity using the Set and Get Position functions that are inherited from hgePolygon.


What Next?

Now you hopefully know enough to start creating a game using the SDK and Editor! This site contains a full reference of all the important parts of the SDK code with descriptions of functions & data members so I advise you browse it a little to familiarise yourself with the code. It will also serve as your reference guide as you program your game.

If you have any comments or suggestions regarding this project please feel free to contact me by email or MSN at mercior@hotmail.com.


Generated on Wed Apr 29 13:30:34 2009 for Opal by  doxygen 1.5.8