GameObject doesn't appear after it disappears in Unity - c#

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.

Related

Can a Unity GameObject Array be used to emulate ToggleGroup like behavior

This app has panels with collections of buttons which are on "Play" disabled. The goal is to utilize a GameOject array to manage these buttons so that only one button can ever be enabled at a time. In an ToggleGroup, it is possible to force only one Toggle object to be selected at any time.
Though growing in Unity c# skills, i readily admit to being more beginner than intermediate in skills. So, any guidance is most appreciated.
The first step was to test the use of ToggleGroups, but Toggles cannot accept the c# script associated with the buttons, which, when enabled, loads a Prefab from an AssetBundle.
Once ToggleGroups were taken off the table, i have been researching the use of an array of GameObjects. Several sources show how in the simplistic manner, to create an array of buttons, and upon Start(), make the buttons inactive. But i am unclear how to emulate the ToggleGroup functionality in an array.
Here is the base of my "buttonMgtArray" script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class buttonMgtArray : MonoBehaviour
{
public GameObject[] button;
// Start is called before the first frame update
void Start()
{
button[0].SetActive(false);
button[1].SetActive(false);
button[2].SetActive(false);
}
}
There are no errors at this time because i am attempting to identify how to emulate the desired behavior in the context of GameObject Array.
To better illustrate the behavior i am attempting to invoke, this screencap may help explain the goal.
Button Behavior Explanation
I am very pleased to report that #Stanley had a very elegant solution that provides the toggling emulation. The key was to apply the script to the button that enabled the hidden button, which are the array references. Here is the final code. Thanks much to #Stanley
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class buttonMgtArray : MonoBehaviour
{
public GameObject[] buttonArray;
public void DisableAllButtonsExcept(int i)
{
foreach (GameObject buttonGameObject in buttonArray)
{
buttonGameObject.SetActive(false);
}
buttonArray[i].SetActive(true);
}
}
IF i understand you correctly you want to use your buttons like radio buttons.
I see that no one has answered your question yet so i'll give it a quick go.
There are more ways of doing this and better ways, but this one does work.
public void DisableAllButtonsExcept(int i) {
foreach(GameObject buttonGameObject in buttonArray) {
buttonGameObject.SetActive(false);
}
buttonArray[i].SetActive(true);
}
before
after
Button number 2 is kept because arrays start at 0
change the parameters in the onClick event to match its position in the array

Unity - opening and closing animation with key binding

I'm making an inventory menu that will be accessed via a key binding (I). When the keybinding is clicked then play the animation which brings in the menu, if the keybind is clicked again then it should close the menu. Not sure where I'm going wrong here.
I've attached the animation controller to the UI.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ShowInventory : MonoBehaviour {
public Animator animator;
// Update is called once per frame
void Update() {
if (Input.GetKeyDown(KeyCode.I)) {
animator.SetBool("isOpen", true);
}
}
}
As well as the code, you must also make sure your state machine in the Animator Controller asset is set up properly too. Check out this tutorial if you haven't already: https://unity3d.com/learn/tutorials/topics/animation/animator-controller

GetComponent function returning null

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.

Unity Scripting Main Menu Not Working? Don't Know Why?

I made a main menu in unity so now I'm down to the scripting. I have tried the mouseup / mousedown functions but nothing is wrong with my code but it won't work period no debug logs not errors just plain nothing.
Here's my C# Script to change levels.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class MainMenu : MonoBehaviour {
public bool Start;
public bool Quit;
void OnMouseUp(){
if(Start)
{
SceneManager.LoadScene(1);
}
if (Quit)
{
Application.Quit();
}
}
}
This is very simple but I still don't see why it isn't working.
Try OnMouseDown
As an event needs to happen first. So the player presses down then upon release the mouse button is up, you need that first click. hope that helps.
https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnMouseDown.html
Make sure that you added the script to a gameobject inside your scene. Also make sure that Start or Quit are set to true.

Add delay in C# in Unity3D projects

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!

Categories