Sol Trader is a science fiction game with a procedurally generated society and history you can befriend, understand and manipulate.

"If you don’t want to play Sol Trader... I’m afraid we can’t be friends anymore. That’s just the way it is."
Rock Paper Shotgun

"Incredibly in-depth."
Indie Gamers UK



Sol Trader will be at EGX in September!

Wed 22 July 2015 07:00

EGX logo

Now that it’s almost reached the playable demo stage, I’ve been wanting an opportunity to show Sol Trader off in person. So we will be taking the game to EGX 2015 with our own booth!

My friend Richard Patching and I will be in the Rezzed area of the show - there will be plenty of opportunity to ask us questions and see the game in action. We’re also hoping that the man responsible for the amazing artwork, Aamar Rana, will also be there for a day.

If you’re from the press or a publisher and want to make an appointment for a demo or interview at the show, I’ll be available Thursday to Saturday morning. Send me an email to book a time.

Latest development plan

After finishing the new GUI and the city mode interface last week, the next major thing to do is to revamp the space mode again. We now have a continuous space model: it’s now possible to fly from one end of the Solar System to another, but it’ll just take a (very) long time…

This week, I’ve been adding jump gates back in to allow faster travel to and landing on the different planets, and I’m in the middle of adding particles back in. After that we’ll put back the AI ships, weapons and trading systems. Finally I’ll be balancing the interaction between characters, and adding simple missions.

By the time EGX comes around, we should have a playable demo and a new Kickstarter campaign running to to raise funds for a marketing push. Spending correctly on marketing is essential for any indie game, especially if not from an already known publisher. I’d like to raise enough money to budget for that, and to give everyone an opportunity to buy the game at an early bird price.

The final release will be early next year, once I’ve added the final features. It’s all coming together and it’s very exciting! Follow us on social media or join our mailing list on the website to keep up to date.

Click here to comment



3 new screenshots of Sol Trader's new interface

Sat 18 July 2015 12:55

I’ve just released three new screenshots showing off the new GUI and space mode. Enjoy!

Looks like our in-game wife might have… other interests:

Flattery will get you… Protective Shoes?

Taking the Protective Shoes out for a spin.

Click here to comment



Trailer: How it will feel to move around Sol Trader's cities

Fri 17 July 2015 16:16

Over the last three weeks, I completely removed all traces of our old GUI code and wrote a fresh GUI from scratch. I also entirely reskinned the GUI to the final look and feel of the game.

It’s been a huge amount of hard work, but I’m very proud of the result. I’ll talk more about the reasons for replacing the GUI soon, but in the meantime, here’s a gameplay trailer showing a short section of the new GUI in action!

In between travelling through space you’ll be spending some time hanging out in cities, hiring ships, taking loans and interacting with the citizens who live there. The trailer shows you playing a character called Harry with a wife and family, who heads to the bank to take a loan. What do you think?


Click here to comment



How Sol Trader uses information as currency

Wed 24 June 2015 06:29

Screenshot showing you gaining information

There are two currencies in Sol Trader: Credits, which are used to purchase ships and goods, and Information, in the form of knowledge about events. Read on about I’m using information to enhance the gameplay.

Gaining information

When you start the game, you know about all the event that have happened to you, and many things that have happened to your close family and friends. The rest of the world, however, is a mystery.

As you chat to other characters in the game, they tell you about events in their past. You can continue the conversation by talking about something else that happened to you, exchanging one piece of knowledge for another. As long as you have similar information to share, they’ll keep about themselves and other people they know. If they tell you about an interaction they had with someone else, you get to learn about that relationship.

Some events are more private than others, and you’ll only get information about them if the character really trusts you, or they’ve had too much to drink…

Using information

This information can be “spent” in various ways:

  • A mission you’ve undertaken will often ask you to discover a particular piece of information in return for a reward.
  • You exchange information about sensitive events with other characters when chatting, in exchange for knowledge about more sensitive events.
  • Event knowledge could be sold to an in-game journalist for credits. This assumes the character is high status enough, or the event is notorious enough. This will really annoy the character that you’re exposing, though, so watch out! Any action in the game you take which has the effect of harming another character will generate a ‘backstab’ event, which can rebound back on you if you’re not careful.

Events have other effects, too. Beware of telling others about your sensitive events! If everyone gets to know about them, your ability to take work with organisations will become limited.

Most of this is already in the game. I hope to release a video or two in the coming weeks showing the gameplay in more detail.

Click here to comment



The difference review and planning makes to indie development

Wed 17 June 2015 07:53

List your accomplishments. Make a realistic plan. Get enough sleep.

I’m currently in a pretty good groove working on Sol Trader’s development. Due to other work commitments I can only manage 2-3 days a week on it at the moment, but my productivity is pretty much at an all time high.

One of the things that’s helped me is reading a great article on how to motivate ourselves as indie game developers. One of the most helpful tips was to keep a list of all our accomplishments week by week, and to plan the week ahead. It sounds simple, but it’s already made a big difference to my work. Here’s how I do it.

List accomplishments from last week

On Monday morning I record a list of what I’ve done using Notes on my Mac. I trawl through todo list items, Github commits and my marketing plan. Here’s Sol Trader’s from last week:

## Time last week

1 full day plus 4 evenings

## Last week - code:

* Switched the renderer coordinate system around
* Added planet rendering
* Refactored rendering out of platform into game code
* Added normal maps and sun angle
* Show the correct planet on the background
* Fill essential vacancies
* Started work on entity sheet pane - loads of refactoring on it
* Refactored all relationships to separate component
* Custom rendering of ship images on GUI
* Auto-reload shaders on Cmd-R
* Tweaked the bloom code loads
* Introduced higher resolution planets
* Moved premultiply of alpha out to script on game start
* Fixed last seen location for friends
* Started ship hiring components

## Last week - marketing:

* Live stream
* Montage: focus
* Weekly promotional thread on /r/indiegaming
* Blog post on bloom
* Facebook ad on new main menu screenshot

This was enormously motivating for me: despite only giving half a week to the game I got a huge amount of development done! It’s worth really celebrating this achievement.

Plan the upcoming week

I then work out how much time I have to work on the game next week. Then I make a realistic list on the goals I want to achieve in the week, with loose estimates, based on the amount of time I have. Here my list for this week - as I have about 3.5 days, I’ve given myself 2.5 days of goals for the week, plus a stretch goal.

