puzzleCode
Tags: octograd2020, githubsdp
Published: 2020-05-22 19:40:26

## About

The objective of this project was to produce a teaching tool for young people. The motivation behind this was to offer young people an alternative method to be introduced to programming concepts while providing a different take on the traditional formula. puzzleCode was the developed solution: a Unity game that utilises abstract programming concepts to solve puzzles.

Initially, the plan was to write manual calls to OpenGL or use a lightweight tool like `PyGame` to assist the process. However, the decision was made to use a game engine that abstracted a lot of the complicated processing. Instead of spending days optimizing rendering performance, the time could be spent building sophisticated solutions for more higher-level challenges such as map handling.

## Tech stack

From a developer standpoint, the toolset involved was fairly basic. The project used the Unity Pro license that was provided with the [Github Student Developer Pack](https://education.github.com/pack). Scripts were written using Visual Studio Code while Blender was used for the creation of assets. PlantUML was also utilised to produce UML diagrams for the report that was written on the project.

![Rendered PlantUML of one of the built systems](https://media.githubusercontent.com/media/Appropriately/programming-tool/master/docs/figures/nodes/Nodes.png)

## Notable achievements

### Grammar-based rendering

Within Unity, groups of GameObjects are contained within a scene. Each scene is a separate instance that during runtime needs to be loaded using Unity’s SceneManager class. When a new scene is loaded, all previously existing objects are deleted unless flagged using some script. There is no standardized way of handling scenes; this is left to the developer’s discretion. In a traditional game implemented in Unity, individual levels are normally just scenes which are loaded when the player character meets a certain condition. However, this comes with numerous challenges. Given that some projects may leverage well over twenty scenes, making changes can be burdensome. A simple script tweak may become an hour-long job, as changes need to be made to each separate scene. Additionally, developing any testing becomes almost impossible. A custom grammar-based rendering system was designed and implemented to solve all of these problems.

Instead of creating a new scene for each puzzle, a single scene named 'Game' was created with a limited number of GameObjects. All level information is stored within a LevelManager script, containing several Dictionary variables indexable through the use of a unique id. A name, string representation of the map, and the blocks that can be used to solve it are all stored. The latter was essential, to ensure that new concepts could be slowly introduced to the player; new Nodes can be slowly introduced to the player as they progress through the levels. The string representation is a new line separated collections of characters, where each character represents a tile on the map. Am "X" signifies that the tile at this position should not be rendered while a 'traversable' tile is signified by an "O". Initialization can be expensive, so this is only performed when the game is first loaded. On the other hand, data retrieval is trivial (with O(1) complexity) as C# implements it as a hash table. When the 'Game' scene is loaded, the LevelManager stores the level’s id. The GameController will request the string representation of the current level’s map. To facilitate the parsing and rendering of the puzzle, an additional MapController script was created. The script is passed the string representation; it is validated, cleaned, and converted into a 2D char array. The GameController can then request the map to be rendered; which iterates over the 2D array, converting the char representation into a GameObject.

### Localisation

One of the key aspects of the project was the need to build everything custom. This resulted in some problems, as Unity did not provide any localisation support. External assets existed that could be imported to add this functionality, but they are either cumbersome or expensive. While developing a system for editing accessibility settings, a custom solution was prototyped that proved to be fairly simple to implement. This prototype used a
comma-separated value file (CSV) to store pairs of values in the format of `token;translation`.

## Links
 
> A `WebAssembly` demo of the project can be found [here](https://appropriately.github.io/programming-tool/).

{% github https://github.com/appropriately/programming-tool %}