Skip to content
Michael Aquilina edited this page Jun 18, 2013 · 104 revisions

This WIKI is currently being built in parallel with development of the Game Engine and the techniques being used. Some pages of note:

Last Updated: 05/06/2013

Game Engine Overview

This section of the wiki is here to give you a quick overview of how to make start making use of the TeeEngine to develop games. More detailed, dedicated subsections will be added in the future.

The main Class that forms part of the Engines interface and runtime is the TeeEngine class. An instance of the TeeEngine class should be instantiated during an XNA Initialise() method. During this time, a Map instance may also be loaded using the LoadMap method provided by the TeeEngine class. At its simplest form, initialization is performed as follows:

TeeEngine engine = new TeeEngine(this, 800, 600);   //start a TeeEngine class at 800x600 resolution

The resolution of the engine can be changed at any stage with the SetResolution() method.

engine.SetResolution(1024, 768);

Once the engine is initialised, a map may be loaded to the engine:

TiledMap someMap = new TiledMap("example_map.tmx");     //load a tiled map file 
engine.LoadMap(someMap);                            //load the specified tiled map instance

This can also be shortened using the following syntax:

engine.LoadMap("example_map.tmx")

You may also provide a dictionary of string key/value pairs as arguments to pass to the map's LoadMap script:

MapEventArgs args = new MapEventArgs();
args.SetProperty("StartLocation", "ForestEntrance");
args.SetProperty("PreviousLocatioN", "Forest");

engine.LoadMap("example_map.tmx", args);

Using Tiled with TeeEngine and XNA

The TeeEngine framework fully supports loading from Tiled (*.tmx) files. However, in order to integrate well with XNA, it is important that for each tileset added to the map, its Content path is specified in the properties. The Content path is the path that would be used to load the appropriate texture in XNA with the Content.Load method. See Tileset Properties for a list of supported properties.

The TeeEngine offers automatic Entity loading from objects. This provides an easy way to add and customize Entities within a map without having the need to write any additional code.

In order to allow additional logic, tiled maps can specify a Map Script to run alongside it when it is loaded into a TeeEngine instance.

Adding and Removing Entities

Any entities that need to be added can be done so with the AddEntity() method. The add method expects an entity object to be passed at minimum. Ideally, an identifying name value should also be supplied with the entity object for quick retrieval from the engine using the GetEntity() method. If no name is specified by the user, one will be automatically assigned internally. The name identifier currently assigned to an Entity can be found in its Name property. If an Entity is not currently registered in the engine, then its Name property will be set to null.

Entities can be removed at any time using the RemoveEntity() method which expects the assigned name of the entity or the entity itself to remove. Automatically generated names and manually assigned entity names can be found in the Name property of an entity object.

Adding and removing entities using these methods ensures that the internal Collder data structure being made use of by the engine will be appropriately updated.

engine.AddEntity("Player", hero);
engine.AddEntity(magicFireball);
engine.AddEntity("MasterVillian", villian);
...
...
engine.RemoveEntity("MasterVillian");    //The villian has been killed and can be removed from the game
engine.RemoveEntity(magicFireball);      //the fireball has reached its max distance

Note about Deferred Adding and Removing of Entities

It is important to note that when a call to AddEntity() or RemoveEntity() is made, the actual operation is not immediate. Addition and removal of entities is deferred to after all update calls for each entity has been completed. In the meanwhile, the entity that has been added or removed can still have its properties updated and methods used, however the change wont be seen till the next game update loop.

This behavior is to ensure that within the same game update loop, the same entities are available. When a call to either AddEntity() or RemoveEntity() is made, the entity's assigned name is placed in a pending entities list, which is then be used by the Engine as a reference to what should be removed and added at the end of a games update loop.

Retrieving Entities

Entities can be retrieved very easily using the GetEntity() method. If say, you wish to retrieve the main player from the engines list of entities, then you may do so with its assigned name identifier. Accessing other entities within an Enitity's update loop should always be possible due to the the Update() method always being passed a reference to the engine in its parameters.

public override void Update(GameTime GameTime, TeeEngine Engine)
{
    Entity player = Engine.GetPlayer("player");
    if( Vector2.Distance(player.Pos, this.Pos) < 20 )
    {
        //attack player if hostile
        //hug player if friend :3
    }
}

Inbuilt Path-finding