## Time this week

3 days plus 1 evening

## Next week goals

[X] finish relational currency work: 0.5d
[ ] Banks and borrowing money: first pass - 1d
[ ] Ability to hire ships: first pass - 0.5d
[X] Marketing: livestream - 0.25d
[X] Marketing: Montage: quote on motivation
[X] Marketing: Weekly promotional thread on /r/indiegaming
[ ] Marketing: Blog post: how I plan my week - 0.25d
[ ] Marketing: Friday Newsletter with a roundup of latest work - 0.25d

## Stretch goal:

Launching a ship - basics of space back in - 1d

It’s very important to pace ourselves here. We should not plan more work that we can realistically do. If we easily achieved last week’s goals, then we should plan a little more: if we didn’t achieve them, then we should ask ourselves why and do a thorough review. Also, we need to make sure we get enough sleep. I definitely need 7-8 hours a day - otherwise when I work on my game I end up subtracting value rather than adding it, and short-changing my family and other commitments.

This week, I’m already ahead of myself. I’ve almost finished adding in banks and borrowing money (the final thing I need to add is handling a loan default, which I’ll do this morning) and I should get ship hiring in today as well. The quote on motivation was popular on Facebook, which is encouraging, and the live stream went well. That leaves most of a day to get the newsletter and the ship launching code back in, which is my stretch goal.

Summary

Sometimes indie development can feel rather like moving the game from 46.001% to 46.002% completed each day. Without a clear measurement of progress, it can be a real struggle. I’ve found this process of review and planning enormously helpful. What methods do you use in order to stay motivated?

Click here to comment



How to quickly add bloom to your game engine

Wed 10 June 2015 17:30

I rewrote Sol Trader’s bloom code last week. I originally added bloom over three years ago, and now I’m refreshing of the internals of the game, it was time to take a fresh look at it.

bloom before and after

Sol Trader's new main menu, before and after bloom was reapplied

The last time that I added bloom to the engine, I had complex and clever code all over the place in order to make bloom optional. This time I’ve simplified it by turning bloom on for everyone. It makes the game look so much better, and these days the chances are small that people cannot run with it turned on.

This is how I did it, along with some example screenshots and some OpenGL sample code.

Step 1: render the source images

First, we render the original image to a temporary buffer. At the same time, we render any glowing parts of the image to a glow buffer.

bloom step 1

Left is the original texture. Right is the glow buffer

This is how we set up OpenGL to draw into two buffers:

cpGenFramebuffers(1, &fb);
cpBindFramebuffer(CP_FRAMEBUFFER, fb);
GLenum fboBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2, fboBuffers);
cpFramebufferTexture2D(CP_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mainBuffer, 0);
cpFramebufferTexture2D(CP_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glowBuffer, 0);

(The ‘cp’ prefixes are my backwards compatible wrappers for OpenGL functions - see the section below on backwards compatibility.

Once we’ve set this up, we refer to gl_FragData[0] and gl_FragData[1] in our fragment shaders. In this snippet from the GUI shader, I’m adding 9% of the GUI’s colour in to the glow buffer to give it a tiny bit of glow:

gl_FragData[0] = colour;
gl_FragData[1] = vec4(colour.rgb * 0.09, col.a);

Step 2: Copy the glow buffer to several smaller buffers

bloom step 2

All we’re doing here is drawing the glow buffer to several other textures:

// Select the VBs for the vertices and the UVs
glBindBuffer(GL_ARRAY_BUFFER, fullscreenVertsVB);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, bottomLeftUvsVB);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);

glUseProgram(copyProgram);
glUniformMatrix4fv(matrix, 1, false, identityMatrix);
glActiveTexture(GL_TEXTURE0);
glUniform1i(texture, 0);
// Draw from the glow buffer
glBindTexture(GL_TEXTURE_2D, glowBuffer);

// Draw to the half texture
glViewport(0, 0, width / 2, height / 2);
cpFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, halfBuffer, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

// Draw to the quarter texture (repeat for even smaller buffers)
glViewport(0, 0, width / 4, height / 4);
cpFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, quarterBuffer, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

Step 3: Blur the glow buffer and smaller buffers

bloom step 3

This is the clever bit. We use an optimised Gaussian filter process on each of the glow textures. To make it fast, we blur in two passes: horizontally to a temporary buffer, and then vertically back to the previous buffer. We also take advantage of linear texture filtering to sample between the pixels to get both colour values.

This speeds up the process massively for the GPU - it brings the number of texture lookups down from 25 to just six. See Philip Rideout’s excellent article for further explanation.

The OpenGL code is similar to the previous step:

glUseProgram(blurProgram);
glUniformMatrix4fv(matrix, 1, false, identityMatrix);
glActiveTexture(GL_TEXTURE0);
glUniform1i(texture, 0);

// Vertices and UVs are already set up from the copy step above

glViewport(0, 0, width / 2, height / 2);
glBindTexture(GL_TEXTURE_2D, halfBuffer);
glUniform2f(offset, 1.2 / width, 0);
cpFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, halfBufferBlur, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

glBindTexture(GL_TEXTURE_2D, halfBufferBlur);
glUniform2f(offset, 0, 1.2 / height);
cpFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, halfBuffer, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

Here’s the fragment shader that does the actual blur:

void main() {
  vec4 c = vec4(0);
  c += 5.0 * texture2D(texture, uv - offset);
  c += 6.0 * texture2D(texture, uv);
  c += 5.0 * texture2D(texture, uv + offset);
  gl_FragColor = c / 16.0;
}

Step 4: Combine these smaller buffers together into the result.

I’ve overdone the bloom effect on this scene so we can see the effect it has:

bloom step 4

The OpenGL code simply sets up a new shader and selects all of the textures. The fragment shader then combines them all together:

void main() {
  vec4 vOriginal = texture2D(uTextureOriginal, uv);
  vec4 vT1 = texture2D(uTexture1, uv);
  vec4 vT2 = texture2D(uTexture2, uv);
  vec4 vT3 = texture2D(uTexture3, uv);
  vec4 vT4 = texture2D(uTexture4, uv);
  gl_FragColor = clamp(vOriginal + vT1 + vT2 + vT3 + vT4, 0.0, 1.0);
}

Making this backwards compatible

