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.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class Interactable : MonoBehaviour
{
//Message displayed to player when looking at an interactable.
public string promptMessage;
// Start is called before the first frame update
public void BaseInteract()
{
Interact();
}
protected virtual void Interact()
{
}
}
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.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FirstSystemSwitch : Interactable
{
[SerializeField] private Material LightMat;
[SerializeField] private GameObject Switch;
[SerializeField] private Renderer FirstSystemSwitchlight;
private bool mainPower;
private bool PointingUp;
// Start is called before the first frame update
void Start()
{
LightMat = FirstSystemSwitchlight.GetComponent<Renderer>().material;
}
// Update is called once per frame
void Update()
{
if (mainPower == true)
{
LightMat.EnableKeyword("_EMISSION");
}
else if (mainPower == false)
{
LightMat.DisableKeyword("_EMISSION");
}
}
protected override void Interact()
{
mainPower = !mainPower;
PointingUp = !PointingUp;
Switch.GetComponent<Animator>().SetBool("pointingUp", PointingUp);
}
}
Please help me this worked before i updated my unity engine from 2020.3.43f1 to 2022.3.26f1
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.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FirstSystemSwitch : Interactable
{
[SerializeField] private Material LightMat;
[SerializeField] private GameObject Switch;
[SerializeField] private Renderer FirstSystemSwitchlight;
private bool mainPower;
private bool PointingUp;
// Start is called before the first frame update
void Start()
{
mainPower = !mainPower;
LightMat = FirstSystemSwitchlight.GetComponent<Renderer>().material;
}
// Update is called once per frame
void Update()
{
if (mainPower == true)
{
LightMat.EnableKeyword("_EMISSION");
}
else if (mainPower == false)
{
LightMat.DisableKeyword("_EMISSION");
}
}
protected override void Interact()
{
PointingUp = !PointingUp;
Switch.GetComponent<Animator>().SetBool("pointingUp", PointingUp);
}
}
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
void Update()
{
if (mainPower == true)
{
LightMat.EnableKeyword("_EMISSION");
}
else if (mainPower == false)
{
LightMat.DisableKeyword("_EMISSION");
}
}
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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FirstSystemSwitch : Interactable
{
[SerializeField] private Material LightMat;
[SerializeField] private GameObject Switch;
[SerializeField] private Renderer FirstSystemSwitchlight;
private bool mainPower;
private bool PointingUp;
// Start is called before the first frame update
void Start()
{
LightMat = FirstSystemSwitchlight.GetComponent<Renderer>().material;
}
// Update is called once per frame
void Update()
{
if (mainPower == true)
{
LightMat.EnableKeyword("_EMISSION");
}
else if (mainPower == false)
{
LightMat.DisableKeyword("_EMISSION");
}
}
protected override void Interact()
{
mainPower = !mainPower;
PointingUp = !PointingUp;
Switch.GetComponent<Animator>().SetBool("pointingUp", PointingUp);
}
}
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.
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.
Coroutine
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FirstSystemSwitch : Interactable
{
[SerializeField] private Material LightMat;
[SerializeField] private GameObject Switch;
[SerializeField] private Renderer FirstSystemSwitchlight;
private bool mainPower;
private bool PointingUp;
// Start is called before the first frame update
void Start()
{
StartCoroutine(Flip());
LightMat = FirstSystemSwitchlight.GetComponent<Renderer>().material;
}
// Update is called once per frame
/*
void Update()
{
if (mainPower == true)
{
LightMat.EnableKeyword("_EMISSION");
}
else if (mainPower == false)
{
LightMat.DisableKeyword("_EMISSION");
}
}
*/
protected override void Interact()
{
mainPower = !mainPower;
PointingUp = !PointingUp;
Switch.GetComponent<Animator>().SetBool("pointingUp", PointingUp);
}
IEnumerator Flip()
{
while (true)
{
LightMat.EnableKeyword("_EMISSION");
yield return new WaitForSeconds(1.0f);
LightMat.DisableKeyword("_EMISSION");
yield return new WaitForSeconds(1.0f);
}
}
}
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.
@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.
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!
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…