Thursday, June 29, 2017

Reflection

hi all,

John Dewey, the famous educator and philosopher, once said that we don't learn from experience, but by reflecting on experience.


In programming, reflection, as I in my extremely limited way, understand it, refers to the ability of code to examine itself and report its findings, and to alter itself at runtime. There are a large number situations where you might want a program to be able to do this, but in my own case it comes from working on my never finished quest system. When I design a quest, I want to be able to set up what conditions and events the quest should pay attention to, how it should change when particular events are met, etc, like in this image from Wolcen Lords of Mayhem's blog post.

One of the ways you can do this, in my opinion one of the more sensible ones, is to use reflection to generate a list of classes or objects which might contain events or conditions you are interested in, then from that list generate lists of events in those classes or objects. Why not just hard-code it? Because hard-coding is EVIL! Really, though, what if you hard code your list of classes and realize that you left out one class? In a full game project, keeping (in your head) a 100% accurate list of classes that are relevant to the task at hand is impossible. Even in my incomplete project, which has almost zero gameplay, and includes a massive TWO characters and ONE item, contains more than 40 scripts. Most of those, of course, deal with the quest system and node editor, but sorting through the other classes by hand is a recipe for disaster.

Same goes for finding the events. If you try to hand code it, what if you make a spelling mistake for one of the events? You might not catch it and your compiler might not catch it until you're playing the game and you get a bug. So, here is some code that does just that. I create a dictionary using strings as the key and storing a list of strings as the value. The key is the class name, and the list of strings is the events found in that class.

Dictionary < string , List  < string  > > targetclasses;
Assembly assem = Assembly.GetExecutingAssembly();
   Type[] types = assem.GetTypes().Where(t => string.Equals(t.Namespace, "QuestSystem", StringComparison.Ordinal) && t.BaseType != typeof(MulticastDelegate) && t.BaseType != typeof(ScriptableObject)).ToArray();
   for (int i = 0; i < types.Length; i++)
   {
    FieldInfo[] fields = types[i].GetFields();
    EventInfo[] events = types[i].GetEvents();
    if (events.Count() > 0)
    {
     List temp = new List();
     for (int j = 0; j < events.Count(); j++)
     {
      //Debug.Log(events[j].Name);
      temp.Add(events[j].Name);
     }
     targetclasses.Add(types[i].Name, temp);
    }

   }

   }



After you select the class and event, the game system will serialize your choice as a string. When you start the system up again, it can deserialize these events (which are just stored as strings) and rehook them up to their appropriate targets using reflection again.

No comments:

Post a Comment