Accessing ScriptableObject data of current gameObject

Hi forum,

i spent about 5h trying to figure out how to access variables of a ScriptableObject by addressing the current gameObject that this very SO is sitting on.

Short idea of what I want to do:
I created a SO RNode (researchNode) that will store information about inventions and the like. They will be represented by card-like looking game objects. I created a UI prefab that also holds RNodeDisplay.cs which basically just makes the text fields on the prefab using the given SO data.

Now I want to drag the card from a starting position (will be something like a ā€œhandā€ or ā€œinventoryā€ later on) to a position that it is designated to. I therefore created two zones called ā€œStoneageā€ and ā€œModernā€. The string type of the SO asset variable will hold the very same information for each asset.

I only want to allow the node to be placed on the zone that matches the type it has.

The problem: I can’t figure out how to access the current gameObjects (the node that is being dragged around) type string, because I can’t inherit, evoke, instantiate and what not the link to the information the SO asset holds.

Because I’m at a point now where I (as a newbie) am so confused about how scripts and SOs and GOs etc. talk to each other… I’m here.

The error message is:
ā€œArgumentException: GetComponent requires that the requested component ā€˜RNode’ derives from MonoBehaviour or Component or is an interface.
UnityEngine.Component.GetComponent[T] ()ā€

I understand the difference between MonoBehaviour and SO, I also tried to work with transform, but just can’t get it to work.

Please find the four related codes here:

SO

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

[CreateAssetMenu(fileName = "New rNode", menuName ="New Nodes/Reasearch Node")]
public class RNode : ScriptableObject
{
    public int ID;              // unique ID
    public int parentID;        // the ID that this node is attached to
    public string newName;      // name of the node

    public Sprite typeImage;    // image that shows the type of node, may later be replaced by prefab allocation?

    public string description;  // description
    public string type;         // type of node, may later be changed to a list/array
    public string timeAge;      // the time age that this node belongs to, may only be one

    public int rCost;           // reasearch costs in points
    public int rTime;           // time it takes to research in minutes
    public int gCost;           // gold costs in points

    public string effect;       // explanation of the effect
    public float effectValue;   // effect value, e. g. 1,1 or -1,5 (later maybe two effects, one positive, one negative)

    public bool milestone;      // is this node a milestone or not?
    public float rarity;        // rarity to find this node ranging from 0,01 to 1

    public string enabledB;     // the building enabled by this node
    public string enabledW;     // the war item enabled by this node
    public string enabledR;     // the research node enabled by this node (must not be a child)

    public string tags;         // tags for tags sake

}

Text display on UI

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

public class RNodeDisplay : MonoBehaviour
{
    // receive all rNode variables that are visible
    public RNode rNode;

    public Text nameText;
    public Image typeImage;
    public Text descriptionText;
    public Text effectText;
    public Text enabledText;

    public Text rCostText;
    public Text gCostText;


   // enable allocation of UI elements to assets data
    void Start()
    {
        nameText.text = rNode.newName;
        typeImage.sprite = rNode.typeImage;

        descriptionText.text = rNode.description;

        effectText.text = rNode.effect;
        enabledText.text = rNode.enabledB + rNode.enabledW + rNode.enabledR;

        rCostText.text = rNode.rCost.ToString();
        gCostText.text = rNode.gCost.ToString();
    }
}

Dropzone

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


public class Dropzone : MonoBehaviour, IDropHandler
{

    public void OnDrop(PointerEventData eventData)
    {

        Draggable d = eventData.pointerDrag.GetComponent<Draggable>();  // receive data based on the position of the mouse (hovering an area)

        if (d != null)  // will most likely never be != null
        {
            d.parentToReturnTo = this.transform;    // receive information about the area and set the area to return to to the current one
            Debug.Log("This is area" + this.name);
        }

    }
}

Dragging operations

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

public class Draggable : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    public RNode rNode;     // does this import the currently dragged nodes rNode information?

    public Transform parentToReturnTo = null;       // variable that saves the last valid slot position
     public void OnBeginDrag(PointerEventData eventData)
    {
        parentToReturnTo = this.transform.parent;       // the place the node starts being dragged is the "home" position
        this.transform.SetParent(this.transform.parent.parent);
        Debug.Log ("We begin dragin'");

        GetComponent<CanvasGroup>().blocksRaycasts = false;
    }

    public void OnDrag(PointerEventData eventData)  // not actively used atm
    {
        this.transform.position = eventData.position;
    }
   
    public void OnEndDrag(PointerEventData eventData)
    {
        this.transform.SetParent(parentToReturnTo);     // sets location that the node is on to new slot, will be enhanced by if statement checking the correct position
        GetComponent<CanvasGroup>().blocksRaycasts = true;

        rNode = this.GetComponent<RNode>();     // this is where it get's messy. I can't access the component rNode from the current node
        Debug.Log("And this is" + rNode.timeAge);   // prompts error

        Debug.Log(gameObject.name + " dragged on " + this.transform.parent.name);   // this debug at least shows me that the current gameObject is actually the node, not the UI zone
    }

}

I’ve read documentations, tutorials, watched tutorials on inventory systems (because these have somewhat comparable actions going on). But I can’t seem to find out the one thing that I’m missing.

Thanks a lot in advance!

Edit:
I found out that if I drag the SO asset onto the editor’s field for R Node, it works. I expected that. I need to find a way to exchange/reference this with the asset that is currently loaded by RNodeDisplay. I cannot ā€œhard linkā€ an asset to the Draggable script obviously. Arghhh…

KR

Gegenton

1 Like

I’m pretty confused by your description, and I suspect that’s because you are pretty confused about what you’re doing.

ScriptableObjects don’t get attached to specific GameObjects in the way that MonoBehaviours do. You can’t use GetComponent to get a ScriptableObject because there are, by definition, NO scriptable objects attached to the game object. Ever. It’s unclear what you think this would do.

Some of your scripts have public RNode rNode;. If that variable already contains a reference to the specific RNode you are interested in (perhaps assigned via the inspector), then to access that RNode you just use the variable. For instance, you could write ā€œrNode.typeā€.

If you want to access the rNode variable on one component from another component, then you can use GetComponent to get the component that contains the variable, and then access the variable from there.

If that variable doesn’t already contain a reference to the appropriate RNode, then you need to figure out some way of specifying which RNode you are interested in.

2 Likes

Hi Antistone,

thanks for your quick reply!

Sorry for being so misleading, yes I was confused. And I got even more confused by your answer because duhhh, that’s exactly what I’m trying to do :smile: Anyway reading more carefully I got your point and added this to draggable.cs:

RNodeDisplay z = gameObject.GetComponent<RNodeDisplay>();
Debug.Log("And this is " + z.rNode.timeAge);

Now it works. I think I simply needed to store the information in a variable first. Will dig deeper though, maybe I don’t even need to temporarily store the ā€œzā€ variable.

Thanks again, seems to work for now…

1 Like