- Home /
Select object with mouse and hide its children with key,
Hi everyone!
I'm making a game where I have several objects, and I'm completely new to C# and unity.
What I'd like to do is if I select an object with the mouse, I can press a key to hide it.
The problem is that some of my meshes are separated into several meshes (too many vertices). These meshes are the children of a GameObject that doesn't have a renderer.
I tried two ways to do this, but none works :
First try : a script attached to the camera with raycast, it works but only detects the partial meshes and when I press H it hides only the clicked child. I tried but failed making a function searching for siblings to hide them at the same time
Second try : a script attached to each object, or partial mesh if the object is split into children meshes. I put the key input into the update function, but when I do that, my list is back to empty, so the key just hides one of the partial meshes. How can I put the List gotten from the OnMouseUp function into the update to make the key hide all the objects from it?
Or is there a simpler solution?
Thank you in advance ;) I hope my question is understandable...
First try script : (this one is also changing the shader of the clicked object, but still it is just the partial mesh...)
using UnityEngine; using System.Collections;
public class SelectionObjetSouris : MonoBehaviour {
public GameObject ObjetClicked = null;
void Update ()
{
if(Input.GetMouseButtonUp(0))
{
Ray ray = GetComponent<Camera>().ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if (ObjetClicked == null)
{
ObjetClicked = hit.collider.transform.gameObject;
for (int i = 0; i < ObjetClicked.GetComponent<Renderer>().materials.Length; i++)
ObjetClicked.GetComponent<Renderer>().materials[i].shader = Shader.Find("Legacy Shaders/VertexLit");
}
else
{
for (int i = 0; i < ObjetClicked.GetComponent<Renderer>().materials.Length; i++)
ObjetClicked.GetComponent<Renderer>().materials[i].shader = Shader.Find("Standard");
NomObjet = hit.transform.gameObject.name;
ObjetClicked = hit.collider.transform.gameObject;
for (int i = 0; i < ObjetClicked.GetComponent<Renderer>().materials.Length; i++)
ObjetClicked.GetComponent<Renderer>().materials[i].shader = Shader.Find("Legacy Shaders/VertexLit");
}
}
}
if (Input.GetKeyDown(KeyCode.H))
ObjetClicked.SetActive(false);
}
}
Second try script : (I manually drag the siblings in the script attached to a partial mesh in unity by chosing the size of "Enfants" if there are children meshes, if there are no partial mesh, I just set "Enfants.size" to 0)
using UnityEngine; using System.Collections; using System.Collections.Generic;
public class GroupeSelectionMesh : MonoBehaviour {
public GameObject[] Enfants;
private int NbEnfants;
private List<GameObject> ObjetActif = new List<GameObject>();
void OnMouseUp ()
{
if (Enfants.Length == 0)
{
ObjetActif.Add(gameObject);
}
else
{
NbEnfants = Enfants.Length;
for (int i = 0; i < NbEnfants; i++)
ObjetActif.Add(Enfants[i]);
}
}
void Update()
{
if (Input.GetKeyUp(KeyCode.H))
{
foreach (GameObject item in ObjetActif)
{
gameObject.SetActive(false);
}
}
}
}
,
Answer by b1gry4n · Oct 21, 2016 at 08:58 AM
Use the raycast method you describe in your first attempt.
Place all objects you want to hide under a new gameobject. (root object>new gameobject>all mesh objects) to act as a "holder" (you said you already had a holder, so that would work)
Now you need a way to find this object. You can either have a reference in your root object script to the new game object, or what I like to do, is create a new script. It can be a blank script, name it something like "ChildHolder" and place it on the new (or existing) game object. find it using GetComponentInParent which recursively traverses upwards until it finds a valid component of type. At this stage you should have a gameobject that is holding all the child mesh objects with a script on it that is used purely to navigate to using "GetComponentInParent"
ObjetClicked = hit.collider.transform.gameObject; ChildHolder holder = ObjetClicked.GetComponentInParent<ChildHolder>(); if(holder){ holder.transform.gameObject.SetActive(false); }
Now no matter what child you click it will find the holder. Instead of turning off each individual child, you are turning off the "holder" that was created in step 2 (or that you already had) which in turn will also hide all the children
So the logic is: Clicked child > Find parent with "ChildHolder" > hide "ChildHolder" game object which in turn hides all children under it including the clicked object
keep in mind, if you want to reverse this process, youll need to have a reference to the gameobject you just turned off stored somewhere. You can not find components using any GetComponent method if the gameobject they are on is disabled.
Extra:
You could add some extra logic to your "ChildHolder" script so instead of directly disabling the gameobject, you could execute some more code. This would allow you to find it again and re-enable the child objects instead of storing a gameobject that has been turned off, since the game object isnt disabled using this method
holder.ShowChildren(false);
and then in the "ChildHolder" script...
public void ShowChildren(bool shouldEnable)
{
Transform[] allChildren = GetComponentsInChildren<Transform>();
foreach (Transform child in allChildren)
{
// do whatever with child transform here
child.gameObject.SetActive(shouldEnable);
}
}
As a side note, you could also use "transform.parent" to get a reference to the childs parent, but that will only return the direct parent of that child. The method i describe above will work no matter how many children, or children of children, are under the "holder" object
Thank you @b1gry4n for answering so fast! But I'm having trouble calling ChildHolder from my script...
I created a blank script called ChildHolder :
using UnityEngine; using System.Collections; internal class ChildHolder { } and I attached it to a holder gameobject
But when I write :
ChildHolder holder = ObjetClicked.GetComponentInParent<ChildHolder>();
in my mouse script, the console is sending me an error message :
"CS0246 The type or namespace name 'ChildHolder' could not be found (are you missing a using directive or an assembly reference?)"
What am I doing wrong?
Ok now I've turned my computer off and on it accepts ChildHolder...
But I don't understand the condition of your "if", and the Console says " Cannot implicitly convert type 'ChildHolder' to 'bool' " What does "holder" represent when you call ChildHolder?
Another problem is the following line, there seems to be a problem with "transform" after holder. : " 'ChildHolder' does not contain a definition for 'transform' and no extension method 'transform' accepting a first argument of type 'ChildHolder' could be found (are you missing a using directive or an assembly reference?)" Sorry I really am a newby... :(
Answer by Popypops · Oct 21, 2016 at 12:16 PM
Thank you @b1gry4n for answering so fast! But I'm having trouble calling ChildHolder from my script...
I created a blank script called ChildHolder : using UnityEngine; using System.Collections;
internal class ChildHolder { } and I attached it to a holder gameobject
But when I write :
ChildHolder holder = ObjetClicked.GetComponentInParent();
in my mouse script, the console is sending me an error message :
"CS0246 The type or namespace name 'ChildHolder' could not be found (are you missing a using directive or an assembly reference?)"
What am I doing wrong?
Your answer
Follow this Question
Related Questions
MonoBehaviour OnMouseOver does not work with mesh colliders. 0 Answers
Invisble Faces 1 Answer
Hide and lock the mouse cursor (beginner) 0 Answers
mouse dissapear 1 Answer