I'm developing a simple game in Unity 2017 in C#.
In my levels menu I have a Text object with a button component in it, and a script attached to it.
This is what's currently in the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class LevelLock : MonoBehaviour {
public bool isLocked = true;
private Button lvlBtn;
// Use this for initialization
void Start () {
lvlBtn = GetComponent<Button> ();
if (lvlBtn != null) {
Debug.Log ("this should be working");
} else {
Debug.Log ("you did something wrong");
}
//if(isLocked){
// lvlBtn.enabled = false;
//}
}
}
The problem is, that GetComponent<Button>() is returning null, meaning it's not finding the button component in the object.
I tried adding an Animator component and perform the same operation just to check and it did work, so I have no clue why it shouldn't find the button component. If anyone could help with this or point out to me something i'm doing wrong, I would really appreciate it
EDIT:
Inspector tab:
Console tab:
Your screenshot shows that you attached the LevelLock script to the Button which is fine.
Possible reasons and fixes:
1.The component/script is not even attached to the GameObject or is attached to the wrong Object.
In, your code, calling GetComponent<Button>(); without finding the GameObject first means that GetComponent should look for a Button component that is attached to this GameObject this script(LevelLock) is attached to.
If the script you want to retrieve, is attached to another GameObject, you can solve this by first, finding the GameObject the Button component is attached to with GameObject.Find then retrieving the Button component/script from it.
Replace
lvlBtn = GetComponent<Button> ();
with
GameObject obj = GameObject.Find("lvl 2");
lvlBtn = obj.GetComponent<Button>();
3.Script is attached to multiple Objects
One of the reasons GetComponent<Button>() might return false is because you mistakenly attached the LevelLock script to another GameObject. It could be an empty GameObject but that GameObject doesn't have the Button component attached to it.
Find this GameObject and remove the LevelLock script from it.
To do that, select the LevelLock script from the Project tab then Go to Assets ---> Find References In Scene. Remove the LevelLock script from other GameObjects.
This will make sure that the LevelLock script is only attached to the "lvl 2" GameObject
3.Multiple scripts with the-same name but in different namespace:
If you have two classes with the-same name but in different namespace and you attached one to the GameObject while trying to access the other one from code, it will be null since they are not the-same. I looked into your project and this was the Problem.
You created a script named "Button" while Unity comes with it's own built-in script/component also named "Button" which is in the UnityEngine.UI namespace.
You attached the Unity's built-in "Button" script to your GameObject but then you are trying to access your own made "Button" script from the script. Supply the namespace which is UnityEngine.UI so that Unity will know that you want to use the Button component that comes with Unity.
Change:
vlBtn = GetComponent<Button> ();
to
lvlBtn = GetComponent<UnityEngine.UI.Button>();
Also change:
private Button lvlBtn;
to
private UnityEngine.UI.Button lvlBtn;
Finally, do not name your script the-same name as any built-in component like Button, Image, Text, Rigidbody and so on. Create a class name and make sure that it doesn't exist with Unity API otherwise you'll continue to run into such issues and even people on SO won't be able to help you unless they have access to your project.
Related
I'm having trouble assigning two Buttons to the Prefab after it is instantiated.
The buttons are in the scene and i don't know how to assign them.
Drag and Drop doesn't work of course. I'm aware of that.
When I make something like
btnnext = GameObject.Find("Next").GetComponent<Button>();
in the Start() function of the Prefabs script it doesn't work either.
Are there any other workarounds?
As #slowikowskiarkadiusz said GameObject.Find is not the best solution, because it's slow and error prone. But there is an easy solution.
On the script which is placed on the prefab make a public function, called AssignButton:
class ScriptOnPrefab : MonoBehaviour {
public void AssignButton(Button button) {
btnnext = button;
}
}
In the script where you instantite the prefab, you then link the buttons and assign them:
var instance = Instantiate(prefab);
var scriptOnPrefab = instance.GetComponent<ScriptOnPrefab>();
scriptOnPrefab.AssignButton(button);
Note: For this to work that the ScriptOnPrefab has to be on the root of the prefab, note on child objects.
Note: prefab is linked as a GameObject.
Note: If you link the prefab as ScriptOnPrefab you can skip the GetComponent step and immediatelly call the Assign method.
By 'doesn't work either' you mean that btnnext is null or you mean that .GetComponent<Button>() throws an exception? The first case would mean the object named "Next" that was found doesn't have a Button component on it. You can check if you're expecting it to have the Button component or maybe something slightly different. You could also have multiple objects named "Next" and the one you're getting is not the one you expect to get. The second case would mean that your object is most likely inactive. Find(string) doesn't search within inactive objects.
That being said - Find(string) is not reliable in any capacity and I would advice to avoid it (it's also terribly slow). Instead I would create a script to be placed on the object with the button. Inside of that script in the Awake() method I would assign the instance of the Button component to some kind of a public static field, so the other script can later pick it up (if you are dealing with two buttons it might be a list or two separate fields. Depends on your case I guess).
I'm a beginner in Unity and C#. I tried building a basic game where the GameObject's presence in the scene is toggled when a key is pressed. The GameObject does disappear when I press "Space", but it never appears when I press the same key again. The following is the code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour {
private GameObject aj;
private bool flag = true;
void Start () {
aj = GameObject.FindGameObjectWithTag("robo");
}
void Update () {
if (Input.GetKey(KeyCode.Space))
{
flag = !flag;
aj.SetActive(flag);
}
}
}
Please let me know where the error lies.
Posting this as answer for future viewers:
The main reason that the gameobject doesn't reappear is because when you turn off the object, the script attached to it is disabled as well. In order to fix this, you must have the script to disable it, on a different object. I usually use a manager object which is just an empty gameobject with scripts on it.
A secondary issue in your code is that you're using if(Input.GetKey(KeyCode.Space)) in update which will try to change it every frame. Change it to if(Input.GetKeyDown(KeyCode.Space)) to have it only be true on the first frame pressed.
From a first view the code seems correctly, the only problem that I could figure it out is that you disable the object where the script is placed or his parent, and so the script won't be executed the second time.
P.s. I recommend you to not use that "flag" variable, instead would be more precise to use the GameObject.activeSelf attribute.
I have a fadepanel gameobject in my scene that has to sit on top of all the other gameobjects. However, when I click on an object int the editor window, since this gameobject is on top of all, is the one that is automatically selected in the hierarchy.
Is there a way to keep the gameobject on top of the canvas, as it is right now, but make it completely unselectable wIen i click on my scene?
You can use HideFlags on gameobject to make it unselectable:
public class HideFlagsSetter : MonoBehaviour
{
public Component target;
public HideFlags customHideFlags;
public enum Mode
{
GameObject,
Component
}
public Mode setOn = Mode.GameObject;
[ContextMenu("Set Flags")]
private void SetFlags()
{
if (setOn == Mode.GameObject)
{
target.gameObject.hideFlags = customHideFlags;
}
else if (setOn == Mode.Component)
{
target.hideFlags = customHideFlags;
}
}
}
Setting customHideFlags to HideInHierarchy would make it disappear from hierarchy so you won't be able to select it.
Edit: As the object will disappear, there is no way to bring it back if you can't access the script. So this script should be attached to a persistent object and target object should be set in the inspector.
You can use Context menu option by clicking on the gear icon in the top right corner and choose "Set Flags". its the last option in the menu.
Read more
Hope this helps :)
(ADDED BY PERSON WHO ASKED THE QUESTION)
I wanted a way for this to automagically happen on editor mode. So i did the same steps, but i changed the script a bit to work on Editor mode. I added [ExecuteInEditMode] on top of the class and also added an Awake() method that executes the same code as in SetFlags. Seems to work just fine.
I currently work on Unity and using C# language.
By far, I need to do something (in smallest case, load another scene).
My question is, how to make this something happens after a few seconds I put the cursor on the area?
this is my code right now.
if (_newGameButton.Contains (Event.current.mousePosition)) {
Application.LoadLevel (1);
Destroy (this);
}
I want to add delay when _newGameButton actives. Right now, when I move my cursor over _newGameButton it'll load scene 1 immediately. I have tried many ways such as using Invoke and WaitForSeconds. None works. If the mistake is how I use it, how's the right way? Thank you so much for your help.
EDIT: This question is answered and I have another question in Activate and Deactivate Invoke function.
To make timers and delays in Unity, simply use Invoke
void Start()
{
Debug.Log("hello from Start.");
Invoke("Test", 3f);
}
private void Test()
{
Debug.Log("hello from 'Test'");
}
Also very handy is InvokeRepeating
Invoke("Test", 5f, 0.5f);
It's that easy.
In your case
if (_newGameButton.Contains (Event.current.mousePosition))
{
Invoke("YourSceneName");
}
private void ChangeScenes()
{
UnityEngine.SceneManagement.SceneManager.LoadScene("ScreenMain");
}
You MUST USE the scene name. Don't forget you MUST HAVE DRAGGED THE SCENE, TO YOUR SCENE LIST. Look at "Build Settings" "Scenes in Build".
Note
That's not really how you load scenes in Unity these days. They changed the syntax. it's more like this...
UnityEngine.SceneManagement.SceneManager.LoadScene("ScreenMain");
If you want to load asynchronously
AsyncOperation ao;
ao = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("SceneName");
while (!ao.isDone)
{
Debug.Log("loading " +ao.progress.ToString("f2"));
yield return null;
}
If you have any questions about scene loading, ask them separately as a new question. Note that you should almost certainly NOT do this "Destroy(this);".
Well ill help you understand something a bit bigger then just pausing cause it seems you are trying to create on OnClick event, nowadays its being used differently.
what you realy want to do is just create the SceneLoader script which can be a very general script such as the following,
using UnityEngine;
using UnityEngine.UI;
public class UIController : MonoBehaviour {
public int numOfSceneToLoad; // number of the scene from the build settings
public void LoadSceneNumber(numOfSceneToLoad){
UnityEngine.SceneManagement.SceneManager.LoadScene(numOfSceneToLoad);
}
}
and then you want to attach this script to your main UI Canvas/Holderplace, go to your button and at the bottom of the inspector you will see onClick(),
click on the + sign and then make the setup as follows, drag the Object you have attached this script to and put it under the "runtime" laber in that small onClick() window, then scroll and find this specific function we just created and in there you can modify the value of numOfSceneToLoad to the scene you want to load, and woilla you have a Dynamic script to load any scene you wish to.
on this note ill reffer you to some pretty amazing toturials made by unity that will teach you how to make a proper UI in unity5.
http://unity3d.com/learn/tutorials/topics/user-interface-ui/ui-button
From your description, it looks to me that your _newGameButton is set to inactive by default and you want it to active and user intractable after few delay.
For that you can create a script and keep reference of _newGameButton in it, something like this:
public GameObject _newGameButton;
and on an event say GameOver, implement like this:
void GameOver()
{
Invoke("EnableNewGameButtonAfterDelay", 5f);
}
void EnableNewGameButtonAfterDelay()
{
_newGameButton.SetActive(true);
// now this game object is active and user can click on it.
}
In this example i demonstrated that the game has been over and after 5 second delay user have new game button set to enable. [This code is not in executable form and just to give you an idea]
Hope this helps!
void OnMouseDown() {
SceneManager.LoadScene ("Scene2");
}
I have tried every conceivable method. The method posted has worked for me using GameObjects with colliders. Instead, this time I am using a button on a 2D canvas. It does not work in this context.
How do I load a new scene using a button in a canvas? I have tried so many different things. This should be simple.
Thanks for any advice.
Here (link: Unity page) you can find a video tutorial how to use Button on canvas in UnityGUI. It's for Unity 4.6 but its really simillar to newest (5.3.1).
It's quite simple. U can make a script with public method e.g
public void LoadScene2()
{
SceneManager.LoadScene ("Scene2");
}
Attach this script to some GameObject e.g Controller. And add event in Button inspector.
In my opinion there is a better solution for the one shown by #Paweł Marecki
I use this in my projects.
OK so you will simply create a script called ButtonManager and inside it you can make a method like this
public void ChangeToScene(string sceneName)
{
Application.LoadLevel(sceneName);
OR
SceneManager.LoadScene(sceneName);
}
Now you have your canvas button, you will select it and look for "Event Trigger"
(i got this image from google to help) add a new mouse down event.
Create an empty GameObject on your Scene, name it "ButtonManager" and drag it onto the event box.
Now you need to click that dropDown list and find your "ChangeToScene" method.
You will see that an editor field appears below, type your desired scene name and hit play :P
This way you will always use this script when you want to change scenes.
You can add other methods and add functionality, but the beautiful part is that you dont need to create a method each time the name of the scene changes.