Unity TextMeshProUGUI.text is NullReferenceException ... not set to an instance [duplicate] - c#

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 3 years ago.
I've been looking around for a possible solution but I don't solve It... This is the problem:
I have in a file with its class the various Ui, including the textmesh.
Another file, with its own class, retrieves and sets them via ".text"
result?
"NullReferenceException: Object reference not set to an instance of an
object Controller_RaceManager.Update () (at
Assets/[GameAssets]/Controller
[MobileCar]/Scripts.Code/Controller_RaceManager.cs:307)"
to better understand:
A) into Controller_UiManager.cs (attached to the canvas with all UIs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI; using TMPro;
public class Controller_UiManager : MonoBehaviour
{
[System.Serializable]
public class UiSettings
{
public TextMeshProUGUI Label_Lap;
}
[SerializeField]
[HideLabel] public UiSettings UiElements;
void OnDrawGizmos()
{
var Canvas = this.gameObject;
UiElements.Label_Lap = getTheChild(Canvas, "Label.PilotLap").transform.GetComponent<TextMeshProUGUI>();
// note: getTheChild is a method that returns the child gameObject
}
}
B) Controller_RaceManager.cs, which of course handles all the values ​​of races (It's attached to his prefab for loops and bla bla bla)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; using TMPro;
public class Controller_RaceManager : MonoBehaviour
{
[System.Serializable]
public class RaceManagerSettings
{
...
public Controller_UiManager UiManager;
}
[SerializeField]
[HideLabel] public RaceManagerSettings sets;
void OnDrawGizmos()
{
if(GameObject.Find("Ui-RaceLoop"))
{
sets.UiManager = GameObject.Find("Ui-RaceLoop").transform.GetComponent<Controller_UiManager>();
}
else
{
Debug.LogError("Controller Race Manage: Ui System not founded - Ui-Raceloop prefab is not in scene");
}
}
void Update()
{
string Label_Lap_Output = "";
if(...) { Label_Lap_Output = "FINISHED";}
else if(....) { Label_Lap_Output = "LAP XX/"+totalloopText; }
else { Label_Lap_Output = "LAP O"+pilotlapText+"/"+totalloopText; }
sets.UiManager.UiElements.Label_Lap.text = Label_Lap_Output;
}
}
here unity pauses and gives notice. If I take the break, it continues quietly ... but am I becoming stupid?
is there a reason?
note: Unity TextMeshProUGUI.text is NullReference not "why not all or some things" ... but textmeshpro.

Solved.
I didn't understand why the It was taken from other scripts but, with TextMesh, no.
So it was obvious that I was wondering about him (in part it was right! Because on the buttons it doesn't happen... the "ui controller" is taken via editor OnDrawGizmos function)
The solution:
TextMesh must be initialized in Start or Awake. If you try a taken it directly from the editor with OnDrawGizmo, even if you reset or empty the caches, will be null.
If instead, in start or awake:
void Start()
{
// find ui elements
sets.UiManager = GameObject.Find("Ui-RaceLoop").GetComponent<Controller_UiManager>();
}
The infamous works ... I have no idea why it happens, maybe they are different procedures between the two functions.

Related

Detecting variables outside method

I was trying to make a 2d Unity Latin translator, but i got a problem. How could i make that it recognises the Text and Dropdown variables already inside the "Declinatio". I need to check for the last 2 characters of this string which is SGenTextStr, and the data should be taken from the SGenText InputField. I dont know if you got a fix for this, i didnt find anything that was helpful on the internet.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
public class LatinDecl : MonoBehaviour
{
public static void Declinatio()
{
string SGenTextStr;
string AnsTextStr;
int StrLength;
SGenTextStr = SGenText.text;
AnsTextStr = AnsText.text;
StrLength = SGenTextStr.Length();
switch (SGenTextStr.charAt(StrLength - 2) + SGenTextStr.charAt(StrLength - 1))
{
default:
break;
}
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
InputField SGenText;
Dropdown DeclDrop;
InputField AnsText;
}
}
One of the things you may use a lot in Unity games is the Gameobject.GetComponent<>() method. It allows you to access values and functions from other components or scripts in your Unity Scene.
There are also an issue with declaring your variables in Update() as it will cause them to be wiped clean every frame, instead you may want to move them outside all together.
Because of that you will also have trouble with Declinatio() as it is currently static, which wont allow it to reference any non-static variables outside of it.
The last issue is that C# doesn't actually have an implementation of String.charat() however you can use String[int] to achieve the same thing.
With all those changes it would look something like this:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
public class LatinDecl : MonoBehaviour
{
public InputField SGenText;
public Dropdown DeclDrop;
public InputField AnsText;
public void Declinatio()
{
string SGenTextStr;
string AnsTextStr;
int StrLength;
SGenTextStr = SGenText.GetComponent<InputField>().text;
AnsTextStr = AnsText.GetComponent<InputField>().text;
StrLength = SGenTextStr.Length;
switch (SGenTextStr[(StrLength - 2)] + SGenTextStr[(StrLength - 1)])
{
default:
break;
}
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}

Why I don't see the reorderablelist in the editor in the inspector?

The goal is to create a simple reorderable list.
For now it's not showing anything in the inspector.
The mono is attached to empty gameobject :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ReorderablelistTest : MonoBehaviour
{
[HideInInspector]
public List<Transform> myTransforms = new List<Transform>();
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
The editor is in the Editor folder :
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
[CustomEditor(typeof(ReorderablelistTest))]
public class ReorderablelistTestEditor : Editor
{
private ReorderablelistTestEditor reorderablelistTestEditor;
[SerializeField] private ReorderableList myTransformsList;
private SerializedProperty myTransforms;
private void OnEnable()
{
reorderablelistTestEditor = (ReorderablelistTestEditor)target;
myTransforms = serializedObject.FindProperty("myTransforms");
myTransformsList = new ReorderableList(serializedObject, myTransforms)
{
displayAdd = true,
displayRemove = true,
draggable = true,
//drawHeaderCallback = DrawMyTransformsHeader,
//drawElementCallback = DrawMyTransformsElement,
/*onAddCallback = (list) =>
{
}*/
};
}
public override void OnInspectorGUI()
{
serializedObject.Update();
myTransformsList.DoLayoutList();
serializedObject.ApplyModifiedProperties();
}
}
For start I want to see the simple reorderablelist of myTransforms List in the inspector.
so first of all you should see a big InvalidCastException for
reorderablelistTestEditor = (ReorderablelistTestEditor)target;
what you want here is not a ReorderablelistTestEditor but rather the targeted type ReorderablelistTest.
Right after fixing this it "works" for me, the list appears in the editor BUT of course still without any drawer for the elements still you haven't implemented that yet so with fixing it to
private ReorderablelistTest reorderablelistTest;
...
reorderablelistTest = (ReorderablelistTest)target;
currently it will look like
In general
Be aware that in newer Unity versions actually the reorderable list is finally the default drawer for any list/array so you might not even need this at all.
Careful with the target. Usually you don't really need access to it. Whenever possible rather go through the SerializedPropertys.

What could be causing selection to be missing activeGameObject?

I am getting the following error trying to build an editor window in Unity 2019.3.14f:
Assets\Editor\CellViewer.cs(19,40): error CS0117: 'Selection' does not contain a definition for 'activeGameObject'
I have found evidence of a single person with this specific error on the unity answer board, but there are no answers or updates in 5 years. I have reloaded the project, restarted unity, and restarted my system multiple times since this error first appeared.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class CellViewer : EditorWindow
{
private Map map;
[MenuItem ("Window/Cell Viewer")]
public static void ShowWindow() {
EditorWindow.GetWindow(typeof(CellViewer));
}
void OnGUI () {
if(Map.isInstanceActive())
{
GameObject obj = Selection.activeGameObject;
Tile tile = obj.GetComponent<Tile>();
if(tile != null) {
map = Map.Instance();
loadCell(map.getCell(tile.coordinates)));
}
}
}
}
How could this have happened, and what can I do about it?
This can happen if the classname Selection is ambiguous because you've created a class by that name in the global namespace.
To make sure you're using the correct one you can have your code be explicit by adding:
GameObject obj = UnityEditor.Selection.activeGameObject

Unity can't acess prefab's script's variable

I am working on a 3D game on Unity but recently a problem occurred. I can't access a variable from another prefab's script. I tried it before when the object which has to be accessed wasn't a prefab and it worked correctly.
This is the script which tries to access the "slashtime" variable, but when I run it gives back 0 though in the other script the variable is changing continuously.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class collision : MonoBehaviour
{
public GameObject sword;
public float slashtime;
private void Update()
{
slashtime=sword.GetComponent<movement>().slashtime;
}
private void OnTriggerEnter(Collider collider)
{
if (collider.tag == "sword" && slashtime+1f > Time.time)
{
Destroy(gameObject);
}
}
}
You can use this. It is also working.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class collision : MonoBehaviour
{
public GameObject sword;
public float slashtime;
private void OnTriggerEnter(Collider collider)
{
sword = collider.gameObject;
slashtime=sword.GetComponent<movement>().slashtime;
if (collider.tag == "sword" && slashtime+1f > Time.time)
{
Destroy(gameObject);
}
}
}
Reason for your code is not working because when you write some code in update then it calls every frame. so when your object is destroyed, update call that code and it shown error.
Reworking your code a bit, with explanations below:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class collision : MonoBehaviour
{
[SerializeField]
private GameObject _sword;
private float _slashTime;
private void Start()
{
_slashTime = GameObject.Find("Movement").GetComponent<Movement>().GetSlashTime();
}
private void OnTriggerEnter(Collider collider)
{
if (collider.CompareTag("sword") && _slashTime + 1f > Time.time)
{
Destroy(gameObject); // What is gameObject in this context? the _sword? something else?
}
}
}
Use private properties. Why? Because it increases modularity and protects the object(s) you're working with from accidentally having their values overwritten.
In conjunction to this, use public methods to obtain/change the values in other objects. Public methods are your API.
It's convention to begin the names of private properties with an underscore.
Like I said in my comment above, you first need to Find() your desired object before you can attempt to GetComponent<T>().
Like others have said, attempting to GetComponent<T>() in Update() is computationally expensive. It's better to get that component at Start() and then talk to it as necessary (in this case, during collision).
CompareTag() is the more modern/accepted way to check a tag.
EDIT:
[SerializeField] will keep the property private while also making it available to the Unity editor. It's good for debugging and linking objects.

Unity GameOver Screen

I am just trying to activate game over screen when the Player's activate is 'false'. There is no animation, just the
There are 3 objects that need to be active and i added the script to those 3 objects but the screen does not appear.
How can i fix?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameOverManager : MonoBehaviour
{
public GameObject _player;
void Start()
{
_player = GameObject.FindGameObjectWithTag("Player");
}
void Update()
{
if (_player.activeInHierarchy == false)
{
gameObject.SetActive(true);
}
else
{
gameObject.SetActive(false);
}
}
}
My suspicion is the following. Whenever a Gameobject is not enabled, its code does not run. Test this by adding a Debug.Log("test") message.
If no message appears you can be certain that this check is never evaluated. To work around this simply add a script that is bound to an active gameObject. Creat a new empty gameobject in the scene. And add something like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameOverManager : MonoBehaviour
{
public GameObject _player;
public GameObject _endscreen;
void Update()
{
if (_player.activeInHierarchy == false)
{
_endscreen.SetActive(true);
}
else
{
_endscreen.SetActive(false);
}
}
}
Assign the Variables in the Inspector by dragging the object to the empty fields. Never use GameObject.Find Methods.
If you need any further help tell me :)
What you're currently doing is to find a single GameObject and checking whether that is active or not.
It would make more sense, and be more optimized, if each player object adds himself to a list of all players when he spawns. You can then loop over that list instead to check all players.
An even better way would be if you only call that "GameOver" check after a player has died. So when you call whichever method kills him.
Based on Franz Answer, I did some modification in the code. You won't need any if else statement if you use a shortcut.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameOverManager : MonoBehaviour
{
public GameObject _player;
public GameObject _endscreen;
void Update()
{
_endscreen.SetActive(!_player.activeInHierarchy);
}
}

Categories

Resources