Skip to content

Development : Mallet Engine : Entry Point

August 3, 2012

When you think about the structure of a typical game engine, it is designed to provide a set of tools for developers to create their games. However, it isn’t a library like SDL, or SFML, as they don’t force the developer to write code in a particular way. So an engine is more like a framework. It provides a set of tools that the developer can extend, add, and modify, but, the developer must adhere to a particular philosophy defined by the engine builders.

Mallet Engine is no different, it provides great flexibility at low levels, but, the developers must adhere to the overall design structure to ensure that their code works as expected and plays nicely with the other systems. As with other applications the entry-point is greatly important. To the Mallet Engine it defines what modules, states, and general settings should be loaded. The entry-point is specified by the game developer and is not strictly defined, however there is typically an order.

  1. Create low-level system.
  2. Load global configuration file and configure low-level system.
  3. Initialise low-level system.
  4. Create game system.
  5. Create appropriate game-states and add them to the game system.
  6. Run game-system

The Mallet Quest entry-point provides an example of this order in action:

public static void main( String _args[] )
{
    GLDefaultSystem system = new GLDefaultSystem() ;
    ResourceManager resources = ResourceManager.getResourceManager() ;

    Settings config = null ;
    config = ConfigParser.parseSettings( ConfigReader.getConfig( "base/config.cfg" ), config ) ;
    resources.setConfig( config ) ;
    displayWidth = config.getInteger( "DISPLAYWIDTH", displayWidth ) ;
    displayHeight = config.getInteger( "DISPLAYHEIGHT", displayHeight ) ;
    renderWidth = config.getInteger( "RENDERWIDTH", renderWidth ) ;
    renderHeight = config.getInteger( "RENDERHEIGHT", renderHeight ) ;
    system.setDisplayDimensions( new Vector2( displayWidth, displayHeight ) ) ;
    system.setRenderDimensions( new Vector2( renderWidth, renderHeight ) ) ;
    system.initSystem() ;
    startGame( system ) ;
}

private static void startGame( final SystemInterface _system )
{
    GameSystem gameSystem = new GameSystem() ;
    QuestGame game = new QuestGame( "GAME" ) ;
    gameSystem.setSystem( _system ) ;
    gameSystem.addGameState( game ) ;
    gameSystem.setDefaultGameState( "GAME" ) ;

    gameSystem.runSystem() ;
}

GL Default System creates and manages the low-level subsystems that handle the resources of the entire engine. It implements the System Interface enabling you to write your own and create specific implementations for different resources. The entry-point quickly moves onto loading the global configuration file and setting the appropriate view dimensions. It then wraps up by calling initSystem to ensure all low-level subsystems have been hooked-up correctly.

The Game System controls game-states, these states contain your game related logic. Only one game-state can be updated at a time. A game-state can make a request to transition to another game-state, for example you can have an Intro State, your Game State, a Menu State, and a Credit State, transitioning between them when it is appropriate. During a transition you can also pass a package to the new state, this package contains relevant information, for instance if the Game State was transitioning to the Menu State it may want to show the game-save page instead of the default character-select page.

The default constructor of a game-state should be bare. The reason for this, is to ensure that a game-state does not consume resource memory when it is not being used. The Credit State, for example, is constructed at the start, but will likely never be seen until the end of the game. We only begin loading and initialising the required resources once the startState function has been called.

// Game State functions used by the State Machine
public void update( final double _dt ) {}

public void startState( final Settings _package ) {} // Called when transitioning to this state
public Settings shutdownState() {}                   // Called when transitioning on a Shutdown request
public Settings pauseState() {}                      // Called when transitioning on a Pause request

public final String getTransition()                  // Name of state to transition too
{
    return transition ;
}
public final int checkTransition()                   // Informs whether state wants to transition
{
    return transitionType ;
}

A game-state has two options when making a transition request, it can either shutdown, or pause. The shutdown request is to allow the state to begin afresh with a blank slate, as if it had just been created. The pause request allows the state to keep track of any relevant data it sees fit. You don’t want your Game State data to disappear when transitioning to the Menu State.

The transition is a linear process which is not very good if you are loading very large game-states as it would produce a visible stall. It would be possible to start the game-state asynchronously by placing the heavy loading on a separate thread, and then move to a loading-screen-state. Once the heavy loading has completed, issue a message that informs the loading-screen-state to transition back to the game-state. I would prefer to implement a more elegant and streamlined process that is less error prone by the developer.

