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 :
- 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.
- 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].
- Semi-Permanent : The room won't appear until X rooms were cleared, then it can appear. Its pseudo-model is [X;+∞[.
- 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
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.
Useful links
Mahara skin made by my teammate Paul Bichler.