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 :wink:
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*.shader = Shader.Find("Legacy Shaders/VertexLit");*

}
else
{
for (int i = 0; i < ObjetClicked.GetComponent().materials.Length; i++)
ObjetClicked.GetComponent().materials*.shader = Shader.Find(“Standard”);*
NomObjet = hit.transform.gameObject.name;
ObjetClicked = hit.collider.transform.gameObject;
for (int i = 0; i < ObjetClicked.GetComponent().materials.Length; i++)
ObjetClicked.GetComponent().materials*.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 ObjetActif = new List();
* void OnMouseUp ()*
{
if (Enfants.Length == 0)
{
ObjetActif.Add(gameObject);
}
else
{
NbEnfants = Enfants.Length;
for (int i = 0; i < NbEnfants; i++)
ObjetActif.Add(Enfants*);*
}
}

void Update()
{
if (Input.GetKeyUp(KeyCode.H))
{
foreach (GameObject item in ObjetActif)
{
gameObject.SetActive(false);
}
}
}
}
,

  • 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();

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?