1
\$\begingroup\$

I'm working on a script to fade UI elements in Unity, similar to a selector, where you can select the type of fading, and duration, and image to fade

enter image description here

I found that enum is the best option to achieve that result, but I have a problem, when I run the code only element of the enum work and the other don't, no matter if I use switchor if just the first statement run, I don't know what's wrong with the code

  • Please explain your answer
  • Please explain why the code is wrong
  • Please give feedback on how to improve

I'm using Unity version 5.3.5f1 and Visual Studio Community 2015

Goal

  • Make the enum work properly using either switch or if
  • Be able to use the variables inside the FadeOperations class to make the calculations inside the Test class
  • Select from an array the type of desired operation
  • Select an UI element from Heriarchy and fade it

Steps

  • Create new Unity project (2D or 3D)
  • Create UI Image
  • Create Empty game object
  • Create new C# script (I called it Test)
  • Attach new script to empty game object

Code

Here's my code so far...

using UnityEngine;
using UnityEngine.UI;

 public enum FadeManager
 {
     fadeIn,
     fadeOut
 };

 [System.Serializable]
 public class FadeOperations
 {
     [Tooltip("Type of fading")]
     public FadeManager fadeType;

     [Tooltip("Duration time of the fading")]
     public float duration;

     [Tooltip("Select the image to fade")]
     public Image fadeImage;
 }

 public class Test : MonoBehaviour
 {
     [Tooltip("Select your type of fade")]
     public FadeOperations[] fadeOperations;

     //Reference to the class FadeOperations
     private FadeOperations _fo = new FadeOperations();

     //Loop for debug
     private void Update()
     {
         switch (_fo.fadeType)
         {
             Debug.Log(_fo.fadeType)
             //This statement works
             case FadeManager.fadeIn:
                 Debug.Log("Fadein"); //Only this piece of code works
                 break;

             //This statement doesn't work
             case FadeManager.fadeOut:
                 Debug.Log("Fadeout");
                 break;
         }
      }
  }

The result of the Log (_fo.fadeType) before the switch

fadeIn
UnityEngine.Debug:Log(Object)
Test:Start() (at Assets/_Scripts/Test.cs:34)
\$\endgroup\$
  • \$\begingroup\$ Your code looks okay. Just before your switch statement, could you add Debug.Log(_fo.fadeType); to see which FadeManager it's using? Wouldn't surprise me if it's not changing as you expect. \$\endgroup\$ – Chris McFarland Jul 5 '16 at 1:56
  • \$\begingroup\$ I changed Update() for Start() and got this Log fadeIn UnityEngine.Debug:Log(Object) Test:Start() (at Assets/_Scripts/Test.cs:34) \$\endgroup\$ – NAYIR55 Jul 5 '16 at 2:02
  • \$\begingroup\$ When you say "only one enum statement work," do you mean you always get the fadeIn behaviour, no matter how you configure your Inspector parameters in the FadeOperations array? If so, it could be because your code as written never references this array. It only looks at the value of the private member _fo which is initialised to a new default FadeOperations struct when your Test class is instantiated and never modified, so _fo.fadeType will always be the default (first) value, fadeIn. If this describes your problem, I can elaborate on this and suggest fixes in an answer. \$\endgroup\$ – DMGregory Jul 5 '16 at 3:11
  • \$\begingroup\$ Exactly as you said, only the first value of the enum is showing, and would you please elaborate more?? \$\endgroup\$ – NAYIR55 Jul 5 '16 at 3:19
2
\$\begingroup\$

Your switch statement is checking _fo.fadeType. Because _fo is private without [SerializeField], it won't show up in Unity's Inspector tab unless you enable Debug mode.

Your code has _fo = new FadeOperations(); which creates a new FadeOperations, and the fadeType is FadeManager.fadeIn by default since it's first in the enum, and that's what's being cased every time.

If you write it as:

[SerializeField] private FadeOperations _fo = new FadeOperations();

^ this will show the _fo variable in the Inspector, and you can see the value, as this is what your switch statement is checking against.

Based on your public FadeOperations[] fadeOperations; line, I assume you've added at least one FadeOperation via the Inspector to this array. Perhaps you'd instead want to make your switch statement check the first item in the array:

