- Home /
How to access and change scriptable objects on instantiated prefabs
Hi, been stuck on this for the last ten hours and going slightly mad.
So trying to create a deck of cards. I made this work in version 1 by creating a bunch of prefabs which were just images. One per card type (e.g. "Strike"). The card had a name, cost, picture and description, but they were just a single flat image. If I wanted to change the card had to be redo the picture. Single script with public gameobject variables for each card type, linked in the editor to matching prefab. A list to store the deck and a loop to instantiate the deck into a card space area [that's all I wanted to do at this stage]. Would use conditional logic later to check the card name and determine appropriate damage, apply effects etc. All worked fine, but limited... so...
Onto scriptable objects... I've scaled back a little, so I have an image with frames and a space just for title and description (I'll add more if I can make this work). Added title and description text fields to image (show as child objects in the hierarchy), created a prefab from it. Then setup scriptable objects with name and description and created those from the assets menu. Have three scripts which I'll attach below. It works, kind of but I have to drag a specific scriptable object onto the prefab. What I wanted was....
I wanted to be able to have just a single prefab, instantiate it and then be able to specify which scriptable object to load to populate it on the screen. So my first question (of two) is is that possible? or should I create multiple prefabs for each card type like before with different scriptable objects attached.. or something else?
Second question (sorry there's two) is how to then access that information elsewhere. So, even if I have one prefab for each card. if I instantiate a "Strike" and it has scriptableobject property of description or a mana cost, how could I access that from any script. My previous method of using a List of card names and checking the name + conditional logic won't work.
I hope that's not a dumb question, I'm still learning. Ok, here's the code, its limited with no actual deck, just producing a single card presently. If anyone can help I would be very appreciative. I have spent ten hours trying to find answers and reading a range of different options, none of which really cover what I'm trying to do.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
// Script to create new scriptable objects
[CreateAssetMenu(fileName = "New Card", menuName = "New Card")]
public class Card : ScriptableObject
{
public string cardtitle;
public string description;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
//script attached to the prefab
public class CardDisplay : MonoBehaviour
{
public Card Card;
public Text cardname;
public Text descriptiontext;
public void LoadCardData(ScriptableObject CardData)
{
cardname.text = Card.cardtitle;
descriptiontext.text = Card.description;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
// script attached to empty game objects
public class GameController : MonoBehaviour
{
// Linked the prefab here
public GameObject BaseCard;
// Area filling the canvas with grid layout
public GameObject CardArea;
public ScriptableObject CardData;
void Start()
{
GameObject PlayerCard = Instantiate(BaseCard, new Vector3(0, 0,0), Quaternion.identity) as GameObject;
// Call LoadCardData from the CardDisplay script to populate the text fields
PlayerCard.GetComponent<CardDisplay>().LoadCardData(CardData);
PlayerCard.transform.SetParent(CardArea.transform, false);
}
}
Answer by $$anonymous$$ · Mar 13, 2021 at 01:08 AM
You can use this
[CreateAssetMenu(fileName = "New Card", menuName = "New Card")]
public class Card : ScriptableObject {
public string cardtitle;
public string description;
}
public class CardDisplay : MonoBehaviour {
public Card card;
public Text cardname;
public Text descriptiontext;
public void LoadCardData(Card cardData){
card = cardData;
cardname.text = card.cardtitle;
descriptiontext.text = card.description;
}
}
public class GameController : MonoBehaviour {
// Linked the prefab here
public GameObject BaseCard;
// Area filling the canvas with grid layout
public GameObject CardArea;
public Card CardData;
private void Start(){
GameObject playerCard = Instantiate(BaseCard, new Vector3(0, 0,0), Quaternion.identity);
// Call LoadCardData from the CardDisplay script to populate the text fields
playerCard.GetComponent<CardDisplay>().LoadCardData(CardData);
playerCard.transform.SetParent(CardArea.transform, false);
}
}
And if you want to access just say CardDisplay.card.
And so on
If you have any questions tell me ill try to answer
@$$anonymous$$ That is absolutely awesome. Sorry it took a while to reply, it didn't work at first (I hadn't dragged the scriptable object onto the new Card Data field in the inspector). I can access that data now with carddata."property" now, but I think that might have given me a new issue. Because the scriptable object is now set on my gamecontroller game object rather than the prefab, what do I do if I want to create a different card? Is there a way through the script to specify which scriptable asset to load? I tried adding CardData.name = "Defend"; (a scriptable asset) to the gamecontroller objects [start] before instantiating and in the inspector it looked like it had worked, but the card information didn't change, plus it seemed to lock the new name in place and I had to reload the project before I could change it again.
Also its 2:41am so I will pick this up in the morning. :)
Ok, so I did get this working after a bit more playing. In GameController I defined each card type as a public card variable and dragged the appropriate scriptable object in the inspector. I was then able to instantiate the cards, looping a list of type Cards and got everything working. That did give me a different problem, that from another script I wasn't able to use "cardname.value" (e.g. Strike.description) which was working OK in the gamecontroller script. In the other script I also had to define each card type as a public Card to access the information and drag the scriptable object in the inspector a second time. I suspect this is down to errors in my thinking about the scriptable object, and the values applied to actual gameobjects instantiated (i.e. There is one type of card "Strike", but I'm instantiating six of them, all called Strike as well, but since all six cards are identical it kind of works for me). Anyway @$$anonymous$$ your code got me here and I'm super grateful, will mark this as answered and thanks a heap.
@Nickshepp Check this link out might help
Your answer
Follow this Question
Related Questions
How to share a script between multiple gameobjects but with different values 3 Answers
how can i test to see if there are more than one objects with a tag C# 1 Answer
looking for a way to set an integer to another number based on a condition. 2 Answers
How can I activate a GameObject Component of type script? 2 Answers
Leader board Getting no error but not showing scores 0 Answers