About runvs

We are runvs, a two person indie game development team and this is our portfolio.

We work solo, as a team or sometimes with close friends. We also like to participate regularly in Ludum Dare and OneGameAMonth.

Links

Mail

Twitter

YouTube

Bitbucket

GitHub

Friends

Planetary motion explained

When KSP was published, planetary mechanics got quite some attention. Coding this on your own is not hard at all and requires just some basic mathematical knowledge. During this tutorial you will learn everything you need to know. A c# console project accompanies this tutorial and can be downloaded from google drive (zip, 40kB). It contains all the code described here and you may use, adapt, modify and use it in your game.

Equations of motion

Motion

Let's start simple: Imagine a particle which can move only in one dimension (so to speak: on a line). To describe the motion of this particle all you need are some variables. The first one is, obviously the position x of the particle. That would be all we need, if we just have a look at it at one single moment in time. As we are interested in the so called trajectory of the particle, we need some more variables. One of them is obviously the time t. The other variable required is the velocity v of the particle. The position and velocity would be all we need, if the particle is just moving without any interactions. If we want to have the particle (satellite) be attracted by other objects (planets) we need one more variable which is the acceleration a. In Physics you can show that those three variables are enough to describe the movement of the particle completely deterministic.

Let's have a look at those variables and the equations, which connect them on physical level! As you know, velocity is the change of the position with time. Think about driving a car: your speed (the velocity) is given in kilometers per hour (for the metric unit system) which is exactly what I just wrote: The change of the position in a given time. When you drive 60km/h for one hour, your position will be different by 60 km after that hour. To put that into an equation, we can easily write:

v = delta_x / delta_t

Note that the delta corresponds to a difference. Think about your car at two different points in time: t1 and t2. delta_t is just the difference between them: delta_t = t2 - t1 The same holds for delta_x.

The acceleration is the change of the velocity with time. Think about ads for cars: "Accelerates from 0 to 100 in 15 seconds." 0 and 100 are known to be velocities. So it can be written:

a = delta_v / delta_t

For our one dimensional case all of those variables are numbers (double), but we can easily see, that all the relations are still true if we exchange the scalar values by vectors (of dimension two or three), as the different axis (x, y, z) can be calculated independently.

Setting up those equations

In the final code, we will be interested in the position at a given time. Therefore some refinements of the equations are required. We know the acceleration. from that we can compute the velocity:

delta_v = a * delta_t

as this is just the change in velocity the real velocity will be

v_new = v_old + delta_v

or as it will be written later:

v += a * delta_t

The same is true for the position and the velocity.

delta_x = v * delta_t
x_new = x_old + delta_x
x += v*delta_t

Those equations now tell us, how a new state of the system will look like, based on the old state of the system. Mathematically this is called "integrating the equations of motion".

Newton's axioms

For particles to interact(planets should attract each other) we need to know, how the forces translate into those equations of motion, we just talked about. This physics building block can be derived from Newton's axiom. One of them states that Force equals mass times acceleration. If we put that into an equation it can be written as:

F = m * a.

OK, so what are those F and m values. F is the type of the force we are looking at. If you want to see satellites move around planets, you need the law of gravity. If you want to have a look at electrons and protons, you need Coulomb's law. All we should care about now is that F tells you "what" is acting on the particle and only depends on the position of the particles. The mass m is just the mass of something you can pick up. The more mass it has, the harder it is to make it move. If you want to lift a light feather (low mass), that is easy. If you want to lift a large heavy crate, that's hard. The mass is sort of the "resistance" of the object against being moved.

As we know the Forces of the particles, we can now use that to calculate the acceleration of the particle.

a = F/m

The Gravitational law

Overcoming Gravity is not easy So how does gravity work? I can not give you an explanation to that on a fundamental level, but for what is required here you just need to know that two masses (m1 and m2) attract each other by the following law:

F_G = G * (m1*m2)/(r**2)

G is called the gravitational constant and r is the distance between the two masses (their centers). This distance can be calculated by Pythagoras' theorem in any dimension.

Show me some code already!

So let's put all that physics knowledge to some code!

We need a PhysObject class, which will store those variables and do the computations for us. The constructor just initializes the values. The addForce function will let a force act on the object. The most important part is the update function. Let's have a closer look at that! The update function puts the equations mentioned above into order.

public void update ( double dt )
{
    vx += ax * dt;
    vy += ay * dt;

    x += vx * dt;
    y += vy * dt;

    ax = ay = 0;
}

Those are exactly the equations explained above. At the end of the function, we reset the accelerations. This is required, since the particles have moved. As the Forces depend on the positions, we need to calculate them in each step.

So in the main function, we need multiple particles, so we create a list of PhysObjects. Then we can add as many particles with any starting conditions we like.

System.Collections.Generic.List<PhysObject> pobjs = new List<PhysObject>();
{
    PhysObject p1 = new PhysObject();
    p1.x = 0;
    p1.y = 1.4;
    p1.vx = 1.2;
    pobjs.Add(p1);

    PhysObject p2 = new PhysObject();
    p2.x = 0.2;
    p2.y = 0.2;
    p2.m = 100000;
    p2.vx = 0;
    pobjs.Add(p2);
}

Then we need an update loop which calculates as many integration steps as we want. In every step we need to determine the forces which are acting on each particle. This is done by looping over all the other particles and calculating the pairwise forces. The Force calculation depends on the distance, which we can easily calculate. After that we normalize the vector from object 1 to object 2 and use those values for the gravitational law. This yields the force. As we know "actio = reactio" from Newton, we can use this to apply the same force on both particles, just with different signs. This helps to reduce computational cost, as the second iteration loop can start at m+1. All previous particle pairs have already been treated completely.

for (int m = 0; m != pobjs.Count; ++m)
{
    for (int n = m+1; n != pobjs.Count; ++n)    // not that all particles <m have already been treated.
    {
        PhysObject p1 = pobjs[m];
        PhysObject p2 = pobjs[n];   // get the objects

        double dx = p2.x - p1.x;    // distance in x and y
        double dy = p2.y - p1.y;

        double r = Math.Sqrt(dx * dx + dy * dy);    // euclidean distance

        dx /= r;    //normalized vector
        dy /= r;

        double c = p1.m * p1.m / r / r; // law of gravity is \propto m1*m2/r**2
                                                    // G is set to 1 without loss of generality.

        p1.addForce( dx * c,  dy * c);  // adding forces symmetrically. 
        p2.addForce(-dx * c, -dy * c);
    }
}

After we have added all the forces, we can now call update. We cannot do the update earlier, as each particle has to know the forces which are acting on it.

// now the forces are calculated. Do the integration step now.
for (int m = 0; m != pobjs.Count; ++m)
{
    pobjs[m].update(0.01);
}

A word about numerics

What is written in the code is the most basic numerical integrator, which is called after the mathematician Leonhard Euler. There are multiple versions of that (implicit, explicit) and many other sort of integrators (Midpoint, Runge Kutta (of arbitrary order), Leap Frog, Velocity Verlet, ... ) and all of them have their benefits and drawbacks. The benefit of this explicit Euler method is that it's simple and that it is computationally very efficient. Unfortunately it is not stable at all. For a large system (many particles, and many in the sense of ten thousands), the largest computational effort will be determining the forces, as each body interacts with all other bodies. This is called an N-squared loop. There are ways to boil that down, but they are out of the scope of this tutorial.

