Gumption

29 Dec 2015

In between the last update and today’s, I’ve been away for a 3-week long vacation, and otherwise also haven’t had much time to work on 2k14: The Game. So not much progress to write about. I did improve and add a few things, which I’ll get to later, first I’d like to take a short detour to say a few words about something called gumption.

Gumption

I may be mistaken, but I’m pretty sure that I first encountered the word gumption in Robert Pirzig’s beautiful book Zen and the Art of Motorcycle Maintenance, which incidentally is one of my favorite books, and changed the way I think about and appreciate some important aspects of life.

What is gumption and why do I want to write about it? Dictionaries typically define gumption as something like this (taken from freedictionary.com):

gump·tion  (gŭmp′shən)
n. Informal
1. Boldness of enterprise; initiative or aggressiveness.
2. Guts; spunk.
3. Common sense.

It’s the first meaning that comes closest to the concept I’m trying to describe, but it still does not quite capture it. This blog is about writing a computer game, so obviously there has to be a link between gumption and software development.

In my mind, gumption in software development is what makes projects move forward and make progress. It’s as much about enterprise and initiative, as it is about determination, discipline and, quite simply, the joy of building things using a computer. I think anyone who has ever dabbled in programming or has been doing professional software development, will recognize that sometimes a project starts to stall. It takes longer to make incremental updates, required solutions and improvements appear to be more difficult than before, things basically seems to have more friction. This saps energy, and takes away the joy of building things. You lack the gumption to sit down and work on the project, because you remember it being a drag, a battle against the tools (programming language, development environment, libraries) you are using, or an endless sequence of replacing or moving around code without any visible progress in terms of features and functionality.

Especially for hobby projects, a lack of gumption can be fatal, as they are by definition something that should be enjoyable. Unless we find a way to increase gumption when working on the project, it will inevitably stall and whither. The longer gumption to work on the project is low, the higher the chance it will stall.

How can we increase gumption when working on a software project? Over the years I’ve been doing software development, both as hobby/side-projects and professionally, I’ve identified a few things that increase gumption:

  1. Starting a project from scratch

    Personally, I think starting a new project from scratch is the most enjoyable part of software development. There’s only ideas about all the greatness you are going to produce, all the novel things you’ll learn, and all the fun you will have seeing the project progress. There’s no backlog of mundane practicalities that need to be addressed at some point, no nagging bugs to solve, no bottlenecks for progress. Yet…

  2. Learning and implementing something new

    Under the assumption that people start personal side-projects because they enjoy solving intellectual puzzles (which is what programming is about, at its core), a big part of the fun is learning new things (algorithms, tools, methodologies) and trying to put them to good use in your project. A healthy dose of research and experimentation is a great way to keep a project going, preventing it from starting to feel like a drag.

  3. Making fast progress adding features

    Adding new features fuels progress and sparks creativity. New features can build on each other, creating opportunities for realizing ever more elaborate ideas. Crossing off implemented features carries a sense of achievement and positive feedback.

  4. A clean and sound codebase and architecture

    When you have the feeling that your codebase is in the best possible state for future improvements and additions, you feel confident to actually start working on them. You don’t have to second-guess yourself with every change you make, whether it will break some earlier assumptions that lead to the current architecture. The state of the project reflects what you think is necessary to move the project forward towards its goals.

The reason I wanted to dwell on the topic of gumption will not come as a surprise: the year 2015 is about to roll over, so now is a good time to consider the progress made on 2k14: The Game.

Looking back at the video in last year’s last post, it appears as if not much progress has been made for a year’s worth of effort. At the end of 2014 I just added sprite rendering, and apart from the fact that the sprites are monochrome in last year’s video, nothing seems to have changed in terms of gameplay or visuals. Of course this is just superficial observation, as behind the scenes, lots of back-end functionality has been added, most notably freeze/unfreeze functionality, full scriptability and looped live code.

That’s not nearly all the work that went into the game though. Many times over the past year progress on 2k14: The Game slowed down to a crawl and almost stalled because of a lack of gumption. Progress was fast while working on the interesting bits: new functionality such as the scripting layer, which increased gumption by virtue of bullet points 2 and 3 listed above (learning new things, new features, fast progress). Invariably though, large additions like the scripting layer introduced all kinds of mundane practicalities that had to be dealt with, or left the codebase in a messy state. Unclear separation of concerns, code duplication, temporary workarounds, todo’s, etc. See also: bullet point 4 in the list above.

