Daniel Lip
Daniel Lip

Reputation: 11325

How can I set a duration for the fading effect time calling from any script?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FadeInOutSaveGameText : MonoBehaviour
{
    public Animator animator;

    private bool hasFade = false;

    // Start is called before the first frame update
    void Start()
    {

    }

    public void FadeOut()
    {
        animator.SetTrigger("FadeOut");
    }

    public void FadeIn()
    {
        animator.SetTrigger("FadeIn");
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.I))
        {
            FadeOut();
        }

        if (Input.GetKeyDown(KeyCode.O))
        {
            FadeIn();
        }
    }

    public void FadeOutMessage(string message)
    {
        if(message == "FadeInEnded")
        {
            FadeOut();
        }
    }

    public void FadeInMessage(string message)
    {
        if(message == "FadeOutEnded")
        {
            FadeIn();
        }
    }
}

This is working when I press on I or O keys and also I added two events for the animations and send the events messages and it's working too. The events make it fade in/out nonstop.

Now I want to add a coroutine method that get time(duration) and it will be able to be called from any other script something like :

public IEnumerator StartFading(float duration)
    {
        yield return new WaitForSeconds(duration);
    }

So if I make a reference to the FadeInOutSaveGameText script and call the method StartFading :

StartCoroutine(StartFading(5f));

Then it will fade in/out for 5 seconds or any other duration time.

I added a new IEnumerator function but not sure how to use it in the Update or how to call it from other scripts and make the fade out/in effect with time duration :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FadeInOutSaveGameText : MonoBehaviour
{
    public Animator animator;

    private bool hasFade = false;

    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(PlayAndWaitForAnim(animator, "FadeOut"));
    }

    public void FadeOut()
    {
        animator.SetTrigger("FadeOut");
    }

    public void FadeIn()
    {
        animator.SetTrigger("FadeIn");
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.I))
        {
            FadeOut();
        }

        if (Input.GetKeyDown(KeyCode.O))
        {
            FadeIn();
        }
    }

    public void FadeOutMessage(string message)
    {
        if(message == "FadeInEnded")
        {
            //FadeOut();
        }
    }

    public void FadeInMessage(string message)
    {
        if(message == "FadeOutEnded")
        {
            //FadeIn();
        }
    }

    public IEnumerator PlayAndWaitForAnim(Animator targetAnim, string stateName)
    {
        targetAnim.Play(stateName);

        //Wait until we enter the current state
        while (!targetAnim.GetCurrentAnimatorStateInfo(0).IsName(stateName))
        {
            yield return null;
        }

        //Now, Wait until the current state is done playing
        while ((targetAnim.GetCurrentAnimatorStateInfo(0).normalizedTime) % 1 < 0.99f)
        {
            yield return null;
        }
    }
}

Upvotes: 0

Views: 131

Answers (1)

derHugo
derHugo

Reputation: 90724

You can set the Animator.speed accordingly.

Make your animation clip duration exactly 1 second - this is the easiest to calculate.

So If you want a certain duration like let's say 5 seconds all you need to do is set the Animator.speed to 1 / 5f.

So in order to generalize this something like e.g.

public void FadeOut(float duration)
{
    animator.speed = 1f / duration;
    animator.SetTrigger("FadeOut");
    StartCoroutine(FadingRoutine(duration));
}

public void FadeIn(float duration)
{
    animator.speed = 1f / duration;
    animator.SetTrigger("FadeIn");
    StartCoroutine(FadingRoutine(duration));
}

private IEnumarator FadingRoutine(float duration)
{
    yield return new WaitForSeconds(duration);

    // Set animator speed to normal
    animator.speed = 1f;
}

What you describe in the comments sounds more like you actually want a continuous ping-pong fade effect.

I wouldn't use the Animator for that at all but a pure code based Coroutine like e.g.

[SerializeField][Min(0.0001f)] private float duration;

private IEnumerator PingPongFade()
{
    while(true)
    {
        // will automatically ping pong between 0 and 1
        var factor = Mathf.PingPong(Time.time * duration, 1);

        //TODO apply the value to your fading (whatever that means)
        // one example could be e.g.
        var color = GetComponent<Renderer>().material.color;
        color.a = factor;
        GetComponent<Renderer>().material.color = color;
    }
}

This way you have to only start this routine once and it will automatically fade-in and out all the time.

Upvotes: 1

Related Questions