Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

UI not setting to Active on click... what am I doing wrong?

Discussion in 'Scripting' started by JackalopeConspiracy, Mar 12, 2015.

  1. JackalopeConspiracy

    JackalopeConspiracy

    Joined:
    Mar 12, 2015
    Posts:
    32
    At a game jam and our code guy bailed last minute. I'm just a UX guy with a smidge of scripting experience. I think I have this thing almost figured out but not sure what I'm doing wrong.

    FPS where when you walk up to an object and click, some UI will pop up.

    I have the raycast working, but the UI is not popping up when I click.

    Here is my code:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PlayerRaycasting : MonoBehaviour {
    5.  
    6.     public float distanceToSee = 5.0f;
    7.     private RaycastHit whatIHit;
    8.  
    9.     public GameObject helloWorld;
    10.  
    11.  
    12.     void Awake()
    13.     {
    14.         helloWorld = GameObject.Find("HelloWorld");
    15.     }
    16.  
    17.     void Start()
    18.     {
    19.         helloWorld.SetActive(false);
    20.     }
    21.  
    22.     // Update is called once per frame
    23.     void Update ()
    24.     {
    25.         Debug.DrawRay(transform.position, transform.forward * distanceToSee, Color.magenta);
    26.  
    27.         if (Physics.Raycast(transform.position, transform.forward, out whatIHit, distanceToSee))
    28.         {
    29.  
    30.             if(Input.GetKeyDown (KeyCode.Mouse0))
    31.             {
    32.                 //I set the code higher up in the code for debug purposes but it's true position is down below, because I intend to use tags to differeniate what UI is meant to pop up for different objects in the room.              
    33.                 GameObject.Find("HelloWorld").SetActive(true);
    34.  
    35.                     Debug.Log ("I picked up a" +whatIHit.collider.gameObject.name);
    36.  
    37.                 if(whatIHit.collider.gameObject.tag == "Keycards")
    38.                 {
    39.                       if(whatIHit.collider.gameObject.GetComponent<KeyCards>().whatKeyAmI == KeyCards.Keycards.redKey)
    40.                       {
    41.                         //GameObject.Find("HelloWorld").SetActive(true);
    42.  
    43.                       }
    44.                 }
    45.             }
    46.         }
    47.     }
    48. }
    49.  
    Also here's what my scene looks like:
    upload_2015-3-12_15-57-38.png
     
  2. Mr-Mud

    Mr-Mud

    Joined:
    Mar 8, 2015
    Posts:
    37
    Your code searches for a GameObject named "HelloWorld"; there does not appear to be an object in the scene which bears that name. Since the function you are using is case-sensitive, it won't find the object "helloWorld". I suppose that if you change either of these to the other, your code should work.
     
    JackalopeConspiracy likes this.
  3. JackalopeConspiracy

    JackalopeConspiracy

    Joined:
    Mar 12, 2015
    Posts:
    32
    I do not believe that is the main issue. Asking around other places online, I have been told that it is a known issue in the API that things which are set to inactive can not be found with Find. Instead I have to create a public variable and link it in the inspector.

    I'm looking into this more. I'll get updated code and pictures in a sec.
     
  4. JackalopeConspiracy

    JackalopeConspiracy

    Joined:
    Mar 12, 2015
    Posts:
    32
    Here's an update on the code:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PlayerRaycasting : MonoBehaviour {
    5.  
    6.     public float distanceToSee = 5.0f;
    7.     private RaycastHit whatIHit;
    8.  
    9.     public GameObject helloWorld;
    10.  
    11.  
    12.     void Awake()
    13.     {
    14.         helloWorld = GameObject.Find("helloWorld");
    15.     }
    16.  
    17.     void Start()
    18.     {
    19.         helloWorld.SetActive(false);
    20.     }
    21.  
    22.     // Update is called once per frame
    23.     void Update ()
    24.     {
    25.         Debug.DrawRay(transform.position, transform.forward * distanceToSee, Color.magenta);
    26.  
    27.         if (Physics.Raycast(transform.position, transform.forward, out whatIHit, distanceToSee))
    28.         {
    29.  
    30.             if(Input.GetKeyDown (KeyCode.Mouse0))
    31.             {
    32.                 //I set the code higher up in the code for debug purposes but it's true position is down below, because I intend to use tags to differeniate what UI is meant to pop up for different objects in the room.              
    33.                 GameObject.Find("helloWorld").SetActive(true);
    34.  
    35.                     Debug.Log ("I picked up a" +whatIHit.collider.gameObject.name);
    36.  
    37.                 if(whatIHit.collider.gameObject.tag == "Keycards")
    38.                 {
    39.                       if(whatIHit.collider.gameObject.GetComponent<KeyCards>().whatKeyAmI == KeyCards.Keycards.redKey)
    40.                       {
    41.                         //GameObject.Find("HelloWorld").SetActive(true);
    42.  
    43.                       }
    44.                 }
    45.             }
    46.         }
    47.     }
    48. }


    upload_2015-3-12_16-31-4.png
     
  5. Mr-Mud

    Mr-Mud

    Joined:
    Mar 8, 2015
    Posts:
    37
    Whoops, skipped over that part. You are indeed correct that objects which are disabled won't be found by the Engine.

    In your new script you are overriding the value you assigned in the editor, with the object it found; in this case none. Also, why exactly do you start looking for an object which you already know? In any case, here is your code with some slight edits; it works for me:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PlayerRaycasting : MonoBehaviour {
    5.    
    6.     public float distanceToSee = 5.0f;
    7.     private RaycastHit whatIHit;
    8.  
    9.     [SerializeField]//shows private field in inspectors.
    10.     private GameObject helloWorld;//Assign from inspector.
    11.    
    12.     void Start()
    13.     {
    14.         if (helloWorld!=null)
    15.         {
    16.             helloWorld.SetActive(false);
    17.         }
    18.     }
    19.  
    20.     void Update ()
    21.     {
    22.         Debug.DrawRay(transform.position, transform.forward * distanceToSee, Color.magenta);
    23.         //Switched these tests for a better performance.
    24.         if(Input.GetKeyDown (KeyCode.Mouse0))
    25.         {
    26.             if (Physics.Raycast(transform.position, transform.forward, out whatIHit, distanceToSee))
    27.             {
    28.                 if (helloWorld != null)
    29.                 {
    30.                     helloWorld.SetActive(true);  
    31.                     Debug.Log ("I picked up a" +whatIHit.collider.gameObject.name);
    32.                
    33.                     if(whatIHit.collider.gameObject.tag == "Keycards")
    34.                     {
    35.                         /*if(whatIHit.collider.gameObject.GetComponent<KeyCards>().whatKeyAmI == KeyCards.Keycards.redKey)
    36.                         {
    37.                             //GameObject.Find("HelloWorld").SetActive(true);
    38.                         }*/
    39.                     }
    40.                 }
    41.             }
    42.         }
    43.     }
    44. }
     
    JackalopeConspiracy likes this.
  6. JackalopeConspiracy

    JackalopeConspiracy

    Joined:
    Mar 12, 2015
    Posts:
    32
    Ah, so that works for me too.

    So a couple of questions because I want to understand the changes. I understand if this is too many questions though.

    If you made GameObject helloWorld private, how can it be viewed in the inspector? My understand was that variables were set to public in order to be viewable.

    Also you switched the order of the raycast and button push in the code for performance. As I understand it, the performance is increased because you're not having to have a raycast constantly being put out, except when the button is pushed, correct?

    Also I tried shifting the code down to be inside the part of the code that specifies which objects will activate the actions via tag


    Code (CSharp):
    1. if (helloWorld != null)
    2.                 { helloWorld.SetActive(true);  
    3.  
    4.                     Debug.Log ("I picked up a" +whatIHit.collider.gameObject.name);
    5.                    
    6.                     if(whatIHit.collider.gameObject.tag == "Keycards")
    7.                     {
    8.                         if(whatIHit.collider.gameObject.GetComponent<KeyCards>().whatKeyAmI == KeyCards.Keycards.redKey)
    9.                         {
    10.                             helloWorld.SetActive(true);  
    11.                         }
    12.                     }
    13.                 }
    And it doesn't work anymore. The way that code originally worked, is that it allowed different objects in the room to be tagged for different actions. Originally I was following a tutorial on how to pick up keys to go through doors. and using the tag, only the red key would be destroyed by the click, since the destroy action was within that piece of tag code. (I hope that made sense).

    But that doesn't seem to be true here...? Why is that?


    also lastly, as I understand it, the primary problem I was having is that once the object was "found" using the inspector, there was no point in searching it with GameObject.Find because that would just override it.

    Lastly, what is SerializeField?
     
  7. JackalopeConspiracy

    JackalopeConspiracy

    Joined:
    Mar 12, 2015
    Posts:
    32
    Ah, I did some research. Now I understand the serialized fields part. Is there a particular reason for doing it that way? Why not just declare public?

    Trying to work on a timer. I understand the concept behind it. Got the timer going up each second but still have to figure out how to integrate it into the actual pop up code
     
  8. JackalopeConspiracy

    JackalopeConspiracy

    Joined:
    Mar 12, 2015
    Posts:
    32
    Okay I thought I figured out how to use the timer, but it does not appear to be working....

    And as I said, I do not understand why this stuff doesn't fit into the tag if statement.


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PlayerRaycasting : MonoBehaviour {
    5.    
    6.     public float distanceToSee = 5.0f;
    7.     private RaycastHit whatIHit;
    8.     private float curTime;
    9.     private float triggerTime;
    10.    
    11.     [SerializeField]//shows private field in inspectors.
    12.     private GameObject helloWorld;
    13.    
    14.     void Start()
    15.     {
    16.  
    17.         triggerTime = 2;
    18.         if (helloWorld!=null)
    19.         {
    20.             helloWorld.SetActive(false);
    21.         }
    22.     }
    23.    
    24.     void Update ()
    25.     {
    26.    
    27.  
    28.      if(Input.GetKeyDown (KeyCode.Mouse0))
    29.         {
    30.             if (Physics.Raycast(transform.position, transform.forward, out whatIHit, distanceToSee))
    31.             {
    32.                 if (helloWorld != null)
    33.                 {
    34.  
    35.                     helloWorld.SetActive(true);  
    36.                     Debug.Log ("I picked up a" +whatIHit.collider.gameObject.name);
    37.  
    38.                     if (curTime < triggerTime) {
    39.                         curTime += Time.deltaTime;
    40.                     }
    41.  
    42.                     else {
    43.                         helloWorld.SetActive(false);
    44.                         curTime = 0;
    45.  
    46.                     }
    47.                    
    48.                     /*if(whatIHit.collider.gameObject.tag == "Keycards")
    49.                     {
    50.                         if(whatIHit.collider.gameObject.GetComponent<KeyCards>().whatKeyAmI == KeyCards.Keycards.redKey)
    51.                         {
    52.                             helloWorld.SetActive(true);  
    53.                         }*/
    54.                     }
    55.                 }
    56.             }
    57.         }
    58.     }
    59.  
     
  9. Mr-Mud

    Mr-Mud

    Joined:
    Mar 8, 2015
    Posts:
    37
    It seems you already figured this out. It is somewhat of a coding convention: you declare fields (, variables , or however you want to call them) as private. This way code cannot access it if it has no permission. Compare it to your PIN code; you don't want others to know - let alone change - it (with a few exceptions).

    That is exacty the reason I switched the order. Not much more to add to it.

    When you say it doesn't work anymore, what exaclty do you mean? If you do not get an exception from this code, I would assume that the key you are checking is not a redKey. My advice it that you add a few logs about the object, so you can test whether it matches your expectations. Also, you appear to be setting the helloWorld object to active twice in this function.

    Here is a piece of (untested) code:
    Code (CSharp):
    1.  
    2. if (helloWorld != null)
    3. {
    4.     Debug.Log ("IOther's name: " + whatIHit.collider.gameObject.name);
    5.     Debug.Log("Other's tag: " + whatIHit.collider.gameObject.tag);
    6.     if(whatIHit.collider.gameObject.tag == "Keycards")
    7.     {
    8.         KeyCards kc = whatIHit.collider.GetComponent<KeyCards>();
    9.         Debug.Log("Key: " + kc.whatKeyAmI);
    10.         if(kc.whatKeyAmI == KeyCards.Keycards.redKey)
    11.         {
    12.             helloWorld.SetActive(true);
    13.         }
    14.     }
    15. }
    The way you implemented your timer is a bit of... Each time you click the left mouse button the script will see whether there is a specific object in raycast range. If that is the case, the timer will increase the passed time by a slight amount. So if you start spamming the left mouse button, you should get the desired result after a few seconds. A coroutine with a delegate as parameter could help here. I made usage from a Lambda expression in this example.
    Code (CSharp):
    1. //Replace this piece of code.
    2. if (curTime < triggerTime)
    3. {
    4.     curTime += Time.deltaTime;
    5. }
    6. else
    7. {
    8.     helloWorld.SetActive(false);
    9.     curTime = 0;
    10. }
    11.  
    12. //And add this in its stead.
    13. StartCoroutine(DelayedFunction(triggerTime,
    14. //The function which will be executed after the specified delay has ended.
    15. ()=>
    16. {
    17.     //Your logic when the timer has run out.
    18.     helloWorld.SetActive(false);
    19. }));
    20.  
    21. //Also, outside of any other function, add this.
    22. IEnumerator DelayedFunction(float delay, System.Action function)
    23. {
    24.     //Resume the execution of this function after some time.
    25.     yield return new WaitForSeconds(delay);
    26.     //Make sure we have a function to execute.
    27.     if (function != null)
    28.     {
    29.         //Perform the specified function.
    30.         function();
    31.     }
    32. }
     
    JackalopeConspiracy likes this.
  10. JackalopeConspiracy

    JackalopeConspiracy

    Joined:
    Mar 12, 2015
    Posts:
    32
    I figured out the redKey tag problem. For some reason every time I close the file, the inspector resets the connection between helloWorld and the Raycast script.

    Also I got the timer working with some help from a friend. I had some screwy logic but got it figured out. It's not very elegant. I'm going to look at the way you did stuff, though for now this is working well enough for our turn in date. I want to keep this in mind though.

    Also thanks for explaining the serialization field stuff, that was really useful to know!