The entry-point process is completed when the runSystem is called, which kicks off the engines game-loop.

public final void runSystem()
{
    double dt = 0.0f ;
    boolean running = true ;
    while( running == true )
    {
        dt = ElapsedTimer.getElapsedTimeInNanoSeconds() ;
        running = system.update() ;
        stateMachine.update( dt ) ;
    }
}

The Mallet Engines’ game-loop is only a few lines of code. Within the while-loop Elapsed Timer is called to get an average delta-time over twenty or so iterations. Afterwards system.update is called, which ticks over the essential subsystems like input, and events, it also returns a boolean to allow the engine to completely shutdown. Finally the state-machine is updated, which in turn updates the currently running game-state.

By allowing the developer to manipulate the entry-point it provides great flexibility to deal with platform specific nuances. It allows the developer to change low-level subsystems to operate better on a specific platform, or change how the engine receives its configuration data, without directly affecting the other platforms, or the game. This design shows its benefits when dealing with Android, as it handles certain concepts differently compared to a traditional Java desktop application.

I plan in the next week or so to go into further discussion on how the system, and game-state operates. If you have any questions please post them in the comments below.

Ross.

Development : Mallet Engine : Input

July 23, 2012

The Mallet Engine supports a multitude of different platforms, in particular Linux, Windows, Mac, and for mobile: Android. Java provides excellent cross-platform  support by enabling a standard interface for interacting with system level components. To gain user-input you simply implement the appropriate Listeners (Key, Mouse, MouseMotion, MouseWheel) and then register them with the appropriate Window, typically a JFrame. Android deals with user-input differently so we will focus on the Desktop implementation of Mallet Engines’ Input System.

Java provides a fairly consistent API and coding for cross-platform is almost built into the language by default. However, when you involve Android you cannot bank on being able to use the entirety of the Java API. To resolve this issue, you must implement an abstraction layer that takes the data from one API and converts it to a standard that the rest of your system adheres to. The Mallet Engines’ Input Framework is designed for this purpose in mind, it takes user-input from X API and massages the data into the Mallet Engines’ input standard.

All Input Systems used by the Mallet Engine implement the Input System Interface, which defines how the engine as a whole will interact with it. The interface is made up of five methods:

addInputHandler( final InputHandler )
removeInputHandler( final InputHandler )
update()
clearHandlers()
clearInput()

The first method is how an external component can register an interest in user-input, and as you have probably guessed the second method is how it can be removed from receiving data. The update method is used to send the input events to the registered input handlers. In a typical game-state, update, is called as many times as possible to ensure the latest input is passed  as soon as possible. The fourth method is to un-register all Input Handlers from the Input System, while the last method clears the current queue of inputs waiting to be passed to the Input Handlers.

The Input System massages user-input into an Input Event object, which can handle a range of input-types, including: mouse, keyboard, and touch. At the moment Input Event supports two-button mouses and supports scroll wheel events. Keyboard events are registered as either pressed or released, and provides the character of the key (if available) and its keycode. Touch events are handled similarly to mouse events, but touch has its own three input-types: move, up, and down.

In an older version of the Desktop Input System all user-input was massaged, stored in a queue, and then passed to the Input Handlers at the appropriate time. However, it quickly became apparent that the Linux version of the Java Listeners had a bug. By default when you press a key an event is sent to the appropriate listener, when you release another event is released. For Linux, when a key was pressed a torrent of repetitive identical key presses were passed which resulted in our queue being filled with irrelevant Input Events.

The problem was resolved by mapping the keycode to a Key State object. The Key State stored an input event, it also identified whether the key-state had changed and stored the last time stamp of the key. When a key event came from a Java Listener the time-difference was compared, if the difference was greater than zero, the input event was updated and the Key State identified itself as changed. During the update phase it would loop through the map only passing input events that had changed. This fix eliminated the irrelevant creation of new Input Events, and the passing of repetitive data to the game.

Luckily Mouse events are not affected by the same bug, but, it does have its own set of problems. The mouse event that come from a Java Listener provide the mouse co-ordinates in relation to the window, however, you could be playing your game in a 1024×768 window, but the viewport could be 800×600. For the mouse to be displayed correctly, we must convert it to the co-ordinate system of our renderer.

This solution is provided through the Render Info class that implements the Input Adapter Interface, allowing you to convert a point in the display co-ordinate system to a point in the render co-ordinate system. The conversion will also translate the point by the camera-position to ensure it is in the expected location.

