How to gets variable information of other scenes c# unity3d - c#

I'm trying to make a script that reads the variables of another script and stores them in itself, but I canĀ“t get the data stored and I don't know how else to do it, please help.
Unity 2019.1
public class contenedor2 : MonoBehaviour
{
public string elemento1;
public void finalizado()
{
contenedor elementos = GetComponent<contenedor>();
elemento1 = elementos.contenedor1;
}
But the script does not read the variables
(
contenedor is a script associated with an element of another scene which contains the variables that I want to read)

You cannot. If a scene is not loaded, then it effectively does not exist until it is loaded.
What you might try instead is putting the script with the data into a prefab that's used by all scenes that need it. If it's script-only variables, you could also try a static class, but then you need to manage the initialization and shutdown yourself.

With your current code structure, Your contendor class can have the variable as static.
Your contenedor class
public class contenedor : MonoBehaviour
{
public static string elemento1;
}
Your New contenedor2 class:
public class contenedor2 : MonoBehaviour
{
public string elemento1;
public void finalizado()
{
elemento1 = contenedor.elemento1;
}
PS: Code can be improved, Let me know if it helps.

Related

Is it the right way to reference other script if it doesn't have MonoBehaviour?

I'm making a saving system for my mobile game. I have a script for economy that tracks the amount of in-game currency and i'd like to reference a non MonoBehaviour script that will hold the data to save
public class Money : MonoBehaviour
{
public int Gold;
public int Platinum;
public int Tokens;
public DataHolder data;
private void Update()
{
data.Platinum = Platinum;
data.Tokens = Tokens;
data.Gold = Gold;
}
}
public class DataHolder
{
public int[] dragonLevel;
public bool[] dragonMasterLevel;
public int Gold;
public int Platinum;
public int Tokens;
}
Will unity automatically get the reference and will it properly transfer this data?
You are allowed to use your own classes / structs in Unity. Unlike Unity components like ScriptableObject and MonoBehaviour, you need to create them and make sure they get deleted.
ScriptableObject
public class DataHolder : ScriptableObject {
...
}
ScriptableObjects are Unity's solution for exactly your use case. You can then create assets that are instances of DataHolder.
In this solution the data gets serialized with the GameObject so you can have default values in Unity Editor Inspector.
Keep using DataHolder as is
private void Update () {
if (data == null) data = new DataHolder();
...
}
In both these solutions the runtime values will not persist between sessions. To save values and restore them there are different options. Here are a few in order of simplicity:
PlayerPrefs:
Add WriteToPrefs() and LoadFromPrefs() methods to DataHolder.
FileSystem
online databases like Google Firebase
Adding to the other answer, you could just create an object of your DataHolder class in one of your monobehaviours, and call DontDestroyOnLoad on the gameObject. you will also need to use the code below in Awake on your DontDestroyOnLoad() object to make sure only one instance of the MonoBehaviour is available, so you dont create duplicates when you navigate between scenes
public DataHolder dataHolder;
public static MyComponent myComponent;
private void Awake()
{
DontDestroyOnLoad(gameObject);
if (myComponent == null) myComponent = this;
else Destroy(gameObject);
dataHolder = new DataHolder();
}
now you can write to this dataHolder object and keep the GameObject alive in case you want to add any more data to it. It is good practice to have a persistant GameObject in the scene to save in-game data, or just about anything that needs to be preserved between scenes.
Alternatively, you can also make your DataHolder class static and it's members static. although i would advise against this, especially if there are multiple players/characters in your game that use the same component. But this will actually help you reference it from any script, without creating objects, or maintaining a persistent GameObject in the scene.

Better way to have static class / method access a gameObject variable from several scripts away?

TLDR: How can I have a script that inherits from a public abstract class have access to an often changing Enemy gameObject variable (so it can't be static) without passing it through several other scripts first?
In my game, I have a battle system where a different "Battle Event" gets loaded for each battle. Each "Battle Event" gets its own script, and each of those events inherits from the same BattleEvent parent (which is public abstract).
The code structure basically goes:
BattleSystem (main brain of battles which holds the Enemy
gameObject) ->
BattleEventsManager (handles both which BattleEvent to load, and which methods to run on that BattleEvent) ->
a random BattleEvent (BattleEventOne or BattleEventTwo etc)
public class BattleSystem : MonoBehaviour
{
BattleEventsManager battleEventsManager;
public Enemy currentEnemy;
// the Enemy data is passed when the battle starts
public void Start(Enemy enemyToLoad)
{
battleEventsManager = GetComponent<BattleEventsManager>();
currentEnemy = enemyToLoad;
}
public void BeginPlayerTurn()
{
battleEventsManager.SetupEvent(currentEnemy);
}
}
public class BattleEventsManager : MonoBehaviour
{
BattleEvent currentBattleEvent;
private void Awake()
{
// define this battleEvent
currentBattleEvent = GetComponent<BattleEventOne>();
}
public void SetupEvent(Enemy currentEnemy)
{
// start the battleEvent with its Setup function
currentBattleEvent.Setup(currentEnemy);
}
}
// inherits from `BattleEvent` parent class, shown below
public class BattleEventOne : BattleEvent
{
// override the method from the parent
public override void Setup(Enemy currentEnemy) {
// we can now use the data we need in `currentEnemy`
// all I wanted was to get access to `BattleSystem.currentEnemy`
// but i had to pass it down all the way here. Is there a better way?
}
}
// parent of all `BattleEvents`
public abstract class BattleEvent : MonoBehaviour
{
public abstract void Setup(Enemy currentEnemy);
} // end BattleEvent class
As you can see, the the currentEnemy variable needs to be passed down through 2 classes in order to get to where it needs to be: BattleEventOne.Setup().
Furthermore, I needed to add the Enemy currentEnemy param to the parent BattleEvent, which is problematic because not all BattleEvents will need this information.
I originally wanted to just call BattleSystem.currentEnemy from BattleEventOne (using a property or something), but because the BattleSystem is abstract/static, it can't access it. And because currentEnemy contains new data each battle, I can't make that a static variable.
So, how can I have BattleEventOne here access BattleSystem.currentEnemy without having to pass it down as I've done above?
(I still struggle a lot with passing information between scripts, so any help here is really appreciated!)

Calling an Object from another Script

This might be a super simple question, but for some reason I can't get it to work:
I have two scripts, both attached to the same GameObject.
One script has a dictionary:
public class RPG_Implementierung : MonoBehaviour
{
public Dictionary<string, string> StoryText = new Dictionary<string, string>();
void Start()
{
StoryText.Add("1", "This is the first Entry");
}
}
The other script wants to call that Dictionary. The method SendMessageToChat` is defined in this script and works well as long as it's not referencing the other script.
The first thing I tried didn't work, I get the Error:
CS0120 An object reference is required for the non-static field, method, or property
public class GameManager : MonoBehaviour
{
void Update()
{
if (Input.GetKeyDown(KeyCode.Y))
{
SendMessageToChat(RPG_Implementierung.StoryText["1"]);
}
}
}
I
this also doesn't work, it gives me the Error
CS0119 'RPG_Implementierung' is a type, which is not valid in the given context
public class GameManager : MonoBehaviour
{
void Update()
{
if (Input.GetKeyDown(KeyCode.Y))
{
SendMessageToChat(GetComponent(RPG_Implementierung).StoryText["1"]);
}
}
}
Can someone please tell me what I did wrong? In standard C# all I would have to do is to set the other class to public and then I can reference it and access it's objects, why doesn't this work in Unity?
To reference another component on a GameObject, you will need to grab that reference either by serializing the field in the inspector (Making it public or using the attribute [SerializeField].
I am not sure how many places you want to eventually call the method you are trying to invoke, but if it is from a bunch of different places, you might want to consider the Singleton pattern.
To quickly fix your current issue, on your GameManager.cs, do one of these two things:
public class GameManager : MonoBehaviour
{
[SerializeField] private RPG_Implementierung rpgImplement = null;
// OR
public RPG_Implementierung rpgImplement;
void Update()
{
if (Input.GetKeyDown(KeyCode.Y))
{
SendMessageToChat(rpgImplement.StoryText["1"]);
}
}
}
Edit: If you want to use the GetComponent in the Update here is how you would call it. I would advise against this as calling a GetComponent in an Update can be quite costly for performance if called frequently. It is better to store the reference to later use.
public class GameManager : MonoBehaviour
{
void Update()
{
if (Input.GetKeyDown(KeyCode.Y))
{
SendMessageToChat(GetComponent<RPG_Implementierung>().StoryText["1"]);
}
}
}

How to send integer value to another script?

I am making a game where the player first has to choose the type of control to use before playing. The three options being: Keyboard, Controller, Touch
The player must click the button corresponding to his choice. Each button runs this script when clicked on:
public class KeyboardButton : MonoBehaviour {
public static int controller;
public void buttonClick () {
controller = 1;
}
}
In reality, each button as its own script, where the value of controller is different depending on the script ran. The idea is that the value of this integer would be sent over to the script responsible of controlling the player so it will make use of the demanded input type. ie: if the keyboard button is selected, it will run the corresponding script, setting the integer value to 1. After the PlayerController script receives this value, it will know to only accept input from the keyboard.
I have consulted a lot of documentation, but a lot of it contains context-specific C# things that I don't understand and are irrelevant to what I want to do.
Also, I would not like an answer around the lines of: "You don't have to make the player choose a control type, here's how you can make your game accept all types of control at once." I already know all this stuff and there is a reason I want the player to make a choice. Furthermore, I would still like to know a way to transfer integers to be able to be more organized, rather than having a single script that does 90% of the things in the game.
There are three way you can pass value to another script.
GetComponent
You can use GetComponent method to get another script.
public class KeyboardButton : MonoBehaviour {
public int controller;
//this is anotherScript instance
public AnotherScript anotherScript;
Start()
{
anotherScript = GameObject.Find("Name of Object").GetComponent<AnotherScript>();
}
public void buttonClick () {
controller = 1;
anotherScript.sendValue(controller); //send your value to another script
}
}
Singleton
Let AnotherScript be a static Singleton,You can get the instance on other side.
public class AnotherScript : MonoBehaviour
{
//need to be static
public static AnotherScript Current;
Start()
{
if(Current == null)
{
Current = new AnotherScript();
}
}
public void sendValue(int val)
{
//todo
}
}
public class KeyboardButton : MonoBehaviour
{
public int controller;
public void buttonClick () {
controller = 1;
AnotherScript.Current.sendValue(controller);//send your value to another script
}
}
SendMessage
If you want to send a value to otherscript,SendMessage is a simple way you can choose.
ps:SendMessage method can just send a parameter.
public class KeyboardButton : MonoBehaviour
{
public void buttonClick ()
{
controller = 1;
GameObject.Find("name of object").SendMessage("sendValue",controller);
}
}
As pointed out in one of the comments, you already exposed that value, you can refer to is via
Debug.Log(KeyboardButton.controller);
without providing an instance. There's multiple other ways of doing it, as this way is only good to a certain level of complexity, after which it starts to get more muddy, but depending on what you need right know it might get you through. It is one of the valid ways, and probably the simplest one.
You may also want to know when the value has changed, for example you could use UntiyEvent and trigger it when value is changed
public class KeyboardButton : MonoBehaviour {
public UnityEvent OnValueChanged;
public static int controller;
public void buttonClick () {
controller = 1;
OnValueChanged.Invoke();
}
}
this is if you like to wire events in the editor. You could also do:
public class KeyboardButton : MonoBehaviour {
public static UnityEvent OnValueChanged;
public static int controller;
public void buttonClick () {
controller = 1;
OnValueChanged.Invoke();
}
}
the downside is that the event won't show up in the editor,but the upside is that you can set up a trigger without having to have a reference to the KeyboardButton instance that just got clicked.
public class ControllerChangeReactor : MonoBehaviour {
void Start()
{
KeyboardButton.OnValueChanged.AddListener(React); // add event listener
}
void React() // will get called when keyboard is clicked
{
Debug.Log(KeyboardButton.controller);
}
}
This approach can become limiting after you've written a dozen or so of those scripts, but a step up involves tailoring a custom system which is probably not worth it on your level (just yet). You can finish a simple game using the above approach, even if its not the most elegant.
You could also parametrize your script (expose 'WHAT DOES IT CHANGE' in editor), to avoid unnecessary multiplication of code

Access a non-MonoBehaviour script from another script (Unity)

I'm working on a Unity project and i would like to access a non MonoBehaviour script from another script.
I can't use GetComponent cause the script isn't MonoBehabiour, is there a solution ?
Here is some code to help you understand :
public class SomeClass {
public static float coolVar = 1.0f;
private string someVar; // EDIT : I need to access this var too and AnotherClass.someVar won't work obviously
public class AnotherClass {
// i want to be able to access coolVar and change her value
// i know i can do SomeClass.coolVar but i was looking for another way close to a GetComponent approach
My SomeClass class is full of static var i need to edit, i didn't implemented those variables and i can't modify them (i know it's bad practices).
Maybe the reflection is the best way :
typeof(SomeClasse).GetField(name).SetValue(null, value);
you only need to include the script with the not MonoBehaviour class inside the Assets path of the project and you will be able to use it inside other behaviour class.
Take care of use only .NET 2.0 specifications in the external class and if u have used a namespace on it add the using in the behaviour script.
#External class
namespace DefNamespace
{
public class ModelList
{
private static List<GameObject> models;
private ModelList ()
{
}
public static List<GameObject> Models{
get{
if(models == null) models= new List<GameObject>();
return models;
}set{
models=value;
}
}
}
}
And then in a MonoBehaviour or another class:
#Behaviour
using DefNamespace;
public class DefBehaviour : MonoBehaviour
{
Start(){
GameObject go=ModelList.Models[0];
}
}

Categories

Resources