Unity Data Structures
Complete Detailed Guide
All 18 Topics with Full Explanations, Examples & Code
Easy English for Beginners
TOPIC 1: Why Data Structures Matter in Games
What is Data Structure?
A data structure is a way to organize information in a computer. Think of it like organizing your
room:
→ Books go on bookshelf
→ Clothes go in wardrobe
→ Toys go in toy box
Real Life Example:
Imagine you have 100 music CDs. If you throw them randomly in a box, finding your favorite song
takes forever - you must check each CD one by one. But if you organize them alphabetically by artist
name, you can find any CD quickly!
💡 Data structures work the same way - they help us find and use information quickly and efficiently.
Why Games Need Data Structures
Games manage many things at the same time:
1. Enemy Management
A game might have:
• 10 enemies on screen right now
• Different enemy types (goblins, orcs, dragons)
• Each enemy has: health, speed, damage, position
• Some enemies are alive, some are dead
Question: How do we store all this information? That's where data structures help!
2. Player Inventory
Player collects items during game:
• Sword (equipped)
• 3x Health Potions
• Shield
• Magic Ring
• 5x Gold Coins
Question: How do we track what player has? How do we add/remove items?
3. Game Settings
Every game has settings:
• Music Volume: 80%
• Sound Effects Volume: 60%
• Brightness: 70%
• Language: English
• Controls: Keyboard or Gamepad
Question: How do we store and quickly access these settings?
Benefits of Good Data Organization
✓ Speed: Game runs smoothly without lag
✓ Memory: Uses less RAM (Random Access Memory)
✓ Organization: Code is clean and easy to understand
✓ Flexibility: Easy to add new features
✓ Bug Prevention: Less chance of errors
Real Example: Subway Surfers Game
High Scores → LIST
List<int> topScores = new List<int>();
[Link](15000); // Player's first game
[Link](18000); // Player improved!
[Link](20000); // Even better!
// Can add unlimited scores
// Can sort to find highest score
Why List? Because player can play many times, and we don't know how many scores we'll store.
Coins Collected → ARRAY or INTEGER
int totalCoins = 0;
totalCoins = totalCoins + 1; // Collect one coin
totalCoins = totalCoins + 1; // Collect another
// Or track coins in current run
int[] coinsPerRun = new int[10]; // Last 10 runs
Why Array or Integer? Coin count is just a number. If we want to track history of last 10 runs, we
use fixed-size array.
Settings → DICTIONARY
Dictionary<string, float> settings = new Dictionary<string,
float>();
settings["MusicVolume"] = 0.8f; // 80%
settings["SFXVolume"] = 0.6f; // 60%
settings["Sensitivity"] = 0.5f; // 50%
// Easy to get any setting by name
float vol = settings["MusicVolume"];
Why Dictionary? We need to find settings by name ("MusicVolume") very quickly.
Achievements → HASHSET
HashSet<string> achievements = new HashSet<string>();
[Link]("FirstKill");
[Link]("Collect100Coins");
[Link]("FirstKill"); // Ignored! Already added
// Check if achievement unlocked
bool hasIt = [Link]("FirstKill"); // true
Why HashSet? Each achievement should be unlocked only once. HashSet automatically prevents
duplicates.
The Main Idea
Good Organization = Fast Game
Just like a clean, organized room makes finding things easy, good data structures make games run
smoothly!
Bad Organization = Slow Game
Just like a messy room makes finding things hard, bad data structures make games laggy and slow!
TOPIC 2: Arrays in Theory (Fixed Collections)
What Exactly is an Array?
An array is like a row of boxes, all connected together:
[Box 0][Box 1][Box 2][Box 3][Box 4]
Key characteristics:
→ Fixed size: If you create 5 boxes, you always have exactly 5 boxes
→ Same type: All boxes hold same type of data (all integers, or all strings, etc.)
→ Numbered: Each box has a number (index) starting from 0
→ Fast access: Can jump directly to any box using its number
→ Memory: Boxes are stored next to each other in computer memory
Real Life Analogy
Egg Carton:
An egg carton has 12 fixed spots for eggs. You cannot add a 13th spot, and you cannot remove a
spot. Each spot has a position (1st spot, 2nd spot, etc.).
• Spot 0 → First egg
• Spot 1 → Second egg
• Spot 2 → Third egg
• ... and so on
Arrays work exactly like this!
Creating Arrays in Unity C#
Method 1: Declare Size First
// Create array for 5 integer numbers
int[] scores = new int[5];
// All values start at 0:
// scores[0] = 0
// scores[1] = 0
// scores[2] = 0
// scores[3] = 0
// scores[4] = 0
Method 2: Create with Values
// Create array with values already inside
string[] enemyNames = new string[3];
enemyNames[0] = "Goblin";
enemyNames[1] = "Orc";
enemyNames[2] = "Dragon";
// Shorter way:
string[] enemyNames = { "Goblin", "Orc", "Dragon" };
Method 3: Unity Specific (GameObjects)
// Array of GameObjects
public GameObject[] enemyPrefabs;
// Array of Transforms
public Transform[] spawnPoints;
// These show in Unity Inspector!
// Drag and drop objects to fill them
Understanding Array Index (Very Important!)
⚠️WARNING: Arrays start counting from 0, NOT from 1! This is very important!
string[] fruits = { "Apple", "Banana", "Orange", "Mango" };
// Accessing items:
fruits[0] → "Apple" (First item)
fruits[1] → "Banana" (Second item)
fruits[2] → "Orange" (Third item)
fruits[3] → "Mango" (Fourth item)
fruits[4] → ERROR! (No 5th item, only 4 items!)
Why start from 0? In computer memory, index represents "how far from the start". First item is 0
steps away!
Array Operations (What You Can Do)
1. Access (Read) Values
int[] numbers = { 10, 20, 30, 40, 50 };
int first = numbers[0]; // first = 10
int third = numbers[2]; // third = 30
int last = numbers[4]; // last = 50
2. Change (Write) Values
int[] numbers = { 10, 20, 30, 40, 50 };
numbers[0] = 100; // Change first value to 100
numbers[2] = 300; // Change third value to 300
// Now array is: { 100, 20, 300, 40, 50 }
3. Get Array Length
string[] colors = { "Red", "Green", "Blue" };
int howMany = [Link]; // howMany = 3
// Use .Length to loop through array
for (int i = 0; i < [Link]; i++) {
[Link](colors[i]);
}
4. Loop Through Array
// Method 1: For loop with index
for (int i = 0; i < [Link]; i++) {
[Link]("Enemy " + i + ": " + enemyNames[i]);
}
// Method 2: Foreach loop (easier)
foreach (string name in enemyNames) {
[Link]("Enemy: " + name);
}
⚠️WARNING: You CANNOT add or remove items from array! Size is fixed!
// This will cause ERROR:
string[] items = new string[3];
items[0] = "Sword";
items[1] = "Shield";
items[2] = "Potion";
items[3] = "Helmet"; // ERROR! Only 3 spots, trying to use
4th!
When to Use Arrays - Perfect Situations
Situation 1: Enemy Types
// Game has exactly 5 enemy types, never changes
string[] enemyTypes = {
"Goblin",
"Orc",
"Troll",
"Dragon",
"Boss"
};
// Spawn random enemy
int random = [Link](0, [Link]);
string enemyToSpawn = enemyTypes[random];
Situation 2: Spawn Points
// Tower defense game has 8 fixed spawn points
public Transform[] enemySpawnPoints;
void SpawnEnemy() {
// Choose random spawn point
int index = [Link](0, [Link]);
Transform spawnPos = enemySpawnPoints[index];
// Spawn enemy at that position
Instantiate(enemyPrefab, [Link],
[Link]);
}
TOPIC 3: Use of Arrays in Enemy Waves, Levels
Now let's see how arrays are actually used in real games!
Example 1: Enemy Wave System
Many games spawn enemies in waves. Each wave has specific enemy types:
public class WaveSpawner : MonoBehaviour {
// Different enemy types in game
public GameObject[] enemyPrefabs;
// Wave 1: Spawn goblins
int[] wave1 = { 0, 0, 0 }; // 0 = goblin
// Wave 2: Mix of goblins and orcs
int[] wave2 = { 0, 0, 1, 1, 0 }; // 0=goblin, 1=orc
// Wave 3: All types
int[] wave3 = { 0, 1, 2, 1, 2, 0 }; // 0=goblin, 1=orc,
2=dragon
void SpawnWave(int[] wave) {
foreach (int enemyIndex in wave) {
GameObject enemy = enemyPrefabs[enemyIndex];
Instantiate(enemy, GetRandomPosition(),
[Link]);
yield return new WaitForSeconds(2f);
}
}
}
💡 This is perfect for arrays because wave patterns are designed beforehand and never change during
gameplay!
TOPIC 4: Lists in Theory (Dynamic Collections)
What is a List?
A List is a flexible collection that can grow or shrink:
→ List = flexible box that can change size
→ Like a bag: can add more items, can remove items
→ Size can change anytime during the game
Difference from Array
ARRAY:
- Fixed size (5 slots = always 5 slots)
- Cannot add more items
- Cannot remove items
LIST:
- Can start empty
- Can add unlimited items
- Can remove items anytime
- Size changes automatically
How to Create List
using [Link]; // Important! Add this at
top
// Create empty list
List<int> scores = new List<int>();
// Create list with starting items
List<string> fruits = new List<string>() { "Apple",
"Banana" };
Common List Operations
List<string> inventory = new List<string>();
// Add item
[Link]("Sword"); // Now has 1 item
[Link]("Shield"); // Now has 2 items
[Link]("Potion"); // Now has 3 items
// Remove item
[Link]("Shield"); // Now has 2 items
// Check how many items
int count = [Link]; // count = 2
// Get item by index
string firstItem = inventory[0]; // firstItem = "Sword"
// Check if item exists
bool hasSword = [Link]("Sword"); // true
// Clear all items
[Link](); // Now has 0 items
When to Use Lists
✓ Inventory system (add/remove items)
✓ Active enemies (spawn/die)
✓ Bullets (create/destroy)
✓ High scores (add new scores)
TOPIC 5: Practical Scenarios for Lists
Scenario 1: Inventory System
public class InventorySystem : MonoBehaviour {
public List<string> inventory = new List<string>();
public void PickUpItem(string itemName) {
[Link](itemName);
[Link]("Picked up: " + itemName);
[Link]("Total items: " + [Link]);
}
public void UseItem(string itemName) {
if ([Link](itemName)) {
[Link](itemName);
[Link]("Used: " + itemName);
}
}
public void ShowInventory() {
[Link]("Your inventory:");
for (int i = 0; i < [Link]; i++) {
[Link](i + ": " + inventory[i]);
}
}
}
Scenario 2: High Score System
public class ScoreManager : MonoBehaviour {
public List<int> highScores = new List<int>();
public void AddScore(int newScore) {
[Link](newScore);
// Sort from highest to lowest
[Link]();
[Link]();
// Keep only top 10
if ([Link] > 10) {
[Link](10);
}
}
public void DisplayTopScores() {
for (int i = 0; i < [Link]; i++) {
[Link]((i + 1) + ". " + highScores[i]);
}
}
}
Scenario 3: Enemy Tracking
public class EnemyAI : MonoBehaviour {
public List<Transform> playersInRange = new
List<Transform>();
void OnTriggerEnter(Collider other) {
if ([Link]("Player")) {
[Link]([Link]);
[Link]("Player detected!");
}
}
void OnTriggerExit(Collider other) {
if ([Link]("Player")) {
[Link]([Link]);
[Link]("Player escaped!");
}
}
}
TOPIC 6: Dictionaries - Key-Value Logic
What is Dictionary?
→ Dictionary = storage with NAME and VALUE pairs
→ Like phone book: NAME → PHONE NUMBER
→ Like real dictionary: WORD → MEANING
Structure
KEY → VALUE
"Ali" → 1500 points
"Sara" → 2300 points
"Ahmed" → 900 points
How to Create
using [Link];
Dictionary<string, int> playerScores = new Dictionary<string,
int>();
// Add items
[Link]("Ali", 1500);
[Link]("Sara", 2300);
// Or create with items:
Dictionary<string, int> scores = new Dictionary<string, int>()
{
{ "Ali", 1500 },
{ "Sara", 2300 }
};
Common Operations
Dictionary<string, int> scores = new Dictionary<string,
int>();
// Add or update value
scores["Ali"] = 1500; // Add
scores["Ali"] = 2000; // Update
// Get value by key
int aliScore = scores["Ali"];
// Check if key exists
if ([Link]("Ali")) {
[Link]("Ali's score: " + scores["Ali"]);
}
// Remove key-value pair
[Link]("Ali");
// Get count
int totalPlayers = [Link];
Why Dictionary is Fast
Finding value by key = VERY FAST (no searching one by one)
Computer uses "hashing" (special fast technique)
TOPIC 7: Examples of Dictionaries
Example 1: Game Settings
public class GameSettings : MonoBehaviour {
public Dictionary<string, float> settings = new
Dictionary<string, float>();
void Start() {
settings["MusicVolume"] = 0.8f;
settings["SFXVolume"] = 0.6f;
settings["Brightness"] = 0.7f;
}
public void ChangeSetting(string settingName, float value)
{
if ([Link](settingName)) {
settings[settingName] = value;
}
}
public float GetSetting(string settingName) {
if ([Link](settingName)) {
return settings[settingName];
}
return 0f;
}
}
Example 2: Localization (Languages)
public class LanguageManager : MonoBehaviour {
public Dictionary<string, string> english = new
Dictionary<string, string>();
public Dictionary<string, string> urdu = new
Dictionary<string, string>();
void Start() {
// Setup English
english["start"] = "Start Game";
english["exit"] = "Exit";
english["settings"] = "Settings";
// Setup Urdu
urdu["start"] = ";"کھیل شروع کریں
urdu["exit"] = ";"باہر نکلیں
urdu["settings"] = ";"ترتیبات
}
public string GetText(string key, string language) {
if (language == "English" && [Link](key))
{
return english[key];
} else if (language == "Urdu" &&
[Link](key)) {
return urdu[key];
}
return "TEXT NOT FOUND";
}
}
Example 3: Item Prices
Dictionary<string, int> shopItems = new Dictionary<string,
int>();
shopItems["Health Potion"] = 10;
shopItems["Mana Potion"] = 15;
shopItems["Sword"] = 50;
shopItems["Shield"] = 30;
// Get price
int swordPrice = shopItems["Sword"]; // 50
// Check if can afford
bool canAfford = playerGold >= shopItems["Sword"];
TOPIC 8: HashSets - Uniqueness in Collections
What is HashSet?
→ HashSet = collection with NO DUPLICATES
→ Automatically removes repeated items
→ Perfect for tracking unique things
How to Create
using [Link];
HashSet<string> achievements = new HashSet<string>();
// Add item
bool added = [Link]("First Kill"); // Returns true
added = [Link]("First Kill"); // Returns
false (duplicate!)
// Check if item exists
bool has = [Link]("First Kill"); // true
// Remove item
[Link]("First Kill");
// Get count
int total = [Link];
What Makes It Special
LIST allows duplicates:
List<string> list = new List<string>();
[Link]("Level1");
[Link]("Level1");
[Link]("Level1");
// Result: "Level1", "Level1", "Level1" (3 items)
HASHSET removes duplicates:
HashSet<string> set = new HashSet<string>();
[Link]("Level1");
[Link]("Level1");
[Link]("Level1");
// Result: "Level1" (only 1 item!)
Example: Achievement System
public class AchievementSystem : MonoBehaviour {
public HashSet<string> unlockedAchievements = new
HashSet<string>();
public void UnlockAchievement(string achievementName) {
bool isNew =
[Link](achievementName);
if (isNew) {
[Link]("Achievement unlocked: " +
achievementName);
ShowAchievementPopup(achievementName);
}
}
public bool IsAchievementUnlocked(string achievementName)
{
return [Link](achievementName);
}
}
TOPIC 9: Performance Considerations
What is Performance?
→ Performance = how fast your game runs
→ Good performance = smooth gameplay, high FPS
→ Bad performance = lag, stuttering, low FPS
Performance Comparison Table
Structure Speed Memory Best Use
Array Fastest ⭐⭐⭐⭐⭐ Low Fixed data
List Fast ⭐⭐⭐⭐ Medium Dynamic data
Dictionary Fast lookup ⭐⭐⭐⭐⭐ Medium Key-value pairs
HashSet Fast check ⭐⭐⭐⭐⭐ Medium Unique items
Detailed Comparison
1. ARRAY
Speed: ⭐⭐⭐⭐⭐ (Fastest)
Memory: ⭐⭐⭐⭐⭐ (Lowest)
Why Fast? Items stored together in memory, direct access by index
2. LIST
Speed: ⭐⭐⭐⭐ (Fast)
Memory: ⭐⭐⭐ (Medium)
Why Slower? Needs to manage size changes, uses extra memory for flexibility
3. DICTIONARY
Speed: ⭐⭐⭐⭐⭐ (Very fast for lookup)
Memory: ⭐⭐⭐ (Medium)
Why Fast? Uses hash codes to find items instantly
4. HASHSET
Speed: ⭐⭐⭐⭐⭐ (Fastest for checking existence)
Memory: ⭐⭐⭐ (Medium)
Why Fast? Also uses hash codes
💡 For 90% of games, all structures are fast enough! Only worry about performance if you have
thousands of items.
TOPIC 10: Choosing the Right Data Structure
Decision Guide (Simple Questions)
Question 1: Does the size EVER change?
→ No, always same size → Use ARRAY
→ Yes, changes → Go to Question 2
Question 2: Do you need to find things by NAME?
→ Yes, find by name → Use DICTIONARY
→ No, find by position → Go to Question 3
Question 3: Can there be duplicates?
→ No duplicates allowed → Use HASHSET
→ Duplicates are OK → Use LIST
Practical Examples
Example 1: Store Enemy Types
Problem: Store 5 enemy types (Goblin, Orc, Dragon, Zombie, Ghost)
Think: Size fixed? Yes, always 5 types
Answer: USE ARRAY
string[] enemyTypes = new string[5] {
"Goblin", "Orc", "Dragon", "Zombie", "Ghost"
};
Example 2: Player Inventory
Problem: Store items player collects
Think: Size fixed? No, can be 1 or 100 items
Answer: USE LIST
List<string> inventory = new List<string>();
[Link]("Sword");
[Link]("Potion");
Example 3: Weapon Damage Values
Problem: Store damage for each weapon type
Think: Need to find by name? Yes (weapon name → damage)
Answer: USE DICTIONARY
Dictionary<string, int> weaponDamage = new Dictionary<string,
int>();
weaponDamage["Sword"] = 50;
weaponDamage["Axe"] = 70;
Example 4: Unlocked Achievements
Problem: Track which achievements player has unlocked
Think: Duplicates? No, unlock only once
Answer: USE HASHSET
HashSet<string> achievements = new HashSet<string>();
[Link]("First Kill");
TOPIC 11: Custom Data Structures in Unity
What are Custom Structures?
Creating your own data types by combining multiple pieces of information
Example: Weapon Data
[[Link]]
public class WeaponData {
public string name;
public int damage;
public float range;
public float fireRate;
}
// Use it:
List<WeaponData> weapons = new List<WeaponData>();
Example: Enemy Data
[[Link]]
public class EnemyData {
public string enemyName;
public int health;
public int damage;
public float speed;
}
public class EnemyManager : MonoBehaviour {
public List<EnemyData> allEnemies = new List<EnemyData>();
}
TOPIC 12: ScriptableObjects as Data Holders
What is ScriptableObject?
→ Special Unity feature to store data
→ Exists outside of scenes
→ Can be reused everywhere
Why Use ScriptableObjects?
✓ Data stays even when scene changes
✓ Memory efficient
✓ Easy to edit in Inspector
Example
[CreateAssetMenu(menuName = "Game/Weapon")]
public class WeaponData : ScriptableObject {
public string weaponName;
public int damage;
public float range;
}
// Use in game:
public class Player : MonoBehaviour {
public WeaponData currentWeapon;
void Attack() {
int dmg = [Link];
}
}
TOPIC 13: Data-Driven Design in Game Development
What is Data-Driven Design?
→ Separating game data from game code
→ Data = easy to change
→ Code = harder to change
Benefits
✓ Easy to change values
✓ Designers can edit freely
✓ Less bugs
✓ Faster development
TOPIC 14: Game Logic Built on Structures
Scoreboard Example
List<int> scores = new List<int>();
Enemy Spawn Manager
Transform[] spawnPoints; // fixed
List<GameObject> activeEnemies; // dynamic
Quest Tracking
HashSet<string> completedQuests;
TOPIC 15: Memory Trade-offs in Data Management
Arrays:
Very efficient but inflexible
Lists:
Use more memory but easy to use
Dictionaries/HashSets:
Extra memory for speed
Main Idea: More speed = more memory, and vice versa
TOPIC 16: Efficiency and Optimization Theory
Good Developers:
✓ Avoid unnecessary data copying
✓ Choose appropriate collections
✓ Use caching when necessary
✓ Use pooling for repeated objects
Result: Optimized structures → smooth gameplay
TOPIC 17: Unity C# vs General CS Theory
Unity Adaptations:
• Arrays → transforms, objects, fixed waves
• Lists → dynamic runtime objects
• Dictionaries → settings, managers
• HashSets → unique gameplay objects
• ScriptableObjects → Unity-specific
TOPIC 18: Recap & Discussion
Remember:
→ Arrays = fixed groups
→ Lists = flexible groups
→ Dictionaries = key/value mapping
→ HashSets = unique items
→ ScriptableObjects = data containers
Use the optimal structure based on gameplay needs.
Efficient structures → fast, smooth games!
Happy Coding! 🎮