Search Unity

CanvasGroup set alpha behaving strangely.

Discussion in 'Scripting' started by Matt_Lacker, Jun 26, 2019.

  1. Matt_Lacker

    Matt_Lacker

    Joined:
    May 12, 2019
    Posts:
    7
    Hello,

    I am running into some issues using CanvasGroup and setting alpha.

    My desired behavior is to display a canvasGroup with a few nested items when an object enters a trigger collider.

    The OnPackageDelivery function is called externally and sets the canvasGroup alpha to 1.

    This works fine if I trigger it with a mouse click (in my update function), but does not work at all when the function is called after the object enters the trigger.

    I know that the trigger is not the problem because print("show success text") logs to the console, but the canvasGroup alpha stays at 0.

    Any help on this would be appreciated, I feel like I am overlooking something but I cant think of what.


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class GUI : MonoBehaviour
    7. {
    8.     [SerializeField] CanvasGroup successText;
    9.  
    10.     void Start()
    11.     {
    12.         successText.alpha = 0.0f;
    13.     }
    14.  
    15.     // Update is called once per frame
    16.     void Update()
    17.     {
    18.         if (Input.GetButtonDown("Fire1"))
    19.         {
    20.            OnPackageDelivery();
    21.         }
    22.     }
    23.  
    24.     public void OnPackageDelivery()
    25.     {
    26.       //  successText.enabled = true;
    27.       //  successText.gameObject.SetActive(true);
    28.         successText.alpha = 1.0f;
    29.         print("show success text");
    30.     }
    31. }
     
  2. calpolican

    calpolican

    Joined:
    Feb 2, 2015
    Posts:
    425
    Hi, in the script you've provided I haven't found any OnTriggerEnter() function.
    If you have an event happening when an object enters the trigger, it should be in that function, like this:
    Code (CSharp):
    1. void OnTriggerEnter(){
    2. Debug.Log("Something has entered the trigger");
    3. OnPackageDelivery();
    4. }
    if you already have this function, please post it. If you have a OnTriggerExit function() also provide it.
    Also, make sure that the object has a collider with the trigger box ticked, and that the object entering also has a collider, (and I think it needs a rigidbody too). Also, check if both objects are in layers that detect collisions between themselves [in unity, go to Edit>Project Settings>Physicis> and open the collision matrix to see if both of your layers are allowed to check collisions with each other].
    For what you say, you do detect the collision, but the alpha won't change, try to run a Debug to show what the alpha is according to unity.
    Is there any other script that might be chaninging it back to zero? if so, put a log to see if it's interfering.
    Also, inside of a canvas group, child objects have their own alpha, if that alpha is 0 you won't see it, as it get multiplied. The docs say:
    "Note that elements retain their own transparency as well, so the Canvas Group alpha and the alpha values of the individual UI elements are multiplied with each other."
    If you have to set individual values, you may try CanvasRenderer.SetAlpha()
     
    Last edited: Jun 26, 2019
  3. Matt_Lacker

    Matt_Lacker

    Joined:
    May 12, 2019
    Posts:
    7
    Hello, thanks for your reply -

    The OnTriggerEnter function is part of a different gameObject so I didnt post it initially. The trigger lets the "gameState" know that package has been delivered, the gameState calls the GUI function to display the canvasGroup.(the script in my original post).

    I do not have an OnTriggerExit function.

    I have printouts for each step so I know they are are being called properly.


    private void OnTriggerEnter(Collider other)
    {

    if (other.gameObject.GetComponent<Package>() != null)
    {
    print("package has entered trigger");
    gameState.PackageDelivered();
    }

    }



    If I pause the game after the collision the Inspector shows the CanvasGroup has alpha of 0, the child elements do not have a separate alpha field in the inspector, but my panels color still has full alpha applied (ex: RGBA x, x, x, 255).

    As far as other scripts possibly accessing the GUI - I do not think that is the issue, this is a fairly small project and the original script I posted is the only one accessing the GUI. I do not have any animations that could be changing the alpha either.

    Setting individual values for each child element might be worth a try but seems like an unfortunate work around.

    Tomorrow I will try to recreate the problem in a blank project.
     
  4. calpolican

    calpolican

    Joined:
    Feb 2, 2015
    Posts:
    425
    If on Collision enter is working, changing OnPackageDelivery to this should pause the game and show the before and after in the console. It's very important to see if it's really changing the value or not. Just for the matter of experimentation you should take the setting of the value from start, just leave it at 0 on the GUI.

    1. Code (CSharp):
      1.     public void OnPackageDelivery()
      2.     {
      3. successText.alpha = 0;
      4. Debug.Log("alfa at start = " + successText.alpha);
      5. successText.alpha = 1.0f;
      6. Debug.Log("alfa at the end = " + successText.alpha);
      7. Debug.Break();
      8.  
      9.     }
     
  5. calpolican

    calpolican

    Joined:
    Feb 2, 2015
    Posts:
    425
  6. Matt_Lacker

    Matt_Lacker

    Joined:
    May 12, 2019
    Posts:
    7
    Ok I am somewhat narrowing down the issue. Sorry for the lengthy upcoming post. Adding your block of code shows the same results, GUI only appears on mouse click. Checking ignore parent groups does not make a difference.

    My "solution" is at the bottom.

    The logic flows like this:
    Trigger is entered and informs gamestate:
    Code (CSharp):
    1. public class PackageReceiver : MonoBehaviour
    2. {
    3.     private GameStateManager gameState;
    4.     void Start()
    5.     {
    6.         gameState = FindObjectOfType<GameStateManager>();
    7.     }
    8.  
    9.     private void OnTriggerEnter(Collider other)
    10.     {
    11.      
    12.         if (other.gameObject.GetComponent<Package>() != null)
    13.         {
    14.             print("package has entered trigger");
    15.             gameState.PackageDelivered();
    16.         }
    17.  
    18.     }
    19. }
    gamestate calls OnPackageDelivery on GUI:
    Code (CSharp):
    1. public class GameStateManager : MonoBehaviour
    2. {
    3.     private bool packageDelivered = false;
    4.  
    5.     [SerializeField] GUI gui;
    6.     void Start()
    7.     {
    8.      
    9.     }
    10.  
    11.     public void PackageDelivered()
    12.     {
    13.         print("gamestate knows package has been delivered");
    14.  
    15.         packageDelivered = true;
    16.  
    17.         gui.OnPackageDelivery();
    18.     }
    19.  
    20.  
    21. }
    GUI only seems to listen if i trigger the function via a mouseclick, but the function IS CALLED because of debug.log entries which seems to have no bearing on what the object is actually doing:

    Code (CSharp):
    1. public class GUI : MonoBehaviour
    2. {
    3.     [SerializeField] CanvasGroup successText;
    4.  
    5.     void Start()
    6.     {
    7.         //successText.alpha = 0.0f;
    8.         Debug.Log("alpha from Start():" + successText.alpha);
    9.     }
    10.  
    11.     // Update is called once per frame
    12.     void Update()
    13.     {
    14.  
    15.  
    16.         if (Input.GetButtonDown("Fire1"))
    17.         {
    18.             Debug.Log("mouse click");
    19.            OnPackageDelivery();
    20.         }
    21.     }
    22.  
    23.  
    24.  
    25.     public void OnPackageDelivery()
    26.     {
    27.  
    28.         Debug.Log("alfa at start = " + successText.alpha);
    29.         successText.alpha = 1.0f;
    30.         Debug.Log("alfa at the end = " + successText.alpha);
    31.         //Debug.Break();
    32.     }
    33. }
    Pictures below show the result-



    upload_2019-6-26_19-29-21.png upload_2019-6-26_19-30-32.png


    BUT if I cut the gamestate out entirely, and have the trigger directly call the GUI function , everything seems to work fine. (in script below I added a serializefield with reference to GUI)

    Code (CSharp):
    1.   private void OnTriggerEnter(Collider other)
    2.     {
    3.      
    4.         if (other.gameObject.GetComponent<Package>() != null)
    5.         {
    6.             print("package has entered trigger");
    7.            
    8.  
    9.             gui.OnPackageDelivery();
    10.         }
    11.  
    12.     }
    upload_2019-6-26_19-44-6.png



    So for reasons I do not understand the function behaves differently when called through the "gameState" which should not be changing anything as far as I can tell.

    Having my collider talk directly to the GUI is not my preferred solution but I will use it for now so that I can get on with my life. Hopefully someone sees this and has an idea of what I am overlooking.
     
    Last edited: Jun 27, 2019
  7. calpolican

    calpolican

    Joined:
    Feb 2, 2015
    Posts:
    425
    I think gameState is changing the wrong element, you can see there that the value changes well, if you don't see it in the inspector, most probably is because your chaning another gui element different from one. are you sure that you've connected the right reference to it? That would explain why your initial value of alpha is 1: because you keep chaning the wrong one, and it was 1 after the last check, and it's still 1 after the function is run.
    Please re check that gameState.gui is referencing the right element. In the inspector go to gameState and double click the gui element in the gui box. See if it's the very same you're trying to change.
     
    Last edited: Jun 27, 2019
  8. Matt_Lacker

    Matt_Lacker

    Joined:
    May 12, 2019
    Posts:
    7
    Im not sure thats the issue - I only have one GameObject with a GUI script attached.

    I added this to gameState and it logs only one GUI object.


    void Start()
    {
    var numberOfGui = FindObjectsOfType<GUI>();
    Debug.Log("number of GUI Objects = " + numberOfGui.Length);


    }


    result: number of GUI Objects = 1
     
  9. Matt_Lacker

    Matt_Lacker

    Joined:
    May 12, 2019
    Posts:
    7
    Actually you were right, I re-dragged the GUI into the gamestate and now everything seems to be working. It does not explain why the function was capable of being in called in the first place, but I guess if I run into issues in the future I can just re-drag references.

    Thank you so much for looking at this, you have been extremely helpful
     
  10. calpolican

    calpolican

    Joined:
    Feb 2, 2015
    Posts:
    425
    I thought so, it had to be that connection. Maybe you renamed the class, or had an old version of it? I'm not really sure why it didn't trhow a null exception either. You could Undo and try to figure what was inside. Double clicking the slot should show you the connected object on the hierarchy. Well, I'm glad that was useful anyway.