Another important point is the time step deltat. The integrator works well if deltat is small. If it is too large, strange things might happen. One of the drawbacks of the Euler method is, that it requires quite a small time step to work. So if strange things happen with your physics, try reducing the time step first.

The Game Jam Survival Guide

Hi there,

Game Jams are a thing! They are a way of life. (quote: Jammer.io)

Title Slide

Participating in a Jam is not hard, though it might contain some pitfalls. To avoid the most common ones, I created this presentation, which was given on 2017-09-30 at the Gaminfection Hackathon in Erlangen.

You can download the slides here (2MB, pdf) .

Interpolation pt.3: Spline Interpolation

This is the third part of the interpolation tutorial series. Here I will finally cover the so called spline interpolation. Part one and part two covered linear interpolation and tweening. Spline interpolation is close to linear interpolation as it works great on arrays of points. So you might want to check out the first part, if you missed it. Again, I will cover most of the mathematical foundation needed to implement the algorithm yourself, as well as provide ready to use code that you may use in your project.

What is spline interpolation?

Let's start from linear interpolation between a set of points. All that is needed for linear interpolation, are the positions (x,y) of the points. Spline interpolation takes this idea one step further. Each point now includes a slope k in addition to the x and y values. This allows not only to fit a linear function (aka a straight line) between the points, but a polynomial of order two. The most simple form of such a polynomial is a parabola. This will make the function smooth (and not zigzag like in linear interpolation) by including higher order terms. In other words, the additional information k will be used to smooth the interpolation function in a smart way.

k is a real valued number. It describes the slope of the tangent of the smooth function at that point. For k = 0, the tangent is horizontal. For larger values of k the tangent will get steeper counter clockwise. For smaller values, the tangent will rotate clockwise. For k equals +/- infinity, the tangent will be vertical (pointing up or down respectively). There are different ways to calculate k values for all points. Three ways will be described later in this tutorial. The smooth interpolation function will go through all points for any k values, but it can occur, that the interpolation function will overshoot.

The Algorithm

The interpolation algorithm is based on the equations introduced in the fist part of the tutorial. At first, the two neighboring points are searched. Then a value t (range 0 to 1) is calculated which describes where in between the two neighboring points the interpolation should be evaluated.

The major change in the algorithm is the calculation of the interpolated value, as the derivatives of the points are taken into account. The idea is to use a second order polynomial and to bring that to the symmetrical form. This means some lines of calculation, but luckily, the equation has been solved by countless maths students for you. And that's it: spline interpolation!

The haxe code is listed below.

private function interpolate (p : Array<SplinePoint>, x : Float ) : Float
{
  // this is all the same as in the first tutorial
  var pMin : SplinePoint =  new SplinePoint(Math.POSITIVE_INFINITY,0);
  var pMax : SplinePoint =  new SplinePoint(Math.NEGATIVE_INFINITY, 0);
  var pleft : SplinePoint = new SplinePoint(Math.POSITIVE_INFINITY, 0);
  var pright : SplinePoint = new SplinePoint(Math.NEGATIVE_INFINITY, 0);

  for (j in 0... p.length)
  {
    var pt:SplinePoint = p[j];

    if (pt.x < pMin.x) 
    {
      pMin.x = pt.x;
      pMin.y = pt.y;
      pMin.k = pt.k;
    }
    if (pt.x > pMax.x)
    {
      pMax.x = pt.x;
      pMax.y = pt.y;
      pMax.k = pt.k;
    }

    if (pt.x < pleft.x && x < pt.x)
    {
      pleft.x = pt.x;
      pleft.y = pt.y;
      pleft.k = pt.k;
    }

    if (pt.x > pright.x && x > pt.x)
    {
      pright.x = pt.x;
      pright.y = pt.y;
      pright.k = pt.k;
    }

  }
  if (x <= pMin.x) return pMin.y;
  if (x >= pMax.x) return pMax.y;

  // t is the local coordinate between i and i-1. 
  // t must be in the range of [0,1] and can be used for interpolation
  // if t == 0, the point [i-1] is chosen, for t == 1, the point [i] is returned.
  var t : Float  = (x - pleft.x) / (pright.x - pleft.x);

  var a : Float =  pleft.k  * (pright.x - pleft.x) - (pright.y - pleft.y);
  var b : Float = -pright.k * (pright.x - pleft.x) + (pright.y - pleft.y);

  // this would be linear interpolation
  var q : Float = (1.0 - t) * pleft.y + t * pright.y;
  // this is the addition from polynomial of order two
  q += a * t +(b - 2 * a) * t * t + (a - b) * t * t * t;

  return q;
}

How to set the k values (slope)

There is still one piece of information missing: How to get the derivatives (k). There is, as usual, no one fits it all way to do it. The simplest way to handle this, is to set all k values to 0. This means, that all points given are extremal values (or saddle points). This means there are no overshoots. For some points at the values (20, 200), (200, 400), (300, 110) and (500, 230, 0) the interpolation would look like this. spline interpolation with k = 0

