I am developing for the HoloLens and I Made an object that follows me around. This Gameobject is actually an UI Canvas with text in it which I set like this because i want to keep the original object as well. (Just like in the MS example):
/// <summary>
/// The object to tag along set in the unity editor
/// </summary>
public GameObject ObjectToTagAlong;
/// <summary>
/// The instantiated object to tag along that follows you around.
/// </summary>
private GameObject instantiatedObjectToTagAlong;
this.instantiatedObjectToTagAlong = GameObject.Instantiate(this.ObjectToTagAlong);
this instantiatedObject tags along just fine but now I want to update the Text on instantiatedObjectToTagAlong but have no idea how to do this. (I can very easily update the text on the 1st object but i want to do it this way)
Does anyone know how to update the text on a gameobject that is initiated from another GameObject?
To build on what Serlite commented with, you need to use GetComponent in combination with another script.
public class MyTextUpdater: MonoBehavior
{
public Text SuperText2;
}
Apply MyTextUpdater to your ObjectToTagAlong prefab (or GameObject if not a prefab) and, in the editor, set the value of SuperText2 to the Text object you want to update (typically this is a child of the ObjectToTagAlong GameObject).
Now anytime you want to update that Text object on your instance, instantiatedObjectToTagAlong, you can do this:
MyTextUpdater text = instantiatedObjectToTagAlong.GetComponent<MyTextUpdate>();
if (text!=NULL && text.SuperText2!=NULL) { /*do whatever you need to do on the text.SuperText2 object*/ }
EDIT:
When Unity instantiates a copy of a GameObject, it makes a "deep" copy of sorts, meaning that the copy will have the exact same structure of child GameObjects.
Original Copy
- Child A - Child A (copy)
- Child B Instanitate => - Child B (copy)
- - Grandchild A - - Grandchild A (copy)
Each child is instantiated with it's own new copy. On top of that, if Original has a MonoBehavior script that points to one of it's children (or grandchildren etc), Copy will have a script that points to the appropriately copied child.
MyTextUpdater [Original] MyTextUpdater [Copy]
- SuperText2 = Child B => - SuperText2 = Child B (copy)
Regarding the question of why have the extra script (the MyTextUpdater script):
Original is just a GameObject. In the editor you can see it has children, but that does not represent a class. You can not do something like this in a script:
Original.ChildB.Text = "Hello World!";
in the same way, you can't do this:
Copy.ChildB.Text = "Hello Copy World!";
You could create code to iterate through all the children of the GameObject looking for a child with the correct name ("ChildB"), but that is inefficient and probably bad programming.
The better way is to create a script class that actually does give you access to the child as a field in that class. And that is where the MyTextUpdater script comes in.
This would be invalid:
GameObject Copy = Instantiate(Original);
Copy.SuperText2.Text = "Some text here";
Copy does not have a field or method called SuperText2, or ChildB, or whatever you would call it. But you could do this:
GameObject Copy = Instantiate(Original);
MyTextUpdater mtu = Copy.GetComponent<MyTextUpdater>();
mtu.SuperText2.Text = "Some text here";
Assuming of course that you applied the MyTextUpdater script to Original and made the right connections to the child text component.
Related
I am trying to display the same game object in a table form of 4 columns and 2 rows so it would look like this:
GO GO GO GO
GO GO GO GO
G0 - gameObject
My gameObject is a button that can be pressed and has a text element on it to display the name of the profile on the button.
I have a List of strings of the names that i need to display on these GO buttons in the table form but i am struggling to position them correctly.
At the moment i have gotten to the point where i can Instantiate them so they all appear on the screen when the game is running, now i just need some advice on how i can position them properly in the format mentioned above.
How do i do this?
This is my code that i used to get the names and add them to the List:
private void GetProfiles()
{
List<string> profileNamesList = new List<string>();
if (Directory.Exists(filePath))
{
string[] files = Directory.GetFiles(filePath);
profileTileTemplate.SetActive(true);
foreach (var file in files)
{
string name;
name = file;
int index = name.IndexOf(filePath + "/", System.StringComparison.OrdinalIgnoreCase);
if (index >= 0)
{
int pathIndexEnd = index + filePath.Length + 1;
int stringLength = name.Length - pathIndexEnd - 5;
name = name.Substring(pathIndexEnd, stringLength);
}
profileNamesList.Add(name);
}
}
DisplayProfiles(profileNamesList);
}
private void DisplayProfiles(List<string> names)
{
}
I have tried using a for loop with in another for loop but i just end up instantiating multiple of the same game object.
This is what i get now:
And this is what i want it to look like:
This is kind of two questions, and I just realized that Unity has a built in component that will do this automatically, so I'll leave the three answers below.
How do I arrange UI gameobjects in rows?
Since it seems like you want to do this for UI elements there's actually a very easy solution. Add an empty GameObject as a child of your Canvas and add a Vertical LayoutGroup component. Add two children to that with horizontal layoutgroups. Add four placeholder prefabs of your gameobject to each horizontal layout group. Arrange them and configure the settings to get them looking the way you want (and make note of what happens if you add fewer than four items!)
Once you have it all set up, delete the placeholders. Then you can add your gameobjects to the horizontal group using Instantiate(Object original, Transform parent) (link) to parent them to the layout group, which will keep them arranged neatly. You can keep a list of those groups and each time you add four, switch to the next parent.
A neater way that seems to fit your use case (assuming there can potentially be more than 8 profiles) is to make a Scroll View that holds horizontal layout groups, which will each be a row of entries. That way instead of tracking which parent you want to add gameobjects to, you can just instantiate a new row every time you pass four entries.
If you're sure there will only ever be eight or fewer, the easiest thing to do would just be arrange eight blank buttons in the UI however you want them to appear. Then keep a list of the eight buttons and edit the text/image on them, no instantiation or looping necessary.
How do I split up a list of gameobjects into rows?
The actual code to process the list is below. This is just an example and there are plenty of different ways to do it, but I thought this demonstrated the logic clearly without depending on what UI elements you choose. As a rules of thumb, make sure to figure out the layout elements you like in Unity first using placeholders (like scroll view etc) and then figure out the code to fill them in. In other words, instantiating and laying out UI elements at runtime is a great way to give yourself a headache so it's best to only do it when you need to.
List<string> profileNamesList = new List<string>();
public int entriesPerRow; //only public so you can edit in the inspector. Otherwise, just use the number per row in your prefab.
public GameObject profileRowPrefab;
public GameObject scrollViewLayout;
private void DisplayProfiles(List<string> names)
{
int i = 0;
while( i < names.Count ) //"while the list has more names"
{
//create a new row as a child of the scroll view content area
//and save a reference for later
GameObject go = Instantiate(profileRowPrefab, scrollViewLayout);
for(j = 0; j < entriesPerRow; j++) //"add this many names"
{
if(i < names.Count)
{
//instantiate a button, or edit one in the row prefab, etc.
//depending on how you're doing it, this is where you'd use the go variable above
YourProfileButtonCreationMethod(names[i]);
i++;
}
else
{
//we've finished the list, so we're done
//you can add empty placeholders here if they aren't in the prefab
break;
}
}
}
}
YourProfileButtonCreationMethod will depend completely on how you want to implement the UI.
I wish I had thought of this an hour ago, but I've never used it myself. Unity has a built in layout feature that will do this for you (minus the scrolling, but you may be able to nest this in a scroll view).
How do I arrange UI elements in a grid?
Instead of making your own grid with horizontal and vertical layout groups, you can use the Grid Layout Group. Then just instantiate each item in the list as a button with the grid layout as their parent (see above). Here's a short video tutorial that shows what the result looks like.
I have the following situation I need an answer to:
I have a parent object with children. These children all have unique meshes. Whenever these children are selected in the SceneView, the parent needs to be selected in stead. The children should never have their inspectors exposed (not even a fraction of a second).
How do I do this?
There are two possible solutions that I have come up with which are not the solution I wish to go for.
First being using [SelectionBase] attribute on the parent object. This work perfectly, but only once. The first time the child is selected, the parent gets selected. However, when I click the child again, it still gets selected.
Second solution was to react on Selecten.onSelectionChanged. This however is too slow. I can set the selection to the parent if a child gets selected, but the child gets exposed for a few frames still.
Is there an instant solution to this which can guarantee me the functionality of SelectionBase, but then every time in stead of only the first time I click it?
Thanks in advance! :)
I have found a way to do exactly what i want. I combine the [SelectionBase] attribute with a piece of code in the editor OnSceneGui.
First add the [SelectionBase] attribute to your class
Second add this code to its editor class
private void OnSceneGUI()
{
HandleUtility.AddDefaultControl(0);
//Get the transform of the component with the selection base attribute
Transform selectionBaseTransform = component.transform;
//Detect mouse events
if (Event.current.type == EventType.MouseDown)
{
//get picked object at mouse position
GameObject pickedObject = HandleUtility.PickGameObject(Event.current.mousePosition, true);
//If selected null or a non child of the component gameobject
if (pickedObject == null || !pickedObject.transform.IsChildOf(selectionBaseTransform))
{
//Set selection to the picked object
Selection.activeObject = pickedObject;
}
}
}
This allows the first pick to select the component. From then on, only when you select non-child objects in the scene, selection will actually change.
I want to move the itemChild away from the parent, but the parent always move to the new position with the child. Why the parent follow the child's position? How can I move the child and leave the parent where it is.
My code:
GameObject go = new GameObject("go");
go.transform.parent = GameObject.FindGameObjectWithTag("Canvas").transform;
itemChild.transform.SetParent(go.transform);
itemChild.transform.localPosition = new Vector2(itemChild.transform.position.x, itemChild.transform.position.y + 250);
Parent should stand still. Are you sure parent is moving with the child ? I mean you are just creating an empty GameObject, can share with us the x,y,z of parent and child ? I tried your code with a bit of change and it is working for me. Here is my code : https://imgur.com/khXrZ07 If you just create an empty game object and click on it in the canvas, since your parent("go" in your case) is empty it will just focus on your child object and it might confuse you.
I am newbie in unity. i am facing a small Problem. I have a different number of items and i want to associate Different Price with them .
but i dont know How to access Text(script) component in Unity? ?????
Lets says Here is the book shop every book Container Have different price
Here what i try to do but i don't know how to access this text Using Script
Thanks in advance
Find the "NumericalScore" GameObject with GameObject.Find then get the Text component from it with the GetComponent function.
//Find the Text GameObject
GameObject textObj = GameObject.Find("NumericalScore");
//Get the Text component
Text text = textObj.GetComponent<Text>();
string bookText = text.text;
Now, let's say that the each book has different names but with a Child text with the-same name called "NumericalScore", find the book name first then use transform.Find to find the child Text GameObject before using the GetComponent function to get the Text component.
//Find Book
GameObject book = GameObject.Find("BookName");
//Find Child Text GameObject
GameObject textObj = book.transform.Find("NumericalScore").gameObject;
//Get the Text component
Text text = textObj.GetComponent<Text>();
string bookText = text.text;
A bit new to Unity, I know that you can get a prefab from the instance of the GameObject (right click on GameObject and Select Prefab). But is there a way to select the GameObjects and Components that were used to created a Prefab? (from the Prefab)
Try this example out. It contains two flavors of selection, one to select all components attached to the prefab, and the other to select just the monobehaviours attached to the prefab.
What this script will do is check what components / monobehaviours are attached to the currently selected GameObject (or prefab) and will output them to the log, as well as select them all.
Copy the below code, put it into a new script named "PrefabComponentSelectorEditor" and save it in a folder called "Editor".
You should then see a Menu Item called "AxS -> Prefab Component Selector". Click on it, and see the console as well as the inspector.
The code is commented, but in case you have any questions, feel free to ask.
P.S. Remember to use ONLY ONE of the flavours (i.e. Monobehvaiour or Component). Comment / Uncomment the code accordingly. I have left the component version uncommented, and the monobehaviour version is right below it.
using UnityEngine;
using UnityEditor;
using System.Collections;
public class PrefabComponentSelectorEditor : EditorWindow {
[MenuItem("AxS/Prefab Component Selector")]
public static void SelectComponents () {
Debug.Log ("GOs "+Selection.activeGameObject);
if(Selection.activeGameObject != null) {
//This will select all the COMPONENTS attached to the prefab
//Let's first get all the components this GameObject has
Component[] components = Selection.activeGameObject.GetComponents<Component>() as Component[];
//If the length of components is > 0 (always WILL be, since every GameObject is
//guarenteed to have a Transform Component at the very minimum
if(components.Length > 0) {
//Print all the components to console
foreach(Component component in components)
Debug.Log (component);
//Set the current selection to the components
Selection.objects = (Object[])components;
}
//This will select all the MONOBEHAVIOURS attached to the prefab
//First get all Monobehavious attached
//MonoBehaviour[] behaviours = Selection.activeGameObject.GetComponents<MonoBehaviour>() as MonoBehaviour[];
//Check if the length of the array is > 0. This is required, since a GameObject
//may have no scripts attached to it
//if(behaviours.Length > 0) {
//Print all attached Monobehvaiours to console
// foreach(MonoBehaviour behaviour in behaviours)
// Debug.Log (behaviour);
//Set the current selection to the Monobehaviours
// Selection.objects = (Object[])behaviours;
//}
//The difference between COMPONENT and MONOBEHAVIOUR
//A Monobehaviour is basically any script you make, so if you use the monobehaviour version
//it will only select the scripts you attach to the prefab
//A component is anything you can see on the inspector, including Unity's inbuilt components
//Essentially, all Monobehaviours are Components
//Eg. If your prefab has a single script called "ExampleScript" attached to it, and has a BoxCollider
//Monobehaviour version will output just the ExampleScript
//Component version will output the Transform, BoxCollider and ExampleScript
}
}
}