Rendering to a texture didn’t become standard in OpenGL until version 3.0 was released in 2008. Thankfully the extension has been around since about 2005, so most if not all drivers do support it in some way. I used glew and a series of macros like this one to choose between either the extension or the standardised version:

#define cpGenFramebuffers(a, b) \
  ((GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object) ? \
   glGenFramebuffers((a), (b)) : \
   glGenFramebuffersEXT((a), (b)))

Now I can use call cpGenFramebuffers and have it call the right thing for any graphics driver.

Summary

The end result looks just great, and really makes our games come alive and look that much more professional. Thanks to the rewrite, I’m able to render much brighter bloom than with my previous code. It’s important not to overuse this effect (there’s already way too much lens flare out there) but it’s amazing just how much a even a little bit of bloom lifts a scene.

Take a couple of hours and put bloom into your game engine. You’ll be glad you did.

Click here to comment



The huge difference a good Entity System could make to your game

Wed 03 June 2015 10:17

Continuing a general theme of discussing the nuts and bolts of Sol Trader’s design, this post is about the huge difference the recent decision to move to an decent Entity System with components has made to the flexibility of the underlying engine.

In case you’re not familiar with Entity Systems, I’ll summarize briefly why they’re important and how they work.

The problem

Most games have multiple things in them that work in similar but varying ways, such as players, bullets, walls, trees, weapons, and so on. The Entity abstraction is a useful one to encode this – all things in the game share basic properties (such as position), but have special behaviour in certain circumstances.

Here’s how Entity systems have often been approached in the past:

class Entity {
  int x, y;
};

class Player : public Entity {
...
};

class Monster : public Entity {
...
};

We have general shared behaviour across all entities stored in the Entity superclass, and special case behaviour in the classes underneath it.

After a while, we come up against two different entities that need to have the same behaviour. To solve this, we might attempt to insert a class in the middle of the hierarchy:

class Destroyable : public Entity {
  int health;
};

class Player : public Destroyable {
...
};

class Monster : public Destroyable {
...
};

However, this becomes quickly unworkable. Inheritance hierarchies are fairly rigid, and this increases with complexity. It’s not easy or desirable to specify in advance all of the different behaviours that our entity might want to have. If for example we wanted to share two different types of behaviour between two other entities, then we might be stuck at that point.

In theory you could use multiple inheritance, but this is a bad idea. See the deadly diamond of death if you’re not familiar with why this could be a problem. Also these designs can rely on virtual functions to override behaviour, which are fundamentally slower to execute.

A solution using components

A way around this problem is to ditch the idea of inheritance entirely (I’d done this already by switching away from C++ at the beginning of the year) and instead break up all your entity behaviour into separate components, which are then associated with each other via an ID.

Here’s a great diagram of an entity system using components from Cowboy Programming:

Entity system diagram

In order to code this in C, we just have the following code to represent an entity:

struct GameState {
  uint32 nextEntity;
};

uint32 pushEntity(GameState* state) {
  return state->nextEntity++;
};

That’s it! An entity is denoted by a simple counter, and has no data attached to it. All the data lives in the components.

Here’s a snippet of the initialisation code from Sol Trader for Human and Ship:

// Human
uint32 humanId = pushhuman(state);
pushEventful(state->history, arena, humanId);
pushHistoricalFigure(state->history, arena, humanId);
pushNameable(state, humanId)->type = NAMEABLE_HUMAN;
pushEnterer(state, humanId);

// Ship
uint32 shipId = pushEntity(state);
pushNameable(state, shipId)->type = NAMEABLE_SHIP;
pushRenderable(state, arena, shipId);
pushEnterer(state, arena, shipId);

Here I’ve listed a few of the components in Sol Trader’s current system:

  • Eventful: Attach this component to entities which can have historical events (currently humans and organisations.)
  • HistoricalFigure: Attach for an entity with a human-like history. Only used for humans.
  • Nameable: Attach to entities with names. This component has different types depending on how it is being displayed. All Nameable entities can can be renamed by the player, allowing them to customise the names of lots of different things in the system. Used for humans, organisations, ships and homes.
  • Enterer: Attached if an entity is allowed inside an entity with the Enterable component.

It’s now trivial for several entities to share the same component, which hits on one key advantage: re-usability.

If you’re interested in more, then this blog post series does a pretty good job of explaining the above in more detail.

Why this is so important

The cost of development is a huge barrier to quickly prototype new ideas for our games. Anything we can do to bring this down allows us to try more ideas and get to ‘fun’ as quickly as we can. The longer it takes to build a new type of entity, the slower the prototyping of new ideas.

It’s so much easier to prototype with entity systems: you can much more easily reuse behaviour between components. Here are some advantages I’ve discovered in just the last two weeks:

  • Added Nameable to ships meant customisation for free. It’s really important to me that the players can rename lots of different things in the game. Previously I would have had to spend ages refactoring the naming code to make it usable across entities. By spending about 45 minutes implementing Nameable for ships, I got customisation for free.

  • Adding landed ships to the GUI took less than 20 minutes. I simply reused the Enterer component for ships, and because they were also Nameable they simply popped up on the GUI in the list of people. After straightening out a few assumptions in the GUI that all Enterer entities also had HistoricalFigure, the game was back up and running.

  • Adding homes for humans took about 2 hours. I wanted to try the idea of humans all having their own homes visible on the planet GUI. Up until now, this was implemented via a simple flag. Adding new entities for homes with a few components on game start caused them to pop up in the GUI immediately. Seeing the human homes on the GUI felt great - but if it hadn’t been so easy to add, I might not have attempted it. It also allowed me to delete a stack of special-case movement code. Wonderful.

  • Components save memory. Previously to create a human in history generation meant you had to store all the data the human could possibly need, even though many humans would die before the game began. With an entity system, I could only add the component I needed for generation, and add the rest of the components to humans that survived to the game start. This also speeds the generation up: the history generator now iterates through less data allowing more efficient use of the memory cache.

I can’t imagine building another game without a decent Entity System. It’s transformed my prototyping speed and is very extensible. There are a few disadvantages, but they pale in comparison to the benefits.

How do you organise your Entities? Do you use a similar system?

Click here to comment



How tone of voice works in Sol Trader's dialogue system

Wed 27 May 2015 10:45