For side-projects like 2k14: The Game, fixing these kinds of things feels a lot like work, and become a gumption drain. I can never bring myself to keep these deficiencies lingering around the codebase though, marching on adding new stuff as if these problems (current, potential, or future) don’t exist. From past experience I know technical debt will build up to a point where factoring out the problems one-by-one will no longer be possible, and large parts of the codebase will need to be rewritten wholesale. To prevent that from happening, I’ve been continually working to improve the various components of the game and how they interact. While this has eaten up a large part of the allotted development time and often prevented me from sitting down to work on the game for longer than a few minutes because of a lack of gumption, all this effort has prevented the codebase from slowly but surely degrading into a mess so big I would have decided to abandon the project altogether and start something new (see also, bullet point 1 of the gumption list ;-)

Obviously, the next time I would build something like 2k14: The Game, some game with a similar feature set, I would (hopefully) avoid introducing the kinds gumption-sucking deficiencies in the game design, architecture or implementation that I have had to fix for 2k14: The Game, thereby significantly speeding up progress. My goal for 2016 is to make the best use of the solid foundation I feel I’ve built so far, towards some more visible progress.

Before that, there’s just a little more under-the-hood improvements to be made though. I’ll talk about in some of these in the following section, the remaining parts (which I’m still working on) will have to wait until the first post of the new year.

JSON-based planet definitions

While trying to add support for modifiable planet topology (for example for trap doors, etc), I hit some limitations related to the way planets were initialized, which I felt had to be resolved before continuing.

First of all, I did not like the fact that the planet surface always had to be defined as a single numbered edge list. This prevented more interesting planet topologies that can not be rendered as a single polygon, and made it annoying to for example place entities somewhere along a planet edge: any time the number of edges in the surface edge list changed, all the entities would be located at the wrong edge.

Second, both the planet definition and initialization had to be encoded inside the planet Lua script: static planet properties as class variables of the Lua planet class, and dynamic initialization (such as placing entities) as Lua code inside the planet class init method. This separation of static and dynamic initialization was messy and unnecessary, and adding new dynamic initialization, such as defining which parts of the planet surface could be modified, would require additional methods in the Objective-C API, Lua bindings for these calls, and longer and more complicated planet init methods.

To make a long story short, I decided to introduce a JSON-based planet definition format, moving the planet definition out of the Lua planet scripts. I added some Objective-C classes to parse, validate and store the planet definition JSON files, and replaced all K14Planet and K14ScriptablePlanet initializers with a single initializer that takes a parsed K14PlanetDefinition that defines the complete initial state of the planet. This includes all of the planet properties that used to be static variables of the planet class, such as gravity, surface and description, but also the names, types and locations of all entities on the planet. The K14Planet class will interpret the planet definition in the passed-in K14PlanetDefinition instance, and perform the necessary initialization calls to realize its initial state.

The flexibility of the JSON-based planet definition immediately made it much easier to support planets with multiple polygonal components, and to change the way entities are placed on the surface of the planet. Instead of a single numbered edge list, the planet surface is now specified as a set of vertices, and a number of components defined using these vertices. An extra level of indirection was introduced to address the planet components, implemented by means of named attachment points. Entities can be positioned on the planet surface by referring to a component and attachment point, instead of by numerical edge id’s.

Putting everything together, the planet definition of ‘Planet 0’ of the game went from this (Lua):

-- Static properties & constants
Planet0.description = "Planet #0"
Planet0.surface = { { x=-16, y=5 }, { x=-12, y=2 }, { x=-6, y=2 }, { x=-3, y=0 }, { x=3, y=0 }, { x=3, y=3.5 }, { x=7, y=3.5 }, { x=9, y=5 } }
Planet0.gravity = { x=0, y=-2 }
Planet0.usedEntityClasses = { "Ship", "Orb", "Pedestal", "FuelPod", "Reactor", "Turret" }
Planet0.tint = { r=1, g=0.2, b=1, a=1 }

-- ...