In order to allow Entities to traverse a map in a correct manner (by avoiding non-walkable areas and possibly other entities), the TeeEngine comes with an inbuilt pathfinding A-star implementation that can be used to direct Entities.

In order to use the Pathfinding to generate a valid Path from start to end, you may use the Pathfinding property in the engine instance to run GeneratePath() to return a Path instance that contains nodes which each represent a tile location on the map:

Path path = engine.Pathfinding.GeneratePath(startVector, endVector, engine, gameTime, ValidateFunction);
Follow(entity, path);  // Use some custom method to follow the nodes within the Path instance.

As can be seen above, an instance of the related TeeEngine instance and the current GameTime also needs to be provided. Additionally, a delegate method to validate incoming tiles must be provided to determine areas of the map which are walkable. Valid tiles are those tiles which the A-star algorithm will avoid and try to move round in order to reach the destination. An example of a Validate delegate can be seen below:

public bool PathfindingValidator(Vector2 txPos, TeeEngine engine, GameTime gameTime)
{
    Tile tile = engine.Map.GetTxTopMostTile((int)txPos.X, (int)txPos.Y);

    return tile != null && !tile.HasProperty("Impassable");
}

Game Drawables Framework

TeeEngine provides an IGameDrawable interface for allowing external games to implement their own types of drawable classes. There are a number of standard built-in classes however that can be used of the box:

  • Animation (BitmapDrawable)
  • StaticImage (BitmapDrawable)
  • PlainText (TextDrawable)
  • TextRegion (TextDrawable)

Drawable items are usually stored in Entities through the use of DrawableSets. A DrawableSet is a set of drawable instances organised into groups called 'States'. An Entity may have ts current state set to one of the States found within the drawable set. Doing so will cause the drawables associated with that state to draw the screen at the location where the Entity is found.

Entity player = engine.GetEntity("Player");
player.CurrentDrawableState = "Running_Left";    // Change to the set of "Running_Left" drawables
...
player.CurrentDrawableState = "Idle_Right";   // The player stopped moving, set to idle

Much like their mathematical counter-parts, DrawableSets may be added together through a Union operation and deducted from one another using a Remove operation. This can be very useful for removing and adding drawables associated with a particular item from an Entity.

Item plateHelmet = ItemRepository.GameItems["PlateHelmet"];    // Load an Item
Entity hero = engine.GetEntity("Player");
...
hero.Drawables.Union(plateHelmet.Drawables);     // Player equips a Plate helmet and its animations
...
hero.Drawables.Remove(plateHelmet.Drawables);    // Player unequips the Plate helmet and its animations

In order to allow properties to be set on drawable items on a per Entity basis, drawable items added to a DrawableSet are wrapped within a DrawableInstance class that provides properties to change the drawables color, opacity, visibility, rotation etc.... for the entity it is associated with.

In order to decouple the design of Entities and their drawable parts seperate from code, the engine supports loading DrawableSets from xml files. Currently there is support for specifying Animation type Drawables - but in the future all types should be supported.

To understand in further detail how changing between drawable states works, take a look at the article about Drawable Sets.

Using Post Render Game Shaders

Shaders that inherit from the abstract PostGameShader class can be added to the Engines runtime using the RegisterGameShader() method. They can also be unloaded using the UnregisterGameShader() method. It should be noted however that if you simply wish to disable the shader from being used for a particular amount of time, then the Enabled property of the PostGameShader object should be used rather than UnregisterGameShader() due to being faster.

PostGameShader someShader = new CustomShader();    // CustomShader class that inherits from GameShader.
engine.RegisterGameShader("myCustomShader", someShader);         // Begin post-rendering using our CustomShader class.
...
someShader.Enabled = false;                    // Turn off the shader for short while.
...
someShader.Enabled = true;                     // Turn the shader back on.
...
engine.UnregisterGameShader("myCustomShader");       // We no longer need the shader.

Drawing the World Viewport

During appropriate XNA Draw calls, a viewport of the current world can be drawn onto the screen using the DrawWorldViewPort() method. This method expects:

  • A SpriteBatch object to draw with that hasnt been started.
  • Center X and Center Y value (in pixels) that specifies where the camera should focus.
  • a Zoom value specifying how much the method should zoom into the specified focus location
  • A Destination Rectangle that specifies where to draw on the screen
  • A Color value with which to tint the draw call with
  • A SamplerState object with which to render tiles and entities.
  • A Loaded SpriteFont instance which will be used to render any text to the screen.