Hot on the heels of the main dialogue system in Sol Trader, I’ve been working on adding tone of voice to the system. I think this will add a lot to the way that the dialogue system works. It will allow for some interesting and thematic interactions, like the one below:

tone of voice

Perhaps I should have chosen a better subject :) Read on for more about how it works.

How tone of voice works

Each tone of voice that can be used has two character attributes attached to it, which are opposed against the other. For example, if you attempt to flirt with someone, your “charm” (basic flirting ability) is pitched against their “wisdom” (how easily they can see through you.)

You select a tone of voice and a conversation subject. We then roll a dice for each person and add their relevant attribute. If your score is greatest, any test that is conducted on the selected conversation subject is that much easier to succeed on. For example, if you’re trying to borrow a ship, or get a bargain, attempting to impress (or flirt with) the person you are speaking to might make the chance of getting what you want that much greater.

However if you fail the tone of voice test, it makes it much harder to succeed in what you’re trying to do. So you have to be careful which tones of voice you select. It pays to use tones for attributes that you are particularly strong in. It also pays to avoid tones where the person you’re talking has a high resistance, if you know them well enough to know what these are. For example, if your conversation partner has high wisdom, flirting with them is unlikely to lead to a successful outcome unless your charm is also very high.

Under the hood: how to mod it

The tone of voice data is completely customisable via a simple CSV file format. Here are some example tones:

String, you,   them,    effect success string,   effect failure string
   TONE_FLIRT, CHARM,  WISDOM, TONE_FLIRT_SUCCESS,      TONE_FLIRT_FAILURE
 TONE_IMPRESS, MIND,   CHARM,  TONE_IMPRESSIVE_SUCCESS, TONE_IMPRESSIVE_FAILURE
TONE_OBLIGING, WISDOM, MIND,   TONE_OBLIGING_SUCCESS,   TONE_OBLIGING_FAILURE

The idea is that people can mod both the different tones of voice that characters are able to use, but also the attributes that are checked when running the tests. It’s easy to add any tone you want: there’s a lively Facebook discussion on Indie Game Developers with lots of ideas for tones that could be added:

Can you think of any others we might add?

Click here to comment



How dialogue works in Sol Trader

Wed 13 May 2015 15:29

I’ve recently designed a dialogue system for Sol Trader. When deciding how to support dialogue, I researched all the different ways that these systems are normally done in video games: I wanted to ensure that our system is as flexible and as immersive as possible. I’ve gone for a hybrid of all the methods I discovered and I explain how it works at the bottom of the post.

Dialogue research

new conversation preview
A basic preview of the new dialogue interface

There are a number of different methods of doing conversations in games, summarised informatively in these two excellent Gamasutra articles. I’ve summarised the most relevant ones here:

  • Non branching dialogue. Players walk up to the character and they deliver their message, which is often the same each time.

  • Branching dialogue. The classic ‘conversation tree’ approach. A preset piece of dialogue is delivered and a player has an option to choose from a range of options in reply. This then delivers another response, and the process is repeated. This is better than the non-branching approach, but can lead to linear and frustrating conversations where the player feels they’ve missed out on a vital piece of information.

  • Hub-and-Spokes dialogue. This is similar to Branching Dialogue above, but in this version the player chooses from a range of options on a ‘hub’ of the conversation. After hearing the response, the player is normally returned back to the main hub, or sent to a deeper hub with more options to choose from. Players can therefore exhaust the conversation options with a particular character, which can lead to rather unreal conversations if the character has infinite patience.

  • Parser driven dialogue. The game attempts to understand the natural language typed in by the player and responds in turn. This is relatively rare in modern games, Façade being a notable exception. The number of responses required to keep the conversation feeling natural is very time consuming to produce, and the potential for the game to misunderstand the player’s intentions is very high.

  • Time limited dialogue. In this version a player only has a certain number of interactions they can conduct during any particular time period, and much choose who they spend time with and what they choose to find out. This creates some interesting and potentially agonising choices for the player, although with a fully scripted game the player won’t get to explore all the options available.

Under the hood: Sol Trader’s conversation system

Conversations are something that Sol Trader has to get right. I decided as far as possible that the gameplay should be based around the character interactions, so the player must enjoy the process and not get frustrated with it.

I have gone for a variation on the Hub-and-Spokes method: a rules based system for choosing options, the addition of tone of voice, and two time limiting factors: patience and time of day.

Patience

When you start a conversation with a character, they have a certain amount of patience for you. This is based on their Wisdom attribute (which is generally used for emotional intelligence and maturity). It’s also modified depending on what they’re doing: if they’re languishing in prison they’ll have a lot more time for you, but if they’re on guard duty they won’t be able to stand around talking all day. If you’re a good friend they will put up with you for longer, but if they can’t stand you, you’ll get hardly any time at all.

You ‘spend’ this patience with every conversation statement you choose. Some statements require a test which will affect how much patience the statement ended up taking. Once you’re out of patience, the conversation is over. Patience regenerates slowly: you won’t be able to immediately start a new conversation with someone if you’ve just finished talking their ear off.

Tone of voice

You’ll be able to select a particular way that you say something, allowing you to flirt, to be extra obliging, try to impress the character, and so on. This will affect both the amount of patience you use up, and any tests the selected conversation statement requires.

I’ll talk more about tone of voice and how it’s implemented in a future post.

Time of day

Character go to work in the morning, and go home or out socialising in the evening. The conversation options available to you will vary depending on what they’re doing, so you’ll have a limited amount of time to interact with them.

Example: a basic greeting

Two typical conversation statements might have the following data:

Required Character Activity: At reception
Minimum Closeness: Personal friend
What to say: "Hey $firstname! Such a pleasure to see you! Anything I can do for you?"
Required Character Activity: At reception
Minimum Closeness: Unknown
What to say: "Hello. How can I help?"

Each of these two statements is checked whenever either the player needs to choose an option, or the character needs to make a response. In this case, this is the initial greeting. If you are a personal friend of the character, they’ll greet you in a warm and friendly manner. If they don’t know who you are, they’ll be much more business-like.

(You can watch me implementing this basic set of statements on this livestream archive video.)

Example: making small talk

Here are a set of conversation statements for small talk:

Required Character Activity: Socialising
What to say: Make small talk
Attribute to test against: Charm
Difficulty: Normal
Patience cost: 1
Tag on test success: SMALL_TALK_SUCCESS
Tag on test failure: SMALL_TALK_FAILURE
Required Character Activity: Socialising
Required tag: SMALL_TALK_SUCCESS
Patience modifier: -1
What to say: You have a long discussion about sports with $firstname.
Required Character Activity: At front desk
Required tag: SMALL_TALK_SUCCESS
Patience modifier: 0
What to say: You chat briefly about the traffic jam outside on the street, agreeing that the local council should ban cars from the area.
Required Character Activity: Socialising
Required tag: SMALL_TALK_FAILURE
Patience modifier: +1
What to say: You attempt to engage $firstname on a discussion about weather vanes geometry with little success.

The player has the option to choose the first statement, which is making small talk. Note that the other options aren’t available as the SMALL_TALK_SUCCESS and SMALL_TALK_FAILURE tags aren’t set. If the player selects this option, then a test on your charm is conducted: if works then the SMALL_TALK_SUCCESS tag is set.

There are two statements that become available once that tag is set, and the choice will depend on whether you are socialising or chatting at a reception desk. If you’re at reception, the cost of the discussion remains 1 for the initial small talk statement, but if you were socialising, this response will give back your patience point to reuse on another statement. People have a tendency to rattle on when at the local bar!

What do you think? Can you think of anything this system doesn’t cover?

Next time I hope to have a short video showing off the basics of the system.

Click here to comment



How face generation works in Sol Trader

Wed 06 May 2015 09:52

We’re finally getting customised faces for characters in Sol Trader! Here’s a preview of some of the different faces that can be generated:

Face piece selection

There are created from individual face pieces that are overlaid together to produce the final result:

Face piece selection

Read on to find out how the code works under the hood.

Faces are completely moddable

Our face generation configuration file is found in face_pieces.csv. All the main data files in Sol Trader are now in CSV format to make modding super easy:

piece,gender,count,chance
male_base_face,MALE,1,100
male_nose,MALE,10,100
male_eyes,MALE,5,100
male_eyes_overlay_cyber_eye,MALE,1,5
male_hair,MALE,10,91
male_ear,MALE,5,100
male_mouth,MALE,1,100
male_scar,MALE,1,5
male_suit,MALE,1,100
male_t_shirt,MALE,1,0
male_beard,MALE,5,30
eyeware,MALE,2,5
female_base_face,FEMALE,1,100
...

Each piece has its own line, with the name of the piece, the gender it belongs to, the number of options for that piece, and the percentage chance the feature is present or not.

It’s pretty trivial to add your own extra options or entirely new face features! The only current restriction is that there must be less that 256 options for a face piece, and under 12 different face pieces in total, although I can increase these limits if modders need more room.

Faces are genetically inherited

Once thing that I really wanted to get right was generated characters looking similar to their parents. In the game the faces are stored for each individual as an array of numeric options, with each face only three bytes in total:

struct Face {
  uint8 pieces[12];
};

The game chooses a new character’s face in a similar way to the way it inherits other attributes from parents. When deciding on a face (when the character reaches the age of two), we go through every face piece in turn. 50% of the time the character will inherit that piece from the parent they most resemble, 25% of the time they will inherit that piece from the other parent, and 25% of the time the face piece is random, to simulate genetic mutation.

This process produces faces that resemble their parents, but aren’t exactly the same. There are currently 66,000 combinations of faces for each gender so you’re unlikely to come across two the same.

Still to do

We’ve currently only modelled Caucasian faces. We’re adding in other ethnicities soon.

Notice also that there aren’t any older faces: Sol Trader is set in the 24th century, but technology hasn’t sufficiently advanced to make 94 year old characters look like they’re in their late 20s! I like that way the Crusader Kings II does ageing with faces, where they visibly get older over time. The drawback is always artist time required to produce these, but we’re hopefully going for a simple overlay which could have the right effect.

What do you think?

Click here to comment



How I'm using Proxemics in Sol Trader's game design

Tue 28 April 2015 20:01
new relationships
Your relationships, shown closest first. Your relationship with your father has cooled lately...

I’ve been trying to get to the heart of Sol Trader’s gameplay in recent months. I’ve been working on rewriting the history generation system in pure C, and concentrating on the interactions between the player and the characters in the game.

This week I completely replaced all the relationships code to make it more manageable and more fun. Read on for a comparison of the old relationship system and the new one, and why the new code is better and more fun for the player.

The old system: numerical levels

Previously a relationship between two people consisted of a status field which described the type of relationship (parent, child, sibling, spouse, etc) and a numerical value from -10 to 15 which described the strength of the relationship. Negative values meant that the characters were enemies, and high positive values signified close friendships.

Each year the history simulation would go through the list of relationships for each character, do some tests on them and work out whether the level should drop or rise. If the level went through a threshold, the relationship might change (people married, divorced, fell out etc).

This worked well enough, but it had some problems. For one thing there was no limit on the number of people a character could befriend. High charm characters had hundreds of extremely close friends, which is hardly realistic. Also, the generation was slowing significantly as a few highly networked characters shared every last detail of their lives with all their friends and relations.

The new system: Proxemics for relationships

Personal space diagram

To counter this, I’ve moved to a simpler system based on the social psychology concept of Proxemics. Proxemics is the study of personal space between people: I’ve used the idea to limit the levels of relationships that each character can have. The idea is that each person is allowed a number of relationships at each of four levels:

  • Intimate: sharing highly personal information with 1-2 very close people
  • Personal: for 4-6 good friends
  • Social: another 5-10 friends and acquaintances who share more public information and gossip
  • Public: other acquaintances, co-workers and random people the character comes across

Each year during history generation, all these relationships are tested for each character and can move up and down the list. New people can be suddenly introduced at a high level: get a new boyfriend or girlfriend and the character’s older family relationships can be pushed down to a lower level, as there’s only room for a few people that close to us. When a type of relationship breaks into a new more intimate space, certain events can be trigged (marriage, for example.)

There’s a hard limit to the number of relationships a character can have in total. This means relationships which bubble downwards can vanish over time as the character loses touch with friends and distant relatives.

The benefits of the new system

There’s both a realism and a fun boost with the new code. It’s much easier for the player to manage and keep track of the number of people a character knows, so that they can use that network to their own advantage. It’s also feels more realistic: low charm characters have many fewer relationships, and even characters with high charm don’t have an overwhelming number. It’s great fun to scroll through a character’s known relationships and see who they’ve chosen to be close to.