switch (fadeOperations[0].fadeType) {
\$\endgroup\$
  • \$\begingroup\$ Thanks for the answer, I tested it and got an error in the switch A switch expression or case label must be a bool, char, string, integral, enum, or corresponding nullable type the [SerializeField] duplicate the variable I am already using in the inspector, and also I edited my question, maybe with more details I can explain better ` \$\endgroup\$ – NAYIR55 Jul 5 '16 at 7:48
  • \$\begingroup\$ Ah. I've updated my answer for the end switch statement: switch (fadeOperations[0].fadeType) { \$\endgroup\$ – Chris McFarland Jul 5 '16 at 8:03
1
\$\begingroup\$

This is an example of an enum being used in a switch statement. I hope that this helps you.

using UnityEngine; 
using System.Collections; 

public class MyScriptFile : MonoBehaviour 
{
    // Define possible states for enemy using an enum 
    public enum EnemyState {CHASE, FLEE, FIGHT, HIDE}; 

    // The current state of enemy
    public EnemyState ActiveState = EnemyState.CHASE; 

    // Update is called once per frame 
    void Update ()
    {
        // Check the ActiveState variable 
        switch(ActiveState) 
        { 
            // Check one case
            case EnemyState.FIGHT: 
                {
                    //Perform fight code here
                    Debug.Log ("Entered fight state"); 
                }
                break; 

            // Check multiple cases at once
            case EnemyState.FLEE: 
            case EnemyState.HIDE: 
            { 
                //Flee and hide performs the same behaviour 
                Debug.Log ("Entered flee or hide state"); 
            } 
            break;

            // Default case when all other states fail 
            default: 
            {
                //This is used for the chase state 
                Debug.Log ("Entered chase state");
            } 
            break; 
        }
    }
}
\$\endgroup\$
0
\$\begingroup\$

As already discussed, your use of enums in a switch statement is actually correct. Your problem is that your checking against a private variable that you only initialise, rather than the public variables that might offer differant values. As a result, the switch statement will always trigger the case:FadeManager.fadeIn case, because a FadeManager variable that has been initialised, and only initialised, will only ever report the default value.

Enums in Switch Statements

As mentioned, your code is correct. Using enums as follows will work correctly, providing you check the correct variable. For the purpose of extending your understanding, I will also mention the int option; while it will likely always be redundant to do so, you could also check against integer values. The integer would need to correspond with a valid index number in your enum, and would still need to be cast as a type of your enum.

public enum FadeManager
{
    fadeIn, // index 0
    fadeOut // index 1
};

switch(fadeOperation.fadeType)
{
    case (FadeManager)0:
    case (FadeManager.fadeIn):
        Debug.Log("Fadein"); //Only this piece of code works
        break;

    case (FadeManager)1:
    case (FadeManager.fadeOut):
        Debug.Log("Fadeout");
        break;

    default:
}

As a small caveat, I will make two more points. Firstly, some will argue that you should always have a default: case to handle any case that does not fall within the above. In cases like this, you can pretty much guarantee that will not happen, so it is more a matter of style. Secondly, in some cases, you can "fall through" cases. For example, if you wanted to run the code in "fadeOut" for "fadeIn" aswell, you could remove the break; from "fadeIn" and have your code "fall through" into the next statement. You can not do that in C#, or at least, not in Unity. That said, I feel it might be useful to know that you can do so in other contexts.

Your Errors

Your primary error actually comes from your understanding of what your doing, and how it should react. The switch, itself, is pretty much solid. That said, there is an error in your switch; your Debug.Log() statement. I believe you have added this by suggestion, and no one has pointed out the error in your implementation.

Checking against a private FadeManager:

Your logic error falls to the instance of FadeManager your trying to check against. In your code, you have a reference to a FadeManager array, and a single FadeManager inside a FadeOperations class. While your array is public, your single reference is inside a private class reference. Given that this is the only code you have, we can infer that this private FadeManager _fo is never changed; being private also means you can not change it directly from the inspector.

As a result, you set up your reference as a default value. Since this value has no means to change, it will always trigger case:FadeManager.fadeIn.

To further test this, simply change private FadeOperations _fo to public FadeOperations _fo. You should not need to include the = new FadeOperations() constructor. While my knowledge on constructor precedence is not perfect, I have confirmed that setting _fo to public and changing its values in the inspector, the values persist when I play-test.

You can see your code correctly prints its Debug.Log() statements, below, where I have simply converted _fo to public.

The debug log correctly responds to changes in _fo.fadeType.

Code inside a switch statement must also be inside a case

As your code stands, it throws many errors, due to the Debug.Log() statement you have added to the inside of your switch statement. all code must correspond to a specific case, and as such, many errors will pop up from misinterpretation of the initial Debug.Log(). You should place Debug.Log(_fo.fadeType) outside of the switch statement, or at least enclose it inside a specific case.

This appears to be a line added at a later date than your original question, but regardless, it is important to understand that as it is this line will prevent your code from compiling.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.