C# - creating a list of classes
Context: In my game code I have a Room class which defines certain related functions and handles instantiation of Rooms. I have other classes which inherit Room and define more particular types such as RoomLong, RoomAttic, RoomBasement, etc... with Build() defined in a base Room class interface.
So I have this list of classes defining rooms and now I want to be able to do things like iterate through them and randomly select from them.
How can I work with a list of classes in C#?
More specifically (perhaps) how can I write a function which returns a reference to a random class?
Can it be collected somehow from the base class? A List() of all child classes? Since RoomLong, RoomAttic, etc... inherit Room is there a way to get a list of all "Rooms" from it?
To be clear I am talking about the class definitions not any instantiated object
Answer by UNDERHILL · Sep 08, 2016 at 06:46 PM
So after some more research I came to the conclusion that C# is a fully typed language and in Unity it has no virtuals. So all types must be cast and known before runtime.
Inheritance helps solve this problem in my structure however. Because all RoomTypes inherit Room I can cast any RoomType as Room without knowing the RoomType itself in advance.
public class NewInitialize : MonoBehaviour {
public string RoomTypeName = "RoomLong";
void Start()
{
GameObject myGameObject = new GameObject();
System.Type MyTypeFromString = System.Type.GetType(RoomTypeName);
myGameObject.AddComponent(MyTypeFromString);
Room myScript = (Room)myGameObject.GetComponent(RoomTypeName);
myScript.Build();
}
}
and if you want to use this with resources.load
GameObject newRoomPrefab = (GameObject)Instantiate(Resources.Load(RoomTypeName, typeof(GameObject))) as GameObject;
if you only want to access the PREFAB and not instantiate it use
GameObject newRoomPrefab = Resources.Load(RoomTypeName, typeof(GameObject)) as GameObject;
Answer by UmairEm · Sep 07, 2016 at 06:01 PM
@UNDERHILL Here is something you can do (IMO):
In one of your manager class:
List<Room> rooms = new List<Room>();
public Room GetRandomRoomFromList()
{
int index = Random.Range(0,rooms.Count-1);
return rooms(index);
}
Now you can check which class object is returned by doing this:
Room randomRoom = GetRandomRoomFromList();
if(randomRoom is RoomLong)
RoomLong roomLong = randomRoom as RoomLong;
similarly do it for other sub classes of rooms.
Hope it helps
So
List<Room> rooms = new List<Room>();
is a list of types/classes? Specifically, it is NOT a list of instantiated objects? In my case Room is a $$anonymous$$onoBehaviour.
Could I do this?
Room randomRoom = GetRandomRoomFromList();
someGameObject.AddComponent(randomRoom); //attaching the class as a script to the gameObject
or even
Room randomRoom = GetRandomRoomFromList(); //get a random type
Room someName = new randomRoom; //instantiate a new instance of whatever room was randomly chosen
testing doesn't seem to support that this is the case.
Answer by metalted · Sep 07, 2016 at 04:48 PM
You could make use of something called Polymorphism.
RoomLong, RoomAttic and RoomBasement are all a kind Of Room. Using polymorphism you could make a Room array to store all your rooms in.
Check out this tutorial to get you started: https://unity3d.com/learn/tutorials/topics/scripting/polymorphism
Answer by JedBeryll · Sep 07, 2016 at 04:39 PM
There are a few ways to do it. One would be to create an instance (kind of a blueprint) for all the child classes and you hold those in a List<Room>
. Second: hold them as types so create a List<Type>
that will be filled with stuff like typeof(RoomLong)
etc. If you go with this, you can create instances with Activator. Third way i can think of is you create a static method in the Rooms class (or anywhere really) with a switch for each child class you created.
If you don't want to manually create the list, you can use Reflection to find the classes you need.
Related link: http://stackoverflow.com/questions/5411694/get-all-inherited-classes-of-an-abstract-class
Answer by AurimasBlazulionis · Sep 07, 2016 at 04:51 PM
As far as I know you can store an instance of child class in a base class. As long as you do not serialize the instance of a class in that list to files or want to use specific function declared only in specific child class you will be fine.
So, just use List<Room>
and store the instances of any classes which derive from the base class, like RoomAttic
and use virtual
and override
for the methods you wish to call.
If you happen to need to use methods or values not available in the base class, you need to cast to the derived class first.