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 Split(',') to a regular expression that supports quoted fields.

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 

Leave a comment

Log in with itch.io to leave a comment.