Wednesday, April 17, 2019

Unity C#: Dictionaries

A dictionary is similar to a list but with a few advantages and a disadvantages, where the dictionary is not displayed in the editors inspector windows (although this can be overcome through Unity packages like the Odin Inspector or by writing your own custom inspector). A dictionary is a list of pairs, where each pair is made up of a key and a value. This is where the dictionary becomes faster than a list. In order to find a value within a list, you have to loop through all of the elements. However with a dictionary, you just give it the key that is associated with the value you want.

[System.Serializable]
public class Item()
{
string name;
ItemType itemType;
int itemId;
string itemDescription
}


public class TestClass : MonoBehaviour
{
// Defining a dictionary
private Dictionary<int, Item> itemDictionary = new Dictionary<int, Item>();

private void Start()
{
// Create new item
Item shield = new Item();
shield.name = "Shield";
shield.itemType = ItemType.Shield;
shield.itemId = 0;
shield.itemDescription = "Something to block attacks with";

// Add the first item to our dictionary
itemDictionary.Add(0, shield);

// Access the first item and display the name of the item in the console log
Debug.Log("First Item: " + itemDictionary[0].name);
}
}

Adding values to a dictionary is similar to a list but with one minor change, you have to provide a key with the value that you want to add. Accessing an value is also similar to a list but instead of using an index, you use the key associated with the value you want.

Looping Through A Dictionary

You can loop through a dictionary using a foreach loop, but there are three ways you can write that loop. The first being as a KeyValuePair, the second being just the keys and the third being just the values. Below are examples of all three loops.

[System.Serializable]
public class Item()
{
string name;
ItemType itemType;
int itemId;
string itemDescription
}


public class TestClass : MonoBehaviour
{
// Defining a dictionary
private Dictionary<int, Item> itemDictionary = new Dictionary<int, Item>();
private void Start()
{
// Create new item
Item shield = new Item();
shield.name = "Shield";
shield.itemType = ItemType.Shield;
shield.itemId = 0;
shield.itemDescription = "Something to block attacks with";
// Add the first item to our dictionary
itemDictionary.Add(0, shield);
// Create new item
Item sword = new Item();
sword.name = "Sword";
sword.itemType = ItemType.Sword;
sword.itemId = 1;
sword.itemDescription = "Something to attacks with";
// Add the second item to our dictionary
itemDictionary.Add(3, sword);
// Create new item
Item helmet = new Item();
helmet.name = "Helmet";
helmet.itemType = ItemType.Armour;
helmet.itemId = 2;
helmet.itemDescription = "Something to put on your head";
// Add the third item to our dictionary
itemDictionary.Add(6, helmet);
// Loop through dictionary using KeyValuePair
foreach(KeyValuePair<int, Item> entry in itemDictionary)
{
Debug.Log("Key: " + entry.key);
Debug.Log("Value: " + entry.value);
}
// Loop through dictionary using Key
foreach(int key in itemDictionary.keys)
{
Debug.Log("Key: " + key);
}
// Loop through dictionary using values
foreach(Item item in itemDictionary.values)
{
Debug.Log("Value: " + item.name);
}
}
}

Note that it is possible that all keys are not going to be sequential as demonstrated above. Also all keys should be unique, but there can be duplicate items. You can also check if a dictionary has a key by using the ContainsKey() function, this stops any exception errors due to missing keys.


Tuesday, April 16, 2019

Unity C#: Static Types

Like with most programming languages, C# has a static keyword that can be used on classes, variables and functions. By using the static keyword, that class, variable or function is available for the lifetime of the game. It's worth noting that if you create a static class, it cannot inherit from the MonoBehaviour class but also that all variables and functions must be static.

Static Members Verses Instance Members

Besides being a member that is available throughout the lifetime of a game, a static member is available to all instances of a class. Instance members on the other hand are different because they are specific to that instance of a class. For example, you have an enemy ship class, that class might have a health member. Generally this type of member would be an instance, as you would want each ship to have a unique amount of health. An example of a static member for an enemy ship class would be a shipCount, which keeps track of how many ships there currently are. With this you don't want each instance of the class to have a unique value for this member, so it would be static.

public class EnemyShip()
{
public EnemyShip()
{
shipCount++;
}
public int health;
public static int shipCount;
}


public class TestClass : MonoBehaviour
{
private void Start()
{
EnemyShip shipOne = new EnemyShip();
shipOne.health = 10;
EnemyShip shipTwo = new EnemyShip();
shipTwo.health = 5;
Debug.Log("Ship Count: " + EnemyShip.shipCount);
}
}

Static Constructor

A static constructor can be used to initialise any static members within a class. This constructor will only be called once unlike the constructors we usually use. It will also be called first before any of the instance constructors.

public class EnemyShip()
{
public EnemyShip()
{
shipCount++;
}
static EnemyShip()
{
shipGroup = "Atlas";
}
public int health;
public static int shipCount;
public static string shipGroup;
}


public class TestClass : MonoBehaviour
{
private void Start()
{
EnemyShip shipOne = new EnemyShip();
shipOne.health = 10;
EnemyShip shipTwo = new EnemyShip();
shipTwo.health = 5;
Debug.Log("Ship Count: " + EnemyShip.shipCount);
}
}

In this example the static constructor is used to set the ship's group to "Atlas", as this is static, all enemy ships will have the same ship group value and is done once before the instance constructors.