Jump to content
  • Advertisement
Sign in to follow this  
  • entries
    2
  • comment
    1
  • views
    594

Debug Tools: Calling Functions Directly From GameObjects

meistermayo

752 views

This is gonna be a heavy programming post.

TL;DR: I made a Unity debug tool that can call functions from MonoBehaviours directly!

 

 

On the edge of starting a new project, I stopped myself and thought about testing debug behaviors. I thought, "Gee, I sure don't like hooking up a bunch of random debug keys to update loops that I'll delete anyway. Wouldn't it be nice to have a debug system that you can type in a gameObject, component, and function name with arguments and just call it?"

Sounds simple... right? :))))))))))))

Well obviously not really.

The first step was to see what unity already had in terms of       N E A R   E F F O R T L E S S    F U N C T I O N     C A L L I N G   .

 

They have a couple options.

 

There's the MonoBehaviour Invoke. You just find a MonoBehaviour, and pass in a string what function you want. It takes in NO arguments, so it's not 100% ideal. 

monoBehaviour.Invoke("Foo", 0); // This calls "Foo()" with a 0 second delay

 

The next best thing is BroadcastMessage. We actually get an argument to pass in, but only one... and there's a second caveat -- If the gameObject has two of the same MonoBehaviour, or the same MonoBehaviour in its children, it will call this on ALL of them. Not ideal for testing!

monoBehaviour.BroadcastMessage("Foo", 1); // Gettin' there... This calls Foo(int i) and passes in one argument... BUT ONLY ONE

 

 

So, what else is there? Well, there is the System.Reflection namespace!

 

Reflection is a program's ability to observe itself at runtime. It's what Unity and Unreal Engine do to allow your classes' fields to be shown in the editor. 

We can use the API in this namespace to get information about our own classes, and call methods from them!

 

Here's what we need:

using System.Reflection; // Gives us the "Info" classes

MethodInfo method = monoBehaviour.GetType().GetMethod("Foo"); // Gets a "MethodInfo" from this mb's type with the name "Foo"

ParameterInfo[] ParameterInfos = method.GetParameters(); // Returns an array of "ParameterInfo"s -- this includes their types.

object[] parameters = new object[ParameterInfos.Length]; // We don't know *what* we'll be passing in yet, but we do know how many things we'll want.

// If we have parameters to pass in, we call this:
method.Invoke(monoBehaviour, parameters);

// It doesn't like being passed in an empty object array if there's no parameters, so in this case we use the standard invoke instead.
monoBehaviour.Invoke(method.Name, 0);

 

To implement this, I got a list of the Scene's MonoBehaviours, and for each one that had the GameObject's name, I searched for a matching component. Parameterizing was tricky -- for now I just stuck with intrinsic types. Passing in classes is going to be a whole other rabbit hole. Using this, I was able to create a debug tool that can call functions off of MonoBehaviours! Despite its current limitations to intrinsic types, I am very happy with it so far.

 

The Caller in action:

image.png.d667325575c92b4f28bdff0a228ece31.png

Calling from GameObject1:

image.png.e4c2912bc23f9459b9faa7e5296a045d.png

 

Testing again:

image.png.059436462d9a555194c272431d58c395.png

Calling from GameObject2 with parameters:

image.png.013f4594b190b7bb0f12c2ad20320d88.png

Next Steps:

  • Overloading Functions
    • This is a tricky one... You would have to get all of the methods with the name you are querying, and then be able to check if the string arguments you passed in can be cast to any of the possibilities... Its a much longer one.
  • Class Types
    • Not sure how to start with this one... Perhaps it could be easy to pass in a newly constructed object in the case of things like Vector3... but what about Transforms? They don't have a name and are attached to gameObjects. I would have to, ideally, parse the gameObject's name and its component... determining which component exactly that is ... that doesn't sound fun.
  • Parented Objects
    • My system currently looks for the first GameObject that contains the given MonoBehaviour, meaning child objects that share similar names are not distinct from each other. A solution would be to have the user type something like "ParentObject.ChildObject", recognize that there is a child to search for, and continue that way.
  • Private Functions
    • Soooo I know being able to access anything private kind of defeats the point of it being private ... but what if I could? Is it even possible? I don't know, I need to look more into it. What I do know is that this is a debugging tool that uses reflection so I would not feel so bad if it touches something private (probably not so nice words, however.)

 



0 Comments


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!