-- Initialize planet
function Planet0:init()

  local ship = self:createEntity("Ship")

  local pedestal = self:createEntity("Pedestal")
  local orb = self:createEntity("Orb")

  local fuel_pod = self:createEntity("FuelPod")
  local reactor = self:createEntity("Reactor")
  local turret = self:createEntity("Turret")

  ship:setPosition({ x=-3, y=10 })
  pedestal:glueToSurfaceEdge(3, 0.5)

  local pedestal_position = pedestal:getPosition()
  local pedestal_size = pedestal:getSize()
  local orb_size = orb:getSize()

  orb:setPosition({ x=pedestal_position.x, y=pedestal_position.y + (orb_size.height + pedestal_size.height) / 2 })

  fuel_pod:glueToSurfaceEdge(1, 0.5)
  reactor:glueToSurfaceEdge(5, 0.25)
  turret:glueToSurfaceEdge(2, 0.5)
end

To this (JSON):

{
  "className" : "K14ScriptablePlanet",
  "subclassName" : "Planet0",

  "description" : "Planet #0",
  "gravity" : { "x":0, "y":-2 },
  "tint" : { "r":1, "g":0.2, "g":1, "a":1 },
  
  "vertices" : [
    { "id":"v0", "x":9, "y":5 },
    { "id":"v1", "x":7, "y":3.5 }, 
    { "id":"v2", "x":3, "y":3.5 }, 
    { "id":"v3", "x":3, "y":0 }, 
    { "id":"v4", "x":-3, "y":0 }, 
    { "id":"v5", "x":-6, "y":2 }, 
    { "id":"v6", "x":-12, "y":2 }, 
    { "id":"v7", "x":-16, "y":5 }, 
    { "id":"bottom_left", "x":-16, "y":-10 },
    { "id":"bottom_right", "x":9, "y":-10 },
  ],

  "components" : [
    {
      "id" : "surface", 
    
      "nodes" : [
       "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "bottom_left", "bottom_right",
      ],

      "edges" : [
        "s0", "s1", "s2", "s3", "s4", "s5", "s6", "border_left", "border_right", "border_bottom",
      ],

      "attachments" : [
        { "id":"fuel_pod", "edge":"s5", "fraction":0.5 },
        { "id":"turret", "edge":"s4", "fraction":0.5 },
        { "id":"pedestal", "edge":"s3", "fraction":0.5 },
        { "id":"reactor", "edge":"s1", "fraction":0.75 },
      ],
    },
  ],

  "entities" : [
    { "className":"K14ScriptableEntity", "subclassName":"Ship", "position":{"x":-3, "y":9} },
    { "className":"K14ScriptableEntity", "subclassName":"Pedestal", "attachment":"surface.pedestal" },
    { "className":"K14ScriptableEntity", "subclassName":"FuelPod", "attachment":"surface.fuel_pod" },
    { "className":"K14ScriptableEntity", "subclassName":"Reactor", "attachment":"surface.reactor" },
    { "className":"K14ScriptableEntity", "subclassName":"Turret", "attachment":"surface.turret" },
  ],
}

In the process of adding the planet definition classes I’ve changed around a few minor things that are not really worth describing in much detail here. The orb is now automatically placed on top of the pedestal, for example, and does not have to be added manually anymore. In terms of functionality and architectural changes though, it’s just the planet definition classes that have been added, the K14Planet initializers that interpret the K14PlanetDefinition, and the removal of all code that previously poked around the Lua planet class to setup initial planet state.

Next steps

I’m currently in the process of refactoring the interaction between game state and the renderer, which was starting to hold me back when trying to modify the renderer to allow rendering multiple planet components. The renderer depended too much on the internal in-memory representation of game and planet state (as encoded by the K14Game and K14Planet classes), and was (ab)using the snapshot classes used for freezing/unfreezing game state to represent render state, leading to code duplication and a murky separation of concerns. In other words, yet another gumption drain ;-). In the following post I will go into more detail on how the game will interact with the renderer in the future.

Development scoreboard

Since I’m still in the process of refactoring the renderer and snapshot classes, I won’t post a SLOC count this time, as the code is currently does not represent what I would consider a well-defined and stable functional state ;-). Development time for implementing and integrating the planet definition classes was about 10 hours, for a total of ~252 hours.