This might sound a little confusing but I’ll try to explain. In my scene I have some Game Objects that have several child objects. These child objects and parent objects have different materials applied to them. My problem is that at the moment, when the mouse hovers over the objects, the object’s (parent and childrens) colour changes to white, then is supposed to go back to their original starting colour when the mouse isn’t over them anymore. This works fine, the issue is that because there are several materials applied, when the mouse isn’t over the object it’s all one colour, which I don’t want. I’m not sure how to code it so that the colours will go back to their previous state and not just one solid colour. I tried searching online but didn’t really get anywhere. I’ll post some screenshots of before and after, and the script. Appreciate any help.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[RequireComponent(typeof(MeshCollider))]
public class GizmosController : MonoBehaviour {
//Sets variable for plug so it can be assigned in the Inspector and moved around
public GameObject plug;
//Allows object position to be edited in Inspector
public Vector3 plugPosition;
private Vector3 screenPoint;
private Vector3 offset;
//Starting colour for game object
private Color startColour;
public List<Transform> objects;
//Variable for saving initial object position
private Vector3 initialPosition;
//Variable for storing target position
public Vector3 targetPosition;
//Used to click on specific object
RaycastHit hit;
//Variable for popup window
//public GameObject popUpWindow;
//public GameObject dvdTray;
//public Vector3 diskTrayPosition;
// Use this for initialization
void Start () {
hit = new RaycastHit ();
//popUpWindow.SetActive (false);
}
//Method that picks up when mouse cursor enters object's collision
void OnMouseEnter()
{
//Sets the starting colour of the object to the default assigned material
startColour = GetComponent<Renderer>().material.color;
//When mouse hovers over object, change it's material colour to red
GetComponent<Renderer>().material.color = Color.white;
//This foreach loop is used to set the component objects as they are made of child objects
foreach (Transform Tform in objects) {
Tform.GetComponent<Renderer>().material.color = Color.white;
}
}
//Method that picks up when mouse cursor exits object's collision
void OnMouseExit()
{
//When the mouse leaves the object, change it back to it's original colour
GetComponent<Renderer>().material.color = startColour;
//This foreach loop is to reset the colour of the components as they are made of child objects
foreach (Transform Tform in objects) {
Tform.GetComponent<Renderer>().material.color = startColour;
}
}
void OnMouseDown()
{
}
bool TestObjectInPlace(Collider target, Transform obj)
{
return Vector3.Distance (target.transform.position, obj.position) < 1;
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0)){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//Allows user to move plug around
if(Physics.Raycast(ray, out hit, 500.0f) && gameObject.CompareTag("Plug")){
//transform.position = plugPosition;
}
//Allows user to move "computer components" around
if(Physics.Raycast(ray, out hit, 500.0f) && gameObject.CompareTag("Computer Component")){
//transform.position = targetPosition;
}
//These if statements check which object is clicked on and opens the appropriate pop up box
/*if (Physics.Raycast(ray, out hit, 100.0f)){
if (hit.transform.gameObject.name == "motherboard 1"){
popUpWindow.SetActive(!popUpWindow.activeInHierarchy);
Debug.Log ("motherboard 1 selected");
}
else if (hit.transform.gameObject.name == "Desktop PC CD Drive" || hit.transform.name == "eject button"){
popUpWindow.SetActive(!popUpWindow.activeInHierarchy);
//dvdTray.transform.position = new Vector3(-0.01, -2.015, 0.44);
//dvdTray.transform.position = diskTrayPosition;
Debug.Log ("Desktop PC CD Drive selected");
}
else if (hit.transform.gameObject.name == "hard drive"){
popUpWindow.SetActive(!popUpWindow.activeInHierarchy);
Debug.Log("hard drive selected");
}
else if (hit.transform.gameObject.name == "computer power supply"){
popUpWindow.SetActive(!popUpWindow.activeInHierarchy);
Debug.Log("computer power supply selected");
}
else if (hit.transform.gameObject.name == "computer case" || hit.transform.name == "computer case lid"){
popUpWindow.SetActive(!popUpWindow.activeInHierarchy);
Debug.Log ("computer case selected");
}
else if (hit.transform.gameObject.name == "keyboard base"){
popUpWindow.SetActive(!popUpWindow.activeInHierarchy);
Debug.Log("keyboard base selected");
}
else if (hit.transform.gameObject.name == "monitor"){
popUpWindow.SetActive(!popUpWindow.activeInHierarchy);
Debug.Log("monitor selected");
}
else if (hit.transform.gameObject.name == "speaker right"){
popUpWindow.SetActive(!popUpWindow.activeInHierarchy);
Debug.Log("speaker selected");
}
else if (hit.transform.gameObject.name == "video card 1"){
popUpWindow.SetActive(!popUpWindow.activeInHierarchy);
Debug.Log("video card selected");
}
else if (hit.transform.gameObject.name == "main computer fan"){
popUpWindow.SetActive(!popUpWindow.activeInHierarchy);
Debug.Log("computer fan selected");
}
else if (hit.transform.gameObject.name == "power button"){
popUpWindow.SetActive(!popUpWindow.activeInHierarchy);
Debug.Log("power button selected");
}
else if (gameObject.CompareTag ("Plug")){
popUpWindow.SetActive(!popUpWindow.activeInHierarchy);
Debug.Log("plug selected");
}
}*/
}
}
}
//}
Why not just create a “Hover Material” instead of modifying the color of each material ?
At Start() each object (or your manager) store a reference of each default material. Then when mouse hover change it to whatever material, and when mouse is out get back to default material.
edit: i didn’t read your code, but i just did it and you already store your child object in a list. You just need to store the initial color of each object in a new list (lets say defaultcolorlist<>) here before changing it to white
foreach (Transform Tform in objects) {
Tform.GetComponent<Renderer>().material.color = Color.white;
}
Then here :
foreach (Transform Tform in objects) {
Tform.GetComponent<Renderer>().material.color = startColour;
}
You just need to apply the colors stored in the defaultcolorlist<>
Save all of the childrens’ start colours first so you can re-apply them
Either in the parent or a script on the children… whatever seems easier for ya.
Then when you loop back, you can assign their respective colours instead of just the one.
I’ve started working on fixing this issue. I’m halfway there. The colours are now separate (I’ll post the new code) because I created a new List for each different colour (there’s three colours max on each object so I made two extra Lists) and also made two new colour variables for the child objects. The only problem now is that because the colour variables are private, Unity doesn’t know what the materials are, so I think what I’ll have to do is make them public instead of private, and hopefully that’ll work.
//Sets variable for plug so it can be assigned in the Inspector and moved around
public GameObject plug;
//Allows object position to be edited in Inspector
public Vector3 plugPosition;
private Vector3 screenPoint;
private Vector3 offset;
//Starting colour for game object
private Color startColour;
//Secondary colour of object
private Color childColour;
//Second slot for secondary colour of object
private Color childColour2;
//Make a list of all the objects (parent and child) in one object
public List<Transform> objects;
//Make two separate lists for different coloured objects so they can be restored to their default colour
public List<Transform> childObjects;
public List<Transform> childObjects2;
//Variable for saving initial object position
private Vector3 initialPosition;
//Variable for storing target position
public Vector3 targetPosition;
//Used to click on specific object
RaycastHit hit;
// Use this for initialization
void Start () {
hit = new RaycastHit ();
}
//Method that picks up when mouse cursor enters object's collision
void OnMouseEnter()
{
//Sets the starting colour of the object to the default assigned material
startColour = GetComponent<Renderer>().material.color;
//childColour = GetComponentInChildren<Renderer>().material.color;
//childColour2 = GetComponentInChildren<Renderer> ().material.color;
//When mouse hovers over object, change it's material colour to red
GetComponent<Renderer>().material.color = Color.white;
//This foreach loop is used to set the component objects as they are made of child objects
foreach (Transform Tform in objects) {
Tform.GetComponent<Renderer>().material.color = Color.white;
}
}
//Method that picks up when mouse cursor exits object's collision
void OnMouseExit()
{
//Get secondary colours for game objects from their child objects
childColour = GetComponentInChildren<Renderer>().material.color;
childColour2 = GetComponentInChildren<Renderer> ().material.color;
//When the mouse leaves the object, change it back to it's original colour
GetComponent<Renderer>().material.color = startColour;
//Get the child objects renderer component so they can be restored to their original colour
GetComponentInChildren<Renderer> ().material.color = childColour;
GetComponentInChildren<Renderer> ().material.color = childColour2;
//This foreach loop is to reset the colour of the components as they are made of child objects
foreach (Transform Tform in objects) {
Tform.GetComponent<Renderer>().material.color = startColour;
}
foreach (Transform Tform in childObjects) {
Tform.GetComponent<Renderer>().material.color = childColour;
}
foreach (Transform Tform in childObjects2) {
Tform.GetComponent<Renderer>().material.color = childColour2;
}
}
I was thinking you could save all of the children colours in Start and just restore them as you loop over the children on your mouse exit. They’d always be in order that way.
I’m not sure what you meant about the variables private that Unity doesn’t know what they are; that’d only be true if you were trying to access those variables outside of this script somewhere.
When you say 3 colours, do you mean each piece can be one of 3 colours, or that there can be up to 3 pieces (parent + children count together)?
It doesn’t seem to be working at the moment, but I’ll keep at it. I tried declaring the colours in the Start() function but it didn’t seem to work.
When I say three colours, I mean that on each parent object, it has one colour, and then the child objects have another colour, either one or two different colours (so one child object of a parent could be one colour and another child object of the same parent has a different colour).
EDIT: Okay, so I’ve got the colours separate, but instead of restoring to the original colour, the child object colours stay white. Still, it’s an improvement.
I don’t see why it’s not working. I’ve essentially got a separate list for separate child objects but they won’t revert to their original colour. Have I missed something? I’ll post my latest code.
//Sets variable for plug so it can be assigned in the Inspector and moved around
public GameObject plug;
//Allows object position to be edited in Inspector
public Vector3 plugPosition;
private Vector3 screenPoint;
private Vector3 offset;
//Starting colour for game object
private Color startColour;
//Secondary colour of object
public Color childColour;
//Second slot for secondary colour of object
public Color childColour2;
//Make a list of all the objects (parent and child) in one object
public List<Transform> objects;
//Make two separate lists for different coloured objects so they can be restored to their default colour
public List<Transform> childObjects;
public List<Transform> childObjects2;
//Variable for saving initial object position
private Vector3 initialPosition;
//Variable for storing target position
public Vector3 targetPosition;
//Used to click on specific object
RaycastHit hit;
// Use this for initialization
void Start () {
hit = new RaycastHit ();
startColour = GetComponent<Renderer>().material.color;
childColour = GetComponentInChildren<Renderer>().material.color;
childColour2 = GetComponentInChildren<Renderer> ().material.color;
}
//Method that picks up when mouse cursor enters object's collision
void OnMouseEnter()
{
//Sets the starting colour of the object to the default assigned material
startColour = GetComponent<Renderer>().material.color;
childColour = GetComponentInChildren<Renderer>().material.color;
childColour2 = GetComponentInChildren<Renderer> ().material.color;
//When mouse hovers over object, change it's material colour to red
GetComponent<Renderer>().material.color = Color.white;
//This foreach loop is used to set the component objects as they are made of child objects
foreach (Transform Tform in objects) {
Tform.GetComponent<Renderer>().material.color = Color.white;
}
foreach (Transform Tform in childObjects) {
Tform.GetComponentInChildren<Renderer>().material.color = Color.white;
}
foreach (Transform Tform in childObjects2) {
Tform.GetComponentInChildren<Renderer>().material.color = Color.white;
}
}
//Method that picks up when mouse cursor exits object's collision
void OnMouseExit()
{
//Get secondary colours for game objects from their child objects
childColour = GetComponentInChildren<Renderer>().material.color;
childColour2 = GetComponentInChildren<Renderer> ().material.color;
//When the mouse leaves the object, change it back to it's original colour
GetComponent<Renderer>().material.color = startColour;
//Get the child objects renderer component so they can be restored to their original colour
GetComponentInChildren<Renderer> ().material.color = childColour;
GetComponentInChildren<Renderer> ().material.color = childColour2;
//This foreach loop is to reset the colour of the components as they are made of child objects
foreach (Transform Tform in objects) {
Tform.GetComponent<Renderer>().material.color = startColour;
}
foreach (Transform Tform in childObjects) {
Tform.GetComponentInChildren<Renderer>().material.color = childColour;
}
foreach (Transform Tform in childObjects2) {
Tform.GetComponentInChildren<Renderer>().material.color = childColour2;
}
}
Well, GetComponentInChildren will always return just 1 component. You cannot set childColour1 and childColour2 using that alone. I’m talking about in Start() here.
Next, for OnEnter and OnExit, do not re-assign the childColour and childColour2 ; you’re re-assigning them to their current colours. (with the exception that you’re using GetComponent , again, which gives just 1… but the point about this comment is that you already have them stored from Start(), you needn’t fetch them, again)
Then, lastly, to set white/reset colour, try this:
for(int i = 0; i < transform.childCount; ++i){
transform.getChild(i).GetComponent<Renderer>().material.color = childColour[i];
}
I think it would be just as easy to get and set the child colours with a loop like that.
I hope that makes sense.