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. Dismiss Notice

Question changing the material of children.

Discussion in 'Scripting' started by Wibaut, Jan 23, 2021.

  1. Wibaut

    Wibaut

    Joined:
    Jan 22, 2021
    Posts:
    5
    I'm still a total beginner at this so this might be obvious.
    but I'm trying to "highlight" the object I'm looking at from an fps perspective by changing the material.
    the object is multiple blocks in an L shape (like the tetris block) all objects are in an empty parent with the rigidbody attached.

    so far I managed to change the material of the block that has the same position as the parent.But now I want to have all children to change material aswell. (I want all the blue ones to be yellow if highlighted) Screenshot 2021-01-23 191845.png
    How do I do this? and if possible I would like an explanation to how that solution works so I can understand it.


    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.Rendering;
    6.  
    7. public class Highlights : MonoBehaviour
    8. {
    9.     public LayerMask Mask;
    10.     public Material highlightMaterial;
    11.     Material originalMaterial;
    12.     GameObject lastHighlightedObject;
    13.  
    14.     void HighlightObject(GameObject gameObject)
    15.     {
    16.         if (lastHighlightedObject != gameObject)
    17.         {
    18.             ClearHighlighted();
    19.             originalMaterial = gameObject.GetComponentInChildren<MeshRenderer>().sharedMaterial;
    20.             gameObject.GetComponentInChildren<MeshRenderer>().sharedMaterial = highlightMaterial;
    21.             lastHighlightedObject = gameObject;
    22.         }
    23.  
    24.     }
    25.  
    26.     void ClearHighlighted()
    27.     {
    28.         if (lastHighlightedObject != null)
    29.         {
    30.             lastHighlightedObject.GetComponentInChildren<MeshRenderer>().sharedMaterial = originalMaterial;
    31.             lastHighlightedObject = null;
    32.         }
    33.     }
    34.  
    35.     void HighlightObjectInCenterOfCam()
    36.     {
    37.         float rayDistance = 1000.0f;
    38.         // Ray from the center of the viewport.
    39.         Ray ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f));
    40.         RaycastHit rayHit;
    41.         if (Physics.Raycast(ray, out rayHit, rayDistance, Mask))
    42.         {
    43.             GameObject hitObject = rayHit.collider.transform.parent.gameObject;
    44.             HighlightObject(hitObject);
    45.         }
    46.         else
    47.         {
    48.             ClearHighlighted();
    49.         }
    50.     }
    51.  
    52.     void Update()
    53.     {
    54.         HighlightObjectInCenterOfCam();
    55.     }
    56. }
    57.  
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    If you have those four cubes as children of another GameObject, you can always go up one level from what you hit with the raycast (go up one level using
    transform.parent
    ), then from that point do a
    GetComponentsInChildren<Renderer>();
    and get all renderers below that parental point.

    For your above cube object that would work assuming your hierarchy looks like:

    Code (csharp):
    1. TopOfBlockObjectEmptyGameObject
    2.    Cube1
    3.    Cube2
    4.    Cube3
    5.    Cube4
    So lets say you hit Cube3, you go up one level with transform.parent and do the get all renderers call above, and then iterate them.

    Code (csharp):
    1. Transform parent = WhatIHitWithTheRaycast.transform.parent;
    2.  
    3. Renderer[] AllRenderers = parent.GetComponentsInChildren<Renderer>();
    4.  
    5. // iterate and change
    6. foreach (Renderer r in AllRenderer)
    7. {
    8.   r.sharedMaterial = .... whatever you like
    9. }
    That's a good cheap and cheerful hack.

    Alternately you can put a script on the parent gameobject that explicitly lists the renderers in the children you want changed. That way you could only change specific ones, such as if you had some other renderers you did NOT want changed but that were also children.
     
    Wibaut likes this.
  3. Wibaut

    Wibaut

    Joined:
    Jan 22, 2021
    Posts:
    5
    I was amazed I got most of that hahaha, I got it working that all child objects highlighted as desired, but if I move my cursor away the highlightmaterial stays, this was working before that if I didnt look at it, it would revert back to the original material.

    Where did I go wrong?
    Here is the part that I changed.

    Code (CSharp):
    1.     void HighlightObjectInCenterOfCam()
    2.     {
    3.         float rayDistance = 1000.0f;
    4.         // Ray from the center of the viewport.
    5.         Ray ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f));
    6.         RaycastHit rayHit;
    7.         if (Physics.Raycast(ray, out rayHit, rayDistance, Mask))
    8.         {
    9.             Transform parent = rayHit.collider.transform.parent;
    10.             Renderer[] AllRenderers = parent.GetComponentsInChildren<Renderer>();
    11.  
    12.             foreach (Renderer r in AllRenderers)
    13.             {
    14.                 r.sharedMaterial = highlightMaterial;
    15.             }
    16.         }
    17.         else
    18.         {
    19.             ClearHighlighted();
    20.         }
    21.     }
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    You were calling
    ClearHighlighted()
    before. :)