Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Button does not work - at all

Discussion in 'Scripting' started by Zalosath, Sep 28, 2016.

  1. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
    The button is clickable and shows that the button is clicked, but when pressing the button, none of the things I set it to do are working.

    I override a function called OnEnable (I tried OnAwake and all the other variations you can possibly have) as I thought it would be a problem with not being able to load the script with the Start function.

    However, this is false. It still doesn't work. I added debugs into the code, in the OnEnable function but none of them were printed, to my surprise.

    Clicking the button calls a function which has arguments so I use delegate to allow me to pass arguments which frankly works for another part of my program. Any assistance is appreciated, here is the code.

    Code (CSharp):
    1.     public void OnEnable()
    2.     {
    3.         Debug.Log ("-0");
    4.         button = this.gameObject.GetComponent<Button> ();;
    5.         upgrades = GameObject.Find ("Upgrade Manager").GetComponent<Upgrades> ();
    6.         button.onClick.AddListener (delegate {
    7.             upgrades.addToUpgrade (upgradeName.ToLower(), (int)clickStrength);
    8.         });
    9.         Debug.Log ("0");
    10.     }
    Neither of the debugs work. Thanks in advance.
     
  2. Vedrit

    Vedrit

    Joined:
    Feb 8, 2013
    Posts:
    514
    I don't know the behavior of OnEnable, and you say you tried OnAwake, but what about Awake? (Which is probably what you were meaning)
    Also, and I don't know if this is causing any problems, but you have an extra semicolon on line 4
     
  3. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    OnEnable is basically like Start except it can be called multiple times (if you turn the object off and then back on again). To that end - you probably would want to use Start so that you only add the event listener once. You wouldn't want Awake because your Find() could fail if this is created before "Upgrade Manager".
     
  4. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
    Upgrade Manager is always active, however, the object that the script provided on is not always active. It becomes active when a button on my navigation bar is clicked. Therefore, using Start would prove pointless (Tried it nonetheless to no avail.)
     
  5. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    So, the OnEnable is in a script on a gameobject that isn't active? If this is the case, the script doesn't run because the object isn't enabled.

    Start also only runs once when the object becomes active.

    Awake runs even if the gameobject isn't active.
     
  6. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    It might be active but it might not exist if you put that code in Awake of another script.

    And yeah - it's not working because it's inactive.
     
  7. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
    So I should change it back to start? It still does nothing...
     
  8. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    Start runs once only if the object is active or the first time it becomes active. So if the object isn't active when the scene loads, your start doesn't run. Awake runs once no matter what. Also, looking at your first post. There is no OnAwake. It's simply Awake.

    void Awake() is the proper method
     
  9. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
    That is indeed a typo, Awake also doesn't work.
     
  10. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    If you put those calls in Awake and the script is on an object in your scene and you're not getting the debug prints, there is something else wrong. Are you getting an error?
     
  11. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
    Absolutely nothing is printed to the console. I'm going to try and restart Unity.

    EDIT: Restarting did not solve the issue.
     
  12. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    Create another script. Add the Awake method. Put a debug into it. Add the script to something in your scene and see if you get that debug.

    Could also try putting your current script on something else.

    Otherwise, you might need to show more info. Show the rest of your script and maybe the object it is on with your inspector.
     
  13. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
  14. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
    Adding it to another object also doesn't work.
    Recreating the script also doesn't work.

    upload_2016-9-28_20-53-15.png
    Ignore the image for the pickaxe, it's temporary. But that's the arrangement in the hierarchy.
     
  15. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
  16. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Awake isn't being called. The only way that happens is if the object is inactive or the script isn't attached to anything in your scene. I can't tell because you expanded your hierarchy to different levels in those two shots and didn't say what you actually did.
     
  17. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
    Not sure I understand what you just said?
     
  18. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    You didn't actually say what you changed in your second post and your screenshot doesn't show the object you've purportedly attached this code to.
     
  19. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
    The point was to show that I changed the arrangement of the code task to no avail.
     
  20. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    That's not what I said. I said your object was inactive and that's why Awake wasn't being called.
     
  21. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    First off I just want to make sure you understand what this line is doing because from the other problem you had with the adding the listener in Update, I think you might be misunderstanding what its doing:
    Code (CSharp):
    1. button.onClick.AddListener (delegate {
    2.             upgrades.addToUpgrade (upgradeName.ToLower(), (int)clickStrength);
    There is an Event Manager out there watching for all kinds of Events (key presses, scenes being loaded ,etc). Now when you use the line above your telling that Event Manager: "Hey when this button is clicked, call my function upgrades.addToUpgrade". The Event manager is keeping track of a list of all the objects that care about that button being clicked and will call every function on its list. If you were to type that line in two times, you will tell the Event Manger to add your function name to his list two times, and it will happily call your function two times in a row. So you only ever want to AddListeners someplace you know is only going to get called one time. Like Start(). When you add them in something like Update, or OnEnable that can fire more than one time, you going to get multiple copies of "Call this function" added to that list, which will cause wonky behaviour in your code.

    The entire OnEnable function you have should be moved to
    void Start()


    Now to the original problem. I realize if you move your code to start, you won't need OnEnable, but it you might in the future. I created Two Game Objects. ObjectOne, ObjectTwo. I added this script to both of them.
    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.IO;
    6.  
    7.  
    8. public class GenericTest : MonoBehaviour
    9. {
    10.  
    11.     void Awake()
    12.     {
    13.         Debug.Log("Awake has been called in " + gameObject.name);
    14.     }
    15.  
    16.     void Start()
    17.     {
    18.         Debug.Log("Start has been Called in " + gameObject.name);
    19.  
    20.     }
    21.  
    22.     void OnEnable()
    23.     {
    24.         Debug.Log("On Enable has been calledin " + gameObject.name);
    25.     }
    26. }
    27.  
    28.  
    And just to test I added this Script to ObjectTwo
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4. using UnityEngine.SceneManagement;
    5. using System.Collections.Generic;
    6. using Random = UnityEngine.Random;
    7.  
    8. public class mageScript
    9. {
    10.  
    11. }
    12. public class GenericTwo : MonoBehaviour {
    13.  
    14.     public GameObject Other;
    15.  
    16.     GenericTest script;
    17.    
    18.     void Start()
    19.     {
    20.         script = Other.GetComponent<GenericTest>();
    21.         StartCoroutine(ToggleStuff());
    22.     }
    23.  
    24.     IEnumerator ToggleStuff()
    25.     {
    26.         yield return new WaitForSeconds(3f);
    27.         Debug.Log("Turning Other object on and off");
    28.         Other.SetActive(false);
    29.         Other.SetActive(true);
    30.         Debug.Log("Turning the Other object script on and off");
    31.         script.enabled = false;
    32.         script.enabled = true;
    33.     }
    34. }
    35.  
    Running the code I got this output:
    Awake has been run in Object Two
    OnEnable has been run in Object Two
    Awake has been run in Object One
    On Enable has been run in Object One
    Start has been run in in Object Two
    Start has been run in Object One

    And not that it matters to this problem, but SetActive and Enable both trigger OnEnable when you turn an GameOjbect on or just the script.

    So if you Imagine your script that is setting the listener is ObjectTwo, and your Upgrade Manager is Object One what was happening is ButtonScript was being instantiated and calling its Awake, then OnEnable was immediately called. At this point ObjectOne (Updgrade Manager) Does not exist yet. So you AddListener was trying to give a reference to a function that didn't exist yet. Then the code goes on to instantiate ObjectOne (upgrade manager) and call its Awake and OnEnable.

    Long Story short you should always follow this rule:

    • void Awake() -- Use this to initialize all the variables in your script that are internal only. Reading data from files, Setting up initial values of various fields, etc.
    • void Start() -- Use this to get references to other scripts, and initialize your variables that need to know about objects/data in other scripts. This way you know for sure the other scripts are active AND they initialized their data.
    Unity auto populates your scripts with Start and Update, but not Awake. Which i think can lead to bad practices. I would get in the habit of deleting Start and using Awake. Only add a Start to your game if you need to get hooks into other scripts
     
  22. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    My mistake, for some reason I was thinking it was called on all objects, but I think I'm just thinking something else.

    So, yes, the object isn't running anything because it's not active. In this case, the minus isn't active because it's parent isn't active, thus the script doesn't run Awake or Start or OnEnable.
     
  23. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
    And I would fix that how? ;/
     
  24. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    Having the object active :) If you just need to set the stuff up, have it active and then turn it off once everything is setup. Otherwise, you need to reference the script through another script that is active and can set up your buttons.
     
  25. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
    Oddly, still doesn't work. I've changed the execution order so that it stays open to begin with and closes after 1 second, to no avail ;/.
     
  26. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    If the object is active (parent also) and then you have an Awake or Start, those should be getting executed. Awake always happens first on all objects and start is during the first frame. If you're not getting your debugs and no errors. I'm currently not sure without being able to investigate myself.
     
  27. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Changing the execution order has absolutely nothing to do with how Awake and Start work in relation to their parent object being active. If the GameObject the script is attached to is not active then these methods will not fire.

    Again - if you have debug statements in your Awake method and those are not appearing in the console at runtime then Awake is not being called. That's your issue.