GoatZero
GoatZero

Reputation: 219

Replacing a texture on Object mouse over

Just started learning C# on Unity, been playing for awhile with mouseover and got it working to change objects color however.

I'm having problems trying to understand, how can i apply this to color AND textures AT THE SAME TIME, here's what i have been trying while following Unity´s material.texture and MouseOver

The following code works flawlesly

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MouseOver : MonoBehaviour
{
    Color m_MouseOverColor = Color.yellow;
    Color m_OriginalColor;
    MeshRenderer m_Renderer;

    void Start()
    {
        m_Renderer = GetComponent<MeshRenderer>();
        m_OriginalColor = m_Renderer.material.color;
    }

    void OnMouseOver()
    {
        m_Renderer.material.color = m_MouseOverColor;
    }

    void OnMouseExit()
    {
        m_Renderer.material.color = m_OriginalColor;
    }
}

The following code doesn't work at all, Notice Im not using any click/keyboard events so I attempted to remove the fors and this is what i came up with

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MouseOver : MonoBehaviour
{
    Color m_MouseOverColor = Color.yellow;
    Color m_OriginalColor;
    MeshRenderer m_Renderer;
    public Texture[] textures; //Create an array for the 2 textures
    public Renderer rend;       //Renderer required

    void Start()
    {
        m_Renderer = GetComponent<MeshRenderer>();
        m_OriginalColor = m_Renderer.material.color;
        rend = GetComponent<Renderer>();
    }

    void OnMouseOver()
    {
        int index = 1;
        index = index % textures.Length;        //Limit array 
        rend.material.mainTexture = textures[index];    //Set texture Number 1           m_Renderer.material.color = m_MouseOverColor;
           }

    void OnMouseExit()
    {
        m_Renderer.material.color = m_OriginalColor;
        int index = 2;
        index = index % textures.Length;        //Limit array 
        rend.material.mainTexture = textures[index];    //Set texture Number 2
    }
}

I'm also setting 2 different textures for the object in the properties named as 1 and 2 so i'm quite sure im just not understanding how material.mainTexture works.

Upvotes: 1

Views: 1275

Answers (2)

GoatZero
GoatZero

Reputation: 219

I finally fixed this by placing the textures in the Resources model and using the function Resources.Load , not it works as intended,

//https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnMouseOver.html

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MouseOver : MonoBehaviour
{
    public Texture TexturaSencillaBlanca;
    public Texture TexturaSencillaBlanca2;

    //When the mouse hovers over the GameObject, it turns to this color (red)
    Color m_MouseOverColor = Color.yellow;
    //This stores the GameObject’s original color
    Color m_OriginalColor;
    //Get the GameObject’s mesh renderer to access the GameObject’s material and color
    MeshRenderer m_Renderer;

    void Start()
    {
        //Fetch the mesh renderer component from the GameObject
        m_Renderer = GetComponent<MeshRenderer>();
        //Fetch the original color of the GameObject
        m_OriginalColor = m_Renderer.material.color;
    }

    void OnMouseOver()
    {
        Debug.Log("El color del objeto es AMARILLO.");
        //Change the color of the GameObject to red when the mouse is over GameObject
        if (m_Renderer.isVisible)
        {   //Change Color of object on mouseHover
            m_Renderer.material.color = m_MouseOverColor;
            //Load Resources directly from folder
            GetComponent<Renderer>().material.mainTexture = (Texture)Resources.Load("TexturaSencillaBlanca");
        }
    }

    void OnMouseExit()
    {
        Debug.Log("El color del objeto es BLANCO.");
        //Reset the color of the GameObject back to normal
        m_Renderer.material.color = m_OriginalColor;
        GetComponent<Renderer>().material.mainTexture = (Texture)Resources.Load("TexturaSencillaBlanca2");
    }
}

Upvotes: 0

So, there's a couple of things here:

1) Arrays are 0 indexed. Your index % textures.Length will avoid an ArrayIndexOutOfBounds error, but you will constantly be confused why the first texture in your array is for mouse over when you told it to use the second (and vice versa). You should be using int index = 0; and int index = 1; respectively.

2) As mentioned in the comments by Eddge, Both GetComponent<MeshRenderer>() and GetComponent<Renderer>() are going to be pulling back the same component. MeshRenderer extends Renderer.

However...

When you modify a material (either by changing the color or changing the texture) you create a new material instance. This might be messing your code up, but I don't think it should be (as you are not storing a reference to the material, but the renderer, which doesn't change, and your code looks very similar to the sample code in the docs). In either case, there's a nicer, cleaner way of doing things:

Option 1: Create two materials and switch between them

Simply create two materials you want to switch between, assign them to (new) fields in your class, and just change the material the renderer has.

rend.material = material[index];

Option 2: Use a MaterialPropertyBlock

MaterialPropertyBlock allow you to use a single material and change the details for that one object without causing a new material instance to be created (and thereby cause less garbage collection, as well as keeping batches for the renderer: your game spends less time cleaning up RAM and it draws faster and you can have more than one object with this script attached without problems!)

There isn't any sample code on the documentation page, but it's pretty straight forward. The hard thing to figure out is the name of the first parameter for the setter functions (they are all of the format public void Set____(string name, T value);). I can never remember off the top of my head which way it goes, but I'm pretty sure that it wants the name as seen by the shader ("_MainTex") rather than it's more friendly name ("MainTex"), though it is not what you see in the editor ("Main Tex", with a space) and I don't currently have access to any of my projects where I've used it before.

Upvotes: 1

Related Questions