During the draw call, any Registered PostGameShader objects will be able to apply their changes to the output before rendering it to the back buffer (i.e. the users screen). The method will return an instance of ViewPortInfo. This class instance contains detailed information about how the world viewport was drawn such as the Top Left X and Y coordinates in terms of the world map, the ActualZoom value (compared to the specified Zoom value passed in the parameter) and the Width and Height of how each tile was drawn.

//Draw the World View Port, Centered on the CurrentPlayer Actor
ViewPortInfo viewPort = Engine.DrawWorldViewPort(
                                  SpriteBatch,
                                  FollowEntity.Pos,
                                  Zoom,
                                  pxDestRectangle,
                                  Color.White,
                                  CurrentSampler,
                                  DefaultSpriteFont);

During the draw call, the following properties can be enabled within the DrawingOptions property of TeeEngine. These options will determine whether to draw certain debug information during the draw call or not:

  • ShowQuadTree: Show the bounding area of every child Quad Tree node.
  • ShowEntityDebugInfo: Draw debug information related to an entity in the center of its bounding box.
  • ShowTileGrid: Draw the boundaries of each tile in a grid.
  • ShowBoundingBoxes: Draw the bounding boxes related to each entity and their origin.
  • ShowDrawableComponents: Draw the bounding box of each separate draw-able component on each entity.

Using in-engine Performance Diagnostics

Each instance of the TeeEngine class also initialises a number of DiagnosticInfo instances that are used to monitor performance in a number of key areas within the runtime of the engine. The storage of this performance information is extremely lightweight and minimal - and as such should have no affect on the net runtime performance for the game.

There are three properties that provide Diagnostic information:

  • OverallEnginePerformance: Runtime performance information related to overall timings such as total entity update time, total tile rendering time, collider update time etc... The following information can usually be found:

    • TotalEntityUpdateTime: Amount of time taken to run all Entity update routines.
    • TileRenderingTime: Amount of time taken to render all the tiles within the last DrawWorldViewPort() call.
    • DestroyEntitiesTime: Amount of time taken to Destroy entities during the last game loop.
    • CreateEntitiesTime: Amount of time taken to Create pending entities during the last game loop.
    • MapScriptUpdateTime: Amout of time taken for the designated MapScript to perform its update routine.
    • ColliderUpdateTime: Amount of time taken for the collider to upate its internal structure due to Entity changes.
    • TotalEntityRenderTime: Amounf of time tkane to render all Entity drawables to the screen.
    • TotalPostGameShaderRenderTime: Amount of time taken for all registered PostGameShaders to perform their Apply() routines.
  • EntityUpdatePerformance: Provides diagnostic information about the Update routine for each Entity currently within the engine. Entities are stored within this DiagnosticInfo instance by their assigned Name.

  • EntityRenderPerformance: Provides diagnostic information about the Render pass for each entity currently within the engine. Entities are stored within this DiagnsoticInfo instance by their assigned Name.

  • UserPerformance: Completely empty DiagnosticInfo instance which is reserved for use by the User to create custom timings to be recorded by the engine. Timing can be performed using the StartTiming(), RestartTiming() and StopTiming() methods.

engine.UserPerformance.RestartTiming("SomeAlgorithm");
algorithm.foo(start, end);
engine.UserPerformance.StopTiming("SomeAlgorithm");

Accessing this diagnostic information can be performed using three different methods depending on what needs to be retreived.

  • GetTiming(string key): Returns a TimeSpan object specifying the amount of time taken during the last game loop for the associated performance metric.
  • ShowTop(int top): Returns the top number of specified performance indicators in the DiagnosticInfo instance in a string with each entry seperated by a line.
  • ShowAll(): Returns a string of line-seperated performance indicators currently stored in the DiagnosticInfo instance. Equivalent to calling ShowTop()

Example Usage:

// Retrieve update timing information for the Entity 'Player'.
TimeSpan entityUpdateTimeSpan = engine.EntityUpdatePerformance.GetTiming("Player");

...
// Show all timing entries.
SpriteBatch.DrawString(.., engine.OverallEnginePerformance.ShowAll(), ..);

...
// Show the 5 largest timing entries.
SpriteBatch.DrawString(.., engine.EntityRenderPerformance.ShowTop(5), ..);    

Tiled Applicable Properties

Other