Devlog4. Board Game Data Structure
Introduction
While developing the multiplayer board game Dice & Domination, I wanted each tile on the board to be fully data-driven. Instead of hardcoding tile properties, I decided to use an external CSV file to control names, colors, prices, rent, and other attributes. This made updates faster and allowed designers to edit data without touching code.
How I Read and Utilized a CSV File in Unity
Workflow Overview
Our team’s designer provided the initial data in an Excel spreadsheet. I cleaned up the formatting (e.g. removing inconsistent text and special characters), then exported it to CSV format. This CSV was then imported into Unity and parsed using a custom script.
CSV File Format
Each row in the file defines one tile and includes data:
Number, TileName, BuyingPrice, Rent, RentWithSet, SetSize, SellingPrice, Description, PowerUp, Effect, ...
File: TileSheet
System Structure
To support this workflow, I split the system into three main components:
-
TilesData.cs
A plain data class. Each CSV row is converted into a TilesData object containing static values like tile number, color, and rent. -
TileCSVReader.cs
A singleton responsible for loading the CSV at runtime using Resources.Load<TextAsset>(). It parses and stores all tile data in a global list. -
TileVisualizer.cs
Attached to each tile GameObject. This component uses its tile number to find the correct TilesData, then updates visuals and stores runtime states (like ownership).
Implementation
TilesData:

TileCSVReader:

The LoadCSV() function uses Resources.Load<TextAsset> to read the CSV file located in Resources/Form/TileSheetForm.csv.

After loading the raw text, the ParseCSV() method processes the file contents into usable objects. It first splits the text into individual lines while ignoring empty ones. Each line after the header row is then split into fields. A regular expression is used to handle splitting, ensuring that commas inside quotation marks are not treated as delimiters. For example, a description like "Roll again, then move 2 tiles" remains a single field. The parser then trims whitespace and quotation marks from each field.

Once split and cleaned, each row is mapped into a TilesData object. During this conversion, numerical fields such as price and rent are parsed using TryParseInt(), colors are interpreted through HexToColor(), and power-up types are processed via ParsePowerUp().
TileVisualizer:
When the game starts, it checks tile's assigned tileNumber and looks up matching data from TileCSVReader.Instance.
The Reset() method tries to detect the tile number automatically from the GameObject’s name. If the name contains a number, it parses it and assigns it to tileNumber.This helps speed up setup when many tiles are added into the scene at once.

Display of tile data after game starts(left) and route hierarchy (right)
In Start() method it checks if the tile’s material is already a unique instance. If not, it clones a new material. This is important because otherwise, all tiles would share the same material, and changing one tile’s color would accidentally change all others.
The main function UpdateTileVisual() handles loading the tile's data from the parsed tilesdata list. It first looks up the TilesData entry that matches the current tileNumber. Once the data is found, it sets the tile’s color by modifying its material color. Also, if the tile is owned by a player, it also displays a clan icon above the tile, using the player's assigned clan symbol from their Photon custom properties. If no owner is assigned, or if the owner has no clan icon set, the icon stays hidden.
The GetPlayerById() method searches through the Photon player list to find the player who owns a specific tile. It matches based on the player's ActorNumber, which is consistent across the network.
Gameplay Demonstration
Changing tile’s color according to its tile data
Place an ownership icon on the tile and synchronize it over the network
Icon visualization
Problems and Fixes
Problem | Solution |
Parsing errors due to commas in text fields | Switched from |
All tiles changed color together | Instantiated a new Material at runtime for each tile to prevent color overlap. |
Default tileNumber was 0 and caused warnings | Updated default to 1 and added a validation check during parsing. |
Design Patterns
- Singleton:The TileCSVReader uses a static Instance to ensure there is only one authoritative source of tile data across the game.
- Mediator: The TileVisualizer acts as a mediator between different subsystems: static tile data, rendering , and UI elements. It coordinates updates without these components needing to communicate directly with each other.
- Bridge Pattern:TileVisualizer acts as a bridge between static TilesData and rendering and UI systems.
- State Separation: Static data (price, rent, color, etc.) are stored in TilesData, while runtime data, such as ownership and ownership icon are handled by TileVisualizer.
Final Outcome
- All tile visuals and logic are driven by the external CSV file, which allows designers to tweak tiles without touching code. Also, the system is modular, scalable, and multiplayer-ready, with syncing possible through tile numbers and ownership state.
Reference
Gerenated ownership icon images. Source: ChatGPT
- OpenAI, 2025. ChatGPT . OpenAI. Available at: https://openai.com/chatgpt [Accessed 30 March 2025].
Dice & Domination
A high-stakes multiplayer strategy game with domination and combat
Status | In development |
Author | Angir |
Genre | Strategy |
Tags | 3D, Board Game, monopoly, Multiplayer, Top down shooter |
Languages | English |
More posts
- Devlog5. Turn Management1 day ago
- Devlog3. Dice Rolling and Board Movement4 days ago
- Devlog2. Programming Architecture29 days ago
- Devlog1. Game Design of Dice&Domination38 days ago
Leave a comment
Log in with itch.io to leave a comment.