Interacting with objects from different Scenes Unity 5 [duplicate] - c#

This question already has answers here:
Access variables/functions from another Component
(4 answers)
Closed 5 years ago.
Good afternoon! I've made a main menu in which you create your RPG character, in this menu I can take values from input fields/buttons that add/substract values from attributes, etc. Everything is stored within a class called CustomCharacterSheet, now this object has a DontDestroyOnLoad script that allows it to be moved into the next scene which is the first level.
In my playerbehavior class I have a method that takes a CustomCharacterSheet object and reads its values and then creates a character with the appropiate values, the problem is that when I want to use the method to generate the character on the Awake() within the playerbehavior, the method requires an object of type CustomCharacterSheet in order to be executed, but how do I tell this method that the CustomCharacterSheet that came from the main menu is the one that has to be read? I tried GameObject.Find(); but it will tell me it cant cast a GameObject to a CustomCharacterSheet class.
Here is the dummy code:
CustomCharacterSheetClass {
//Values, this was created into an object in the main menu with a DontDestroyOnLoad() script to be moved into the 1st Scene
}
PlayerBehavior Class {
private void generatePlayer(CustomCharacterSheet cs){
//Do Stuff, this method requires the CCS in order to pull data from it and generate the player
}
void Awake(){
generatePlayer();//This is inside the playerBehavior class and needs to reach the CustomCharacterClass created in the main menu that was later moved to the 1st Scene
}
}

GameObject.Find is made to find a certain gameObject by name not for finding a script.
Since you said that script was attached to a gameObject, what you need to do is call GameObject.Find("ObjectName") with the name of that object and then you can access the script CustomCharacterSheet with GetComponent
public class GetComponentGenericExample : MonoBehaviour
{
void Start()
{
GameObject gObject = GameObject.Find("ObjectName")
CustomCharacterSheet ccSheet = gObject.GetComponent<CustomCharacterSheet>();
}
}
GetComponent allows you to access any component of a GameObject.

Related

NullReferenceException: Object reference not set to an instance of an object in unity c# [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 1 year ago.
Im facing problem in accessing SerializeField inside the method that is implemented from a interface.
public class UIManager : MonoBehaviour, IGameOver
{
[SerializeField]
public GameObject gamePlayPanel;
[SerializeField]
public GameObject gameOverPanel;
[Header("Score-board")]
public Text coinScoreText;
public Text diamondScoreText;
private static int coinScore, diamondScore;
public void EndGame(string reason)
{
Debug.LogError(gamePlayPanel); // returning NULL
Debug.Log("Game Over: UI Manager " + reason);
gamePlayPanel.SetActive(false);
gameOverPanel.SetActive(true);
}
}
And the interface looks like below
public interface IGameOver
{
void EndGame(string reason);
}
Is there any other way of accessing SerializeField inside the EndGame() method which is overrided from IGameOver interface
Regardless of the implementation of the interface, the object itself and its children can always access public/protected functions and variables at any time.
So, in the code above, accessing the SerializeField instance inside the EndGame() function scope shouldn't be a problem.
Check out the two lists below.
First, make sure you have connected the Monobehaviour to the SerializeField in the Unity Editor's Inspector window.
Second, make sure that the gamePlayPanel and gameOverPanel objects are destroyed by the OnDestroy function at the moment the EndGame function is executed. This is a matter of order, so you need to think carefully about the order of execution of your code.

Object Reference Not Set to an Instance - Unity2D

I have this simple code to change the sprite of an image everytime I click a button.
using UnityEngine;
using UnityEngine.UI;
public class SampleChange : MonoBehaviour {
public Sprite sampleSprite;
public Image sampleImage;
public void Start()
{
sampleImage = GetComponent<Image>();
}
public void changeColor()
{
sampleImage.gameObject.GetComponent<Image>();
sampleImage.sprite = sampleSprite;
}
}
I attached this script to an EmptyGameObject and Loaded the function on the Button that is parented on a Canvas alongside the Image. I already also placed the Image and Sprite objects in the inspector:
Inspector Settings
When I run the game and click the Button, it gives me this error:
NullReferenceException: Object reference not set to an instance of an object
SampleChange.changeColor () (at Assets/Scripts/SampleChange.cs:18)
The cs:18 is the sampleImage.sprite = sampleSprite;. I really don't know why it's not working.
OK simple,
public Image sampleImage;
that means
you will set "sampleImage" variable in the inspector, in the editor, before you hit Play
But this one ..
sampleImage = GetComponent<Image>();
means
you will set "sampleImage" variable in code when the scene is running.
You have to sort it out and do it "one way or the other".
Suggest you use the first method while U learning.
(If you do use the second method, the "Image" must actually be on the game object which is holding the script in question. If you struggle with that, I would urge you to ask a separate question, or just study up on the basics using Unity tutorials.)
Cheers
It appears that you have no constuctor defined for your class and that you are just trying to call the changeColor() method as if it were a static function of the class. You need to construct objects of your class and then call the methods you defined on those objects, not on the class itself.

How to set different classes at runtime in Unity

