Deeply Dreaming

So what is happening with Polyology and Spy Game at the moment? Well unfortunately I don’t have time for the next few months as I’m currently busy working for Dambuster Studios and The Chinese Room on upcoming projects. I’ll still bring Polyology to Steam, I’m still going to continue the Spy Management Game but in the short term I need to be practical and make sure I have enough money.

dream1

dream2

dream3

Greenlit!

Polyology has been Greenlit and will be available on Steam in the coming months! This is excellent news, it’ll allow Polyology to entertain more people and hopefully help me carry independently developing games. More usefully I’m including my Greenlight statistics to give you an idea of what numbers are needed to get onto Steam.

votes over time

Most the views for Polyology came through launching a Greenlight campaign, from Steam users who happened to look at their Greenlight queue. The second small bump was from doing a YouTube Video with Action Soup Studios and finally the second large spike was from doing a Lazy Guys Bundle. It’s very heartening seeing my actions correlate with Greenlight votes.

stats

However as you can see the statistics above Polyology didn’t get that many votes, at least compared to the Average Top 50 (on the day I took the screenshot). The average number of Yes/No vote ratios are about the same. The followers at 1.9% is higher than the top 50 average of 1.36%.

cumulative

So why did I get Greenlit? To be honest I have no idea. Maybe they played Polyology, or liked the Rock, Paper, Shotgun review? I suspect it’s because Steam is becoming a more open platform and they’re generally letting more games through. Regardless should go and integrate the steam overlay, localize and think of some achievements for Polyology.

One Year on

So it’s been a year, to be honest it’s flown by and doesn’t feel like any time at all, Maybe I’m just getting old.

There have been many highlights this year

  • Showing at Gamecity 9
  • Polyology Released
  • Contract Work
  • Greenlit
  • Homefront Gamescom Demo

New Year’s Resolution

  • More social updates
  • Polyology on Steam
  • Spy Game

I’ll talk more about my contract work and Greenlight stats in future posts, until then here’s the Homefront Gamescom Demo I mentioned above.

Two’s company

Over the last few months I’ve been working for myself three days a week on Polyology, and working for Dambuster Studios on Homefront: The Revolution the other two days. Both jobs are essentially doing the same thing, creating games, however in practice they’re extremely different.

Working at Dambuster Studios is great, particularly because of the development team, yet I’ve choose to work independently with the majority of my time for a few reasons….

  • Freedom – I don’t have to work on another FPS game, the last 7 years of my career I’ve worked on various shooters. Now I can more variety in the genre of game I work on.
  • Scale – Everything is easier with a small team and a small game. Communicating with the team, syncing builds, changing design all become trivial. It’s like the different between guiding an oil tanker and rubber dinghy.
  • Challenging – Working independently involved doing lots of different things; design, programming, QA, art, business, marketing. It’s making me grow as person and appreciate all the different skills that go into creating a game.

Polyology 11-13-2014 2-16-00 PM 0 10

However I do still go to turn up to work, and I enjoy it more than ever.

  • Resources – The amount of time, from a large group of extremely intelligent people, that is going into Homefront: The Revolution is just astounding. One day’s work at the studio with approximately the amount of development time that has done into Polyology.
  • Support – Having other people when you have questions, bounce ideas off or just have a tea break with is fantastic.
  • Marketing – Something that’s hit me hard since releasing Polyology is the amount of time and effort that needs to go into marketing. I just don’t have to worry about that at Deep Silver, they have a talented and experienced team to deal with it.

hf2

A few weeks ago my boss asked me “Do you mind working on some checkpoint load bugs?”, traditionally a less fun and difficult part of programming in CryEngine, like a good employee I agreed. But I really don’t mind, work just more enjoyable when it’s not full time. I can just get stuck into whatever task I’m lucky enough to get and not have to worry about the 17 different tasksI could be doing as an indie, let alone how it’s going to put food on the table.

If you get the change to work in a AAA team and independently I suggest you take it and enjoy the variety of what both jobs have to offer.

Telemetry for Indie Games: Replay System

Following on from Posting Basic Data I’m going to talk about how I implemented a system to record users inputs, upload them to a webserver and replay them as needed. This was extremely helpful for designing the puzzles for Polyology, recreating bugs and testing fixes.

Determinism

An important base line for creating a consistent replay system a deterministic game engine. So if you do exactly the same thing, you get exactly the same output. Typically the only complication comes when we use random numbers to create interesting particle effects, or spawn objects at changing locations. Fortunately computers aren’t really random at all, and the randomness is typically generated based on the millisecond you called the random function as a seed. You can either record that seed, set it to a fixed number of use an existing library such as David Bau’s Seedrandom.

//Fixed seed, so random always generated same results
Math.seedrandom('hello.');
console.log(Math.random());          // Always 0.9282578795792454
console.log(Math.random());          // Always 0.3752569768646784

//Random seed makes life more interesting but less determistic
Math.seedrandom();
console.log(Math.random());          // Reasonably unpredictable.

External Inputs

Now your engine is deterministic just need to record all external inputs so allow you to replay the game. Typically they include

  • User Input
  • Frametime
  • Random Seed
  • Which is fairly trivial to collect at runtime, bundle up and send to a webserver. However if you game is multi-threaded life is significantly more problematic as the OS can give you threads at different times but there are more extreme virtualization solutions out there.

    Wrapping this information in xml, json or whatever you prefer and upload it to a webserver.

    <Replay seed="42" level="rooftops" >
        <record type="KeyDown" frame="132" key="18" />
        <record type="KeyUp" frame="193" key="18" />
    </Replay>
    

    Personal I also included other information so allow me to search and sort the data such as

  • Users score
  • Current date and time
  • Length of replay
  • Replaying the data

    Getting the replay to work is fairly simple, just step through the file, doing what you recorded. There are a few gotchas like disable current user input, handling remapping and any state that influences the same (e.g. if the player has the key to unlock that door) but nothing that can’t be overcome quickly and easily.

    Proof of the Pudding

    This proved an invaluable resource from a design perspective, allowing me to see what users are doing from a distance. So players that don’t give you any feedback when playing your game online still give you a huge amount of valuable data. Allow you to see where 60% of users stop, and what they were doing on that level, or letting you know that after someone emailed you feedback, they continued to play the game for another 2 hours and finish off every bit of content.

    From a code side it was also useful, when users reported bugs I just watched the replays until they happened, then I could fix the code and verify it was fixed by running the new code against the replay.

    A replay system is a wonderful tool to give you a huge amount of information, and as long as you spend the time and care to mine this information you’ll undoubtedly end up with a better product in the end.

    Telemetry for Indie Games: Posting Basic Data

    If want to find out how to implement a quick telemetry system, or just want to me nosey about how I used Django to create a telemetry system for Polyology, then this post is for you.

    Django

    One of the various tag lines is “Django makes it easier to build better Web Apps more quickly and with less code.” which I can’t help but agree with. It does take some time to setup and learn but once you know Django you’ll be able to quickly create and extend your telemetry system. It has solid documentation and a lovely tutorial for getting you started on their website (disclaimer – This article was written using Django 1.4).

    Uploading data from the game

    Below is a small snippet of javascript code for uploading some bit of information, some thing like a player has loaded a level, restarted or quit your game. It ties in some situational information, the set and level, where the event occurred. Then it’s a fairly trivial matter of sprinkling your code with PostTelemetry calls in suitable places, and you can extend it with new telemetry without changing any web server code.

    function PostTelemetry(statName)
    {
        var formData = new FormData();
        formData.append("levelset", gLevelSystem.GetLevelSet())
        formData.append("level", gLevelSystem.GetLevelName())
        formData.append("stat", statName);
    
        var xmlhttp = GetXMLRequest();
    
        xmlhttp.open("POST", "/telemetry/", true);
        xmlhttp.send(formData);
    }
    

    Handling the data on the server

    Django lets you define models, layouts of how information will be defined, this is a quick model for some generic telemetry. In this case it’s just a couple of short reference strings and an integer (and a cheeky increment function for later on).

    class Telemetry(models.Model):
      levelset = models.CharField(max_length=32)
      level = models.CharField(max_length=32)
      stat = models.CharField(max_length=32)
      value = models.IntegerField()
    
      def increment(self):
        self.value = self.value + 1;
    

    Then when a post comes in simply increment the existing telemetry, if it doesn’t exist add a new one.

    def telemetry(request):
      if request.method == 'POST':
        _set = request.POST['levelset']
        _level = request.POST['level']
        _stat = request.POST['stat']
        if (_set and _level and _stat):
          try:
            query = Telemetry.objects.get(levelset=_set, level=_level, stat=_stat)
            query.increment();
            query.save();
          except ObjectDoesNotExist:
            newTelem = Telemetry(levelset=_set, level=_level, stat=_stat, value = 1)
            newTelem.save()
    ...
    

    Administrating the data

    If you add a quick Admin class, saying what is displayable and filterable

    class TelemetryAdmin(admin.ModelAdmin):
      list_display = ('stat', 'levelset', 'level', 'value')
      list_filter = ('stat', 'levelset', 'level')
    

    Django will give you a admin site, setting you add, edit, delete telemetry as well as filtering and sorting.

    Django Admin Site

    Conclusion

    So that’s it, that’s most of the code for the telemetry, and you can just add new post calls and everything is just handled. Every indie dev out there should have a simple, extensible web framework for telemetry. If you don’t have one, I’d try Django and see what you think.

    Finally I’d like to thank Mark Tully for introducing me to Django in the first place.