XENOPlanet

Summary

Xenoplanet is a game demo created to research procedurally generated worlds inside Unity. The player has the possibilities to explore an endless map to collect, craft, and fight enemy robots.  Chunks are created and saved outside of the render distance to give the illusion of an endless world.

View On GitHub

Procedural Generation

Xenoplanet’s world is procedurally generated at runtime, producing a unique and seemingly infinite world in each playthrough. Each chunk has three Perlin noise maps that affect how the chunk looks. A height map, which determines the height of the terrain, a moisture map which determines what kinds of plants grow, and a density map which determines how dense the plants are. Combining these three maps creates very unique outcomes that wouldn’t be possible with just one noise map. Only a certain amount of chunks are loaded around the player at any given time, with new chunks being generated ahead of the player and old ones being unloaded behind the player. These old chunks are not deleted, but rather set as inactive and stored in a C# dictionary, allowing for two important things. Firstly reloading these chunks takes a lot less time as the maps and foliage have already been generated. Secondly Any changes made to these chunks will persist when the chunks are re loaded.

Enemies and Combat Encounters

One of my main aesthetic goals when creating Xenoplanet was to create intense encounters that put the player on the edge of their seat. Many survival games accomplish this by putting the players hours of hard work on the line but that conflicted with our goal of creating a shorter term less grindy experience. In order to accomplish both these aesthetics I had to look towards the enemies and the dynamics of how the player interacts with them.

Awareness and Spawning

The second mechanic I implemented was enemy awareness. All enemies have a limited field of view and max view distance. However once the player is seen other enemies in the surrounding area are also alerted to the player’s position and more difficult enemies are spawned. Together these two mechanics forced the player into a more methodical and sneaky playstyle where one wrong move meant serious consequences.

Permadeath

Our first decision was to make the game permadeath. This immediately increased the stakes of every enemy encounter as all the players progress was put on the line. Even though the game only lasts 10 minutes dying to an enemy would put the player right back where they started

Movement

It was essential that the movement in Xenoplanet was physics based as opposed to animation based. This means the player is moved by manipulating and dampening velocity to prevent slipping. This allows better fine-tuning of movement from the inspector. There are also a series of checks that are run each frame to keep track of the player’s current state. This includes checking if the player is grounded, whether they are sprinting, crouching, or jumping, aiming, etc.

Ammo and Critical Hits

Finally we gave the player very limited ammo and added critical hit spots to the enemies. The player typically finds themselves with around 5 to 10 arrows in their inventory with a maximum of 20 (10 normal, 10 explosive). Without critical hits it takes around 3 to 6 arrows to kill an enemy depending on the type of arrow and enemy, around 60% of the arrows the player is typically holding. However by using critical hits the player can kill enemies in only 1 or 2 arrows greatly reducing the time to kill and the resources expended. These two mechanics combine in a way that allows precision to make or break a combat encounter. This inturn increases the pressure on the player to perform and increases the intensity of these encounters.

Modeling

All of the models in Xenoplanet were created using a combination of Blender 3D for modeling and animations, and Adobe Substance Painter for texturing. The process for generating models is quite long and cumbersome. First, I created a basic sketch of the model so that I can get an idea of the general shape as a reference. I then blocked out using basic geometry. I then add more geometry and start fine tuning the shape. For hard surface modeling, this is the whole process. For more complex models the workflow is a lot harder. I first add millions of polygons in order to sculpt the mesh with accuracy. After the sculpting was finished, I retopologized the entire model to reduce the geometry. If there is too much geometry, the game engine will not be able to handle the rendering. I then baked the high poly mesh into the normal map of the low poly mesh. This allows the lower poly mesh to be more detailed with being too expensive on the game engine. I also tried to practice modular models. This means each piece of the model can be used to create other models. Take a tank car for example, I can use the base of the tank with a different turrets to quickly create many variants of the same models

Animation

At this point I can finally start animating. This process involves adding bones to your entire model so you can manipulate them over time. After the bones have been placed, you can parent them to the model. I have to specify which bones influence which parts of the mesh in a process called weight painting. Weight painting is the worst part of generating models, since you have to go through each individual bone to determine what part of the mesh is manipulated by that bone. At this point you can start keyframing animations. For most of the models, I animated by hand which is an incredibly long process. So simplify this, I used Mixamo with Expy Kit (a free Blender add on) to get animations and retarget them to the bones on my model. This helped speed the process with the time crunch. I then reset the pose of the model and exported as a .fbx to prepare for texturing.

UV Editing

The next step is to UV unwrap the entire model. This involves marking and hiding seams of where the 3D model will be taken apart. If the seams are visible, the texture will clip when laid out. It is also important to minimize stretching, as the texture will stretch out to wrap the model. I learned that you want as few references to different UVs as possible, so I ensured that each model on had one UV map.

Texturing

I chose to use Adobe Substance Painter since it has a more artistic workflow compared to Blenders node based workflow. We wanted to have a hand painted style so Substance was the perfect choice. Since we were using a cel shader, having too much texture makes the model look weird with the simplified shadows. It is better to use basic blocks of color instead. I used minimal texturing as well techniques with generated and blurred noise which helped create a hand painted look. As mentioned before, it is important not to go overboard with this. I was able to use these techniques with every model to create a cohesive feel to the game. I used Substance’s smart materials to ensure that I could use the same base material for each model. This saves time since I could reuse the same base while fine tuning the settings on each model. I then exported as .png to use in the game engine.