Tuesday, 8 November 2016

Announcing Greenlight


I've submitted Blackshift to Steam Greenlight. Vote here.

For those unaware, Greenlight is Steam's indie game vetting program. If enough people vote for Blackshift, it gets accepted to be made available on the Steam game marketplace, giving it the opportunity to become much more popular. This means more people making levels, and more people playing yours.

Friday, 4 November 2016

Beta 2.1.0 Released

I finally did some wall graphics
Thanks to all Alpha Testers. We're finally in Beta.

The choice of when to declare beta is pretty arbitrary, but really it just means I feel Blackshift is stable and polished enough to start showing it to a wider audience. If you wanted to help me out — and you don't have to, I mean you already bought the game — but if you wanted to, you could spread the word on Twitter, Facebook and so forth. If you have a Youtube channel it would be great to see some Blackshift videos. Post 'em here if you make any.

For my part, I'll be working on getting a second trailer together, and just generally adding polish and fixing bugs.

Edit: I just noticed I posted this exactly a year after the post announcing the start of Alpha. I did not plan that!

Changes

Saturday, 15 October 2016

New Stuff

I've added some features to the server (you don't need to download anything — this stuff will just start happening):
  • You can now change your password
  • Old wins are now “carried forward” when a level is edited
The new “carry forward” feature works like this:

When you edit a level, all the old plays are invalidated as usual (they turn grey in the high score table and will get pushed out when people play the new version).

BUT, now, the server starts going through all those old plays and trying them against the new version of the level. Any that still work get carried forward and turn white again.

Basically this means you can make small changes to your levels and people won't always lose their high-scores. Small changes mean things that don't affect the actual gameplay of your level — decorative floors, walls, that kind of thing.

Adding save points won't always count as a small change, I'm afraid, but I'd like to fix this in the future.

Wednesday, 29 June 2016

Alpha 2.0.55

  • Added offline mode under options. When offline, the level pit will not be accessible.
  • Changed camera projection for a slightly nicer view.
  • Fix bug where bullets hitting walls made too loud a sound.
  • Loading screen before entering the level pit.
  • Fixed glitchy loading screen when creating a new level.
  • Made the awards page more readable.
  • New graphics.

Sunday, 15 May 2016

Why I Don't Need a Scene Graph

(And Why You Might Not Either)


A couple of months ago I completed the switch from OGRE to BGFX as Blackshift's
rendering library. While OGRE is a full-featured graphics engine, BGFX is more
of a thin layer over OpenGL and DirectX. So why the switch?

Well, it really comes down to scene graphs.

When you use a general-purpose engine — and here I include full game engines
like Unity as well as graphics-only engines like OGRE — you're usually required
to encode your scene as a “Scene Graph” — a tree-like data structure which
describes each object's position, orientation, 3D model, etc.

Each node is transformed relative to its parent
Scene graphs are versatile, and are used in 3D tools as well as in game engines. There's basically no scene you can't describe with a scene graph.

But you pay for that.

Because the scene graph is such a general structure, it won't be optimized for your particular game. And Blackshift is a very particular sort of game.

When Blackshift was using OGRE, the naive approach was to create one scene node for each game object, including all floor tiles, wall segments, blocks, items, enemies, etc.

This was a performance nightmare, so I ended up having to merge all “static” objects into 16x16 “chunks”, with a mesh for each chunk of walls. But, nothing is really static in Blackshift, because most tiles can change and get blown up, and even the walls need to change quickly in the editor. So the chunks needed to be recomputed all the time. And, because each chunk needed its own unique mesh, instancing was out the window.

Scene graph in Unity
Adding to that, scene-nodes needed to be updated when their associated game objects moved, or performed any action needing an animation, leading to a complex system of events and messages to keep everything updated.

Finally it got to the point where I noticed I was expending a ton of effort just to keep OGRE's scene graph happy, and I wasn't even reaping any of the benefits of using one:
  • Scene graphs help with culling complex scenes, but Blackshift has a fixed camera position and all objects are on a grid, so culling is incredibly easy.
  • Scene graphs work well when each scene-node “is” its object, but Blackshift follows a MVC design where the game logic runs totally separately from the renderer. This means extra overhead was required to keep the scene-nodes in sync with the game objects.

Blackshift's new renderer is much faster and much easier to work with. The main render loop now looks something like this:

To render a frame:
  For every grid cell within the view-range of the camera:
    For every object in that cell:
      Draw that object

To decide how to draw an object, every object type has a “graphic”, which is a compiled native-code routine that sends the appropriate draw commands to BGFX. This is super-fast. At runtime, all commands to draw that kind of object are in a pre-optimized routine that's just a pointer lookup away.


Drawing a given object is a simple matter of

object->type->graphic();

The animation code is mostly stateless. For example, the moving parts of the customs door (the one that closes when you have an item) are simply drawn with an orientation which is a function of the time since you last picked up or dropped an item. This is orders of magnitude faster than updating a scene node every frame for every moving part of the door (which would then trigger cascading bounding box updates, all to be thrown away when the culler can't make use of the BBs.)


If a scene-graph is declarative in style, Blackshift's new renderer is less so. The renderer no longer knows or remembers object positions. It simply reaches into the game's own state each frame and fires off rendering commands to BGFX.

I was amazed how much faster this is. For example, the “morpher”, the bit of code that decides which wall shape to draw for a certain wall tile by looking at its neighbours, doesn't even need to be precomputed. It simply runs every frame for every tile on screen, and it doesn't even register in the performance graph. This is something that took a lot of effort to implement efficiently before.

So, advice to my fellow game devs:

When thinking about how to implement your renderer, think about a typical scene from your game and what API calls you'd make to render it. Then, if you can, design a renderer that does that and nothing more.

I've written all these words but all I'm really doing is restating the First Law of Optimization:

To make your code run fast, have the computer do as little as possible.


Friday, 6 May 2016

Alpha 2.0.53-54 — The Surprise Update

Surprise! I know the last update only came out three days ago, but I need to put this one out as soon as possible.

For one, it fixes the Windows updater which always used to fail when applying more than one update, for embarrassing reasons relating to me being dumb it applied the updates in reverse order and for two, it accommodates future changes to the replay format.

The replay format needs to change because the annoying bug where your wins don't count hasn't quite gone away and I need to put more debugging info into the replays themselves in order to figure out what's going on.

As a bonus, this update also includes the new item door graphic I did the other day when I mistakenly believed the bugs were fixed and it was time for a new age of prosperity and graphics.