0
\$\begingroup\$

I want to change the aperture of the depth of field in the camera smoothly by using Mathf.SmoothDamp and a Coroutine, however, since I'm new to game development, I don't know if this is the right way to do it. Any suggestions?

Code:

using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityStandardAssets.ImageEffects;

public class GameStartController : MonoBehaviour {
    public Button startButton;
    public GameObject cubeSpawner;

    // Use this for initialization
    private void Start() {
        startButton = startButton.GetComponent<Button>();   
    }

    public void StartGame() {
        EnableCubeSpawner();
        SpawnStartingCubes();
        HideStartMenu();
        StartCoroutine("FocusCamera");
        PlayBackgroundMusic();
    }

    // Enables the cube spawner, so it can start spawning cubes
    private void EnableCubeSpawner() {
        cubeSpawner.SetActive(true);
    }

    private void SpawnStartingCubes() {
        cubeSpawner.GetComponent<CubeSpawner>().GenerateStartingCubes();
    }

    private void PlayBackgroundMusic() {
        var audio = GameObject.FindWithTag("Audio").GetComponent<AudioController>();
        audio.PlayBackgroundMusic();
    }

    private void HideStartMenu() {
        startButton.transform.parent.GetComponent<CanvasGroup>().interactable = false;
        startButton.transform.parent.GetComponent<CanvasGroup>().alpha = 0f;
    }

    private IEnumerator FocusCamera() {
        var camera = GameObject.FindWithTag("MainCamera").GetComponent<Camera>();
        var velocity = 0f;

        while (Mathf.Abs(camera.GetComponent<DepthOfField>().aperture) > 0.001f) {
            Debug.Log(Mathf.Abs(camera.GetComponent<DepthOfField>().aperture));

            camera.GetComponent<DepthOfField>().aperture = Mathf.SmoothDamp(camera.GetComponent<DepthOfField>().aperture, 0f, ref velocity, 0.3f);
            yield return null;
        }

        camera.GetComponent<DepthOfField>().aperture = 0f;
    }
}
\$\endgroup\$
3
  • \$\begingroup\$ I would probably use Update or FixedUpdate myself, unless I was using a Tween plugin, then I'd use that. \$\endgroup\$ Jan 5, 2016 at 21:15
  • \$\begingroup\$ @Draco18s I can't schedule when to perform operations with Update or FixedUpdate unless I use flags, which can get really annoying. \$\endgroup\$ Jan 5, 2016 at 21:19
  • \$\begingroup\$ Huh. Ok then. I haven't played with DepthOfField before, so if its something that can't be tweaked that easily, that's a bummer. \$\endgroup\$ Jan 5, 2016 at 21:21

2 Answers 2

2
\$\begingroup\$

Should I use Coroutines to change variables in inspector smoothly?

The real answer is "it depends" but to start, there's nothing wrong with your approach. While the alternative would be to just place a function call in your Update(), what you're doing allows you more flexibility, allows you to start and stop easily, and keeps you from needing to litter your class with flags. Arguably, utilizing the Update() built into MonoBehaviour would make debugging slightly easier.

While that hopefully answers your question, I would still clean up some parts of the coroutine you wrote. In Unity, you want to avoid calling GetComponent<T> during runtime so you should hold onto the reference to the DepthOfField component you're access 4 times each frame (unless there's the possibility that component is destroyed and recreated) :

private IEnumerator FocusCamera() {
    var camera = GameObject.FindWithTag("MainCamera").GetComponent<Camera>();
    var velocity = 0f;

    DepthOfField dof = camera.GetComponent<DepthOfField>();

    while (Mathf.Abs(dof.aperture) > 0.001f) {
        Debug.Log(Mathf.Abs(dof.aperture));

        dof.aperture = Mathf.SmoothDamp(dof.aperture, 0f, ref velocity, 0.3f);
        yield return null;
    }

    dof.aperture = 0f;
}

I also figure I'd mention using the string version of StartCoroutine() has more performance overhead that just calling the IEnumerator directly. The string version would also only allow you to pass a single parameter (which doesn't matter in this case but can make a difference down the line):

StartCoroutine(FocusCamera());

The tradeoff here is whether or not you'd like to call StopCoroutine() at some point. When using strings you can call StopCoroutine("FocusCamera") and it will simply kill the first coroutine with that name. This makes things simple when you're managing a single instance that starts and stops regularly but, from what I can tell, you don't have a need for StopCouroutine() at the moment and there's also minimal work to do for stopping with the non-string approach:

private IEnumerator coroutine;

...

coroutine = FocusCamera();
StartCoroutine(coroutine);

...

StopCoroutine(coroutine);
\$\endgroup\$
0
0
\$\begingroup\$

Using coroutines in this kind of situations is more convenient. It's pretty flexible, for example, you can create series of events.

IEnumerator Start () {
    yield FocusCamera();
    yield ShowTitleGraphic();
    yield FadeTitleGraphic();
    yield FadeInMainMenu();
    // etc.
}

Pretty informative discussion is here.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .