Dungeon Escape

Dungeon Escape is a narration based adventure game developed for a 48-hour game jam using Unity. I have synchronized the narration with the player's actions.

Code Snippets

Narrator Manager

public class NarratorManager : MonoBehaviour
{
    public static NarratorManager Instance { get; private set; }
    [SerializeField] private AudioSource audioSource;

    [Header("First Level")] [SerializeField]
    private GameObject deadDwarf;

    [SerializeField] private GameObject dwarfBracelet;
    [SerializeField] private GameObject lockedDoor;
    [Header("Second Level")] public bool HasDiedOnTheSecondLevel = false;
    [SerializeField] private PlayerMovement playerMovement;

    [Header("Third Level")] [SerializeField]
    private float thirdLevelSecondsUntilTimeStop;

    [SerializeField] private Rigidbody rb;

    [SerializeField] private GameObject correctLever;

    //[SerializeField] private bool correctLeverPulled;
    [SerializeField] private GameObject thirdLevelTeleporter;

    [Header("Fourth Level")] [SerializeField]
    private GameObject lavaToDisable;

    [SerializeField] private GameObject grapplingHookUI;
    [SerializeField] private GameObject theEndText;

    private Coroutine currentRoutine = null;
    [SerializeField] private SerializedDictionary<AudioType, AudioClip> clipsDic;

    private void Awake()
    {
        if (Instance != null && Instance != this)
            Destroy(this);

        else
            Instance = this;
    }

    private void Start()
    {
        Teleporter.OnTeleported += NarrateLevels;
        deadDwarf.GetComponent<DeadBody>().OnBraceletPickedUp += StartNarratingFirstLevelPartTwo;
        lockedDoor.GetComponent<CageDoor>().OnDoorOpened += StartNarratingFirstLevelPartThree;
        currentRoutine = StartCoroutine(NarrateFirstLevelNoBracelet());
        playerMovement.canWallRun = false;
    }

    private IEnumerator NarrateFirstLevelNoBracelet()
    {
        audioSource.clip = clipsDic[AudioType.Intro];
        audioSource.Play();
        yield return new WaitWhile(() => audioSource.isPlaying);
        deadDwarf.layer = LayerMask.NameToLayer("Interactable");
    }

    private void StartNarratingFirstLevelPartTwo(object sender, EventArgs e)
    {
        StartCoroutine(NarrateFirstLevelGotBracelet());
    }

    private void StartNarratingFirstLevelPartThree(object sender, EventArgs e)
    {
        StartCoroutine(NarrateFirstLevelDoorOpened());
    }

    private IEnumerator NarrateFirstLevelGotBracelet()
    {
        audioSource.clip = clipsDic[AudioType.Intro2];
        audioSource.Play();
        yield return new WaitWhile(() => audioSource.isPlaying);
        lockedDoor.layer = LayerMask.NameToLayer("Interactable");
    }

    private IEnumerator NarrateFirstLevelDoorOpened() // Edge case: Player speedruns to level 2
    {
        audioSource.clip = clipsDic[AudioType.Parkour];
        audioSource.Play();
        yield return new WaitWhile(() => audioSource.isPlaying);
    }

    private void NarrateLevels(object sender, TeleportEventArgs e)
    {
        switch (e.NewLevel)
        {
            case 1:
                StartCoroutine(NarrateSecondLevel());
                break;
            case 2:
                StartCoroutine(NarrateThirdLevel());
                break;
            case 3:
                lavaToDisable.SetActive(false);
                break;
        }
    }

    private IEnumerator NarrateSecondLevel()
    {
        // Disable wall jump!
        audioSource.clip = clipsDic[AudioType.Parkour2];
        audioSource.Play();
        SubtitleManager.OnSubtitle?.Invoke();
        yield return new WaitWhile(() => audioSource.isPlaying);

        while (true)
        {
            if (HasDiedOnTheSecondLevel)
            {
                yield return NarrateSecondLevelFirstDeath();
                yield break;
            }

            yield return null;
        }
    }

    private IEnumerator NarrateSecondLevelFirstDeath()
    {
        audioSource.clip = clipsDic[AudioType.Parkour2Second];
        audioSource.Play();
        SubtitleManager.OnSubtitle?.Invoke();
        playerMovement.canWallRun = true;
        yield return new WaitWhile(() => audioSource.isPlaying);
        audioSource.clip = clipsDic[AudioType.MomAreYouStillPlaying];
        audioSource.Play();
        SubtitleManager.OnSubtitle?.Invoke();
        yield return new WaitWhile(() => audioSource.isPlaying);
        audioSource.clip = clipsDic[AudioType.Parkour2Third];
        audioSource.Play();
        SubtitleManager.OnSubtitle?.Invoke();
    }