The history generation is also faster now, as I’m storing fewer relationships and less information for each, which means more info is being fetched each cache miss (see this article for why this matters). Overall it’s a win for realism, fun, speed and code simplicity and I’m pretty happy with it so far.

Do you think this model works well for modelling relationships? Anything I can improve?

Click here to comment



Why I ditched all the build tools in favour of a simple script

Wed 22 April 2015 10:42

white elephant

Build tools are wonderful and impressive constructions. We developers invest colossal amounts of time, effort and code into their creation and maintenance.

Perhaps a lot of this work is unnecessary.

On Sol Trader, by ditching the complex dependency checking compilation system I was doing in favour of a simple homegrown script, I cut my build time from several minutes down to 5 seconds.

I’m not talking about continuous integration tools such as Jenkins, but tools such as CMake, Boost.Build and autotools. Perhaps these build tools are white elephants? They require endless maintenance and tinkering: does this outweigh their actual usefulness?

Incremental compilation: the end of the rainbow

One of the main aims of a compilation tool is to allow us to divide all the pieces of a system up into component parts to be built individually (another main aim is portability, which I’ll address below). This allows us to only build the part of the code which changed each time, and link all the compiled pieces together at the end.

However every time we build a source file, we have to grab a piece of code, grab all the dependencies of that code from disk. The disk is probably the slowest thing in our machines, and we have to grab everything from disk every time, for each source file we’re building. If we’re building a lot of files, this can get very slow.

The second problem with this is when we change an often-reused piece of code, such as a header file, we have to compile the whole lot again. In order to cut the amount of things to build down, we can set up complex dependency management systems to try to limit the amount of things built. We can also set up a precompiled header which tries to minimise disk access by building a lot of the code in advance for us, but more and more of our time is handling the side effects of pushing for an incremental build system.

Trying to get a build tool set up is like searching for a pot of gold at the end of a rainbow, which gets further away no matter how much effort we put into finding it. Even when it’s working, it’s not that fast, and it requires constant tinkering to get it right.

How I build code now: the Unity build

How about instead of building incrementally, we build everything every time? Sounds counter-intuitive, doesn’t it? It’s actually faster, easier to maintain, and doesn’t require setting up a complicated build tool.

We create one Unity.cpp file. This includes all the C files and headers that I wish to build. We build that one file each time, and then link it with the 3rd party libraries. Done. It takes about 3-4 seconds to run, or 10 seconds on the Jenkins server.

Now, when I change a header, the script just builds everything again, so it doesn’t take any long that a few seconds to see the effects of any change I want to make.

Caveats

“Strategy is about making choices, trade-offs; it’s about deliberately choosing to be different.”

– Michael Porter

There are a few caveats with Unity builds that we should be aware of:

One compilation unit means no code isolation

The static keyword will stop working as we expect: we won’t be able to constrain variables and methods to one file any longer. The power of good naming helps us out here. We also have to be disciplined about keeping our code modular and not referring to code that we shouldn’t.

We still need to discover platform-specific properties

On an open source project which must be built everywhere, we’re never going to get away with something as simple as this: we’re going to need to check to see what headers exist and which libraries are available.

However, there’s no reason we can’t set up make to do a simple unity build such as this one.

Also, many of these portability problems we patch over with our build tools stem from the fact that our code wasn’t correctly written to be portable in the first place. Also, many build systems still in wide use today have a lot of cruft left over from the 1980s - do we really still need to check for the presence of <stdlib.h>?

Additionally, in the case where we can control our build environment, it becomes even easier: we simply create a build script for each compilation platform we need to support (a build.bat for Windows, for example).

Sol Trader’s Unity build setup

This is my current build setup for Sol Trader in its entirety.

#!/usr/bin/env bash

MACOSX_DEPLOYMENT_TARGET=10.6
CC=clang++
EXE=sol
CFLAGS=" -DGLEW_STATIC -DSOL_SLOW -DCURL_STATICLIB -DNDEBUG -D_GNU_SOURCE=1 -D_THREAD_SAFE -g -O0 -I.. -I../src -I ../lib/include -I ../dist/build/include -I../dist/build/include/boost -O0 -I ../dist/build/include/freetype2 -I ../dist/build/osx/include -I ../dist/build/osx/include/SDL -Wall -Werror -Wno-unused-private-field -Wno-unused-variable -Wno-missing-braces -mmacosx-version-min=10.6 -F../dist/build/osx/frameworks"

LIBS="../dist/build/osx/lib/libSDL_mixer.a ../dist/build/osx/lib/libvorbis.a ../dist/build/osx/lib/libogg.a ../dist/build/osx/lib/libvorbisfile.a ../dist/build/osx/lib/libyaml-cpp.a ../dist/build/osx/lib/libRocketCore.a ../dist/build/osx/lib/libRocketControls.a ../dist/build/osx/lib/libRocketDebugger.a ../dist/build/osx/lib/libfreetype.a ../dist/build/osx/lib/libpng15.a ../dist/build/osx/lib/libboost_system-mt.a ../dist/build/osx/lib/libboost_filesystem-mt.a ../dist/build/osx/lib/libboost_thread-mt.a -l SDL_image -l SDLmain -l SDL -L ../dist/build/osx/lib ../lib/libcurl.a ../dist/build/osx/lib/libz.a -Wl,-framework,Cocoa -Wl,-framework,OpenGL -headerpad_max_install_names"

set -e
set -x

mkdir -p build
pushd build
$CC $CFLAGS -c ../src/Unity.cpp -o Unity.o 2>&1 | sed 's|../src|src|'
$CC $CFLAGS -o ../$EXE Unity.o ../src/main.cpp $LIBS 2>&1 | sed 's|../src|src|'
date
popd

This is working fine for me right now. It’ll need expanding on in the future, but instead of spending endless time screwing with my build system now, I’m actually adding game features instead.

Want to hear the other side of the debate? Here’s a well-argued opposing point of view: the evils of unity builds.

Click here to comment



How to choose between realism and fun in game design

Wed 15 April 2015 12:39

city-view-screenshot

I’ve been working on the city interaction screens this week on Sol Trader, shown above. I’ve been considering how to implement the ‘business as usual’ tasks that players complete on landing at a city, such as filling the fuel tank, repairing their ship, or buying and selling trade commodities.