float convertInputToRenderX( final float _x )
float convertInputToRenderY( final float _y )
Vector2 convertInputToRender( final Vector2 _input )

For many games, particularly two-dimensional ones, they have a desired aspect-ratio (4:3, 16:9, etc).  If the display-ratio is not the same, then the game can appear squashed or stretched. A solution to this problem is to ensure that your game is not dependant on a particular ratio and that content on the periphery is not of great concern to the player. Sometimes, the aspect-ratio is greatly important and must be consistent irrelevant of the display ratio. The solution is to only allow the render to be scaled to the maximum resolution the display-ratio will allow, while ensuring the render keeps its aspect-ratio, creating a letterbox, or pillarbox effect. Render Info deals with this effect and takes into account the offset caused while converting the mouse co-ordinates.

float convertInputToRenderX( final float _x )
{
    return ( ( ( _x - screenOffset.x ) * renderDimensions.x ) / scaledRenderDimensions.x ) - cameraPosition.x ;
}

float convertInputToRenderY( final float _y )
{
    return ( ( ( _y - screenOffset.y ) * renderDimensions.y ) / scaledRenderDimensions.y ) - cameraPosition.y ;
}

_x/_y : The mouse position.

screenOffset : Takes into account the pillar/letterbox effect. If there is no black-bars then this will be zero.

renderDimension : The original resolution of the final rendered frame.

scaledRenderDimension : The resolution the frame will be scaled to when displayed on screen.

The Android Input System operates in a very similar manner except how it massages the input-data. At a later date I would like to improve the system by reducing the amount of Input Events it creates. Currently a new Input Event is created for each mouse/touch event and then discarded soon after. I would like to implement a pool of reusable Input Events to alleviate a potential garbage collection nightmare.

Ross.

Development : Mallet Engine

July 19, 2012

Over the past few months I have been writing a new game-engine in Java. It ‘s cross-platform and also supports Android devices. I have written a mixture of small one-off games with it and have even released a title on the Android market. It is still in heavy development but is completely usable in its current state.

The engine is built on the assumption that sooner or later the Developer will want to replace or modify something at a low-level. To either improve performance, add-in a new feature, or support a custom platform. For example, Mallet currently supports three rendering systems based on: JOGL, Graphics2D, and Androids Drawable. You can swap between these renderers and your game will not be affected. It could visually look different, for instance, the DRAWLINE request could not be available in the Android Renderer.

My current game-project takes advantage of this functionality by using the Graphics2D render for the Level Editor, and the JOGL based Renderer for the actual game. Using the Graphics2D renderer allows me to quickly prototype and add in additional Editor specific features with ease. I could do the same with the OpenGL renderer, however, it wouldn’t be as quickly developed.

Over the next few weeks I plan on writing about each of the different Mallet Engine systems. This is more for my own benefit as it keeps it fresh in my mind and ensures that any  modifications don’t get forgotten about. I’ll also want to discuss more on my game-project but we’ll talk about that another time. 😉

Ross.

Current Events

November 27, 2011

It has been a while since my last post, but, in my defence I have been rather busy! Linx Online attended Scotland’s New Start Exhibition and entered the New Start Competition. We succeeded to the final round, however, was pipped to the post by a rather clever invention. Though we failed to win, interest in the Read Easy product has been phenomenal.

Read Easy is an assistive program for Dyslexic and the visually impaired. It allows users to convert all their documents in a single click to a pre-defined font, font-size, background and foreground colour.

Within the next few months we aim to release Read Easy to the public. Read Easy supports all the major operating systems( Windows, Linux, and Mac ) and is designed for speed and simplicity.

We believe this product will be beneficial to individual users and companies that need to adhere to the Disability Act.

We are currently cleaning up the code base and ensuring the features work perfectly for all platforms.

If you would like to know more about Read Easy, contact-us at http://linxonline.co.uk/index.php?page=contactus.php

Ross.

Engine Development – Basic Structure

November 4, 2011

The Dragon Engine is built with modularity in mind. It is designed to allow a developer to strip out large chunks of it’s default code and replace it with their own version. The engine is built on flexibility and ensuring systems can be easily optimised for whatever the developer wants to do. Below I describe the overall engine structure and I will aim to go into further detail with later blogs.

