Norsevar

Level Generation

Tags: Collaborative Project, GD4, Level Generation, Norsevar, Red Axes

In Norsevar, you venture deeper and deeper into a forest cursed by the trickster God Loki. In order to reflect this curse and to make the game a proper roguelite, level generation has to be generated procedurally for every run.

I started with room generation, before scrapping the concept and moving on to level generation itself. Whilst developing this feature, I also ended up making it so the system supports a minimap system, but this feature was not implemented in-game.

Data structure

From a data structure perspective, a run in Norsevar is comparable to a tree. You always start in the same room (or root), and then have to progress to one of the following rooms (or children).

Therefore, it makes the most sense to define a run tree as a recursive type, using rooms as nodes. Here, a Room Node possesses six attributes and a property, as listed in Table 1.

Attribute name Type Description
Depth Integer How deep the node is (The root has a depth of 0)
Children Array of RoomNode The node's children (The rooms currently accessible to the player)
RoomType RoomType Information about the node's type (see Table 2 for the details)
Origin Vector3 Where the node is placed
_childrenCount Integer How many children the node has
_siblingIndex Integer The node's place compared to its siblings
Property name Type Value Description
MAXCHILDREN Integer 3 How many children a node can have at most
Table 1: Attributes and property of RoomNode
Attribute name Type
roomName string
sprite Sprite
identifier int
persistence Persistence
weightInformation WeightInformation
Table 2: Attributes of RoomType

It was decided that, during a run, some room types wouldn't appear until X rooms were cleared beforehand. Therefore, the notion of persistence was introduced. There are four levels of persistence, each with its own "pseudo-model" akin to 2D geometry :

  1. Starting Room : The room serves as the root of the run tree. It cannot appear later. Its pseudo-model is (0), as it is the starting point.
  2. Segment : The room won't appear until X rooms were cleared, can appear for the next N rooms, but won't appear again afterwards. Its pseudo-model is [X;X+N].
  3. Semi-Permanent : The room won't appear until X rooms were cleared, then it can appear. Its pseudo-model is [X;+[.
  4. Permanent : The room can appear from the start and won't disappear. Its pseudo-model is ]0;+[.

Weight information

Not all room types are created equally. A boss fight shouldn't have the same odds of occurring as a regular fighting room. Therefore, we are using weighted probabilities to influence the odds of some types. However, there was also the need for some weights to evolve over time (e.g. a boss fight starting with a low probability of happening, becoming more and more likely to appear until it actually happens before returning to its original low probability).

To account for this, I implemented a system to define the weight information of a room type designed to support various weight functions. There are currently three functions, but it would be easy to add more.

Weight function Mathematical representation Parameters
Constant weight f(x) = W W is the weight
Linear growth f(x) = gx + W g is the growth factor
Linear growth with presence reset f(x) = ga + W a is the number of rooms since this type last appeared
Table 3: Weight functions currently implemented

Example : Weight evolution

Details

Abandoned idea : Run minimap

When I implemented the level generation, I added a visualization system which displayed the type of the room the player is currently in and the ones they can move to afterwards. This was a few tweaks away from being a working run minimap, which could have shown the player what rooms they had already cleared.

This feature was abandoned as it was not deemed interesting for Norsevar.

Abandoned part : Room generation

The first thing I worked on was room generation, in order to procedurally build every level of the run. It would have made use of evolutionary computation. I linked below the four papers on this subject I was using.

This part was abandoned because pre-built levels were preferred.