Here’s the city market screen from the old prototype version of the game:

old market screen

I could bring this up to date and polish it for the current look of the game, but considering this has brought up an important gameplay question.

Do I make the interaction between the player and the organisations purely a GUI experience, or do I make the player interact with the employees of the organisation to achieve their goals?

For example, instead of clicking on a table view like the one above, players would head to the market, start a conversation with a broker, state what they wanted and get a price direct from them. Which is better?

For a number of reasons, I’ve chosen the less realistic ‘interaction with employees’ option for now. Here’s why.

Focusing on a compelling vision of fun

It’s easier for the player to buy goods from a tabular view like the one above, by just clicking on what they want. It’s efficient and fast. It also isn’t very realistic to make these interactions personal, especially for the 24th century. Much of our interaction with organisations is via an automated system these days, and I would hazard a guess that this is only going to increase as the years pass.

However, my game is all about relationships: the friendships that the player forges during both the pre-game history generation and whilst playing the game. When at cities, players are getting ships fixed, finding contract work and buying and selling goods. If I make this daily business solely done through interacting with in-game individuals, then the game won’t feel nearly as impersonal and cold. The game isn’t about making stacks of money or buying the biggest ship as fast as possible (although players could do that if they wanted) - it’s about the interactions with the individuals along the way.

I want to create a game where players will genuinely look forward to landing at a certain remote city to catch up with an old friend whilst upgrading their ships, or actively avoiding a certain hotel through a poor relationship with the manager. That sounds fun to me, and that’s what’s going to keep people coming back to the game. Having a compelling vision of what the fun looks like is essential to ensuring we stay on target with our design.

It might not be ‘realistic’ but fun is more important than realism every time. The only important type of realism in a game is a ‘sense of realism’. Players should be able to suspend disbelief long enough to immerse themselves in the world we’ve created.

The right decision isn’t always the easiest to implement

This decision causes some design headaches. If the only way to do business with an organisation is through an AI employee, this means a few things:

  • The conversation engine has to be top notch. I’m just about to start working on this and I’m doing my research first to find out the best way to make this work well.
  • What happens if a job is vacant? If no-one took a certain job though history generation, then potentially that organisation cannot be interacted with at all. The way I’m handling this is to have the concept of ‘essential jobs’. Certain jobs simply have to have someone doing them. Just after history generation we trawl through all the eligible characters in the game and match them to these jobs.

We’ve added more complexity to the code base, but some extra work is justified. It’s very easy to simply choose the option that’s easier (or cleaner) to code, but that’s how we end up with poor design and no fun.

Finding the fun is hard work

Once we have a decision, it’s important to implement our chosen solution as quickly as possible and then to play around with it, to see if it captures the fun that we’re looking for.

Fun in games is something that has to be worked for. It doesn’t appear without effort. Our raw materials are art assets, sound files and code: we grind them together searching for the fun in the midst of the three. The formula is elusive and uncertain, and it can take hours of effort, but eventually our game will catch light and burn bright, almost like magic.

It’s very important not to gold-plate game code too early. Jumping to ‘clean well-factored code’ too early is dangerous: it’s essential for maintenance, but overdoing refactoring too early is a failure to understand that we’re in the complex Cynefin space. We could well be throwing everything away. As long as we don’t neglect code cleanup once we’ve found what works, hammering in a basic solution minimises the potential of wasted effort.

Summary: beware realism

"The whole value of a game is in the mental model of itself it projects into the player’s mind."
-- Tynan Sylvester, The Simulation Dream


Beware realism. It sounds like the holy grail of game development, and it’s very enticing to us developers. Ultimately however it can pull us away from what’s fun to play.

An appearance of realism is what we’re actually looking for, and this can be a very different thing.

I’ll post an update when I’ve got this interaction into the game, to see whether it does indeed give us the fun we’re looking for. Stay tuned!

Click here to comment



How I doubled the speed of my game by giving up on C++

Wed 01 April 2015 11:49

C++ is fast. It’s a good fit for games. It’s certainly faster than Ruby. However, there’s a better fit for game development. It’s called C.

This isn’t an April Fool’s joke. Look at what happened to the Sol Trader history system when I ditched the slow C++ version and rewrote it in optimised C. The line count is also about 20% reduced.

C++ code can be fast, but the way C++ is commonly used and the language features that it promotes can get in the way of this goal. Here are a few things I’ve learnt about C++ that are essential for anyone to know who wants to write modern performant code.

Memory access is slow

In case you hadn’t realised: compared to your CPU, your memory is slow. Very slow. It’s probably the thing that’s most holding your CPU back right now.

Memory has been gradually increasing in speed over the last few decades, but at 10% of the rate of CPU speed:

memory vs. CPU speed incrase

Memory cache misses cause the CPU to stall, losing several hundred cycles each time it happens. Every year, cache misses become a more and more significant cause of CPU slowdown.

With the previous version of the history generation, using classic object oriented patterns, my data was all over the place. I had hundreds of little objects all encapsulating their own data, using virtual method calls to access tiny pieces of it.

I moved to arrays of values, storing references to other objects via indexes everywhere. I moved all the string processing right out of the generation engine, so that the engine was only dealing with small data structures of perhaps 20-30 bytes at a time.

Virtual function calls are slow

A virtual function is one that changes it’s behaviour depending on the type of the object. For example, if we use an interface in C++, we create an abstract class with some virtual functions attached to it. We then derive our class from this interface, passing pointers of the interface type around our program. When our program calls the interface function, the program is able to work out which method to call on the derived object, based on extra information that’s kept in our object.

So far, so good. Except virtual functions are slow for the same reason that the memory is slow. With virtual methods, the right method to call can only be decided at run time, and there’s normally one or two cache misses for these method calls. The compiler is constrained about what it can do to make this quicker. It might not seem like much, but it stacks up for inner loops.

Back in 2002, when I was working in the games industry, I lambasted the PS2 to my fellow AAA games developers for not even supporting virtual pointer tables, meaning that virtual functions were impossible. In deriding the platform I showed my ignorance about the speed trade offs that smarter people than me were making. It turns out that the constraints of the PS2’s architecture changed the face of games development for the better.

A few virtual calls aren’t going to massively slow down a codebase. However, my code was a mass of tiny virtual calls for trivial operations. Parts of my code were iterating over every entity in the game with at least three or four chained virtual function calls each time!