I am making a game in Unity C# where the character will have different characterstics and movement functions in each scene. So I am trying to have different scripts for a player in different scenes, while all of them inheriting from the same base class. The definition will be something like below
public class PlayerScript1 : PlayerBase { /* for scene 1*/
public void Move(){
/* my movement code*/
}
}
Similarly, I have a separate class for Scene2 as
public class PlayerScript2 : PlayerBase { /* for scene 2*/
public void Move(){
/* my movement code*/
}
}
Now the problem is, my other scripts, like HealthScript,ScoreScript etc they do not change with scene. But they do access PlayerScript1 script. And thats why, I have the PlayerScript1 declaration in them. Like below:
public class HealthScript : MonoBehaviour {
PlayerScript1 playerScript;
void Start(){
/*accessing the script attached to game object*/
}
}
So how can I have my Health Script access different instances of my PlayerScript based on the scene? I know I could use delegates to call different methods in runtime, but how can I do the same with classes?
So how can I have my Health Script access different instances of my PlayerScript based on the scene?
Well first, you'll want to declare that object as of Type PlayerBase as you will be unable to assign an instance of PlayerScript2 to a variable of type PlayerScript1: those classes might inherit from the same parent, but they are not the same and you cannot convert from one to the other.
After that you will need to search for the player object in the scene, something like...
void Start(){
playerScript = GameObject.Find("Player").GetComponent<PlayerBase>();
}
Assuming, of course, that PlayerBase extends MonoBehaviour. If it doesn't you can't get a reference this way (as it won't exist in the scene at all). Additionally if you want this health object to persist from scene to scene, you need to call DontDestroyOnLoad() for it (as well as remembering that if you don't start testing from Scene 1 where this object is, it won't exist at all, or if you have a copy in every scene, you'll have duplication problems).
Someone answered to my question on the Unity forum which cleared all my doubts:
The key was using the below line in my HealthScript :
PlayerBase player = (PlayerBase)FindObjectOfType(typeof(PlayerBase));
http://answers.unity3d.com/answers/1348311/view.html

store a reference to a script to attach at runtime

Another best practice question. I have a list of ScriptableObjects now (thanks to LearningCocos2d) which defines a list of sprites I can load at runtime.
I followed this tutorial: http://www.jacobpennock.com/Blog/?p=670
In order to drive some custom behaviour, I want different scripts applied to my various in-game objects when I instantiate them. What's the best way to store the references to the desired scripts I want to apply?
[Edit] Some more details:
My scriptable object is a simple list of serializable objects. I have a series of defined scripts that I want to attach to the objects I define. Unity however does not seem to allow me to store a reference to the script using the below method.
public class TestList : ScriptableObject {
public List<MotionSpriteData> MotionSprites;
}
[System.Serializable]
public class MotionSpriteData {
public Component motionPath;
}
Create a class that loads all the scripts into an array. This class does not necessarily have to be a MonoBehaviour, but for this example it will be.
You have two options:
Drag and drop the scripts into the array via the Editor.
Or put all the scripts in the Resources/Scripts/ folder so that they can be loaded at run time.
public class ScriptManager : MonoBehaviour
{
public Object [] list;
void Awake()
{
// Comment this line if you used step 1 above.
list = Resources.LoadAll("Scripts");
gameObject.AddComponent(list[0].name);
}
}
Now you can use your own logic to determine which GameObject gets which Script, but that should be trivially easy for you.
Just coming back to this question, since my original answer is actually incorrect as someone pointed out. Monoscript stores references to individual scripts (strongly typed), but Monoscript is only valid in the UnityEditor namespace.
Since my question is about best practice, I offer what I have done as a proposal, but since I'm still only 2 months into Unity dev, I'm interested in other opinions. What I ended up doing is building prefabs for each object type, which leverages the power of the Unity WYSIWYG interface. Thus, storing references to scripts becomes irrelevant, since the prefab contains all the behaviours I need.
Since I still need a data layer for my game to drive the game play, my scriptable objects have hence become simpler. The problem of referencing the script becomes instead the problem of referencing the prefab which contains the scripts.
FunctionR has described in his answer how you can use Resources.Load to load content at runtime. However, my question is about how to reference the individual script I want. What I have done is simply store a path to the resource (ie: prefab) I want loaded, as a string.
Unity script assets are of type "MonoScript". Simply declare a variable as this type and it will work.
http://docs.unity3d.com/ScriptReference/MonoScript.html

GameObject creation order issue

I'm currently working on an inventory system in Unity3D, and came upon a weird problem. I have created non-MonoBehaviour classes for my inventory system (in case that matters), so that I have an Inventory class which holds a list of Slot objects, which in turn holds a list of Item objects.
Then I added a component script to my "HudInventoryPanel", called "HudInventoryController", which looks like this:
using UnityEngine;
using System.Collections;
public class HudSlotController : MonoBehaviour {
private InventoryController ic;
// Use this for initialization
void Start () {
ic = GetComponent<InventoryController>();
}
// Update is called once per frame
void Update () {
}
}
However, inside the Start() method, the InventoryController (part of my Player) hasn't been created yet, and it seems to me like the gameobjects are created in alphabetical order...?
How should I deal with this problem?
You can specify script execution order in the project settings (Edit -> Project settings -> Script execution order), so use that to make sure your scripts are executed in the correct order. In addition to that, you can use the Awake() method as all Awakes are executed before any Start() method. Hope a combination of these helps you!
I solved this by creating an intermediate variable in my InventoryController script, plus creating a "manual" getter; https://gist.github.com/toreau/f7110f0eb266c3c12f1b
Not sure why I have to do it this way, though.

Categories