Hopefully simple question about data from scriptableobject.

I have a simple space game set up and I have the UI displaying data about planets on mouseover.

Each planet has a set of strings that contain data like planet name etc. that is referenced from a Scriptable object.

Here is the code for that:

[CreateAssetMenu(fileName = "New PlanetData", menuName = "PlanetData")]
public class PlanetData : ScriptableObject
{
public string planetName;
public string planetDescription;
public string planetType;
public string planetMass;
public string planetMinerals;
}

So I have created a bunch of assets that get data from this SO that is then attached to each planet GameObject in editor, and on mouseover, you get a pop up with this data, which is sent to a canvas object, that contains the text fields that Im using to display this data.

I link the text element from the inspector to the game object.

This is adapted from a brackeys tutorial.

Here is the code for the data:

public class PlanetUI : MonoBehaviour
{
public PlanetData planet;
public Text name;
public Text description;
public Text type;
public Text mass;
public Text minerals;
public void Update()
{
name.text = planet.planetName;
description.text = planet.planetDescription;
type.text = planet.planetType;
mass.text = planet.planetMass;
minerals.text = planet.planetMinerals;
}
}

The issue I have is that the text does not update with the new data for each planet. I have had it work before when using a seperate canvas for each game object individually but this seems convoluted and probably unnecessary

So no matter which planet i mouse over, the UI displays the same strings.

Is it possible to refresh or update the strings?

Im sure its a simple fix but I just cant get my head around it.

Any help would be appreciated.

edit(moved from answer)

using UnityEngine;
using UnityEngine.UI;

public class PlanetInfoUI : MonoBehaviour
{
    private RaycastHit hit;
    public Ray ray;
    [SerializeField]private GameObject planetInfo;

    void Start()
    {
        planetInfo.SetActive(false);
    }

    void Update()
    {
        ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        
        if(Physics.Raycast(ray, out hit, 3.1f))
        {
            if(hit.collider.tag == "RayPlane")
                {
                    planetInfo.SetActive(true);
                    planetInfo.transform.position = Camera.main.WorldToScreenPoint(hit.collider.transform.position);
                }
        }
        else
        {
            planetInfo.SetActive(false);
        }
    }
}

The problem is that you never assign the data specific to the hovered planet. Your PlanetData SOs contain the data for one planet, and you need to link it to the corresponding gameobject in some way. Then, in PlanetInfoUi, you need to get this data from the hit object, and link it to your PlanetUI. So, something like this:

(Assuming you have a “Planet” MonoBehaviour on your planets):

public class Planet : MonoBehaviour
{
	public PlanetData data;
}

On each of your planet gameobjects, assign the corrsponding SO.

As for the PlanetUI, you could directly assign the data and wait for the update, but you should always try to avoid using the Update function where not necessary. Something like this:

public class PlanetUI : MonoBehaviour
{
	public Text planetName;
	public Text description;
	public Text type;
	public Text mass;
	public Text minerals;

	public void SetPlanetData(PlanetData planetData)
	{
		planetName.text = planetData.planetName;
		description.text = planetData.planetDescription;
		type.text = planetData.planetType;
		mass.text = planetData.planetMass;
		minerals.text = planetData.planetMinerals;
	}
}

Finally, in the PlanetInfoUI, replace the planetInfo by the component itself rather than the gameobject, because you will need to have that ui component specifically. Then, in your update function, get the Planet component of the hovered gameObject and assign the data to the ui component:

public class PlanetInfoUI : MonoBehaviour
{
	private RaycastHit hit;
	private Ray ray;
	[SerializeField] private PlanetUI planetInfo;

	void Start()
	{
		planetInfo.gameObject.SetActive(false);
	}

	void Update()
	{
		ray = Camera.main.ScreenPointToRay(Input.mousePosition);

		bool showPlanetInfo = false;
		if (Physics.Raycast(ray, out hit, 3.1f))
		{
			Planet hitPlanet = hit.collider.GetComponent<Planet>();
			if (hitPlanet)
			{
				showPlanetInfo = true;
				planetInfo.SetPlanetData(hitPlanet.data);
				planetInfo.transform.position = Camera.main.WorldToScreenPoint(hit.collider.transform.position);
			}
		}
		planetInfo.gameObject.SetActive(showPlanetInfo);
	}
}

I’m not sure what is the RayPlane tag in your script, but each planet should have its own collider so you can know which is which.

Hope it helps, good luck :slight_smile: