Thursday, 20 March 2014

AVR

It's been a while since I did what I call 'pioneering' AVR development, something new and interesting, something not within the realms of personal day to day work. Thankfully I've picked up a project interfacing an ATMega8 with a WIZnet W5100, which has me all enthusiastic about AVRs again. This post isn't really about that, however, it's more because I've decided to give my collection of AVR code a review, particularly as I'm one of those perverse types who insists on using C++ with Atmel Studio. The thing I've found about C++ is that it's much easier for me (personally) to organise my code into something clean and reusuable this way, so I've been modularising the most often used features of the ATMega8 (although it works with other MCUs such as the 328 and 88 with barely a modification) and building up a library I can use to piece together new projects quickly. Because there doesn't seem to be many resources for C++ on AVRs I've uploaded what I have to Github. There's not a huge amount yet, but hopefully it'll expand over time. Currently there are some useful utilities for accessing the ADC channels, creating timers, and using the UART / serial communications - including the ability to print debug data via RS232. The long term plan is to make it as widely compatible and as easily configurable as I can, but for now it will probably just be growing as and when other projects provide opportunity.

Saturday, 8 March 2014

Space Racers Binaries

That's Right!

Windows
Linux

I finally pulled my finger out and uploaded the binaries for Space Racer. The linux version worked for me on Mint 15 32 bit (which is what I compiled it on) - but I have a rocky history with linux so I have no idea how well it'll work for anyone else. Some people have reported a bug where the game loads to a white screen on Windows, which I've narrowed down to the AMD 13.12 graphics card drivers. Reverting to 13.9 or updating to the beta drivers seems to fix this. I'm not going to release the source for Space Racers, but I have uploaded the base framework code to github for anyone interested. This is basically what I start with whenever I create a new project, and where any new features I may create end up, if I think they are features I might want to use again in the future. There's no documentation particularly, as I've only released it for anyone who is curious. If you want a decent framework to start your own project I'm sure there are plenty of much better alternatives.

Saturday, 22 February 2014

Creating a Command Console

So, on the second try, I managed to implement a command console to use in my project framework. When I say command console I mean the text input box many games have which allow you to alter variables and dispatch commands to the game in real time, as introduced (I think) in the Quake engine. I'd been after a feature like this for a while as it is very useful for developing game play where a lot of variable tweaking is required, which can become tedious very quickly if it means recompiling from source every time a small change is made. So how does it work? Well the basic idea is this:
    The console class stores a map of strings to command objects. The strings represent the command as it is input to the console window, and the command is the data to be acted upon, be it a variable or a function. When the console class is requested to execute a command, it looks up the command string in the map and, if it is found, executes the command, passing any other text entered on the command line as arguments to the command function. My main reference was this article, which inspired my class, although it appears a little outdated (it was written around 10 years ago). In it is explained a command format which is derived from the source of the Quake games, which are C based. Briefly it looks like:

typedef void(*CommandFunc)(vector<string>&);

enum DataType
{
    INT,
    FLOAT,
    //others
    FUNCTION
};

struct Command
{
    string name;
    DataType type;
    union
    {
        void* var;
        CommandFunc func;
    }
};

It seems a bit intimidating, but it's not all that complicated. First there is a type definition for a function pointer which declares the prototype for a command function that takes a vector of strings as a parameter. It is this vector which holds any arguments being passed from the command line. Using a function pointer means a command can be told to point to any suitable function on the fly, enabling quick rebinding of commands to functions. The DataType enumeration is used by the command to store what kind of data the command is pointed at. The Command struct contains a union of two pointer types - one a function pointer, the other of type void which can be pointed at any variable. Storing the data type as a separate member means that the void pointer can be cast to the correct type when necessary, by first checking the data type value. The two pointers are stored in a union which means they share the same memory space. A command will only ever point to one or the other type and, as both members are pointers (not the data that they are pointing at), will only ever require the same amount of memory.
    While this works, and is efficient, it is also error prone. For example a command may be pointed at something else during its lifetime - but if the type member isn't correctly updated then trying to read the data pointed at can cause an error. If a command is pointed at a float variable but the type member is left stating that the data is of unsigned char, the data format will be both misinterpreted and only partially read (one byte of uchar for a four byte float). A compiler may or may not catch this error, but it will cause all kinds of undefined behaviour.
   I decided that a more modern approach could be taken using C++11 features, specifically std::function and lambda expressions. std::function is a class for creating objects which fulfill the requirements of a function pointer. You can bind existing functions to the object, or create them from lambda expressions. Lambda expressions allow you to declare a function inline with the code, and without any forward declaration. They also allow you to capture local variables. This is useful because it does away with the need to point to any variable data in the Command struct, you need only a single function which can then act upon that variable. My command struct is, in fact, not a struct at all:

