- Home /
change material on object when touched.
Hi guys i've written a short script for a VR project I'm doing, its basically a highlighting tool.
so when I point towards an object it moves a sphere to the end of my pointer. the sphere then highlights the object it is touching (changes its colour). and gives me some info.
// the Color Change Script Snippet on the sphere
void OnTriggerEnter( collider other)
{
other.gameObject.renderer.material.color = Color.blue
}
My problem is, when I touch something without a renderer it crashes and brings up an error.
is their a way I can say;
if object has renderer - turn blue
else ignore
I'm also hoping to change the colour back using OnTriggerExit, if anyone knows how to do that, it would also be helpful.
Thanks in advance!!!
Lee
I'm done updating my answer. I've added two solutions to the problem of restoring the original colors.
Answer by Ady_M · Jan 07, 2019 at 03:36 PM
Accessing the Renderer only if it exists
gameObject.renderer is deprecated (just like .rigidbody, .collider, etc). Instead, you need to use GetComponent.
Renderer renderer = other.GetComponent <Renderer> ();
if (renderer != null)
{
// Change color
}
Restoring the original color on TriggerExit
Let me know if the code comments do not explain well enough what's happening.
Solution 1: Only one object can be affected at a time
private Renderer touchCurrentRenderer; // The Renderer that belongs to the object that the pointer is currently touching
private Color touchOriginalColor;
public Color touchHighlightColor;
// Has to be "Stay" instead of "Enter", if you have overlapping objects
private void OnTriggerStay (Collider other)
{
// If the pointer is not touching an object.
// This if statement prevents the pointer from affecting multiple objects simultaneaously
if (touchCurrentRenderer == null)
{
// Get Renderer component
touchCurrentRenderer = other.GetComponent <Renderer> ();
// If the touched object has a Renderer Component
if (touchCurrentRenderer != null)
{
// Save the Original Color
touchOriginalColor = touchCurrentRenderer.material.color;
// Highlight Object
touchCurrentRenderer.material.color = touchHighlightColor;
}
}
}
private void OnTriggerExit (Collider other)
{
if (touchCurrentRenderer != null)
{
// Restore the Original Color
touchCurrentRenderer.material.color = touchOriginalColor;
touchCurrentRenderer = null;
}
}
Solution 2: Can handle multiple objects simultaneously
There are, of course, several ways to solve this. I chose the one that, in opinion, is easiest to understand and manage.
It simply adds a component to the touched objects which contains the original color and removes the component on TriggerExit.
Another solution is to use a collection (List, Dictionary, etc) combined with a custom class/struct to hold the data (renderer reference and original color), but you risk running into serialization problems which can be quite tricky to fix.
Here's the simple solution (using a custom component called TouchObjectData).
Pointer script:
public class Pointer : MonoBehaviour
{
public Color touchHighlightColor;
private void OnTriggerEnter (Collider other)
{
// Get Renderer component
var renderer = other.GetComponent <Renderer> ();
// If the touched object has a Renderer Component
if (renderer != null)
{
// Get TouchObjectData component
var touchObjectData = other.GetComponent <TouchObjectData> ();
// If the object does not have a TouchDataObject component
// (Meaning: If this object hasn't been handled yet)
if (touchObjectData == null)
{
// Add a new TouchObjectData component to the touched object
touchObjectData = other.gameObject.AddComponent <TouchObjectData> ();
// Save the Original Color on the new component
touchObjectData.originalColor = renderer.material.color;
// Highlight Object
renderer.material.color = touchHighlightColor;
}
}
}
private void OnTriggerExit (Collider other)
{
// Get Renderer component
var renderer = other.GetComponent <Renderer> ();
// If the touched object has a Renderer Component
if (renderer != null)
{
// Get TouchObjectData component
var touchObjectData = other.GetComponent <TouchObjectData> ();
// If the object has a TouchDataObject component
if (touchObjectData != null)
{
// Restore the Original Color
renderer.material.color = touchObjectData.originalColor;
// Remove the TouchObjectData component
Object.Destroy (touchObjectData);
}
}
}
}
TouchObjectData script:
// This component will be added to touched objects through code.
// Do not manually attach this script to objects in the editor.
public class TouchObjectData : MonoBehaviour
{
public Color originalColor;
}
Thanks So much for your help this works great, although I'm still getting this message when I touch the UI Canvas (which obviously has no renderer)
There is no 'Renderer' attached to the "Canvas" game object, but a script is trying to access it. You probably need to add a Renderer to the game object "Canvas". Or your script needs to check if the component is attached before using it.
Which solution and which line? (not the line number, of course)
If you type Debug.Log (other), does it say Canvas is the other object?
Answer by Tazza08 · Jan 07, 2019 at 03:40 PM
Thanks, I knew it would be relatively simple.
I will try it on the game later.
Your answer
Follow this Question
Related Questions
Changing two different objects renderer colour 1 Answer
Change material when an event occurs 2 Answers
Changing Emission Scale UI with Script 0 Answers
Renderer Removed When Scene Started 0 Answers