Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

Changing a child's meshrender to false

Discussion in 'Scripting' started by twetzel2k, Aug 10, 2018.

  1. twetzel2k

    twetzel2k

    Joined:
    Jan 26, 2015
    Posts:
    11
    I have a Hide objects script in which anytime something comes between the player camera and player object, the meshrenderer is turned off.
    I am using this:

    Code (CSharp):
    1. hit.collider.gameObject.GetComponent<MeshRenderer>().enabled = false;
    However, when it hits something that doesn't have a meshrenderer - such as an empty game object parent, it is giving this error:

    MissingComponentException: There is no 'MeshRenderer' attached to the "PF_Shield_Side" game object, but a script is trying to access it.
    You probably need to add a MeshRenderer to the game object "PF_Shield_Side". Or your script needs to check if the component is attached before using it.

    My hierarchy looks something like this.

    Empty Game object (Master Parent)
    - Model with Mesh renderer and collider on it.
    - etc.
    AND
    - another empty game object (sub parent)
    - Model with Mesh Renderer.


    How can I get this to work correctly?

    Thanks!
     
  2. ThermalFusion

    ThermalFusion

    Joined:
    May 1, 2011
    Posts:
    906
    Check for components existence before trying to access properties.
    You can use GetComponentsInChildren to find all components of a type on a GameObject and all of its children.
     
  3. twetzel2k

    twetzel2k

    Joined:
    Jan 26, 2015
    Posts:
    11
    Ok, trying to use that GetComponentsInChildren and trying to use Unity's script help... But I am getting nothing but errors. I have attached my code.
    Code (CSharp):
    1. public class HideObjects : MonoBehaviour {
    2.  
    3.     public Transform WatchTarget;
    4.     public LayerMask OccluderMask;
    5.     private List<Transform> _LastTransforms;
    6.  
    7.     void Start () {
    8.         _LastTransforms = new List<Transform>();
    9.     }
    10.  
    11.     void Update () {
    12.         if (WatchTarget == null){
    13.             return;
    14.         }
    15.  
    16.         //reset and clear all the previous objects
    17.         if(_LastTransforms.Count > 0){
    18.             foreach(Transform t in _LastTransforms)
    19.                 t.GetComponent<MeshRenderer>().enabled = true;
    20.             _LastTransforms.Clear();
    21.         }
    22.  
    23.     //Cast a ray from this object's transform to the watch target's transform.
    24.         RaycastHit[] hits = Physics.RaycastAll(
    25.             transform.position,
    26.             WatchTarget.transform.position - transform.position,
    27.             Vector3.Distance(WatchTarget.transform.position, transform.position),
    28.             OccluderMask
    29.             );
    30.  
    31.               print("contents = " + hits);
    32.     //Loop through all overlapping objects and disable their mesh renderer
    33.         if(hits.Length > 0){
    34.             foreach(RaycastHit hit in hits){
    35.                 if(hit.collider.gameObject.transform != WatchTarget && hit.collider.transform.root != WatchTarget){
    36.                     // New code
    37.                     Component[] _meshobjects;
    38.                     _meshobjects = hit.collider.gameObject.GetComponentInChildren<MeshRenderer>();
    39.                     _meshobjects.enabled = false;
    40.                     // end new code
    41.                 //    hit.collider.gameObject.GetComponent<MeshRenderer>().enabled = false;
    42.                     _LastTransforms.Add(hit.collider.gameObject.transform);
    43.                 }
    44.             }
    45.         }
    46.     }
    47.  
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,599
    A generally better approach is to create a script to do this for you, and to hook each of your prefabs up in precisely the right way with that script at the root.

    For instance, you could have a HittableThing.cs script and it would contain a list of MeshRenderer references to turn off.

    Every prefab would be designed precisely so that ONLY the MeshRenderers you want to turn off are in there.

    Your collision script intelligence would only go: "This thing I just hit, does it have a HittableThing script? If so, then call the method .YouHaveBeenHit() on that HittableThing. If not, do nothing."

    Then the .YouHaveBeenHit() method on the HittableThing object would know how to turn off what it needed to do, and in the future could also do things like spawn particle effects, etc.

    That way your collision code never changes again.

    And it can get even better when you come up with subclasses of HittableThing, but that's a topic for another day.
     
  5. twetzel2k

    twetzel2k

    Joined:
    Jan 26, 2015
    Posts:
    11
    two clarifications if you will..

    1. What do you mean by this: "a list of MeshRenderer references to turn off."

    2. and would this set up work?

    Empty Game Object (with HitAbleThing.cs as a component)
    - all the other stuff parented in.

    if the raycast hits something that has the HitAbleThing on it, make everything under it meshrender = false
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,599
    Code (csharp):
    1. public MeshRenderer[] WhatToTurnOff;
    and be sure to drag mesh renderers into it in the editor, as with any public inspector field.

    Sure, sounds reasonable, give it a try. Remember that the raycast will return the object that the collider is on, so if that's not where you put the HittableThing, you won't find it there.
     
  7. twetzel2k

    twetzel2k

    Joined:
    Jan 26, 2015
    Posts:
    11
    Ok, I have tried something else and am running into errors again. I would appreciate the help.

    I am shooting out a RaycastHit[ ] array.

    I am trying to turn off anything with a Meshrenderer that is hit. Some of my objects have Empty Game objects with colliders on them and then a mess of smaller mesh objects parented to that empty object.

    The different code snippets I have tried are below. Any help would be appreciated.


    Code (CSharp):
    1. // Attempt 1  returns code errors.
    2. test = GetComponentInChildren<MeshRenderer> ();
    3. foreach (MeshRenderer test2 in test)
    4.        test2.enabled = false;
    5.  
    6. // Attempt 2  - no code errors, but error when meshfilter not found on object.
    7.  if (hit.collider.gameObject.GetComponent<MeshFilter>().mesh = null)  
    8. return;
    9.  
    10.  // Attempt 3  - returns code errors
    11.  hit.collider.gameObject.GetComponent<MeshRenderer>().enabled = false;
    12.  hit.collider.gameObject.GetComponentsInChildren<MeshRenderer> ().enabled = false;
    13.  
     
  8. twetzel2k

    twetzel2k

    Joined:
    Jan 26, 2015
    Posts:
    11
    I think I may have solved this. I tried this. If this raises any flags, please let me know.

    Code (CSharp):
    1. Renderer[] rs = hit.collider.GetComponentsInChildren<Renderer> ();
    2.         foreach(Renderer r in rs)
    3.         r.enabled = false;