using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Fading : MonoBehaviour
{
[Header("Fading")]
public List<GameObject> objectsToFade = new List<GameObject>();
public float duration;
public Coroutine fadeCoroutine;
public bool automatic = false;
public bool startFading = false;
[Header("Random")]
public bool randomObjects = false;
public bool randomDuration = false;
public bool faded = false;
private bool fadeInOut = false;
private bool coroutineIsRunning = false;
private List<Material> objectsToFadeMaterials = new List<Material>();
private bool randomOnce = false;
private Material randomMaterial;
private float originalDuration;
private void Start()
{
originalDuration = duration;
for (int i = 0; i < objectsToFade.Count; i )
{
objectsToFadeMaterials.Add(objectsToFade[i].GetComponent<Renderer>().material);
}
}
private void Update()
{
if (startFading)
{
if (automatic)
{
if (!coroutineIsRunning)
{
Fade();
}
}
else
{
if (Input.GetKeyDown(KeyCode.G))
{
Fade();
}
}
}
}
private void Fade()
{
fadeInOut = !fadeInOut;
if (fadeCoroutine != null)
StopCoroutine(fadeCoroutine);
if(randomDuration)
{
duration = Random.Range(1, 20);
}
else
{
duration = originalDuration;
}
if (randomObjects && objectsToFade.Count > 1)
{
if (randomOnce == false)
{
randomMaterial = objectsToFadeMaterials[Random.Range(0, objectsToFadeMaterials.Count)];
randomOnce = true;
}
if (fadeInOut)
{
fadeCoroutine = StartCoroutine(FadeTo(randomMaterial, 0, duration));
}
else
{
fadeCoroutine = StartCoroutine(FadeTo(randomMaterial, 1, duration));
}
}
else
{
for (int i = 0; i < objectsToFadeMaterials.Count; i )
{
if (fadeInOut)
{
fadeCoroutine = StartCoroutine(FadeTo(objectsToFadeMaterials[i], 0, duration));
}
else
{
fadeCoroutine = StartCoroutine(FadeTo(objectsToFadeMaterials[i], 1, duration));
}
}
}
}
public IEnumerator FadeTo(Material material, float targetOpacity, float duration)
{
Color color = material.color;
float startOpacity = color.a;
float t = 0;
coroutineIsRunning = true;
while (t < duration)
{
t = Time.deltaTime;
float blend = Mathf.Clamp01(t / duration);
color.a = Mathf.Lerp(startOpacity, targetOpacity, blend);
material.color = color;
if(t > duration)
{
coroutineIsRunning = false;
}
if(color.a == 1)
{
randomOnce = false;
}
if(color.a == 0)
{
faded = true;
}
yield return null;
}
}
}
I know that if the color.a is 0 then the object faded out finished then I set faded to true.
In the second script that is attached to a teleporter I want to start teleporting if the object faded out then teleport to the next teleporter and fade in back and so on.
This script is attached to each teleporter :
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class Teleport : MonoBehaviour
{
public Fading fading;
public List<GameObject> objectsToTeleport = new List<GameObject>();
//Start is called before the first frame update
void Start()
{
objectsToTeleport = GameObject.FindGameObjectsWithTag("ObjectToTeleport").ToList();
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter(Collider other)
{
StartCoroutine(fading.FadeTo(objectsToTeleport[0].GetComponent<Renderer>().material, 0, 2));
}
}
and this script is the teleporting script :
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.WebSockets;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
public class Teleporting : MonoBehaviour
{
public List<ObjectToTeleport> objectsToTeleport;
public List<ObjectToTeleport> currentlyTeleportedObjects;
public List<GameObject> teleporters;
public float teleportingTime;
public float teleportingStartTime;
public bool startTeleporting = false;
public GameObject[] groups;
public bool loop = false;
public bool random = false;
public int teleportationsCount = 0;
[Serializable]
public class ObjectToTeleport
{
public GameObject teleportableObject;
public int teleportOrder;
}
public void Start()
{
StartTeleporting();
}
private void Update()
{
}
public void StartTeleporting()
{
if (startTeleporting)
{
if (teleporters.Count > 1 && objectsToTeleport.Count > 0)
{
InvokeRepeating("MoveTeleportableObjects", teleportingStartTime, teleportingTime);
}
}
}
private void MoveTeleportableObjects()
{
if (teleportationsCount < objectsToTeleport.Count)
currentlyTeleportedObjects.Add(objectsToTeleport[teleportationsCount]);
for (int i = 0; i < currentlyTeleportedObjects.Count; i )
{
if (!loop)
{
MoveObjects(i);
}
else
{
MoveObjects(i);
}
}
teleportationsCount ;
}
private void MoveObjects(int i)
{
GameObject destinationTeleporter = teleporters[currentlyTeleportedObjects[i].teleportOrder];
currentlyTeleportedObjects[i].teleportableObject.transform.position = destinationTeleporter.transform.position;
if (currentlyTeleportedObjects[i].teleportOrder < teleporters.Count - 1)
{
currentlyTeleportedObjects[i].teleportOrder ;
}
else if (loop == true)
{
{
currentlyTeleportedObjects[i].teleportOrder = 0;
}
}
}
}
I need somehow a synchronization between the fading and the teleporting in the Teleport script. But it seems a bit complicated.
The Fading script on it's own and the Teleporting script on it's own are working fine but making a synchronization between them is the problem.
Update :
What I tried :
In the Fading script I added two methods FadIn and FadeOut and calling the FadeOut in the Teleport script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Fading : MonoBehaviour
{
[Header("Fading")]
public List<GameObject> objectsToFade = new List<GameObject>();
public float duration;
public Coroutine fadeCoroutine;
public bool automatic = false;
public bool startFading = false;
[Header("Random")]
public bool randomObjects = false;
public bool randomDuration = false;
public bool faded = false;
private bool fadeInOut = false;
private bool coroutineIsRunning = false;
private List<Material> objectsToFadeMaterials = new List<Material>();
private bool randomOnce = false;
private Material randomMaterial;
private float originalDuration;
private void Start()
{
originalDuration = duration;
for (int i = 0; i < objectsToFade.Count; i )
{
objectsToFadeMaterials.Add(objectsToFade[i].GetComponent<Renderer>().material);
}
}
private void Update()
{
if (startFading)
{
if (automatic)
{
if (!coroutineIsRunning)
{
Fade();
}
}
else
{
if (Input.GetKeyDown(KeyCode.G))
{
Fade();
}
}
}
}
private void Fade()
{
fadeInOut = !fadeInOut;
if (fadeCoroutine != null)
StopCoroutine(fadeCoroutine);
if(randomDuration)
{
duration = Random.Range(1, 20);
}
else
{
duration = originalDuration;
}
if (randomObjects && objectsToFade.Count > 1)
{
if (randomOnce == false)
{
randomMaterial = objectsToFadeMaterials[Random.Range(0, objectsToFadeMaterials.Count)];
randomOnce = true;
}
if (fadeInOut)
{
fadeCoroutine = StartCoroutine(FadeTo(randomMaterial, 0, duration));
}
else
{
fadeCoroutine = StartCoroutine(FadeTo(randomMaterial, 1, duration));
}
}
else
{
for (int i = 0; i < objectsToFadeMaterials.Count; i )
{
if (fadeInOut)
{
fadeCoroutine = StartCoroutine(FadeTo(objectsToFadeMaterials[i], 0, duration));
}
else
{
fadeCoroutine = StartCoroutine(FadeTo(objectsToFadeMaterials[i], 1, duration));
}
}
}
}
private IEnumerator FadeTo(Material material, float targetOpacity, float duration)
{
Color color = material.color;
float startOpacity = color.a;
float t = 0;
coroutineIsRunning = true;
while (t < duration)
{
t = Time.deltaTime;
float blend = Mathf.Clamp01(t / duration);
color.a = Mathf.Lerp(startOpacity, targetOpacity, blend);
material.color = color;
if(t > duration)
{
coroutineIsRunning = false;
}
if(color.a == 1)
{
randomOnce = false;
}
yield return null;
}
}
public IEnumerator FadeIn(Material material, float duration)
{
StartCoroutine(FadeTo(material, 1, duration));
yield return new WaitForSeconds(duration);
}
public IEnumerator FadeOut(Material material, float duration)
{
StartCoroutine(FadeTo(material, 0, duration));
yield return new WaitForSeconds(duration);
}
}
In the Teleport script
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class Teleport : MonoBehaviour
{
public Fading fading;
public List<GameObject> objectsToTeleport = new List<GameObject>();
//Start is called before the first frame update
void Start()
{
objectsToTeleport = GameObject.FindGameObjectsWithTag("ObjectToTeleport").ToList();
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter(Collider other)
{
StartCoroutine(fading.FadeOut(objectsToTeleport[0].GetComponent<Renderer>().material, 3));
}
private void OnTriggerExit(Collider other)
{
}
}
How do I continue from here ? what should I do next ?
CodePudding user response:
There are multiple ways.
Simply yield the routine
You already have both as Coroutines so you could wrap them in another Coroutine and yield return it instead of StartCoroutine (this is something you should do in FadeIn and FadeOut anyway!)
// If this returns IEnumerator Unity automatically runs it as Coroutine
private IEnumerator OnTriggerEnter(Collider other)
{
yield return fading.FadeOut(objectsToTeleport[0].GetComponent<Renderer>().material, 3));
// Something after fading finished
Debug.Log("Fade Out finished!");
}
You could of course as well have them separately like
private void OnTriggerEnter(Collider other)
{
StartCorouine (EnterRoutine(other));
}
private IEnumerator EnterRoutine ()
{
yield return fading.FadeOut(objectsToTeleport[0].GetComponent<Renderer>().material, 3));
// Something after fading finished
Debug.Log("Fade Out finished!");
}
Callback
Another way would be passing in a callback that is executed once the routine finishes like e.g.
private void OnTriggerEnter(Collider other)
{
StartCoroutine(fading.FadeOut(objectsToTeleport[0].GetComponent<Renderer>().material, 3, OnFadeOutFinished));
}
private void OnFadeOutFinished ()
{
Debug.Log("Fade Out finished!", this);
}
or using a lambda, especially helpful if you want to do something with the other reference
private void OnTriggerEnter(Collider other)
{
StartCoroutine(fading.FadeOut(objectsToTeleport[0].GetComponent<Renderer>().material, 3, () => {
Debug.Log("Fade Out finished!");
}));
}
and have it as parameter in your routine like
private IEnumerator FadeTo(Material material, float targetOpacity, float duration, Action callback)
{
Color color = material.color;
float startOpacity = color.a;
float t = 0;
coroutineIsRunning = true;
while (t < duration)
{
t = Time.deltaTime;
float blend = Mathf.Clamp01(t / duration);
color.a = Mathf.Lerp(startOpacity, targetOpacity, blend);
material.color = color;
if(t > duration)
{
coroutineIsRunning = false;
}
if(color.a == 1)
{
randomOnce = false;
}
yield return null;
}
callback?.Invoke();
}
public IEnumerator FadeIn(Material material, float duration, Action callback = null)
{
yield return FadeTo(material, 1, duration, callback));
}
public IEnumerator FadeOut(Material material, float duration, Action callback = null)
{
yield return FadeTo(material, 0, duration, callback));
}
CodePudding user response:
There are a lot of ways you could do this, but I personally in this case would create new coroutines FadeIn and FadeOut, instead of directly calling the following:
fadeCoroutine = StartCoroutine(FadeTo(objectsToFadeMaterials[i], 0, duration));
Then, at the end of your FadeOut coroutine you can take some additional step(s) to trigger a teleport or whatever else you need to trigger. It looks like you don't want your Fading to hold a reference to your Teleporting, which is smart, so you could choose to fire an event instead that your Teleporting component can subscribe to.
