Unity: C# lookup tables

Can anyone explain how to do a lookup table in C#? I’m coming from excel world with vlookups (columns & rows) and am having a hard time replicating in Unity C#. (put this in Game Room b/c I’m doing amateur game programming in Unity)

For example, say I have a list of characters (column A) and a list of attributes (rows B-Z) with integers. If I want to lookup Character A’s Charisma in excel, it is trivial with a vlookup/match formula. (e.g. go down until you find Character A, then go over to the Charisma column and return the value)

How do I set up essentially the same operation in C#? I looked at arrays, but they seem just to be a single list. Dictionaries are slightly better with a key pair, but it’s only a single pair, whereas I need to have multiple attributes for each character.

All help welcome (even better if in plain English). Thanks!!!

I think you might be shoehorning excel into the problem by thinking of your character as a spread sheet instead of an object.

Your character should simply be an instance of Character with the relevant properties:



public class Character
{
    public string Name { get; set; }
    public int Charisma { get; set; }
    public int Strength { get; set; }
    ...

    public Character(string name)
	{
        this.Name = name;
	}
}



Then you instantiate your object:

Character Player1 = new Player1(“Kinthalis the awesome”);

And you get it’s properties like so:

int cha = Player1.Charisma;

Now, if you’re dealing with a collection of characters, you’d probably place them in a List<Character> (or maybe an array) like so:

List<Character> myCharacters = new List<Character>();

myCharacters.Add(Player1);

etc. you can then iterate on the collection or search that collection for a particular player.

Hastily written, so corrections:

It occurred to me that I didn’t answer your question :wink:

So, if you do need to reference data as you would in a spread sheet, there a few ways to do that.

A staggered array: characters[10][10]

A multidimensional array (matrix): characters[10,10]

A List of Lists: List< List<string> > matrix = new List< List<string> >();

Not sure if unity allows this, but you could also use a DataTable object: https://msdn.microsoft.com/en-us/library/6zd7cwzh(v=vs.110).aspx

EDIT: so I really hate the 5 minute edit limit… or I suck at using preview. One of those.
So maybe something like this:

string characters = new string
{
/// {name,strength,charisma}
new string {“player1”,“2”,“4”},
new string {“Player2”,“11”,“22”}

};

And you’d reference player one strength like so: characters[0][1];

Note that there is a powerful, in-use game engine paradigm that emulates a database or spreadsheet called an “Entity Component System.” (one example) Where different sets of properties are “components” which can be treated like (sometimes empty) columns in a spreadsheet. Unity is partially one already, but actually writing a full-on ECS on top of Unity is non-trivial.

If you just need a simple look-up, I’d use an array of structs:



public struct Character {
public String name;
public int strength;
public int intelligence;
public int wisdom;
}

//  In the class where you use the data, initialize the array:

Character[] characters = new Character[50];

// When you need to access an element, use this syntax:

characters[10].strength = 18;



Structs have less overhead than classes. And I prefer arrays over the c++ container classes like List because the container classes sometimes perform inefficient memory manipulations behind the scenes.

I’m pretty sure List is just a dynamic array, so you can probably avoid any dynamic allocations by allocating a large enough buffer. It does mean every time you add to the list it has to increase an internal counter, but the overhead is generally trivial.

At AAA, professional, or resource-constrained console or embedded game development levels where the programmers are experienced or resources are extremely scarce, it’s probably worth worrying about this. But beginner-level indie game dev in Unity is probably not the best place to explore these bottlenecks. At least not until significant profiling hints it’s an issue at least. At the beginner level there’s likely much lower hanging fruit than worrying about cache locality or dynamic heap allocations.

E: The struct vs class point is more fair, though. If you’re just storing data a struct is absolutely appropriate.

Hmmm, interesting. I need to take a look. Doesn’t sound very testable.

Yep, although I figured he might eventually have the need to add behaviour to his objects like Player1.jump() and he might possibly want to abstract behaviours out to parent classes or interfaces.

Yep.