A system deals with a particular over-arching task that may consist of a variety of smaller jobs. For instance, the input-system handles all of the key and mouse gestures produced by the user. It stores the gestures in a queue and passes the input data to the appropriate classes that have requested it. A system is generally devised to enable the developer to either extend or replace the current version. Many of the systems implement an Interface that standardises how one should interact with it. Enabling it to be replaced with relative ease.

The Dragon Engine is built from a multitude of different systems:

The Game System can be considered the root of the engine, it pulls everything together and gets the ball rolling. The Game System contains a Finite-State-Machine that can be filled with States. A State can be extended to implement game specific logic.  When a State is added to the Game System it registers it to the Input System and Event System, it also passes it a pointer to the Game Window. The Game System will only allow one State to update at a time, ensuring that States cannot conflict with each other.

The Game System also loads the global Configuration file and initialises the Game Window. The Game Window is passed the State to handle its own Rendering and refresh times.

The Resource Manager is the gateway to retrieve game content. It provides access to the other managers that keeps track of content currently being used by the game. This includes: Models, Textures, Animations, Sounds, and Fonts. The Resource Manager is effectively a Façade that hides the more gruelling details of retrieving and storing the content requested by the game. Each resource is tracked by their respective manager, enabling content to be quickly cleaned up if space is required.

The Input System does what it says on the tin, it handles the users input and feeds it to the appropriate classes. The Event System operates on a similar basis as the Input System but it handles Events instead. An Event is a message from one object to another.  An Event is a list of relevant information that an object/s may find useful. It enables an object to send a message to multiple other objects without having to know anything about them.

The Entity System is contained within a Game State, it manages all of the Entities that are currently being used. An Entity is a game object that can represent anything within the game. This can be something simple like a door, to a complex AI operated NPC. It is built on a Component based design enabling a vast amount of flexibility. The Component structure implemented really requires a whole( or more ) blog post of its own.

As stated previously the Rendering System is contained within the Game State and enables content to be rendered onto the Game Window. Currently it only supports 2D rendering and is rather simple in its implementation. Though it does support alpha sorting and optimises the rendering list to ensure the minimal amount of binding. The Renderer is based purely on OpenGL and takes advantage of VBOs, however I have yet to implement Shaders, one day!

A recent implementation to the Engine is the Collision System. At the moment it only sports AABB collision detection with the aim to implement OBB soon. It also requires a moderate clean-up and some general optimisations as the system has a processing performance of (O)n. Which I’m sure you can agree is rather slow!

Well I believe that is most of the important Dragon Engine systems covered, though it does have a large range of support classes that are invaluable to its running. In particular the Settings class. Though for now I believe I have written enough.

Ross Forshaw.

Engine Development – Introduction

October 25, 2011

Hello and welcome to the Dragon-Engine development project.

To start off, my name is Ross Forshaw. An avid Programmer and Director of Linx Online Ltd, a small software development company that loves to develop software, with an exceptional passion for games-programming.  With this Blog I aim to detail the progression of building a game-engine and the development of an actual game. Writing about the different systems involved in a game-engine and how I implemented them for our game.

My passion for games development began at the early age of twelve. When I first played Crash Bandicoot 2 on the original Playstation. With my interest sparked, I began developing my own grandeur games on any piece of paper at hand.

At the ripe age of fourteen I began learning how to make maps for Soldier Of Fortune 2. Many of them never to see the light of day, and many that should never have seen the light of day. With the new found experience in map design, I tried my hand at modelling and animation using the renowned Blender3D. It would take two years of learning, but in the end it was worth it.

Though I have a deep interest in graphic design, my passion lay in programming. During my secondary education I taught myself Java and afterwards began learning C++.

Going to University I learned a great deal about games programming from some of the best lecturers in Scotland: Dr. Daniel Livingstone, Dr. John Sutherland, and Mr. Alistair McMonnies. My drive in university was to build my own cross-platform game-engine. Which I managed in third year with the development of the Moombacoot engine. My Honours dissertation was focused on AI development, in which I created an AI framework for programmers.

Learning from my past mistakes with the Moombacoot engine and AI framework, I have set out to develop a new modular engine, the Dragon Engine. It has already been in development for a few months, with most of the major systems already implemented. The graphics system is rather primitive, though there are plans on improving that.

Here is a short video of the most recent Developments :

I have yet to decide whether I will post on a weekly or monthly basis. However the next post will go into details on the overall engine design and will have more programming content than just my past history. I promise!

Ross.