In the new version of the code, I cut out all the virtual methods completely, sticking to bare C++ method calls. I inlined a lot of these, leaving the game with fewer longer methods but without the need for the CPU to constantly be jumping around to figure out what to do.

Templates are slow (to build)

Templates were introduced to C++ in order to help make parts of the code generic with respect to type. For example, the supplied vector type in C++ is a template type, meaning that we can store multiple different types of objects in the same data structure. This allows us to seperate two concerns: the way the object is stored and how it works, which partitions complexity for our minds.

Templates reduce the number of lines of code in our programs. They are harder to understand when reading them later, but the bigger disadvantage is that they slow down build time. The compiler has to effectively copy all the code each time for each template and do a lot of processing in order to produce efficient executables out of them.

By cutting out all the templates from my code (including all uses of the C++ Standard Template Library), I’ve cut down the full build time of the entire game to about 4 seconds. With a debug loop as short as this, I barely have time to sip my tea before I’m testing the code I just wrote, and I can change headers without having to wait 10 minutes for a new build to compile.

Encapsulation can be unhelpful

Encapsultation is the packing of functions and data into one component. It is one of the fundamental concepts behing Object Oriented programming.

Much of encapsulation in C++ (and other OO languages) is promoted through the use of classes with private members to hide data from outside code.

Promoting encapsulation is held up as a pillar of good code design. However, I think we might be doing encapsulation wrong. I don’t think encapsulation should be at the class or method boundary, but at the data boundary.

Essentially I’m advocating a switch from this style of coding:

Traditional OO

To this style:

Data transformation

It’s important to get our architecture right. We encapsulate concepts in the correct sections of our program and ensure data flows well through the various pieces. If we use simple value objects (perhaps arrays of data) as the handoff between different sections of our program, calling methods that transform data between different types, then our code becomes more isolated and easier to reason about. It’s also far easier to parallelise.

Incorrect encapsulation is worse than no encapsulation at all. Hiding data behind code limits what the calling code can do. Those constraints can be helpful, but they can also hinder us. If we get the architecture right and use data structures to provide bounded contexts to our code, rather than layers of method abstraction, then we have less need to hide our data from others.

By rearchitecting my application to not require callbacks at all, I’ve made it simpler to test and debug. There’s less code reuse, but inevitably the concepts I thought were duplicated were actually subtly different. I’m also treating the data in batches, looping through arrays of small amounts of data rather than arrays of objects. Rather than one big loop bouncing up and down the layers of abstraction for each object (exacerbating the method call overhead, which is further increased if we are using virtual methods), I have multiple loops doing one small stage of data transformation each time.

There are no methods in classes: it’s all public structs and functions. I still have encapsulation, because each stage of data transformation is distinct from the others, but I’ve no need to hide my data behind code.

Summary

There are some bits of C++ I find useful. Operator overloading is helpful to clean up verbose code, for example. I still compile my ‘mostly C’ code using a modern C++ compiler.

It’s the paradigms that C++ promotes and supports through its language features that aren’t for me, and I’ve doubled the speed of my code as a result.

Click here to comment



4 things every space game must have

Wed 25 March 2015 10:39

4 things: exploration, knowledge gain, story, mastery

The process of designing Sol Trader has helped me to crystallise some of the essential components of any space game. Here are four I’ve discovered so far.

Space games must have: Exploration

The wild unknown is a powerful draw, and the vastness of space is the ultimate wilderness. Players love to explore new worlds, and they like to be the first to make any discovery.

The challenge in this genre specifically is that there’s an awful lot of emptiness in space. It’s no accident that most space game development teams release screenshots of massive asteroid fields, strange planets, or nebula, rather than shots of empty space. Screenshots of endless stars get rather samey after a while!

Keeping space interesting is challenging but essential to any space game. Hiding hidden bases, mineral caches wrecks within asteroid fields, or drifting wrecks in deep space will keep the interest high. Ensuring that players are able to share and explore the same worlds through the use of shared random seeds can also be a powerful way to allow players to race to certain discoveries.

Sol Trader will support many of these features to keep players exploring: seeded word generation, drifting wrecks and asteroid fields will all be in the game.

Space games must have: Knowledge gain

The lure of the unknown isn’t just spatial. Similar to the fascination with magic in the fantasy genre, players love to interact with and eventually conquer forces they don’t quite understand.

With space games, this need to gain knowledge is normally satisfied by giving players the opportunity to interact with advanced technology. For example, you might allow the upgrading of ships to carry the latest weapons, or the most powerful scanners to spot distant objects. In Sol Trader, I’m taking the technology route, but I’m also allowing players to navigate a vast network of interactive relationships via the generated history. As players gain friendships with powerful characters, they get access to unique missions and technology upgrades.

Space games must have: Story

Without a compelling tale to take part in, players will quickly lose interest. People love to be part of a story that’s bigger than themselves, and this is no less true in space games. When there’s no story built in, there must be enough malleability in the game to allow players to create their own story, perhaps with friends: Minecraft is the canonical example of this.

It’s important to show enough glimpses of the stories that can be told in your game, if you want anyone to be interested in it! With Sol Trader, I omitted this on the first Kickstarter video, and corrected it on the second after a lot of feedback.

Space games must have: Mastery

Ultimately players want to be able achieve their goals. Sometimes that’s to “win the game”, if it’s finite and limited, or perhaps they set their own goals. Either way, it needs to be challenging to achieve them, but not too challenging. Games that are too easy will fail to hold the player’s interest and quickly become boring. However, if games are too hard with no obvious route to proceed, players become frustrated and the fun seeps away.

I’m of the opinion that games should always err on the side of being too hard. We should never frustrate the player, but we should make it challenging to achieve what they want to achieve. This approach makes gaming more satisfying in the long run.

I’m a big fan of Roguelikes in this regard, as they don’t allow ‘checkpoint’ saves, ensuring that when a player dies, it’s permanent. This is also true in Sol Trader. When you’re dead, the game is over and you have to start again.

How do you ensure that this doesn’t become frustrating? By making it fun to start again and tell a new story. The Dwarf Fortress motto is “Losing is fun” - your fort might go down in flames (and plenty of mine have) but you’ve always had a blast along the way. With Sol Trader, there are always more characters to get to know, and more stories to discover and weave into your own.

What other elements must all space games have?

Click here to comment