Im writing (trying) a coroutine to handle the loading of rooms in a game. Once a player enters a trigger it starts a coroutine to handle loading the different elements of the next room. Question here, im having trouble with a screen transition that uses a shader and a float in the material to transition from transparent to black, but when I call this in a coroutine using Mathf.MoveTowards is only changing a tiny portion of the float at a time, almost as if it's getting interrupted.
public class RoomManager : MonoBehaviour {
public static RoomManager Instance { get; private set; }
public Room currentRoom;
private void Awake() {
if (Instance != null && Instance != this) {
Destroy(this);
} else {
Instance = this;
}
}
public IEnumerator LoadRoom(Room nextRoom) {
Debug.Log("Started Coroutine : Room loading is " + nextRoom);
StartCoroutine(RoomTransitionController.Instance.RoomTransitionHide());
yield return new WaitUntil(RoomTransitionController.Instance.TransitionHasLoaded);
Debug.Log("waiting done");
currentRoom = nextRoom;
CameraController.Instance.UpdateCameraPos(currentRoom);
StartCoroutine(RoomTransitionController.Instance.RoomTransitionShow());
yield return null;
}
}
public class RoomTransitionController : MonoBehaviour {
public static RoomTransitionController Instance { get; private set; }
private Image image;
public float transitionSpeed = 1.25f;
private bool loadedTransition;
private void Awake() {
if(Instance != null && Instance != this) {
Destroy(this);
}
else {
Instance = this;
}
}
private void Start() {
image = GetComponent<Image>();
if(image.material.GetFloat("_Cutoff") != 1f ) {
image.material.SetFloat("_Cutoff", 1f);
}
loadedTransition = false;
}
public bool TransitionHasLoaded() {
return image.material.GetFloat("_Cutoff") == -0.1f - image.material.GetFloat("_EdgeSmoothing");
}
public IEnumerator RoomTransitionHide() {
loadedTransition = false;
while(!loadedTransition) {
image.material.SetFloat("_Cutoff", Mathf.MoveTowards(image.material.GetFloat("_Cutoff"), -0.1f - image.material.GetFloat("_EdgeSmoothing"), transitionSpeed * Time.deltaTime));
yield return new WaitUntil( TransitionHasLoaded );
loadedTransition = true;
}
yield return null;
}
public IEnumerator RoomTransitionShow() {
while( loadedTransition ) {
image.material.SetFloat("_Cutoff", Mathf.MoveTowards(image.material.GetFloat("_Cutoff"), 1f, transitionSpeed * Time.deltaTime));
loadedTransition = false;
}
yield return null;
}
I know the shader is working correctly because it can get it working using the update method, but i would prefer use a coroutine and understand it better.
well you call the line
exactly once and then you wait until
TransitionHasLoadedreturnstrue- or in the second routine you just setloadedTransition = false;which means your loop will iterate maximum once as well.To reduce complexity right away: You can directly
yield returnanotherIEnumeratorfrom your main one!So there isn't really a need to expose
TransitionHasLoadedat all as you will already know when the innerIEnumeratoris finished:To take this one step further: I usually would prefer to use a given
durationinstead of a "magic"transitionSpeed. Your value of1.25is just way harder to understand then just setting0.8seconds. So I would actually rather doand then - regardless which of the above ways you choose - you can actually just yield and await these from within