It’s actually more testable, IMO (and from experience). It makes it relatively trivial to factor out a given component or system, or construct an object without any rendering in its loop or whatever. Theoretically all systems are independent, but in practice that’s obviously not true (the positions and orientations the physics component updates has to be read by the renderer at some point, after all), but it means that code one person touches is generally independent of code someone else touches, and you can test most components and systems in a vacuum devoid of other components. Nothing is stopping you from doing integration testing over multiple components, of course.

That all sounds fantastic actually. Bookmarked for afternoon reading :wink:

Ok, so as a beginner I just need to wipe the concept of having a table of data that gets referenced and think of objects that have classes/structures assigned to them with the relevant dataholders. And then using Lists and ForEach I can iterate over them.

I guess i was thinking more of loading the initial data as well. So instead of having to say

Player1.Strength = 10;
Player1.Charisma = 10;
Player2.Strength = 20;

Player20.Wisdom = 17;

I could just have a spreadsheet that has all players listed that loads to their initial states.

I know there are ways to load datasets from text files and I was extending it to try to load a table. (I know, I need to forget the concept of tables:))

Also, I **really **appreciate the thoughtful answers and you all putting up with my fairly rudimentary questions. I just find a lot of the Unity vids assume that you have a blank slate and can readily absorb the concepts of classes/structures/arrays (arrays kill me because I go straight to thinking of tables… and then dictionaries, hash-tables… all very confusing terminology for a spreadsheet guy):slight_smile: Thanks!!

Agreed. I’m an old-school C++ programmer, so I tend to keep my data structures lean and simple out of habit. But if he’s not resizing the List willy-nilly, it doesn’t make much difference.

Off the top of my head …

Each of those Players would indeed be instances of a player object. The basic way of doing this would be creating a GameObject and having a script assigned to it that holds all that info. That script would be a class definition.

If you’re going to have a lot of this, it would be better to define this as a prefab. This prefab would then be instantiated with the Instantiate() method.

If you need to keep a list of all object of a certain type, you should keep a list of references to them and add/remove as and when things are instantiated. This is best stored in a Handler class. Handlers are quite common, the are generally scripts attached to a GameObject that is not visible but it is always present in the scene. It can watch for events, update things etc.

The handler would be a bit like:



using UnityEngine;
using System.Collections;
public class PlayerHandler : MonoBehaviour {

public List<GameObject> players = new List<GameObject>();

void Start()
{
    players = new List<GameObject>();
}

public void createPlayer()
{
    GameObject player = Instantiate(playerPrefab) as GameObject;
    players.Add(player);
}

}


And then the player, as part of the prefab, a bit like:



using UnityEngine;
using System.Collections;

public class player : MonoBehaviour {

    public int charisma;

    void Awake()
    {
        charisma = 0; // Or whatever initial value
    }
}


You can then iterate through all the elements in the players list and access the public value of charisma.



foreach (GameObject player in players) {
    Debug.log("Charisma is " + player.charisma);
}


And then in the class for each player object (instance of the prefab) you can access the values defined in the class without having to specify the object.

I hope that helps. All coding done from memory as I am at work.

Oh and if you want to access the players list from a completely different object, you could store a reference to the Handler in your object when it is instantiated (you should only do this really at startup as searching is intensive) and do something like this.

This is a script that would be attached to another GameObject in your scene. It assumes that the PlayerHandler class is attached to a GameObject called “Scripts”.



using UnityEngine;
using System.Collections;

public class ClassAttachedToOtherObject : MonoBehaviour {

    private PlayerHandler playerHandler;

    void Start () 
    {
        playerHandler = GameObject.FindGameObjectWithTag("Scripts").GetComponent<PlayerHandler>();
    }

    public void logCharisma()
    {
        foreach (GameObject player in playerHandler.players) {
            Debug.log("Charisma is " + player.charisma);
        }
    }
}



I think. Try it!

Oh, I forgot. If using List I think you need to add this at the top of the script:



using System.Collections.Generic;


Be careful; while this works with an array of a struct, I don’t think it will work if characters is defined as a List.

Instead, to change characters[10].strength to 18, you have to do something like:



Character C = characters[10];
C.strength = 18;
character[0] = C;


Note that you can use characters[10].strength to read the value; you just can’t use it to change the value.