It’s easy to get lost when you’re a solo developer. Now and again it’s a good idea come up for air and try and think about what your goal is, or even your critical path, and ask your self questions like “Is this a game I would play?”.
I’d like to say my goal was to make the best space game out there, but that’s not realistic. Whilst I was looking into procedural generation of solar systems and planets I came across an intersesting debate. There were voices declaring that procedural generation of 18 billion stars in NoMansSky didn’t sound like fun, that the variation between systems would develop patterns and not be engaging enough. The fear is that computer generated content can be boring by the virtue that it will inevitably have constraints on the parameters involved, creativity and purpoe will be limited. We humans are incredibly good at feeling repetition, even if we can’t immediately see it. What’s the point in travelling across a few thousand planets if you feel that they all are roughly the same. Maybe that’s the inevitability of the universe. It probably is like that, but even more boring. Let’s not forget how excited scientists are to sample some dust or have the mere hint of water on Mars.
Players often want some kind of journey full of delight and surprises, others are quite happy being a nomad and living away from civilization to build their own game in their heads – but surely enough real content needs to exist for this to be more than a fleeting engagement.
Of course, procedural generation takes a huge load off a development team; not having to create every minute scrap of content, so it’s perfect for a solo developer (as long as it’s kept simple). In my search for the balance of fun and procedural generation I came across this great blog post by Kate Compton. I hope you appreciate the link – it took me an hour to re-find it from yesterday!
What am I making (the generator)?
- A star system generator, which can layout space stations, jump gates, hidden treasures, asteroid belts, resources, planets, nebulas, you name it. Ok – maybe that’s too much right now – let’s focus on just planets and nebulas.
What’s good/important about my star systems?
- If system is a solar system, it should contain a sun/star (solar gives it away?).
- Planets should move around elliptical orbits centred around the biggest mass. Those orbits do not have to be on the same plane, although most probably will.
- There may be one or two nebulas in the system with size constraints.
- Some planets have moons, which should also rotate.
- The background skybox
- The same solar system must exist and behave exactly as it did if we visit again (unless we add some catastrophic event).
What must not happen?
- Planets must not be too close to each other
- Objects must be limited in size.
- Planets shouldn’t all be the same size or texture.
- Moons should be smaller than the planets they circle, and must not collide.
Ok, that’s still a lot to think about – so the first mission is just to get the central star procedurally generated, and the skybox.
To start procedural generation, we need to have a deterministic algorithm based on a fixed set of values. We always want the same output for a specific input. This prevents us having to store lots of detail, configure scenes, test, you name it.
I imagine my starting star system is a box at coordinate 0,0,0.
Imagine there’s other boxes above (0,1,0), below (0,-1,0), left (-1,0,0), right (1,0,0), forward (0,0,1) and back (0,0,-1). This can be the key for all the detail we need in the universe. Of course, this doesn’t mean we can only move in 6 directions, there’s nothing stopping diagonal movement in the game. I may decide that some kind of routes are available through the universe, based on the availability of jump gates, and that we do not expose all of these boxes to the user. But i’ll leave that alone for now – see how easy it is to get lost in your own thoughts.
If I wanted to make the player’s universe more sparse at the edges or center, I could use those x,y,z values to influence the cap on numbers of planets, or other features.
e.g. if x,y,z fall in the range of 5 to -5, we are in ‘high security space’, where bandits do not appear, and as we leave that zone the percecntage chance increases. If we have a huge universe, then we might have a more complex algorithm that used sine waves, or use simplex noise to produce interesting waves of security, which then inform what type of ships, alliances, predators are present.
But for now, I’ll just use those universe coordinates to populate some data that I’ll use as a starting point for my skybox and solar system.
Here’s the code to generate a deterministic set of numbers from vector coordinates. This gives us 20 bytes (values 0..255). We can isolate individual bit patterns for simple on/off decisions, or use the modulus operator to select an item out of the array. If we wanted to we could combine four bytes to make a large 32 bit integer.
This algorithm only gives us 20 bytes, but what if we need more (we will). Simply add on some text to the base string and generate another hash. e.g.
planetData = baseData + “Planet”;
Then call ComputeHash() using planetData.
I think that’s enough blogging for now – I’m going to get my head down and bash out the nebula, orbits and planets and see what problems arise. Till next time.