Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Other Problem with the not bool toggling

Discussion in 'Scripting' started by Kuvaaja, Apr 27, 2024.

  1. Kuvaaja

    Kuvaaja

    Joined:
    Dec 9, 2023
    Posts:
    8
    I'm trying to control the emission of one of my lights with a switch. I use this kind of "template" for all my interactions.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public abstract class Interactable : MonoBehaviour
    6. {
    7.     //Message displayed to player when looking at an interactable.
    8.     public string promptMessage;
    9.     // Start is called before the first frame update
    10.     public void BaseInteract()
    11.     {
    12.         Interact();
    13.     }
    14.     protected virtual void Interact()
    15.     {
    16.  
    17.     }
    18. }
    19.  
    So the problem I have is in the Interact method where i toggle two boolean's Pointing up that toggles the animation and MainPower that toggles the light. When i flick the switch in game the animation plays what indicates that pointing up is true but the light doesn't turn on. I have tested by setting the mainPower variable public and toggling it when the game is on that the if statements do work so those aren't the problem.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class FirstSystemSwitch : Interactable
    6. {
    7.     [SerializeField] private Material LightMat;
    8.     [SerializeField] private GameObject Switch;
    9.     [SerializeField] private Renderer FirstSystemSwitchlight;
    10.  
    11.     private bool mainPower;
    12.  
    13.     private bool PointingUp;
    14.     // Start is called before the first frame update
    15.     void Start()
    16.     {
    17.         LightMat = FirstSystemSwitchlight.GetComponent<Renderer>().material;
    18.     }
    19.  
    20.     // Update is called once per frame
    21.     void Update()
    22.     {
    23.         if (mainPower == true)
    24.         {
    25.             LightMat.EnableKeyword("_EMISSION");
    26.         }
    27.         else if (mainPower == false)
    28.         {
    29.             LightMat.DisableKeyword("_EMISSION");
    30.         }
    31.     }
    32.  
    33.     protected override void Interact()
    34.     {
    35.         mainPower = !mainPower;
    36.         PointingUp = !PointingUp;
    37.         Switch.GetComponent<Animator>().SetBool("pointingUp", PointingUp);
    38.      
    39.     }
    40. }
    Please help me this worked before i updated my unity engine from 2020.3.43f1 to 2022.3.26f1
     
  2. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,936
    Make sure the Update is actually being called.

    What shader are you using?
    Have you tried just setting the emission color?

    Code (csharp):
    1.  
    2. if (mainPower == true) {
    3.  
    4.   LightMat.EnableKeyword ("_EMISSION");
    5.   LightMat.SetColor("_EmissionColor", Color.white);
    6.  
    7. } else if (mainPower == false) {
    8.   LightMat.SetColor("_EmissionColor", Color.black);
    9. }
    10.  
     
  3. Kuvaaja

    Kuvaaja

    Joined:
    Dec 9, 2023
    Posts:
    8
    The if statement works. I changed the boolean manually and the light turned on. The only problem is that the boolean doesn't change when I click the lever. The problem is that the "Pointing up" and the "mainPower" boolean is set to toggle the same way, but only the "Pointing up" boolean changes.
     
  4. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,936
    That's impossible from the code you've posted.
     
  5. Kuvaaja

    Kuvaaja

    Joined:
    Dec 9, 2023
    Posts:
    8
    I know. You think it's a bug?
     
  6. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,936
    How can you change the boolean manually if the boolean is private?

    Is it because your code to change the material isn't working, so you're assuming the boolean isn't changing?
     
  7. Kuvaaja

    Kuvaaja

    Joined:
    Dec 9, 2023
    Posts:
    8
    No, I put the toggle part "mainPower = !mainPower" to the start function and it worked. The light turned on. It's just so weird.
     
  8. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,936
    You're not thinking clearly about this.
    The material isn't changing the way you expect, so you're assuming there's a bug with a bool.
     
  9. Kuvaaja

    Kuvaaja

    Joined:
    Dec 9, 2023
    Posts:
    8
    The if statement work heres the proof.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class FirstSystemSwitch : Interactable
    6. {
    7.     [SerializeField] private Material LightMat;
    8.     [SerializeField] private GameObject Switch;
    9.     [SerializeField] private Renderer FirstSystemSwitchlight;
    10.  
    11.     private bool mainPower;
    12.  
    13.     private bool PointingUp;
    14.     // Start is called before the first frame update
    15.     void Start()
    16.     {
    17.         mainPower = !mainPower;
    18.         LightMat = FirstSystemSwitchlight.GetComponent<Renderer>().material;
    19.     }
    20.  
    21.     // Update is called once per frame
    22.     void Update()
    23.     {
    24.         if (mainPower == true)
    25.         {
    26.             LightMat.EnableKeyword("_EMISSION");
    27.         }
    28.         else if (mainPower == false)
    29.         {
    30.             LightMat.DisableKeyword("_EMISSION");
    31.         }
    32.     }
    33.  
    34.     protected override void Interact()
    35.     {
    36.         PointingUp = !PointingUp;
    37.         Switch.GetComponent<Animator>().SetBool("pointingUp", PointingUp);
    38.    
    39.     }
    40. }
    When i do this(the mainPower variable is set to toggle in the start function instead of the interact function wich is called whenever i flick the switch) And because the mainPower is default false the toggling line in the start function "mainPower = !mainPower" toggles the mainPower variable to true and that activates the if statement
    Code (CSharp):
    1.     void Update()
    2.     {
    3.         if (mainPower == true)
    4.         {
    5.             LightMat.EnableKeyword("_EMISSION");
    6.         }
    7.         else if (mainPower == false)
    8.         {
    9.             LightMat.DisableKeyword("_EMISSION");
    10.         }
    11.     }
    And turns on the light PERFECTLY just like I expected. But when i put the toggle to the interact function that for a reminder is called every time i click the switch ingame it doesent work
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class FirstSystemSwitch : Interactable
    6. {
    7.     [SerializeField] private Material LightMat;
    8.     [SerializeField] private GameObject Switch;
    9.     [SerializeField] private Renderer FirstSystemSwitchlight;
    10.  
    11.     private bool mainPower;
    12.  
    13.     private bool PointingUp;
    14.     // Start is called before the first frame update
    15.     void Start()
    16.     {
    17.         LightMat = FirstSystemSwitchlight.GetComponent<Renderer>().material;
    18.     }
    19.  
    20.     // Update is called once per frame
    21.     void Update()
    22.     {
    23.         if (mainPower == true)
    24.         {
    25.             LightMat.EnableKeyword("_EMISSION");
    26.         }
    27.         else if (mainPower == false)
    28.         {
    29.             LightMat.DisableKeyword("_EMISSION");
    30.         }
    31.     }
    32.  
    33.     protected override void Interact()
    34.     {
    35.         mainPower = !mainPower;
    36.         PointingUp = !PointingUp;
    37.         Switch.GetComponent<Animator>().SetBool("pointingUp", PointingUp);
    38.    
    39.     }
    40. }
    And you might be wondering maybe theres something wrong with the interacting? No there is not. Because the pointing up is the variable that controls the switches animation. And the animation works perfectly what indicates that the PointingUp variable has changed.
    I'm not trying to be hostile or anything and I'm not that experienced I just can't see why changing the toggling line to a different place would change how the if statements behave.
     
  10. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,698
    You've only proven that it works once. I suspect the problem here is with the shader not the boolean and that it's only working the first time you enable or disable the keyword after that it's ignoring all future requests. Here's the same code but with a coroutine that constantly flips the keyword on and off. Try it and see if it's working.

    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class FirstSystemSwitch : Interactable
    6. {
    7.     [SerializeField] private Material LightMat;
    8.     [SerializeField] private GameObject Switch;
    9.     [SerializeField] private Renderer FirstSystemSwitchlight;
    10.  
    11.     private bool mainPower;
    12.  
    13.     private bool PointingUp;
    14.     // Start is called before the first frame update
    15.     void Start()
    16.     {
    17.         StartCoroutine(Flip());
    18.         LightMat = FirstSystemSwitchlight.GetComponent<Renderer>().material;
    19.     }
    20.  
    21.     // Update is called once per frame
    22.     /*
    23.     void Update()
    24.     {
    25.         if (mainPower == true)
    26.         {
    27.             LightMat.EnableKeyword("_EMISSION");
    28.         }
    29.         else if (mainPower == false)
    30.         {
    31.             LightMat.DisableKeyword("_EMISSION");
    32.         }
    33.     }
    34.     */
    35.  
    36.     protected override void Interact()
    37.     {
    38.         mainPower = !mainPower;
    39.         PointingUp = !PointingUp;
    40.         Switch.GetComponent<Animator>().SetBool("pointingUp", PointingUp);
    41.  
    42.     }
    43.  
    44.     IEnumerator Flip()
    45.     {
    46.         while (true)
    47.         {
    48.             LightMat.EnableKeyword("_EMISSION");
    49.  
    50.             yield return new WaitForSeconds(1.0f);
    51.  
    52.             LightMat.DisableKeyword("_EMISSION");
    53.  
    54.             yield return new WaitForSeconds(1.0f);
    55.         }
    56.     }
    57. }

    Additionally there was a change to the way shader keywords work with Unity 2021.2, and they added a new way to pass keywords using
    LocalKeyword
    . It's intended to improve performance but it's possible it broke something with the string variant.

    https://docs.unity3d.com/ScriptReference/Material.EnableKeyword.html
    https://forum.unity.com/threads/shader-keyword-system-improvements-in-2021-2-alpha.1104865/

    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class FirstSystemSwitch : Interactable
    6. {
    7.     [SerializeField] private Material LightMat;
    8.     [SerializeField] private GameObject Switch;
    9.     [SerializeField] private Renderer FirstSystemSwitchlight;
    10.  
    11.     private LocalKeyword emissionKeyword;
    12.  
    13.     private bool mainPower;
    14.  
    15.     private bool PointingUp;
    16.     // Start is called before the first frame update
    17.     void Start()
    18.     {
    19.         LightMat = FirstSystemSwitchlight.GetComponent<Renderer>().material;
    20.         emissionKeyword = new LocalKeyword(LightMat.shader, "_EMISSION");
    21.     }
    22.  
    23.     // Update is called once per frame
    24.     void Update()
    25.     {
    26.         if (mainPower == true)
    27.         {
    28.             LightMat.EnableKeyword(emissionKeyword);
    29.         }
    30.         else if (mainPower == false)
    31.         {
    32.             LightMat.DisableKeyword(emissionKeyword);
    33.         }
    34.     }
    35.  
    36.     protected override void Interact()
    37.     {
    38.         mainPower = !mainPower;
    39.         PointingUp = !PointingUp;
    40.         Switch.GetComponent<Animator>().SetBool("pointingUp", PointingUp);
    41.  
    42.     }
    43. }
     
    Last edited: Apr 28, 2024
    Spy-Master likes this.
  11. Spy-Master

    Spy-Master

    Joined:
    Aug 4, 2022
    Posts:
    847
    @Ryiah you probably want to get rid of the Update for the first experiment, lest the thing just reset to the state set in Update on most frames. Also, if using LocalKeyword, there's conveniently Material.SetKeyword.
    Code (csharp):
    1. LightMat.SetKeyword(emissionKeyword, mainPower);
     
    Ryiah likes this.
  12. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,698
    Oops, you're right, I've commented it out.
     
    Spy-Master likes this.
  13. Kuvaaja

    Kuvaaja

    Joined:
    Dec 9, 2023
    Posts:
    8
    It does accept new requests I tested the first code and all the lights turned on and the light that was supposed to turn on and off did just that. I'm now looking into the other possible problem. Thanks!
     
  14. Kuvaaja

    Kuvaaja

    Joined:
    Dec 9, 2023
    Posts:
    8
    I tested the other code you send and still nothing. I checked the materials shader and there is the _EMISSION keyword. I still believe that the boolean is not changing for some reason...
     
  15. Kuvaaja

    Kuvaaja

    Joined:
    Dec 9, 2023
    Posts:
    8
    At this point could someone please redo the code in some different way if theres any.
     
  16. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,936
    Is there some reason why the _EMISSION keyword needs to be toggled?
    If using the Standard shader the code I posted above should work:

    Code (csharp):
    1.  
    2.  
    3. if (mainPower == true) {
    4.   LightMat.EnableKeyword ("_EMISSION");
    5.   LightMat.SetColor("_EmissionColor", Color.white);
    6. } else if (mainPower == false) {
    7.    LightMat.SetColor("_EmissionColor", Color.black);
    8. }
    9.  
    The material should start out with the Emission check-mark enabled.