You can also do a type of three point interpolation. This means, k for a point i is calculated as the mean value of the slopes between the points i-1 and i as well as i and i+1. Or you use some sort of forward integration. This is depicted in the following imagenine interpolation with mean k](httenter image title hereine interpolation with mean k")

One Last way to calculate the k values is to do this by solving a linear system of equations. This corresponds to the midpoint interpolation formula. Note that this is the way most spline interpolation libraries handle it and the results look "the smoothest". But since the math is cumbersome, most ready to use libs use some sort of linear algebra framework. There are many very good tutorials on this, and I could not explain better. (remember, this is purely optional)

Interpolation is easy (Summary)

This tutorial series started from linear interpolation, covered tweening and touched spline interpolation in this part. It was meant to give you a broad overview about interpolation and to give you the needed mathematical tools and the understanding of the meaning of the equations. You are free to use or adapt the presented code.

Interpolation pt.2: Tweening

This is part 2 of the interpolation tutorial series. In part 1, linear interpolation was covered between two points and for an array of points. This part covers tweening. Tweening describes how to change a value between two points. In most cases, tweening is used with time as a parameter (like tweening a sprite's alpha from 1 to 0 within a given time).

Tweening

The basic idea is to have a number of tweening equations. Each equation gets a parameter t between 0 and 1 and produces an output value in the same range. Since all equations work on the same parameter range they can easily be exchanged, which is very helpful in day to day use.

If you want the function to tween not in the range between 0 and 1 but between two arbitrary values A and B, you can do this by the following transformation. f(x) is the tweening function between 0 and 1, g(x) the function between A and B.

g(x) = A + (f(x) /(B-A))

Power of x Functions

Let's dive into the tweening functions! The easiest thing to do is a linear function. But since this is no improvement to the first tutorial part, we will skip that. It is also possible to use functions in the form of f(x) = x^p with p being a positive number. This leads to curves as shown in the picture.

power of x functions

Thos functions are called power of x functions (as they contain only x to the power of p). Linear interpolation is the most simple case with p = 1. For some p there are special numbers, like p = 2 is "square", p = 3 is "cube" and p = 4 is "quad".

More functions

There are many more functions you can use. Instead of the powers of x as described above, you can use trigonometric functions (sin, cos), some exponential functions or some dampened wave equations. This site is a very good overview over all common tweening functions.

Taking a step back

Another nice thing about all tweening equations is that they are cut in half and that you can modify the first and the second part independently. The different types of tweening functions on the website are named with an In/Out/InOut suffifx. This suffix describes whether the tweening starts, ends or starts and ends with the respective equation.

As there are many tweening libraries/code files available, I recommend you try the one fitting to your language. A collection of the equations described above for about 15 different languages is available on Robert Penner's Website.

That's it for the second part of the interpolation tutorial. The third (and last) part will cover spline interpolation.

Interpolation pt.1: Linear Interpolation

Whenever something in a game should vary smoothly between two values this can be done by interpolating. Examples are changing an object's position to make it move from A to B or changing the alpha value of a sprite to fade it in or out of the scene. I tried to learn more about the idea and theory of interpolating, but there is not that much information available that is explained well and captures the math up to a point at which the reader can use it by himself confidently.

About this tutorial

This tutorial is part of a series, which will cover interpolation. At first I want to show you linear interpolation. A second part will cover tweening (often called easing). And the third part will cover the dreaded spline interpolation. The tutorial will empower you to implement interpolation on your own by explaining the math step by step. The code given is in haxe, but is easily applicable to the language of your choice as no advanced libraries or language features are used.

Linear interpolation

Ok, what is this interpolating thing about? At first I want to talk only about linear interpolation. Let's stick with the example of the moving object. A game object should move from A to B in a smooth way, e.g. in a cutscene. You (or your designer) provides the positions A and B (y0 and y1) as well as the time the movement starts (x0) and the time you want to reach position B (x1). Note that the y values do not have to be numbers, but can also be vectors, or if you want to interpolate a rotation, they can even be rotation matrices or quaternions. The x values will always be a number.

If you imagine a coordinate system with the time on the x axis and the position on the y axis, calculating a linear interpolation means drawing a straight line between the two points created by (x0, y0), (x1,y1).

To interpolate between those position you can use the following code. It will calculate a variable q which is the interpolation at the point x.

// first get a value t in the range [0,1].
var t : Float  = (x - x0) / (x1 - x0);
var q : Float = (1.0 - t) * y0 + t * y1;
return q;

The value t is in the range between 0 and 1. If x is equal to x0, t is 0. If x is equal to x1, t is 1. The variable t is then used to calculate the value q, which is in the range y0, y1. This represents an linear interpolation between two points.

Interpolation between multiple points

You can extend the same behavior to an array of points. This is shown in the following code example. SplinePoint is a class that has a x and y value. The function linterp takes an array of those SplinePoints and an x value which indicates where to evaluate the interpolation. The array does not have to ordered.

private function linterp (p:Array<SplinePoint>, x : Float) : Float { var pMin : SplinePoint = new SplinePoint(Math.POSITIVEINFINITY,0); var pMax : SplinePoint = new SplinePoint(Math.NEGATIVEINFINITY, 0);

    var pleft : SplinePoint = new SplinePoint(Math.POSITIVE_INFINITY, 0);
    var pright : SplinePoint = new SplinePoint(Math.NEGATIVE_INFINITY, 0);

    for (j in 0... p.length)
    {
        var pt:SplinePoint = p[j];

        if (pt.x < pMin.x) 
        {
            pMin.x = pt.x;
    	    pMin.y = pt.y;
        }
        if (pt.x > pMax.x)
        {
            pMax.x = pt.x;
    	    pMax.y = pt.y;
        }

        if (pt.x < pleft.x && x < pt.x)
        {
            pleft.x = pt.x;
    	    pleft.y = pt.y;
        }		
        if (pt.x > pright.x && x > pt.x)
        {
    	    pright.x = pt.x;
    	    pright.y = pt.y;
        }	
    }
    if (x <= pMin.x) return pMin.y;
    if (x >= pMax.x) return pMax.y;

    var t : Float  = (x - pleft.x) / (pright.x - pleft.x);
    var q : Float = (1.0 - t) * pleft.y + t * pright.y;
    return q;
}

At first, the points with minimal and maximal x in the array p are searched. If the value x (this is where you want to evaluate the interpolation) lies outside of the values specified in the array, then the value of the most left or right Splinepoint will be returned. Furthermore the closest points to x from the left and right (pleft, pright) are searched. Then the interpolation formulae from above is used to calculate the value between the two points pleft and pright.

linear interpolation The result will look something like this. I added four points (indicated by the red squares) to the array p and called the function to calculate the values in between (white squares).

Ok, that's it for this part. The next part will cover tweening, which will cover mainly interpolating between two points, but with some fancy functions.

Another useful haxe macro

My current game, Dino Guy had a json file 'maps.json', that contained the filepaths to each map. As the game starts, the json file is parsed to an array of strings and all levels are loaded afterwards. But every time I added a map, I had to remember to add it's path to the json file.

This is a screenshot of the game

Dino Guy screenshot

A file list with haxe macros

Some months ago, I wrote a tutorial on a great feature of the haxe programming language. You can find all the basics there. Basically macros are functions that are run at compile time. So here is another cool haxe macro that solved the problem I introduced:

public static macro function getFileList ( folder :String, extension: String) : Expr
{
    // the list of files to return
    var list : Array<Expr> = [];	
    // read everything that is in the directory
    var content = FileSystem.readDirectory(folder);
    for (s in content)
    {
        // if the file has the correct file extension, add it to the list
        if (s.endsWith(extension))
        {
            var path = folder + s;
            // convert the string to an expr and add it to list
            list.push(macro $v{path});
        }
    }
    // convert Array<Expr> to Expr and return
    return macro $a{list};
}

This little function will now parse through a directory at compile time and return an 'Array<String>' with all files ending on the correct file extension. Another trick: Using an empty string ('""') as extension will automatically return all files in a folder.

Computational Creativity using Neural Nets

Greetings!

Last week I was giving a talk at Indie Outpost, a meeting of franconian Game Developers. My topic was Computational Creativity using Neural Nets. If you are interested in the slides, you can download them here.

Making cool stuff with Haxe macros

There is a rule in computer science: Whenever a developer learns a new feature, it will be used extensively in his next project.

Introduction

During the past half year, I worked on many games using HaxeFlixel, for example the platformer Meteor Dave or the action RPG and Ludum Dare project Raiders of the Ancient Technology.

In the process of creating those games, I gained some knowledge of lower level parts of HaxeFlixel and Haxe itself. Just some clarification: Haxe is the programming language, HaxeFlixel is the game framework. In this post, I want to share one of the best features of Haxe with you: macros.

History of macros

If you know C or C++, you probably may have stumbled upon macros yourself. In this family of languages, they are preprocessor directives. It is a simple replace mechanism, that runs before the actual compilation of the code.

Some C++ code might look like this:

#define PI 3.141592
#define MIN(X,Y) ((X) < (Y) ? : (X) : (Y))

Often times, macros are also used for compiler flags or for the famous include guards (prior to pragma once). If you look at the code it looks perfectly fine. Everywhere you write PI in your code, the preprocessor will insert the numeric value. The use of the MIN macro also works (mostly) as intended.

...at least until you don't rely on type safety for the Pi example. The second one is even worse, because consider something like

int c = MIN(a,--b); 

What will be the value of c? Remember, the code will just get substituted. Even worse, depending on the value of a and b, b might even be decremented twice. For a = 3 and b = 4, c will have a value of 2, which is just wrong. On a side note: the modern way of doing this in C++ would be to use constexpr and the template function std::min.

Macros in C++ are a powerful tool, but cumbersome and dangerous. The Haxe language also offers macros, but with improved features like type safety, syntax checks and another connotation that is very powerful.

Macros in Haxe

Haxe macros do not run before the build process, but as a part of it. Thus all Haxe macros are completely type safe, offer syntax validation and meaningful error messages, in contrast to C++ templates. But the best part about macros is, that they allow you to execute and modify code at compile time. Lets check out some examples!

Examples

As stated with the rule at the beginning of this post, I wanted to use these macros in some of my projects. Most of the examples are based on the Haxe Code Cookbook.

Showing compile time

When working on some larger projects, it would be nice to have the latest commit message and compile date displayed somewhere in the main menu. This makes it easy to identify which version is currently being tested. You could manually add a version string in a global variable, but that's not what you want, because the string would have to be changed every time you create a build.

This macro can do just that:

// macro function for getting the build date
public static macro function getBuildDate() : Expr
{
    var d : Date = Date.now();
    var date : String = d.toString();
    return macro $v { date };
}

This is a static function that has the keyword macro. Despite some peculiar syntax at the end, this looks very familiar. The return value Expr is a macro type and can be understood as a Dynamic at compile time.

The function itself is not very complicated. It gets the current date and converts it to a string. The return statement is somewhat special: since it is a macro function, returning a macro Expr, it needs to create such a type. $v {} is an abbreviation for creating an Expr value object.

And that's it. Congratulations on your first Haxe macro.

Getting the commit hash

The same can be done with the git commit hash or commit message:

var process = new sys.io.Process('git', ['rev-parse', 'HEAD']);
if (process.exitCode() != 0) 
{
    var message = process.stderr.readAll().toString();
    var pos = haxe.macro.Context.currentPos();
    Context.error("Cannot execute `git rev-parse HEAD`. " + message, pos);
}
// read the output of the process and create the string expression
var commitHash:String = process.stdout.readLine();
return macro $v{commitHash};

The code block uses sys.io.Process to call git rev-parse HEAD, which retrieves the commit hash. Since this might fail for reasons (e.g. no git repo initialized, git executable not found in path, no commit performed), it will print an error if something went wrong. A nice bonus is, that the error gets a line number, so the compilation error message will show you exactly where you have to look. The return statement works just as in the date example.

To get the last commit message, exchange the process line with

var process = new sys.io.Process('git', ['log', '-1', '--pretty=%B']);

If you are on a Windows machine, make sure the git executable can be found in the path.

A remark about compiler flags

Haxe offers some compiler flags to check whether it is in normal compilation or code completion mode. Because Haxe also evaluates macros during code completion it is advisable to exclude the commit hash. This can be done using a #if display ... #end block to check if you are in code completion mode. I did not add this to the code block due to readability.

Checking JSON during compilation

For games, JSON files are a handy way for configuration and Haxe offers an easy way to parse them. Unfortunately it will throw an exeption and thus crash if the JSON file's syntax is wrong. This is something that could (and should) be checked at compile time.

This is a very handy feature. You can check out the code for this in the Haxe Code Cookbook.

Creating a class from a CSV file

The inspiration for this came from grapefrukt. In most of my projects there is a class called GameProperties which has only static members. It includes variables like Gravity, WorldSizeInTiles, TileSizeInPixel, PlayerMovementSpeed and so on.

It would be super nice to have a CSV File instead that contains all those values. But parsing this at runtime (an push the values to a dictionary) will not allow any code completion when writing code. Again, this can be solved with Haxe macros:

public static macro function addFunctions(file : String) : Array<Field>
{
  // get the currently available fields
  var fields = Context.getBuildFields();

  // parse the file and split it in separate lines
  var f : String = File.getContent(file);
  var lines : Array<String> = f.split("\n");

  for (l in lines)
  {
    // get the info in the line
    var thisline : Array<String> = l.split(",");
    var myName : String = thisline[0];
    var value : Float = Std.parseFloat(thisline[1]);
    var pos = Context.currentPos();

    // create a new field
    var propertyField : Field = 
    {
      name : myName,
      access : [Access.APublic, Access.AStatic],
      kind: FieldType.FProp("default", "null", macro:Float,macro $v{value}), 
      pos: pos,
    };

    // append the field
    fields.push(propertyField);
  }
  return fields;
}

The largest part of this code block is just parsing a CSV file and extracting the values from it. One of the more interesting lines is Context.getBuildFields();, which gets the fields of the class where this function is called from. Later, our custom fields will be added to this. The var propertyField is the field that is parsed from the CSV file. We set some access identifiers (fields should be public and static) and tell Haxe this is a property that just returns that parsed value.

If you want to use this, just create an empty class

@:build(BuildExtender.addFunctions("assets/data/test.csv"))
class MyClass
{
}

If the file assets/data/test.csv looks like test, 10 gravity, -9.81

MyClass will now have two properties, called test and gravity, both with the respective values. This is done at compile time, so no performance loss for loading and parsing the file at run time.

The best part is, that this can also be combined with static members in the class. If your IDE supports code completion (like FlashDevelop) all the properties from the class and all that have been parsed from the CSV will show up in code completion.

Summary

I hope I could raise your interest for Haxe macros. Of course there are a lot of other applications not mentioned here and a lot of extensions for the examples I provided (like parsing a JSON file instead of a CSV and creating not only floats, but ints, strings or whatever you need). There are also great macro libraries on GitHub that can teach you a lot more about how to use macros.

IGJam Postmortem

Last week the gaming industry met in Cologne, Germany. But besides Gamescom, the largest video games convention, another event took place: IGJam, the first game jam at Gamescom. I was one of the lucky participants. This post is going to be a postmortem about the game Koza i Babushka which was a collaborative project.

The Jam

As I started jamming in 2013 with Ludum Dare and #1GAM, on-site game jams (which means, that you are gathering at a specific location for a game jam) are not what I am used to do. The IGJam was my second on-site game jam. The first one was the very nice SemesterGameJam (mini edition) in June 2016, where I created Clichee Wars.

As the tag (mini edition) implies, SemesterGameJam was not that big. I only realized how big game jams can grow, when I entered the IGJam room at the Koelnmesse conference center. Up to 200 people gathered there to create a game within 48 hours.

IGJam Room

All the people were very nice and I had many interesting discussions. I really liked the jammers being very diverse. Some developers even came from Indonesia. At first I was a little bit afraid of team building, because I knew no one prior to the jam. But the organizers did an awesome job and everybody found a team quickly. I got to work with three very nice game designers on our project. They worked on graphics, level design, animations and so on, while I worked on programming. For sounds and music there was a separate team, which provided excellent work for most of the teams at the jam.

Every jam needs a theme and the IGJam's theme was "Masks", which I personally liked very much.

The Game

We quickly decided to do a game about a russian woman who is looking for her goat. The old woman can use different animal masks (which you have to find first) to gain the animal's power or ability (like jumping higher, getting smaller or seeing in the dark). Using a mask will drain some of your personality, which you can refill in your house. If you loose all of your personality, the game is over for this run. Dangerous spikes and other obstacles also drain personality.

Koza i Babushka Screenshot

Day One

Besides team building and starting the jam on day one, I took some time and checked various booths at Gamescom. This was a great experience, since the last time I visited Gamescom was in 2010. The exhibition was even bigger and really good and inspiring. Back at the jam, we spent the evening with planning our workflow and setting up the basic project.

Day Two

... was the main day for working on the game. We started importing the level, implemented most of the gameplay features (like climbing on ladders, switching mask, losing and refilling energy. etc..) At some point during the day I felt really overwhelmed by the amount of work that would be needed for the game to be completed, but after starting to write down the tasks and removing the finished tasks, I slowly gained the feeling it would be a very nice game.

At the end of day two, there was a feedback round, where we could show our game to the public. Of course none of the games shown there were really finished. The idea to force all teams having a playable prototype after 24 hours is nice, because it forces you to focus on what is important.

The final day

In the morning of the third day there were only a few hours left and I felt like I was really struggling a lot. The game needed a lot of balancing (which mask uses how much energy?) and the cut scenes (mainly intro and outro) had still to be created. I really crunched for working for the last hours, and we finished 11 minutes before the deadline. I am very proud of the final game.

The real post mortem

Every post mortem needs to contain a "good vs. bad" section. Criticizing your own game is hard, but I like doing so, because I learn a lot from looking at one of my games some days after finishing. Yesterday I had some friends at my place who played Koza i Babushka and they mainly support my points.

Ok, so let's start ...

What went wrong

  • Due to time issues on the last day, no one did a play test of the game from start to end. This led to balancing just based on assumptions and gut feeling. It worked out ok-ish, but I had a really bad feeling about this.
  • The game can feel very frustrating due to the high difficulty in the second half.
  • It's permadeath, but we would have needed some sort of checkpoint system. Probably no player is going to play it again after dying 10 steps before the end.
  • Focus: I personally would have loved to be more focused during the jam, especially on the last day. I was jumping between different tasks and solutions, which is not a very relaxed way to work for me.

What went right

  • We created a game in 48 hours as a team that never met before.
  • Working in a team with (game) designers is a great opportunity. We really had a precise idea of how the game should feel and what the player's task would be.
  • Like every time when working with a larger team, it is a great experience to see all the parts of the game coming together the first time we loaded the level
  • The game has a remarkable playtime for being created in 48 hours. The level is large and even a speedrun would need about 5 to 10 minutes.
  • The gameplay mechanics, the puzzles and the level design for the first half of the game is great. Many people told me, they had the feeling of exploring a world. Once they bounced into obstacle, they had to search for the solution and were quite happy when they found it. I think the game can be very rewarding, which is a good thing.
  • Working with a dedicated sound team was awesome. Normally I doodle some melodies in cubase and create some blips and blops in SFXR. But this time, the sound was done by professionals and you can clearly hear that. This adds a lot to the mood of the game.

What's next

The IGJam has been a great experience and I am eager to visit more on-site game jams right away. Next weekend there is Ludum Dare, so August will have been a pretty creative month with three games done.

Publishing a HaxeFlixel Game on Android

Yesterday I released Pig Jumper on Android via the Google Play.

Pig Jumper Screenshot

It is a Game where you help Piggy jump from one to the next platform. It was originally created for the OneHourGameJam. In this gamejam it is the task of the developer to create a game in one hour. Of course Pig Jumper needed some additional polishing and bugfixing (in the original version you could land on the same platform, which would increase your score) after the one hour in the original jam. Porting it to android also took some time, as the jam version was built for the Flash target of HaxeFlixel.

Publishing on Android

For publishing a HaxeFlixel Game on Android via the Play Store there are some additional steps that need to be performed. You can find all of the information provided here on the internet, but I had not found one comprehensive guide which walks a developer through from beginning to start. Some links I recommend:

I assume a more ore less finished game in HaxeFlixel. We will go through the process step by step.

Setting up HaxeFlixel

At first it is a good Idea to update all HaxeFlixel libraries to the newest version. This is done by typing haxelib upgrade. Confirm the questions to upgrade. With haxelib list you can then get a list of all installed Libraries, including the installed and selected (square brackets) versions.

HaxeFlixel has to setup the Android Target. (If you want more information than provided here, there is a nice guide on the website.) This will take some time as a lot of tools have to be installed. Use lime setup android and follow the instructions. Then you need to select an Android SDK Version in the android virtual device managment software. I choose Version 16, since this works on a lot of devices and is compatible to many devices.

Now you can build your project with lime build android (in the respective project folder). This will work for some time. Don't worry. When you call it the first time, all HaxeFlixel Files will be compiled. After that only files that have changed will be compiled, so the process will be much faster.

In the export/android/bin/bin/ folder there will be a [Project Name]-debug.apk file. To get this working on your Android device, you will need to change the smartphone's settings to allow installation from unknown sources (which is not the official Play Store). The exact location of this property depends on your Android version, but you should be able to find it somewhere in the settings. Then you can copy the created apk to your device (by usb, email or ftp, jst get the file on the phone ;) ) and install it. Congratulations, you have created your first Android game!

Your first Android Game

Signing your apk

You will have noticed that the apk file is named ...-debug.apk. For creating a fully publishable release version, you need to sign the file. For signing you need a key. A key can be generated by a java tool, named keytool. You can find this for example in the java installation, that was done when you were setting up the android target.

Go to the bin folder and type:

keytool -genkey -v -keystore YOUR_RELEASE_KEY.keystore -alias YOUR_ALIAS -keyalg RSA -keysize 2048 -validity 10000

You should change the placeholders YOUR_RELEASE_KEY and YOUR_ALIAS to appropriate values. Follow the instructions. I suggest to use a strong password that you store some place safe. This will give you a keystore file.

In your project folder create a new folder, called templates and copy the keystore file here. If you use version control, you should not add the keystore file to it, as someone could spoof you app with this file.

Then open the Project.xml file and add the following line in the android section.

<certificate path="templates/YOUR_RELEASE_KEY.keystore" alias="YOUR_ALIAS" password="XXXX" if="android" unless="debug"/>

Again, use the correct values for the placeholders. Make sure to remove the Project.xml from version control as it contains your password in plain text.

If you build your game now, there will be a ...-release.apk.

Setting App Permissions and package name

Permissions

When installing the app, the phone asked for some permissions, like network, vibrate or wake up. If you are not using any of those features, you should remove them. Actually, google requires you to remove any permissions you do not use.

This can be done by setting up a file called AndroidManifest.xml. You can find a template in your HaxeFlixel folder. I recommend to use the one from samcodes-admob as this is the most complete one.

Copy this file to the template folder. Now you should remove all of the uses-permission lines. This will get rid of the requirements that are not needed.

Package name

Also make sure, to set the correct package name in the AndroidManifest.xml. If you use com.example.myapp you will not be able to upload it to the Play Store.

Using your own AndroidManifest

One additional line is needed in the Project.xmlfile. Again, in the android part, add

<template path="templates/AndroidManifest.xml" rename="AndroidManifest.xml"/>

This will then use your own Manifest file.

Icon and Pictures

For your app to be memorizable, you want to have an icon. This must have a square size, but no further requirements to size. For example using a 100x100 px image is totally fine. I like to store that image in the assets/images folder.

Again in the Project.xml file, add some lines, like those:

<icon path="assets\images\icon_100.png"/>
<icon path="assets\images\icon.png" size="36" if="android"/>
<icon path="assets\images\icon_100.png" size="100" if="android"/> 

You can use different sizes and Haxe will pick the correct one to use. This is very handy.

When it comes to images: You will need some images for the Play Store. This is a little bit of work, since you need them to be of the correct size. You will need one 512x512 image and one 1024x500 image, and some screenshots of arbitrary size. A promotion video or trailer might also be helpful.

Going Live

You need to get a google developer console account. Google requires a 25$ fee (from a credit card) for setting it up. With that account you can then upload the game and create a store entry with all the images and some nice desctiption. You will also need to do a quick survey on how violent the game is.

After providing all this information you press "publish". This will take some minutes. Then you will be able to find you game in the Store.

Pathfinding Explained

Whenever an object in a game should move from A to B, pathfinding is involved. This is a dreaded topic, but I want to shed light on how to tackle creating a proper and fast pathfinding algorithm. This is an ab initio approach, so you don't have to know anything about pathfinding.

As an easy example I will relate to square tiles, but the method described here can be used for any sort of map and is not even limited to 2D. You can find a Haxe implementation on gamejolt and the relevant part of the source code on pastebin. This method is called A* and you can also find many lots of code examples on google or wikipedia. I encourage you to try this for your own and create your own pathfinding. It is not that hard! :)

Processing Info

As a first step, the information from the map needs to be processed to a set of variables so the algorithm can work with it in an efficient way. The x and y position of each tile is enough to continue. What is needed is a representation of the map as a graph. A graph is a set of nodes that are connected to each other. The absolute positions are not that important. What the algorithm is interested in is the local neighborood of each node. The graph for the square tiles example can be build by spawning nodes on the center of each passable square tile. Any tile that is not passable (like any obstacle) will not spawn a node. To connect the nodes, we want to use the nearest neighbors. For the 2d square tiles all 8 neighboring tiles. If you do not want to have diagonal movement, simply omit these tiles.

Each node needs to have three variables: The travelling distance (which should just be the distance between two nodes. 1 for horizontal and vertival connections, sqrt(2) for diagonal ones.) and the node offset. Normally the offset is 0, but it can be used to tag areas that should be avoided (like if they are in the range of enemy turrets => positive values) or that should be very likely to pass (e.g. to punish going up or down a hill => negative value). Finally the node value will be set by the algorithm and should be initialized to -1.

Forest path

With that we have our graph ready to be processed by the algorithm. From here on, it is safe to forget about the underlying map, as the graph contains everything needed.

Initial Search

The A algorithm requires a list of connected nodes, with one start and one end node. The algorithm checks all neighboring nodes of the start node and sets the respective node values to the node's offset plus the travelling distance. The algorithm will then do a heuristic search (for everyone who is intersted: this is what sets A apart from dijkstra). Use the straight line distance to the end node as a rough estimate. The node with the lowest heuristic value will be examined next. Then start with this new node as the next start node. Every time the node value will be set. The heuristic map will continue to be used over all iterations. It is worth mentioning, that the node value must only be calculated if the node has not been visited previously.

This continues until the end node is hit. If all tiles have been visited and the end this has not been found, there is no connection.

There and back again

pathfinding

The algorithm has found one or multiple paths from start to end. To get a valid succession of tiles as a usable path from that, it must perform a downhill search. Start at the end, which should be the node with the highest node value. From there on, search the neighbouring node with the lowest node value. This will be your next node to visit. Then do this over and over again, until you reach the start node again, which is the node with the lowest node value.

Then the last thing to do is to inverse the ordering.

... also worth mentioning

Since we use a heuristic, it can (and will happen) that not the optimal path will be found. An example would be if there is an obstacle in the way. Then the algorithm might take the long way around it, instead of the short one.

One easy trick to handle this is to swap start and end and calculate the path also the other way round. Then just use the path with the lower summed up node values.

If you are tempted to do pathfinding on a large map, there are many tricks on how to speed this up. One might be to divide your map into large regions and calculating a coarse grained travel map. Then you can use this as a starting point for a refined version.

There is also a dynamic version, which can handle events like a bridge that is no longer passable. This is useful, since you don't have to recalculate the whole path again.

As mentioned above, it is also possible to use any kind of graph, not just square tiles. This will allow for any type of layout, e.g. on hex tiles or on a map, which is not created by tiles at all.

Using irregular tiles

GameCamp Munich and Indie Outpost

Lately there have been two big events for the German game development scene: GameCamp Munich 2016 and Indie Outpost 18. I visited both and presented a 25 minute talk about name generation. If you are interested in the slides, please follow this link.

About 35 people visited Indie Outpost. Another talk was given by a good friend, Lisa about immersion in games and she provided a hands-on show of her bachelor project "Collect" which uses the Oculus Rift. After the talks we had some really nice discussions in a super friendly atmosphere at Coworking Space Nürnberg.

GameCamp was another ball park with about 200 participants. It is a BarCamp, so everyone can give one or multiple talks or prepare a workshop. I learned a lot about very different themes: how to use Facebook, why business cards are important, proper merchandise/giveaways, neuronal networks, "Bastarde" a great text adventure for android and some other great topics. This was a great experience and I can't wait for next year's GameCamp.

Generating Names

What is a name? What makes it unique? What makes you easily identify it as such? How can we intuitively see from which cultural domain it emerges?

PROCJAM Names

For this week its PROCJAM. There are many resources and tutorials available on how to generate levels (like heightmaps or connected rooms). But when it comes to fill these levels with life and personality, not that much information is available. Nevertheless it is a requirement to generate Names for persons, cities, locations, enemies or anything in your game that should be identified uniquely. This task becomes even more interesting, when you want to have distinct names for different cultural or social domains or races. Of course your elvish cities should be named differently from your orc warriors.

Three Methods

In this post I will present three distinct ways to generate names. I will start with the most rigid way and end with the most flexible way. I implemented the second and third method in a C# program. The source code is available on Bitbucket.

Method 1: Lookup lists

The most simple (and not very procedural) way of creating names is just to have a list of names. When you need a name just randomly pick one from the list. If you want to avoid duplication just pop the name.

For different cultural domains it is feasible to have different lists. On the internet there are various lists of names, that can be used free of charge and will yield a large amount of input.

The big drawback of this approach is that you are limited to the names on the lists. Especially if you have some special requirements.

typo screenshot

For Example, for the game Typo I needed names that are more or less difficult to type and thus had to maintain different lists and could not just copy and paste some reference lists.

One large list (most common US citizen names) that I used for my name generation can be viewed here: Name List (bitbucket)

Method 2: Grammar rules

If you want to go one step further and really get a large amount of unique and procedurally generated names, you can use what is called grammar rules. For this you manually specify some rules on how names should be built out of basic blocks.

The most basic building block of names are single characters. But when you start to roll your name by appending randomly selected chars, you will get strange names like "grtnsa" or "mhowz". So we need a little bit more attention to detail here. What works very well is to divide all characters into groups, like consonants, vowels and special characters (inverted commas, e.g. for orc city names).

Then think about an arrangement of this building blocks. What works nice is to alternatingly use consonants and vowels. This will yield reasonable names that can mostly be pronounced correctly. The following list presents some five letter names created by alternating consonants and vowels.

Negic Tadal Caten Fahot Nafot Baber Lenal Warog Firig

Of course you can also create names of other length. If you want to do even better, think about the following: Not all letters of the alphabet occur with the same frequency. Therefore it is useful to aid the generator with a little help in the right direction. On Wikipedia you can find a frequency table that can easily be used to mimic this behaviour.

This Method works even better if you use some larger building blocks. Like fixed suffixes

il, en, ith, son, ... 

that can be concatenated to the names above. Some of them work better with three or four letter names.

What you can also do is some consonant duplication in the middle of the name. Therefore you need additional information, since some consonants can easily be doubled (like "n" or "t") while some can not (like "h" or "x"). Adding duplication the middle consonant in the upper list (with exclusion) and appending some suffix will yield

Neggicil Taddalen Catten Naffotson Babberman Lennalen Warrogil Firrigson

which are also perfectly fine names. Note how on Catten no suffix has been appended, since the last two characters already match one suffix. I encourage you to create your own set of rules. The possibilities are endless though not all rules will generate sensible names.

The big advantage is that this method allows you to generate random names by using some simple rules. The disadvantage is to create distinct cultural domains. A lot can be done with the suffix but again this is some kind of prepared list of words.

Method 3: Monte Carlo names

Monte Carlo methods describe a class of computational algorithms that are based on random decisions. The basic idea for this topic is to start with a name that is composed of completely random characters, which is most likely a bad name. Iteratively throughout the Monte Carlo process the name becomes better and better until it is good enough to hold as a name for a person, city or anything else.

To define bad or good names, we need some criteria, which can be trained by the lists mentioned earlier. This criteria can be anything you like (e.g. number of consonants in a name or how often the same letter appears twice or more). Here I will use two simple concepts: Pairs and Correlations. A pair of length N is just the sequential occurrence of N characters. As an example

Name: helen
Pairs N=2: he el le en
Pairs N=3: hel ele len
Pairs N=4: hele elen

A Correlation just looks N characters forward in the name and reports which chararacter follows in a certain distance

Name: helen
Correlation N=1: h?l e?e l?n
Correlation N=2: h??e e??n   

Where a ? denotes any arbitrary single character.

Armed with Pairs and Correlations and a list of names you can now create the rating function. By analysing all names in the list you will get some frequency table for Pairs and Correlations. For every occurrence (like in the "helen" example above) you add 1 to the respective Pair and Correlation count. As the input data have been real names you want to mimic the behaviour of those names and thus have criteria for good names. The rating function just checks the name it is given and looks for any Pairs and Correlations it has been trained with. For each hit it adds the number that is according to the Pair or Correlation that has been found.

Now we have the rating function and can start creating names. This is like rolling consonants and vowels according to the letter frequency table in the grammar method. You start over with a completely random name. Calculate the current rating of the name. Then exchange a random character in the name with another random character of the letter frequency table. Then calculate the new rating. If this value is better than the old rating, accept the change, otherwise refuse it and undo it. This should be done in a loop (you should make sure that each character has been touched at least some couple of times). After about 100 iterations you will have a very nice name. As Monte Carlo algorithms are iterative, the longer it runs the better the results will get.

Some names that have been created with this method are

Lana Eran Anaara Alan

An interesting fact is that you can feed the rating function lists with different cultures and will get names that follow that cultural rules. (notice how the training with Chinese city names also added ' to the name list).

Orc names: Ogrugu Kug Duguk Trugga
Chinese cities: Qhang Yangua Angsho Ing'ang

The drawbacks of this method are, that you need a list of names that you can feed in the rating function. Also it can be quite expensive to do all those iterations. The number of possible pairs with N=2 are 24*24 (number of characters for the first and the second letter multiplied) are 576. For Pairs with N=3 it is already 13824 and for Pairs with N=4 it is something over three million. Let's assume that only 5 percent of the combinations will occur. Then there is a massive amount of substring checking to be done. If you do many iterations (remember, that is what you need to do to get good names) this can take some time.

Nevertheless the Monte Carlo Name Generator is my favorite as it can produce huge varieties of very nice names that follow a certain cultural trend and is truly procedural.

Cleaning up

As you probably noticed, I did not investigate the questions proposed at the beginning. So far I am still a physicist and not a linguist. But at least I try to answer those questions in the way I have learned (namely statistical methods, numerics, data analysis and correlation functions). The proposed simple criteria for the rating function work surprisingly well - at least for me. It is also stunning that by using a really simple alternating grammar it is feasible to create such names.

I hope you enjoyed reading this tutorial on how to generate names procedurally.

1 hour projects & Devmania

One hour game jam

As I announced in the last blog post, I did some more one hour projects. There is the fantastic one hour game jam (#1hgj) which runs every Saturday evening (22:00 in my time zone). This #1hgj is a great opportunity to get in touch with some great gamedevs, strengthening your gamedev muscles and decision making abilities as well as developing a focus for what is the core idea of a game. So far I handed in two games, and thus had the chance to evaluate some new (for me) game mechanics with a minimum investment of time. Of course this means sitting down for one crazy hour, crunching the hell out of your keyboard and producing really awful hacks and not only spaghetti code, but true spaghetti dough code. Nevertheless this is a great opportunity which I can strongly recommend to any gamedev.

In the last two weeks I created two games for #1hgj 24 and 25. The first one is called chainsquares (theme "chain reaction", a puzzle mash up of Connect Four and Tetris with colors. The second (and much more evolved one) is called dissident. You need to maintain order and conformism in your parade and have to bring dissidents back in line. The game was inspired by a news show, I saw some hours prior to the jam about a North Korean nationalist parade. Obviously this is a futile attempt, but you might want to try to survive as long as you can.

Devmania

As it was incredible fun, rushing through the creation of those two games, I will definitely take part again. But next Saturday I won't - as there is the largest German indie gamedev meeting in Mainz, called Devmania. Unfortunately there is no internet connection, so I won't be able to join the #1hgj. Instead there will be an overnight contest at the Devmania for which I released already three great games.

I am looking forward to this event, especially to meet some people!

Crunching GameDev

As I take part in One Game A Month (#1GAM on Twitter) I create a (more or less) small game every month. Since I have been traveling around, working on my PHD, I totally missed the September deadline. Up until yesterday evening, the last day of September.

So I crunched and pushed a little tech demo out within one hour.

FTCS

What you see is a 2D FTCS integrator. This is a numerical construct that computes the stable time evolution of a partial differential equation, in this case the heat equation. Yes, I tutored a university course about this topic.

As it was quite boring to watch the initial peak decay I added some timed random scatter noise in the last ten minutes.

For normal human beings

Imagine the map as a heat map, e.g. the heat in your room viewed from above. Blue means cold, red means hot. As you would expect any heat will spread out through the room. The walls are cold and will take any amount of heat. That is why you need to turn on your radiators during winter.

If you are interested in the source code behind this, please feel free to check it out or comment.

As I kind of liked working with extreme time constraints there will probably be some more 1h demos in the future.

Shadowing your code

PHD and new projects

A lot of big things are happening right now. I started working as a Ph.D. for the physics department in Erlangen, we had some fun with Ludum Dare 33 and did a personal jam for a weekend two weeks before. This post will cover one of the features I implemented for the latter. The game itself is a tile based roguelike which is not finished yet.

Shadowing your code

So one thing you notice when looking at different tile based games (e.g. like Hammerwatch) is that they feature some sort of shadows for their tilemaps.

When you start developing your game it might look something like this:

This looks boring

As you can see there is no depth and looks kind of boring. I don't want to do any specific raycasting or dynamic shadow calculation since those might not be feasable on certain platforms due to performance issues. The technique shown here will be much simpler and uses just four images. You just need to distinguish between wall and floor tiles. As the shadows are cast by the individual tiles, it's easy to do some local recalculations if the tilemap changes.

Defining the different cases

So here is the basic idea: break down your number of options of shadows down to 7 and deal with them individually.

The basic options of tile arrangements are:

7 Options without shadows

The obvious case number seven is that there are no shadows to draw. This happens if we are completely within a wall or on the plain floor.

The desired result is something like this:

7 Options with shadows

What you need are those four images: enter image description here.

The first two are to be drawn right of a wall tile, the latter two above a wall tile. Both north and east shadows feature a normal and a cropped version. If you want to emphasise depth a little more, blur the edges and make use of the alpha channel.

Show me some code!

So lets get into code! The seven options are:

None, North, East, NorthEast, NorthCropped, EastCropped, NorthCroppedEastCropped

They are basically the possible combinations of the four tiles above. Now we need to check, which of them to apply when. This can easily be distinguished by the sketch provided above. For this we only need four tiles:

  • the tile we are currently working on (x, y)
  • the tile above (x, y - 1)
  • the tile to the right (x + 1, y)
  • the diagonal tile (x + 1, y - 1)

This is how it's done:

// get the four needed tiles
tile         = level.getTile(x, y);
tileRight    = level.getTile(x + 1, y);
tileUp       = level.getTile(x, y - 1);
tileDiagonal = level.getTile(x + 1, y - 1);

// abort if tile is not a wall
if (!tile.isWall()) 
{
    tile.shadow = None;
    return;
}    

// all three neighboring tiles are floors => draw the full shadow
if (!tileUp.isWall() && !tileRight.isWall() && !tileDiagonal.isWall()) 
{
    tile.shadow = NorthEast;
    return;
}

// only up and right are floors, diagonal is a wall => draw only cropped versions
if (!tileUp.isWall() && !tileRight.isWall() && tileDiagonal.isWall()) 
{
    tile.shadow = NorthCroppedEastCropped;
    return;
}

// right is a floor, above is a wall
if (tileUp.isWall() && !tileRight.isWall() )
{
    if (tileDiagonal.isWall())
    {
        tile.shadow = EastCropped;
        return;
    }
    else
    {
        tile.shadow = East;
        return;
    }
}

// above is a floor, right is a wall
if (!tileUp.isWall() && tileRight.isWall())
{
    if (tileDiagonal.isWall())
    {
       tile.shadow = NorthCropped;
       return;
    }
    else
    {
        tile.shadow = North;
        return;
    }
}

And this is the result you will get:

Shadows implemented

I hope you enjoyed this little tutorial. We are looking forward to your comments.

 

Cobra Hunter #80s racing game now p…

Writing games in C++

University courses

This semester I mentored a lecture on "computer physics and numerical methods" at university. Though one key aspect of the lecture was to allow the students to use whatever tools they wanted to use most of them did their assignments in C++. Topics included numerical root finding, ordinary and partial differential equations as well as monte carlo methods and numerical fourier transforms. I also created the weekly exercise sheets and programmed the sample solution which allowed me to polish my C++ skills again. Please cross your fingers for the students as the lecture's written exam will be tomorrow. Good luck to all of you! I also visited an university seminar on "advanced C++ programming" in which i learned a lot about C++11, C++14 and the cool new feature of concepts to be introduced in C++17.

Writing Games in C++

All this made me want to write a game in C++. Since I began developing games using C++ (but got stuck with barely playable prototypes for various reasons) this was some sort of coming home. You can play the result Quad Triad.

Most of our games have been developed in some (abstract) high level languages like C# or Haxe with some very helpful tools and engines like Unity3D or HaxeFlixel. Going back to a kind of native approach using just vim, plain C++11 and SFML 2.3 felt really clumsy and very unproductive at first. It took me days just to set up a basic game loop and get some sprites rendered as well as some input routines. That's one of the reasons, the graphics for Quad Triad are really simple. Having to think about which data type should be stored in which pointer, when memory has to be allocated and when it can be safely deleted again (although C++11's shared and unique smart pointers are really handy!) was a real pain. Not to speak of the really broken include model (include guards) of C++ or my deep rooted hate for Makefiles.

After the game has been brought to a level where I didn't have to cry myself into sleep I started playtesting. Besides the above-mentioned problems there are of course the usual bugs that sneak into a game. One funny thing that happened: placing a card removes the card from your deck and places it on the table. Bad stuff happens when the slot is already ocupied: The player's deck did not have the possibility to check if the slot was free. Test early, test often!

Compiling for different OS

Somehow I managed to finish the game to a playable state. Bad luck for me, I developed on my Linux laptop. Most gamers still are on Windows. Trying to compile on Windows failed for almost two days for various reasons:

  • Visual Studio does not offer most of the C++11 features I use (like the shared pointers, constexpr, auto, ...)

  • MinGW can (and will) be a real pain concerning versions and compatibility (DW2, SJLJ).

  • You want to use that library (SFML2)? Good for you there is a windows port, bad for you it was built with a different compiler!

  • Compile a library on your own? Good for you there is cmake, bad for you you have to do all the windows path tinkering.

Recap, Summary

Nevertheless I finished with a working Linux and Windows build. No, there won't be a Mac version. Though it was a really hard process I must say that it was kind of fun and I really learned some valuable skills. Currently I am totally proud of myself to offer my first real C++ project (though it's ugly, not juicy and probably no one will play it). It is even my first cross compiled project that works on different operating systems.

Though my next project will be definitely done using HaxeFlixel (for the Indies vs Gamers Jam on Gamejolt) I want to keep creating games with C++. Not that I especially like pain that much, but because for a long time I really had the feeling that this project in particular boosted my skills.

 

Finished our #LDJAM entry Tungsten …

 

We're all set for #LDJAM http://t.c…