    private IEnumerator NarrateThirdLevel()
    {
        audioSource.clip = clipsDic[AudioType.Puzzle];
        audioSource.Play();
        SubtitleManager.OnSubtitle?.Invoke();
        yield return new WaitWhile(() => audioSource.isPlaying);
        //yield return new WaitForSeconds(thirdLevelSecondsUntilTimeStop);
    }

    public void DoNarrateThirdLevelDeath()
    {
        StartCoroutine(NarrateThirdLevelDeath());
    }

    private IEnumerator NarrateThirdLevelDeath()
    {
        audioSource.Stop();
        //subtitle stoplayacagız.

        rb.constraints = RigidbodyConstraints.FreezeAll;
        Time.timeScale = 0f;
        // ---------------------------------------Freeze player HERE!---------------------------------------
        audioSource.clip = clipsDic[AudioType.PuzzleSecond];
        audioSource.Play();
        SubtitleManager.OnSubtitle?.Invoke();
        yield return new WaitWhile(() => audioSource.isPlaying);
        correctLever.SetActive(true);
        Time.timeScale = 1f;
        rb.constraints = RigidbodyConstraints.FreezeRotation;
        Destroy(lavaToDisable.GetComponent<Animator>());
        lavaToDisable.transform.localScale = new Vector3(0.2f, 1.5f, 0.2f);
        // Make lava smaller
    }

    public void DoNarrateCorrectLevelPulledThirdLevel()
    {
        Debug.Log("Lever pulled!");
        StartCoroutine(NarrateCorrectLevelPulledThirdLevel());
    }

    private IEnumerator NarrateCorrectLevelPulledThirdLevel()
    {
        Debug.Log("BRUH");
        thirdLevelTeleporter.SetActive(true);
        yield return new WaitForSeconds(0.75f);
        yield return NarrateFourthLevel();
        thirdLevelTeleporter.SetActive(false);
    }

    private IEnumerator NarrateFourthLevel()
    {
        audioSource.clip = clipsDic[AudioType.Parkour3AfterLevelFinish];
        audioSource.Play();
        SubtitleManager.OnSubtitle?.Invoke();
        yield return new WaitForSeconds(25f);
        grapplingHookUI.SetActive(true);
        yield return new WaitUntil(() => Input.GetKeyDown(KeyCode.C));
        grapplingHookUI.SetActive(false);
        //yield return new WaitWhile(() => audioSource.isPlaying);
    }

    public void DoNarrateCoinsCollectedFirstTimeFourthLevel()
    {
        StartCoroutine(NarrateCoinsCollectedFirstTimeFourthLevel());
    }

    public void DoNarrateCoinsCollectedNotFirstTimeFourthLevel()
    {
        StartCoroutine(NarrateCoinsCollectedNotFirstTimeFourthLevel());
    }

    public void DoNarrateCoinsNotCollectedFourthLevel()
    {
        StartCoroutine(NarrateCoinsNotCollectedFourthLevel());
    }

    private IEnumerator NarrateCoinsCollectedFirstTimeFourthLevel()
    {
        audioSource.clip = clipsDic[AudioType.EndCoinsCollectedFirstTime];
        audioSource.Play();

        yield return new WaitWhile(() => audioSource.isPlaying);
        yield return NarrateMomTalkFourthLevel();
    }

    private IEnumerator NarrateCoinsCollectedNotFirstTimeFourthLevel()
    {

        audioSource.clip = clipsDic[AudioType.EndCoinsCollectedNotFirstTime];
        audioSource.Play();

        yield return new WaitWhile(() => audioSource.isPlaying);
        yield return NarrateMomTalkFourthLevel();
    }

    private IEnumerator NarrateCoinsNotCollectedFourthLevel()
    {
        audioSource.clip = clipsDic[AudioType.EndCoinsNotCollectedAtAll];
        audioSource.Play();

        yield return new WaitWhile(() => audioSource.isPlaying);
    }

    private IEnumerator NarrateMomTalkFourthLevel()
    {
        audioSource.clip = clipsDic[AudioType.MomGoToSleep];
        audioSource.Play();

        yield return new WaitWhile(() => audioSource.isPlaying);
        audioSource.clip = clipsDic[AudioType.OkayMom];
        audioSource.Play();

        yield return new WaitWhile(() => audioSource.isPlaying);
        theEndText.SetActive(true);
    }
}

public enum AudioType
{
    Intro,
    Intro2,
    Parkour,
    Parkour2,
    Parkour2Second,
    Parkour2Third,
    Parkour3AfterLevelFinish,
    Puzzle,
    PuzzleSecond,
    EndCoinsCollectedFirstTime,
    EndCoinsCollectedNotFirstTime,
    EndCoinsNotCollectedAtAll,
    MomAreYouStillPlaying,
    MomGoToSleep,
    OkayMom
}