Jump to content

How do you figure out what you can do with a GameObject?


Recommended Posts

With a normal modern object oriented system, you can inspect the public members of a class to understand what it can do and how to access those capabilities (and if all else fails, you check the documentation). If new capabilities are needed on an existing object, new public members are added, and if the new capabilities that you need are not a good fit for any existing object, a new class can be created instead.

In Unity, as I understand it, the world is made up of GameObjects, each of which has Components to add capabilities. Consequently, many tasks in Unity boil down to finding the right GameObject, accessing the right Component of that GameObject, and then manipulating the Component's properties. But since a Component can be of any underlying type, and added and manipulated at run time by any code that has a reference to the GameObject, this breaks the in-code link between the outer object's type and its own capabilities; in effect, Unity encourages application developers to escape from the self documenting properties of languages like C#. (On the plus side, this is far more mod-friendly because the stock code can be added to without requiring a recompile.)

I'm currently struggling to get my bearings in this environment. Specifically:

  1. Given a GameObject, is it possible to inspect its Components at run time to figure out what the object can do? There's no public Components collection, and GetComponents requires a type parameter, meaning you must already know the type you're looking for.
  2. Given a GameObject and a task that you know it can handle, how would you figure out which Component to access? I guess this might be the same as #1, but maybe there's a way to do it without listing them.
  3. Given a GameObject and a task that you know it can't handle, how would you find the appropriate Component to add? Is there an index of them somewhere, or a base class that would show up as the root of inheritance trees in online documentation?

If you'd like an example to work from, I have a DialogGUIImage (because the DialogGUI* API is easy for simple pop-ups), and I'd like to change it to display a different image. I have tried a few things so far and not gotten good results.

No effect, as expected because of how DialogGUI* works (visibleTexture is my DialogGUIImage, nameToTexture works when the popup is initially loaded, and 's' is a valid name):

						visibleTexture.image = nameToTexture(s);

Compile error (texture property is read only):

						Image img = visibleTexture.uiItem.GetComponent<Image>();
						img.sprite.texture = nameToTexture(s);

The desired image appears on screen, offset outside of the window to the left and slightly up, and the original remains visible (based on @TaxiService's helpful post about adding and removing UI elements):

						Stack<Transform> stack = new Stack<Transform>();
						stack.Push(visibleTexture.uiItem.gameObject.transform);
						visibleTexture.Create(ref stack, UISkinManager.defaultSkin);

Image is hidden (technically a successful action, but I don't know how to replace it after this):

						visibleTexture.uiItem.gameObject.DestroyGameObjectImmediate();

I feel like there must be a GameObject.GetCompoment<SOMETHING>().SetTexture() call somewhere out there that I should use, but I don't know what the SOMETHING is or how to find it, hence my questions above.

Thanks for any answers or tips!

Link to comment
Share on other sites

Well, the first answer is pretty easy to solve (you could've googled that really). Using GetComponents(typeof(Component)) will get you an array of all the components on an object. You can then use this to check what components are there. You can even use it in a debug-manner and log all the components names to the console. This allows you to discover the components. You can also look through the documentation right here.

As for the second question, you just need a reference to the component. Again, GetComponent is your friend here.

The third question is really about what you want the object to do. You add whatever component you need to add to it to allow that function.

Link to comment
Share on other sites

1). Object's getComponents can take base type and will return instances of derived types, so typeof(MonoBehaviour) or typeof(Component) should return all sorts of stuff.

2). By reading the docs of components I've found \ googling similar questions, if the class in question is stock and not developed by Squad. If it is, reversing is the fastest way to learn how to use it.

3). Unity scripting docs. https://docs.unity3d.com/Manual/ScriptingImportantClasses.html

https://docs.unity3d.com/ScriptReference/GameObject.html

etc.. Or create your own.

 

For your case, I think you can try to assign new sprite to an image, by creating it from the texture (your second code snippet, assing sprite itself instead of it's texture):
https://docs.unity3d.com/460/Documentation/ScriptReference/Sprite.Create.html

but i'm not an expert in Unity's UI.

Link to comment
Share on other sites

40 minutes ago, Bmandk said:

Using GetComponents(typeof(Component)) will get you an array of all the components on an object. You can then use this to check what components are there. You can even use it in a debug-manner and log all the components names to the console. This allows you to discover the components.

4 minutes ago, Boris-Barboris said:

1). Object's getComponents can take base type and will return instances of derived types, so typeof(MonoBehaviour) or typeof(Component) should return all sorts of stuff.

Thank you both! This is what I was missing.

Link to comment
Share on other sites

... and just like that, I have the answer (shared in case anyone finds this thread by searching for a similar question):

	RawImage img = visibleTexture.uiItem.GetComponent<RawImage>();
	img.texture = nameToTexture(s);

Thanks again to @Bmandk and @Boris-Barboris!

Here's my simple component lister in case anyone needs that, too. Prints to KSP.log. Public domain license if it matters:

		private static void printComponentNames(GameObject gameObj)
		{
			Component[] comps = gameObj.GetComponents<Component>();
			for (int i = 0; i < comps.Length; ++i) {
				MonoBehaviour.print($"Component {i}: {comps[i].GetType()}");
			}
		}

 

Edited by HebaruSan
Link to comment
Share on other sites

I will just add for other who stumble here that if you call GetComponents often then you dhould use the call that take a list as an argument, and reuse that list.

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...