I have the following piece of code. I referenced the text component in the editor to no_lives. The gamemanager (singleton) is being instantiated a scene before. The debug.log() shows 5 in the console. But when I try to set the text I get that the reference is not set to an instance of the object. Why is that?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class level1_script : MonoBehaviour {
public Text no_lives;
// Use this for initialization
void Start () {
no_lives = GetComponent<Text>();
}
// Update is called once per frame
void Update () {
int lives_n = gamemanager.lives_f ();
Debug.Log (lives_n);
no_lives.text = lives_n + " x";
}
}
Are you certain that Start() was called before Update and that the GetComponent is actually setting a value to no_lives?
If not then code defensively. Also lives_n needs to be converted to a string lives_n.ToString() + " x" or use a format.
void Update () {
int lives_n = gamemanager.lives_f ();
Debug.Log (lives_n);
if(no_lives != null) {
no_lives.text = string.Format("{0} x", lives_n);
}
}
EDIT:
But when I try to set the text I get that the reference is not set to
an instance of the object.
That's because when you do GetComponent<Text>(), it will look for the instance of Text component on the-same GameObject your level1_script script is attached to.
You have two choices:
1.Attach Text component that GameObject your level1_script script is atached to then your current code should work.
2.If you already have the Text component attached to another GameObject, let's say an Object called "MyText", use GameObject.Find to find "MyText" then perform GetComponent on it to get the Text component.
no_lives = GameObject.Find("MyText").GetComponent<Text>()
Edit:
Well, both Text and script are attached to the same object
prntscr.com/f7p7vx
It's likely attached to multiple GameObject and the other GameObject does not have the Text script attached to it.
Select the level1_script script, go to Assets --> Find References in Scene then remove the duplicated script from other objects.
As the script logs '5' in the debug log, it seems to me that the variable lives_n is used correctly.
My guess is that the component "no_lives" isn't filled (that's what is often causing the "reference is not set to an instance of the object" error)
I suggest that you try to add the script to the UI Text object in your scene, this way the script finds the "Text" component on that object.
It's important to know the differences between objects and components, because they're both essential parts of unity. Objects are "things" in your scene, like cubes, cameras and stuff like that. Components on the other hand are part of object and define the properties of that object. For example: a camera object has a camera component to make it a camera and to make it actually viewable by the user.
The GetComponent<>() method searches for a (in your case) Text component on the object the script is attached to.
Hope this helps!
(oh and don't forget to remove the script from the other object you've placed it on, in case this works. Otherwise you'll still get errors)
Related
BreakableObject script is a foreign script that came attached to describe how barrels exploded. When those barrels explode, I want a new object to pop up in their place. So I've added the following to the top of the code:
public class BreakableObject:MonoBehaviour{
public GameObject gamePiece2;
One of the methods in this class, which houses the overall process, is coded as follows. Unimportant lines have been dashed out.
public void triggerBreak() {
//if(transform.parent.CompareTag("Winner"))
//{
//Destroy(transform.FindChild("object").gameObject);
//Destroy(transform.GetComponent<Collider>());
//Destroy(transform.GetComponent<Rigidbody>());
//StartCoroutine(breakObject());
//foreach (Transform child in transform.parent)
//{
// GameObject.Destroy(child.gameObject);
//}
//animalSpawn = Random.Range(0, 4);
Instantiate(gamePiece2, transform.position, Quaternion.identity);
}
}
Lastly, I have verified (with 'Find References in Scene') that this script is only applied to one empty Game Object titled 'Animal Array' and that I have assigned a reference object in the inspector, as seen the attached picture.
Nonetheless, I still get an 'UnassignedReferenceException' saying that gamePiece2 of BreakableObject has not been assigned. Any thoughts?
#UnholySheep: My main script is called game manager. This is a side script defining when a barrel will explode. My goal is to have it instantiate an object where the barrel was right when it explodes. It seems easiest to do that in the barrel script.
This image is where I thought I assigned it
I have a prefab, which is used multiple times in my game (it will not be instatiated during runtime, I only use the prefab by dragging it into scene view to build my level).
Inside this prefab are many locations, where a specific text is written. This text is unique for every prefab.
So, it is like:
InstanceA
TextA (multiple times inside the instance)
InstanceB
TextB (multiple times inside the instance)
and so on ...
At the moment, I see two options to do it:
I change every text manually in every instance. This would work, but is a little annoying, also I can see me making mistakes (like a misspelling or forget to change one of the texts).
I solve it by a script and change the texts in the Awake or Start method. This would work, but it must be done every time, I start the game.
What I would hope for would be a solution like 2) but not every time (because nothing changes, it es every time the same) but only once - so it is generated by a script but after that, it will be always there. Even when I'm not in runtime and just work in the scene view.
Do you know any approach to get something done like this?
Thank you!
If you wish to run a piece of code outside the run-time, you can use one of the following two options.
OnValidate method
OnValidate is triggered when your MonoBehaviour script is loaded or an inspector value has changed.
using UnityEngine;
public class TestScript : MonoBehaviour
{
private void OnValidate()
{
Debug.Log("test");
}
}
ExecuteInEditMode attribute
Adding ExecuteInEditMode to a MonoBehaviour class will make it function both during and outside the runtime. If you do not wish the script to function during the runtime, feel free to also use Application.isPlaying.
using UnityEngine;
[ExecuteInEditMode]
public class TestScript : MonoBehaviour
{
private void Update()
{
if (!Application.isPlaying)
Debug.Log("test");
}
}
I've followed this tutorial (https://unity3d.com/pt/learn/tutorials/projects/roll-ball-tutorial/displaying-score-and-text) to make a Text updates every time my scripted score changes and it worked fine.
But i'd like to use TextMeshPro instead of the simple Text.
I've already made all the necessary changes in my code, such as:
using TMPro
public TextMeshProUGUI scoreText; (instead of public Text scoreText)
scoreText = gameObject.GetComponent(); (inside void Start())
scoreText.text = "Score: " + score.ToString(); (inside my function)
When in Play Mode I receive the "NullReferenceException: Object reference not set to an instance of an object" message.
I discovered the reason. When I enter Play Mode, I see in the Inspector that the TextMeshProUGUI that was assigned to the script is automatically unassigned.
I've made a stand alone script and added to a TextMeshProUGUI to check if my code was working with TextMeshPro, and it was.
The thing is: I don't want one separated script only to update the TextMeshPro. I need, as the tutorial above, the TextMeshPro being a public variable inside a big script with all other functions.
If, after I enter Play Mode, I assign the TextMeshProUGUI manually by dragging it to the Inspector, the Score works!
Why Texts, preFabs and everything stay assigned to my gameObject when I enter Play Mode, but the TextMeshProUGUI doesn't?
I think the code is ok, because it works if I assign the TextMeshProUGUI manually. But, anyways...
public class SnakeController : MonoBehaviour
{
public TextMeshProUGUI scoreText;
private int score;
void Start()
{
....
scoreText = gameObject.GetComponent<TextMeshProUGUI>();
score = 0;
setScoreText();
}
public void setScoreText()
{
scoreText.text = "Score: " + score.ToString();
}
}
The big issue is the TextMeshProUGUI be unassigned in the moment I enter Play Mode.
Your textmesh does not get "automatically unnasgined". You are explicitly telling it to assign something else, on this line:
scoreText = gameObject.GetComponent();
Your textmesh is probably not on the same object as the controller, as it needs to be child to a canvas to work. So that command is not finding what it's looking for, returning null, and thus assigning null. Use GetComponentInChildren<TextMeshProUGUI>() or FindObjectOfType<TextMeshProUGUI>() instead. Depending on if the textmesh is decendant of the controller object or on a different object entirely. And since you are assigning through script, don't worry about assigning in the inspector. In fact, make the field private so it doesn't even show up in the inspector.
Or assign in the inspector and remove the script assignment. Doing both is unnecessary, redundant and confusion- and error-prone. As you just found out.
how can I display 3D text after certain time then hide it after certain time
My tries
public Text text_tap;
GameObject.Find("3dtext").active = true; // first try but it dosnt work
if (Time.time > 5) {
// second try but it I cant attach my 3d text to my script
text_tap.gameObject.SetActive(true);
}
I cant find any thing in 3D documentation
I don't know the exactly problem, but there you have some hints:
If you search in the scene for a GameObject that is deactivated it won't find it. The Gameobject MUST be active for the GameObject.Find() function to work. The easiest thing you can do is to keep the GameObject activated, and if the initial state is for it to stay hidden just hide it in the Awake().
Secondly, seems that you are trying to access a TextMesh object
but you reference in your code a Text object.
If you find a GameObject and request a Component that the GO does not contains, it returns null.
Finally The api to Activate/Deactivate a GameObject (GO) is
myGameobject.SetActive(true)
The one you are using (myGameobject.active = true) is deprecated
Try this example, it should work:
public YourMonoBehaviour : MonoBehaviour
{
public TextMesh text_tap;
float awakeTime;
void Awake()
{
// Remember to activate the GO 3dtext in the scene!
text_tap = GameObject.Find("3dtext").GetComponent<TextMesh>():
awakeTime = Time.time
}
void Update()
{
if ((Time.time - awakeTime) > 5)
{
// second try but it I cant attach my 3d text to my script
text_tap.gameObject.SetActive(true);
}
}
}
If you need to "do something after a delay" you're talking about Coroutines.
Checking Time.time will only check if the game has been running for x time, and using Thread.Sleep in Unity will cause it to delay since you're causing an Update or similar to lock and not return.
Instead, use
yield return WaitForSeconds(5);
text_tap.gameObject.SetActive(false);
As another warning, this code assumes that the target object is not the same gameObject as the one hosting this script, since coroutines do not execute on inactive objects. Similarly, disabling an ancestor (via the scene hierarchy, or transofrm.parent) of a gameObject disables the gameObject itself.
If this is the case, get the component that renders 3d text and disable it instead of the whole gameObject via the enabled field.
you can also use Invoke() to achieve. as explained above note that the text would have to be set by other means than Find cause if it is not active it will not find it.
void Start() //or any event
{
Invoke("ShowTextTap", 5f);//invoke after 5 seconds
}
void ShowTextTap()
{
text_tap.gameObject.SetActive(true);
//then remove it
Invoke("DisableTextTap", 5f);
}
void DisableTextTap()
{
text_tap.gameObject.SetActive(false);
}
I am making a small 2d click'n'point in Unity, and what I want to do is: I want to move towards the door and when my Player steps on a game Object with an attached SceneSwitcher Script he shall go through the door, into another scene. That works fine so far. Now I don't want him to appear in the middle of the room, but on the door, where he entered the room.
using UnityEngine;
using System.Collections;
using PixelCrushers.DialogueSystem;
public class ScenSwitcher : MonoBehaviour {
public string SceneName = "";
void OnTriggerEnter2D(Collider2D other) {
SwitchScene();
}
void SwitchScene(){
LevelManager levelManager = DialogueManager.Instance.GetComponent<LevelManager>();
levelManager.LoadLevel (SceneName);
changePosition ();
Debug.Log ("Scene Wechseln nach: " + SceneName);
}
void changePosition(){
GameObject player = GameObject.Find("Player");
player.transform.position = new Vector3(12,12,0);
}
}
That is my code, it does change Scenes, but not change the position. I would appreciate any help :)
On your ChangePosition() method you are passing hardcoded values to player position and it will assume always (12,12,0) on your scene space.
You need to define a spawn manager where you will get dynamically witch spawn point in your scene you want to use.
edited:
1: Try to create a singleton GameManager ( you can find singleton pattern examples here ) (IMPORTANT: Add DontDestroyOnLoad on your GameManager Awake).
2: In your GameManager define a Vector3 NextPosition property or something like this.
3: Declare a public Vector3 Destination on your "teleport" script to set it per teleport on inspector/editor.
4: Before this line levelManager.LoadLevel (SceneName) of code set GameManager.NextPosition = this.Destination;
5: If you are not persisting your character between scenes just call on one of hes behaviours Awake() or, if he persists create a method void OnLevelWasLoaded(int level) and chage players position setting GameManager.NextPosition ( wisely testing if it is valid for the current level before ;) ).
I cant try or do better coding now because I don't have access to unity editor so I hope it helps at last start a good research to solve your problem =/.
I would think the loadLevel function destroys the current script so changePosition does not get executed? I could be wrong.
Even if it is getting executed, there is a good chance it is executed before the level load and the properties for the next scene override where it got moved to.
I forget the exact syntax but look into getting GameObjects to not be destroyed on scene change.
EDIT
Object.DontDestroyOnLoad