typedef std::function<std::string(std::vector<std::string>&)> Command;

The template declares a function prototype similar to that of the function pointer in the previous example - with the exception of the std::string return value (I'll come back to that later). Now creating a command is safer and easier, and can be done anywhere in code which is accessible to the console class.

Command c = [&myVar](std::vector<std::string> args)->std::string
{
    myVar = args[0];
    return "variable changed to: " + args[0];
};

This is a little generalised of course, a proper function would include code for validating argument values etc. Note how the lambda is able to capture the local variable myVar by reference and update it. There is a possibility, however, that myVar will go out of scope before the command is called, so you must be wary of its lifetime.

So having settled on a command format, the Console class begins to take shape. The class needs to perform a few things:

  • Map commands to command line strings
  • Provide ability to add and remove commands
  • Provide a visible interface for the user to input command strings
  • Parse inputted command strings and forward them to the correct commands.

The first two points are pretty straight forward. A private member

std::map<std::string, Command> m_commands;

is all that's needed to store available commands. Then two simple public functions can add and remove commands from the map:

void Console::Add(const std::string name&, command cmd)
{
    assert(m_commands.find(name) == m_commands.end());
    m_commands.insert(std::make_pair(name, cmd));
}

void Console::Remove(const std::string& name)
{
    const auto c = m_commands.find(name);
    if(c != m_commands.end())
        m_commands.erase(c);
}

By asserting that the command doesn't already exist in the Add function we make sure that it's not possible to accidentally assign the same command name to a different function during development. This could otherwise lead to some serious head scratching...
    The second two points on the list are a bit more involved. So far what has been covered is fairly generic and will work with any framework you may be using, but the graphical side of the interface is very much dependent on which library you use to draw on screen. In my case I'm using SFML, so from here I'll probably be covering a lot of SFML specific stuff. Actually parsing the command string is fairly generic and portable but, in my example, is tied to the SFML code.
    Moving the string data around requires a couple of buffers for the input and output. The input buffer can be a single string member

std::string m_inputBuffer;

For the output, however, its nice to be able to view a bit of history, so I use a list

std::list<std::string> m_outputBuffer;

Whenever a message is printed to the console it gets put in the output buffer, by pushing it onto the back. The reason I use a list is so that once it reaches a predefined length (usually the max number of lines visible on the screen) then I pop the front member. This could also be done with a vector by using

vector.erase(vector.begin());

There are most likely pros and cons of each method - if you feel it is better to do it the other way feel free to comment as to why, I'm always looking to better improve my code :)

To draw text on screen the most straight forward way is to make the Console class inherit from sf::Drawable and implement the draw() function. In my specific case I then used an instance of sf::RectangleShape for the background, and two instances of sf::text to display the input and output buffers. These are all private members of the Console class. The draw function then overlays all of these onto the screen when the console is set to visible. If you want to get a bit more creative it wouldn't be a stretch to also inherit sf::Transformable and create a floating window for the console, which can be dragged around the screen. I'll not cover that here though. I also added a small private function which then updates the display

void Console::m_UpdateText()
{
    m_inputText.setString(m_inputBuffer);

    std::string output;
    for(const auto& s : m_outputBuffer)
        output += s + "\n";

    m_outputText.setString(output);
}

where m_inputText and m_outputText are the sf::Text instances. Handling the text input is a bit more involved. To get the keystrokes the Console class needs to handle the SFML TextEntered event. This can be done via a HandleEvent function, which needs to be called from the event polling loop of the main application. This way the console can hook any events and deal with them appropriately. Later on this function will also prove useful for another reason:

void Console::HandleEvent(const sf::Event& event)
{
    if(m_show)
    {
        if(event.type == sf::Event::TextEntered)
        {
            if (event.text.unicode > 31
                && event.text.unicode < 127
                && m_inputBuffer.size() < maxBufferLength)
            {
                m_inputBuffer += static_cast<char>(event.text.unicode);
                m_UpdateText();
            }

        }

        else if(event.type == sf::Event::KeyPressed)
        {
            switch(event.key.code)
            {
            case sf::Keyboard::BackSpace:
                if(!m_inputBuffer.empty())m_inputBuffer.pop_back();
                m_UpdateText();
                break;
            }
        }
    }
}

First I should note that m_show is a boolean set depending on whether or not the console is visible on screen. It's used in several places; here to prevent text being entered when the console is not visible. If an event is of type sf::Event::TextEntered it is then hooked, checked and appended to m_inputBuffer. The range check between 31 and 127 makes sure that the text is in the ASCII range of characters, and that Delete and Backspace strokes are ignored. The ASCII range it not so important - for other locales you may want to update this, but for my purposes it was enough to keep it simple. Once the character has been added to the line m_UpdateText() is called so that the changes are visible on screen.
    If the event is of type sf::Event::KeyPressed then any Backspace strokes are used to remove the last character from the input buffer (after checking that it has any characters to remove) then the display updated once again.

Hopefully at this point you are still with me. The console should now be drawable on screen, and allow the user to enter commands as text. The final bullet point is to be able to parse the commands entered and use them to execute any stored Command functions if they are found. This is done with

void Console::m_ParseCommand()
{
    if(!m_inputBuffer.empty())
    {
        std::vector<std::string> commands = tokenize(m_inputBuffer, ' ');
        const auto c = m_commands.find(commands[0]);
        if(c != m_commands.end())
        {
            m_commands.erase(m_commands.begin());
            std::string result = c->second(commands);
            if(!result.empty()) Print(result);
        }
        else
        {
            Print(commands[0] + ": command not found");
        }

        m_inputBuffer.clear();
        m_UpdateText();
    }
}

I've removed some of the string formatting code from the function for brevity - normally I would do a bit more validation on the input string - but the code will still parse a command which is properly formed. First the tokenize function splits the command input string at each space it finds. Each sub-string is then placed in the commands vector as a new entry. The definition of the tokenize function is omitted here; you can either use boost or roll your own. The first entry in the command vector is expected to be the command itself, it's used to search the map of commands for a match. If the command is found the first entry is then erased from the command list as it is no longer needed, and any remaining lines are passed as parameters to the function of the found command

std::string result = c->second(commands);

Notice that the return value from the function is stored in result. When creating the typedef for the Command function I stated that the return value is of type string. I added this so that when a function is called it can return a message that can be printed to the console to indicate either success or some sort of error message. result is then checked to see if it is empty, and printed to the console if not. Print is a public member function of console:

void Console::Print(const std::string& str)
{
    m_outputBuffer.push_back(str);
    if(m_outputBuffer.size() > maxBufferLines)
        m_outputBuffer.pop_front();

    if(m_show)
        m_UpdateText();
}

It simply pushes the supplied string onto the output buffer and removes the front entry if the size exceeds a predefined limit. Then, if the console is visible, the sf::Text instances are updated with the new text.
Returning to m_ParseCommand, if the command is not found an error is printed to the console. Finally the input buffer is cleared, and the on screen text is updated.
    To bring it all together m_ParseCommand has to be called when the user presses Return. In the HandleEvent function, below where the Backspace key press event is handled, an extra case is added:

case sf::Keyboard::Return:
    m_ParseCommand();
    break;

which completes the basis for a fully functioning console. As a test I created a command in the Console constructor:

Command c = [this](std::vector<std::string> l) -> std::string
{
    for(const auto& i : m_commands)
        Print(i.first);

    return std::to_string(m_commands.size()) + " commands found.";

}
Add("list_commands", c);

which simply prints a list of all available commands to the console when you type list_commands.



If you made it this far down the page, well done (and thanks!) this post has turned out to be a tad longer than I anticipated - hopefully a fact mitigated by providing at least some useful information. I had planned originally to go into the key binding system where the console class keeps a list of key bindings which can be used to execute commands at a single stroke but I shall have to save that for a post of its own, which will, with any luck, appear in the near future.

Tuesday, 18 February 2014

Space Racers Breakdown Part 3: Vehicle Handling

Part 2: Node Navigation

I've actually wanted to post about the vehicle physics for several months now, but it's such a vast topic I've never really known how to approach it, even when I have had the time to write something. Now, though, I've decided to break it into smaller parts, starting with the handling of the vehicles. There are numerous resources out there on the interwebs which cover how to do this sort of thing, and I'll link as many as I can remember, although not all are directly pertinent to Space Racers - which this post is about. The first option I looked at was the ever-present box2D, and there are many useful articles based around it, but in the end it just didn't feel right to me. This left me with one other option, which was to attempt to try to understand and create my own vehicle physics system. No small task. Credit to the authors of the afore-linked articles; although I chose not to use box2D the articles themselves did help explain what I needed to do to get my own system up and running.

    First off, then, was to get some basic movement going. The movement of a vehicle (or any object for that matter) in 2D can be broken down as:

directionVector * speed * dt;

directionVector is a two component unit vector which represents the direction the vehicle is facing. Note that it is important to use a unit vector else multiplying it with any number will lead to an incorrect magnitude. speed is a floating point scalar which represents the number of units per second at which the vehicle is currently traveling. dt is the delta time - the time elapsed since the last frame update. Multiplying the movement by dt will make sure the final movement represents the distance the vehicle would have traveled between two frames. Calculating the directionVector is pretty easy in SFML. Assuming you have a Sprite or Shape representing your vehicle you can use its on-screen rotation to rotate the normal vector taken from the front of the vehicle. This can be broken down as:

const sf::Vector2f frontNormal(0.f, 1.f); //pointing down
sf::Transform t;
t.rotate(vehicle.getRotation());
directionVector = t.transformPoint(frontNormal);

Rather than use cos() and sin() to rotate the vector I use the SFML Transform class which uses a 3x3 matrix that can perform translation, rotation and scale calculations, and is computationally lighter than a call to cos() and sin(). I don't use the vehicle's getTransform(), however, as this will also include translation and scale which I don't want applied to the unit vector.

    Speed is generally not a constant, we want to start and stop our vehicle, and, rather than come to a dead start or stop on key presses, it would be nice to employ some acceleration and deceleration. This is pretty straight forward too, set up a few constants - maxSpeed and minSpeed (although minSpeed could just be 0)  and acceleration and deceleration (which are, again, in units per second). Then the current speed can be calculated:

if(sf::Keyboard::isKeyPressed(accelerate))
{
    currentSpeed += acceleration * dt;
    if(currentSpeed > maxSpeed) currentSpeed = maxSpeed;
}

else
{
    currentSpeed -= deceleration *dt;
    if(currentSpeed < minSpeed) currentSpeed = minSpeed;
}

acceleration and deceleration are also multiplied by dt, so that the increase / decrease in speed is smooth and consistent between frames. Assuming you also handle key presses for rotating the vehicle this is all that's needed to get a vehicle moving around on screen. If you try it you'll notice you get movement similar to that of Asteroids - where the vehicle can rotate while still traveling in the same direction. If you want to try it out there's a gist here which will work with SFML 2.x.

This isn't the most natural handling in the world, and so this is where it gets a bit more complicated. The first and easiest thing I found to add was to add a 'wheelspin' effect to the vehicle when turning sharply and accelerating in the opposite direction. By taking the dot product of the vehicle's direction vector before and after a sharp rotation we get a value, handily between 0 - 1 thanks to the use of direction as a unit vector, which can be used to multiply the move speed. This is most notable in the sample code when turning ~180 degrees before accelerating in the opposite direction - the speed appears to slow right down before speeding up, rather than letting the vehicle shoot off in the new direction at its current speed. When rotating smaller amounts, however, this effect does not work so well. In fact this was a real head scratcher for me, and it took a lot of reading before I found this post which provided a convenient way of controlling how much lateral (sideways) motion the vehicle should have. The lateral motion is what gives the feeling of skidding when turning - and is not controlled at all in the demo - which is why the vehicle feels so 'floaty'. A sideways vector can be created by using a constant value and rotating it about the vehicle, the same way as the front facing vector. The only difference is the the constant value will be (-1.f, 0.f) rather than (0.f, 1.f). Taking the dot product of this rotated vector and the current movement vector we get a value based on how far the vehicle has rotated compared to its current velocity. It's then fairly trivial to reduce the sideways velocity by multiplying it by the dot product - a value which can also be controlled by, say, a handbrake which allows more skidding (lessens the lateral force reduction) when it is activated.

    That pretty much sums up the basic handling in Space Racers. It's probably not the most ideal method - it's certainly not the most advanced, but it is configurable enough that I can create different vehicles with different styles of handling. It's just one of those things that can be tweaked almost indefinitely. It certainly gave me a healthy respect for the programmers who worked on games such as the original Micro Machines. In the next post I plan to write about how the vehicles interact with each other, and collisions between the map/race track.

Monday, 10 February 2014

Space Racers Breakdown Part 2: Node Navigation

 Part 1: Map Format

So as promised I shall attempt to explain some of the techniques used in Space Racer. This post will be about the node system I used, which performs three main tasks.

   The first is to stop cheating by short cutting. This is pretty easy to do using the collision detection of the Tiled map. Nodes themselves are objects created in Tiled, and parsed via the tmx map loader class. Using the MapObject::Contains() function it is trivial to detect which node a vehicle has passed through, and update the vehicle's currentNode property with the ID of the last node the vehicle touched. If a vehicle then comes in contact with a new node whose ID is not one more or one less than the currentNode property the vehicle must have taken a shortcut, and therefore gets reset.

    The second task of the node system is a bit more complex. When I was researching the game I found little to no information on how to measure just how far around the track a vehicle was - and therefore no way to sort player positions. The solution I came up with is as follows: Each node has a position in world coordinates, which is derived from the centre of the map object representing the node. This allows a one dimensional chain to be created around the track from the list of positions. The complex part is calculating just how far along this one dimensional path a vehicle is, when the vehicle obviously has free range of movement in two dimensions. Just measuring the distance between a node and a vehicle is not enough. For example:

Vehicle B is further from the current node, but because it's not taking an as direct route Vehicle A is actually in the lead. To fix this I use a bit of vector maths, along with some pre-processing of the node data. When the map is loaded the nodes are parsed into a series of objects which look like this:

struct Node
{
    int ID;
    vec2 position;
    vec2 nextUnit;
    float nextMagnitude;
};

Besides the ID and position of the node in world coordinates I also store a unit vector which points to the next node, and its magnitude - which is the distance between the node and the next one. Storing the vector in its component form let me use the dot product of the unit vector and the relative vehicle vector to find the vehicle's magnitude were it to be traveling along the vector between the two nodes. This sounds a bit wordy, so here's another diagram:

D is the distance we are ultimately trying to find: if we calculate this for each vehicle then it is simple to find which is furthest along the vector between the nodes, and therefore which race position the vehicle is in. To calculate D we first find rv, the relative vector of the vehicle position to the node position

vec2 rv = vehiclePosition - nodePosition;

D is then the result of the dot product of the *unit* vector and rv. This is why it is important to store the unit vector in the node properties. Normalising a vector is also relatively computationally heavy because of the square root, so as it is a constant for each node it makes sense to just calculate it once and store it. We now end up with

float D = dot(node.nextUnit, rv);

This solves part of the problem, but of course not all vehicles are going to be between the same two nodes. It also doesn't provide the total distance traveled around the track. This is solved by using the nextMagnitude property of the node. Each vehicle has a cumulative distance property, so each time a vehicle reaches a new node not only is the vehicle's currentNode property (the ID of the node) updated,  nextMagnitude value is added to vehicle.currentDistance. Again, calculating the length of a vector is computationally expensive, so it makes sense to calculate it once and then store it. The total distance is then solved as

float total = vehicle.currentDistance + D;

Now we know  the total distance traveled by each vehicle, and a simple std::sort() provides the vehicle's race position. Here's a shot of the debug view of this technique in action  (the orange numbers are the total distance):



The final task of the node system is to provide navigation data to the AI used for computer controlled vehicles. The vehicle class itself provides an interface which allows control input from various sources, such as keyboard, controller or via the network. The AI class creates its own control output which is then fed to the vehicle class through this interface. Each AI has a destination position calculated as

vec2 destination = currentNode.position + currentNode.nextUnit * currentNode.nextMagnitude;

The AI then steers the vehicle until it points (approximately) at the destination and accelerates towards it. I say approximately because the accuracy is deliberately varied between AI objects to stop them being too perfect, and too hard to race against. Each AI also measures its distance between its current location and the destination, and will start to brake as it gets closer. Again the distance before the AI starts to brake is varied, although not only between AI objects, but also over the course of the race. This is done to help try and reduce predictability of AI players, and also allows for varying grades of AI 'competence' -  how difficult to beat the AI player is.

That pretty much sums up the node system of Space Racers. In the next post I'll try to describe how the vehicle physics work. As always questions / comments are welcome.

Part 3: Vehicle Handling

Sunday, 9 February 2014

Space Racers Breakdown Part 1

EDIT: Download it from here!

Happy new year and, indeed, happy Chinese new year! It's been a little quiet on the blog front, so I'm going to start off the blogging new year with a couple of articles that are, hopefully, a bit more interesting than some of my recent content. To kick it all off check out this trailer of a game I made, written in C and C++ using mainly SFML: Space Racers!


Space Racers has been my pet project since around June last year. From the video it should be pretty obvious that it's based on the classic 90s era Micro Machines games by Codemasters, particularly the Sega Genesis / Megadrive port. It has been a fun and definitely educational project to work on, and has helped me further develop some of my side projects such as the Tiled map loader. It also features some real time 3D graphics which are overlaid to create the details and buildings which appear in the video, and has been a great exercise in using OpenGL. Unfortunately I've lost interest a little bit in the project itself (I haven't actually worked on it since last November) so to try and maximise its usefulness I intend to document some of the features, such as the vehicle physics, spread over a couple of articles as a kind of post mortem. When researching the project certain topics are apparently not that well documented, so hopefully sharing my experiences may help other people who wish to work on something similar. One day I may even release the source code - although I fear that although there may be techniques worth learning from the Space Racers project my coding practices probably don't count, and I'd not like to be blamed for passing on any of  my bad habits...

In this post I'll start with a break down of the tile maps used in the game, and how the Tiled map loader is used to parse the stored data into a navigable track.

The visual elements of the tracks themselves are fairly basic. The base layer for each map / track (be forewarned - I'm likely to use these terms interchangeably) is created using a simple tile set which I drew in Photoshop using the grid tool. Indeed the hard edges are not very inspired and, if I'm honest, I could have put a bit more effort into it.

It serves its purpose though and, when combined with a tile set consisting of various decals, gives a reasonable impression of a race track. The decals are placed on two separate layers, mainly to make sure that the decals are drawn on top, but also because the decals themselves are separated into 'standard' decals and those used as neon lights. Because the neon graphics are stored on their own layer which, via the map loader class, can be drawn on its own means that the layer can be preprocessed via a RenderTexture and a set of tuned GLSL shaders based on a bloom effect. This is what gives the layer its neon appearance, before it is drawn over the track layer.
    The power of Tiled comes in to play, however, in its ability to store non-visual data not just as a set of objects, but also by being able to isolate tile set layers. Looking closely at the video it's noticeable that the track appears to bend and distort the moon behind it as if it were made of glass or some other non-flat, semi-transparent material. This is done with a second tile set which mimics the first (the set used to draw the underlying track) but is created, again in Photoshop, as a set of black and white tiles representing height data, which is then converted to a normal map using SSBump.

This means that any track I create with the standard tile set can be recreated on a new layer as a normal map image. By being able to isolate this (or any other layer) when drawing with the Tiled map loader I can use the normal data to pre-render the background on another RenderTexture via a fragment shader which uses the normal coordinates as a DuDv map (the blue channel data is ignored) to distort the image. The standard tile set used to create the visible track layer is semi-transparent (an option which can be set via a slider in Tiled) so when it is drawn over the distorted background, it appears as though the track itself is causing the distortion.
    Collision data is also stored in the Tiled map. In this instance I decided to roll with my own physics - mainly as exercise - although collisions may have been better handled by Box2D. I'll go into more detail about handling the collisions in an article specifically about car physics in the future because it's fairly complex. Here, however, I'll point out the different object layers used to detect collisions. The collision types are separated into four groups:

 Solids
Nodes
Space
Kill

Each of these performs a particular task, and only the solid objects involve any real complexity in handling their collisions. Nodes are placed around the track and numbered sequentially. These are used for the navigation of AI controlled vehicles, and determining the order of players around the track. They are also used to make sure no short cuts are taken by players, by checking that the player's current node is sequentially numbered compared to the previous node. Again AI and navigation deserve their own post, so I'll go into more detail at a later point. Space and Kill objects are very similar, in that their job is to detect when a vehicle leaves a track, and trigger a reset sequence. The Space type detects when a vehicle has left the track and is effectively 'in space' and therefore should fall off (I know, I'm kind of playing fast and loose with the laws of gravity considering the whole game is set in space). The vehicles all perform slightly differently, however, and of the three the space ship has the ability to leave the track without falling off. Preventing the abuse of this necessitates the Kill object type, which is used to outright kill any ships which fly too far out. I've also used Kill objects to detect when players hit an electric barrier, and then destroy their vehicle. If you've read my previous post on collision detection you'll know that map objects parsed by the map loader have some basic detection functions, which include MapObject::Contains(point). This is all that is needed for the basic detection used in all but the solid types. Each vehicle has a list of four points surrounding it, so by checking how many points an object contains it is fairly trivial to work out whereabouts the vehicle is in relation to the map, and whether or not it needs to be updated in some way (usually by resetting it). The detection is, of course, optimised via the map loader's QuadTree class.

That about sums up the 2D map data, which is created in Tiled. There are 3D meshes used to embellish the map details, which I'll post about in the future, hopefully not too far away.

Part 2: Node Navigation

Thursday, 26 December 2013

Tiled map loader for SFML and box2D

A couple of posts back I covered how I use the tmx map parser for collision detection. In that I speculated that it ought to be possible to parse the MapObject geometry data into physics bodies for box2D, which I've since decided to follow up. I know box2D is not for everyone, so I've written a BodyCreator class and added it to the source on github, which is optional to include. If you want to use the map loader without box2D simply leave out the tmx2box2d source files from your project (if you try including them without linking against box2D you'll get errors). In this post I'm going to assume you have at least some basic knowledge and/or experience of box2D but if all else fails there's always the manual.

    I've tried to keep the interface as simple as possible, so the class contains a collection of static functions of which five are public, most notably:

b2Body* BodyCreator::Add(const MapObject& object, b2World* world, bool dynamic);

This function takes a MapObject as a parameter from which the box2D body will be created, a pointer to the physics world to which to add it, and an optional boolean variable which states whether or not the created body will be dynamic, which is false by default. The function also returns a pointer to the newly created box2D body which you can then use to process physics objects in any way you wish. Static and dynamic bodies are supported, but kinematic bodies are not, although I'll probably add support at some point. All MapObject shape types are supported; Rectangles, Circles/Ellipses, Polygons and Chain shapes. Non-convex shapes (which are not supported by box2D) are broken down into smaller convex shapes when necessary. The code for that is based on this article which details an ActionScript class written by Antoan Angelov. I've tested each case as best I can although there may be some edge cases which throw an error, in which case I'd be happy to hear about them / try to fix them.
    The four other public functions are actually sat in the tmx namespace and are utilities for converting world coordinates. Box2D not only uses real world units, metres, kilograms, seconds, it also uses inverted Y coordinates compared to SFML so it made sense to wrap the conversion in these functions. It also takes care of the fact that box2D has its own 2D vector class, by converting the data from one type to another.

    b2Vec2 SfToBoxVec(const sf::Vector2f& vec);
    sf::Vector2f BoxToSfVec(const b2Vec2& vec);
    float SfToBoxFloat(float val);
    float BoxToSfFloat(float val);


The names, I think, are self-explanatory, and the functions should be used wherever you need to convert data from one world space to another. The scale factor which defines SFML units per metre is declared at the top of tmx2box2d.cpp and is set to 100 by default. Adjusting this will affect the outcome of the conversion functions. To save on writing  lengthy passages of code in this post I've also added an example to the source on github. It takes a simple tmx file and creates a selection of static and dynamic bodies from the objects contained within. The map file looks like this:






The green objects are stored on a layer called 'Static' and the white objects on a layer called 'Dynamic'. The example code then uses the separate layers to decide which kind of object to create. Here's a short video of it in action:

video

As always comments are always welcome below, or on the github page.