쯔꾸르식 유니티 게임 공부

14.이벤트 구현하기

ruripanda 2025. 1. 23. 10:05

using UnityEngine;
using System.Collections.Generic;//<= 제네릭 필수!
using System.Collections;//<=코루틴을 적용하는데 필요
using TMPro;//<=텍스트 매쉬 프로 전용 using

public class DialogueManager : MonoBehaviour
{
    public static DialogueManager instance;//씬을 이동하더라도 인스턴스로 남게 함

    #region Singleton
    private void Awake()
    {
        if (instance == null)
        {
            DontDestroyOnLoad(this.gameObject);
            instance = this;
        }
        else
        {
            Destroy(this.gameObject);
        }
    }
    #endregion Singleton

    public TMP_Text text;//텍스트 메쉬 프로로 작성
    public SpriteRenderer rendererSprite;//캐릭터 스프라이트 조절
    public SpriteRenderer rendererDialoguWindow;//다이어로그 윈도우 조절

    public List<string> listSentences;
    public List<Sprite> listSprites;
    public List<Sprite> listDialogueWindows;//리스트 형으로 대화창 실행불러오기

    private int count;// 대화진행 상황

    public Animator animSprite;//캐릭터 애니메이션
    public Animator animDialogueWindow;//다이어로그 애니메이션

    public string typeSound;//사운드 이름
    public string enterSound;//사운드 이름

    private AudioManager theAudio;//오디오 메니져 불러오기

    public bool talking = false;//bool값으로 대화
    public bool keyActivated = false;//bool값으로 키 입력 방지
    //private OrderManager theOrder;오더 메니져 불러오기

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        count = 0;
        text.text = "";
        listSentences = new List<string>();
        listSprites = new List<Sprite>();
        listDialogueWindows = new List<Sprite>();
        theAudio = FindAnyObjectByType<AudioManager>();
        //theOrder = FindAnyObjectByType<OrderManager>();
        //각종 변수 초기화와 컴포넌트 불러오기
    }

    public void ShowDialogue(Dialogue dialogue)//다이어로그 실행
    {
        talking = true;

        //theOrder.NotMove();//오더메니져에서 움직임 실행 정지
        for (int i = 0; i < dialogue.sentences.Length; i++)
        {
            listSentences.Add(dialogue.sentences[i]);               //대사
            listSprites.Add(dialogue.sprites[i]);                   //캐릭터 이미지
            listDialogueWindows.Add(dialogue.dialogueWindows[i]);   //대사창
        }

        animSprite.SetBool("Appear", true);
        animDialogueWindow.SetBool("Appear", true); //애니메이터 파라메터 조작
        StartCoroutine(StartDialogueCoroutine());   //코루틴 실행
    }

    public void ExitDialogue()//대화창 종료
    {
        text.text = "";
        count = 0;
        listSentences.Clear();
        listSprites.Clear();
        listDialogueWindows.Clear();
        animSprite.SetBool("Appear", false);
        animDialogueWindow.SetBool("Appear", false);
        talking = false;
        //theOrder.Move();//종료하면서 각종 변수와 코루틴 초기화,이벤트에서 관리하게 변경
    }

    IEnumerator StartDialogueCoroutine()//대화창 실행
    {
        if (count > 0)//대사 카운트가 0보다 크면
        {
            if (listDialogueWindows[count] != listDialogueWindows[count - 1])//바로 전 다이어로그와 비교
            {
                animSprite.SetBool("Change", true);
                animDialogueWindow.SetBool("Appear", false);    //파라메터 조작
                yield return new WaitForSeconds(0.2f);          //코루틴 대기
                rendererDialoguWindow.GetComponent<SpriteRenderer>().sprite = listDialogueWindows[count];
                rendererSprite.GetComponent<SpriteRenderer>().sprite = listSprites[count];                  //컴포넌트 불러오기
                animDialogueWindow.SetBool("Appear", true);
                animSprite.SetBool("Change", false);
            }
            else//조건문으로 만약을 실행
            {
                if (listSprites[count] != listSprites[count - 1])//바로  전 캐릭터 이미지와 비교
                {
                    animSprite.SetBool("Change", true);
                    yield return new WaitForSeconds(0.1f);
                    rendererSprite.GetComponent<SpriteRenderer>().sprite = listSprites[count];
                    animSprite.SetBool("Change", false);
                }
                else
                {
                    yield return new WaitForSeconds(0.05f);
                }
            }
        }
        else
        {
            rendererDialoguWindow.GetComponent<SpriteRenderer>().sprite = listDialogueWindows[count];
            rendererSprite.GetComponent<SpriteRenderer>().sprite = listSprites[count];
        }

        keyActivated = true;//키입력 방지
        for (int i = 0; i < listSentences[count].Length; i++)
        {
            text.text += listSentences[count][i];//첫번째 문장에 가나다라 마바사가 있다면 한글자씩 출력
            if(i % 7 == 1)
            {
                theAudio.Play(typeSound);//대사창이 움직일때 오디오 실행
            }
            yield return new WaitForSeconds(0.01f);
        }
    }
    // Update is called once per frame
    void Update()
    {
        if (talking && keyActivated)//조건문으로 키입력 방지와 대화 시작
        {
            if (Input.GetKeyDown(KeyCode.Z))//Z키 클릭
            {
                keyActivated = false;
                count++;
                text.text = "";
                theAudio.Play(enterSound);//각종 초기화
                if (count == listSentences.Count)//대화창 코루틴 실행
                {
                    StopAllCoroutines();    //모든 코뤁틴 정지
                    ExitDialogue();         //대사 코루틴 나가기
                }
                else
                {
                    StopAllCoroutines();    //모든 코루틴 정지
                    StartCoroutine(StartDialogueCoroutine());//대사 코루틴 시작
                }
            }
        }
    }
}
using System.Collections;
using UnityEngine;

public class Event1 : MonoBehaviour
{
    public Dialogue dialogue_1;
    public Dialogue dialogue_2;

    private DialogueManager theDM;
    private OrderManager theOrder;
    private PlayerManager thePlayer;// animator.getFloat "DirY"==1f;위를 바라볼때

    private bool flag;

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        theDM = FindAnyObjectByType<DialogueManager>();//다이어로그 찾아오기
        theOrder = FindAnyObjectByType<OrderManager>();//오더메니져 찾아오기
        thePlayer = FindAnyObjectByType<PlayerManager>();//플레이어 매니져 찾아오기
    }

    private void OnTriggerStay2D(Collider2D collision)
    {
        if (!flag && Input.GetKey(KeyCode.Z) && thePlayer.animator.GetFloat("DirY") == 1f)
            //조건문 플레그가 flase이면서 z키를 입력하고 캐릭터가 보는 방향이 위일때
        {
            flag = true;
            StartCoroutine(EventCoroutine());
        }
    }
    IEnumerator EventCoroutine()
    {
        theOrder.PreLoadCharacter();
        
        yield return new WaitUntil(() => !theDM.talking);

        theOrder.NotMove();
        theDM.ShowDialogue(dialogue_1);
        theOrder.Move("Player", "RIGHT");
        theOrder.Move("Player", "RIGHT");
        theOrder.Move("Player", "UP");

        yield return new WaitUntil(() => thePlayer.queue.Count == 0);

        theDM.ShowDialogue(dialogue_2);
        yield return new WaitUntil(() => !theDM.talking);
        theOrder.Move();
    }
}

 

이번 시간은 좀 쉬어가는 시간이다

Event1이라는 스크립트를 만들어 준다

 

 

첫번째로 작성할 부분은 다이어로그 1,2를 등록할 수 있게 커스텀 이벤트를 만들어준다

그리고 그 아래 9~11줄까지는 필요한 컴포넌트를 불러와 준다

그뒤 void Start()에 장착한다

그 뒤 플레그가 아니면서 Z키를 누르고 플레이어 캐릭터가 위를 바라보면이라는 조건을 달아준다

그 뒤 flag를 true로 바꿔주고 코루틴을 실행한다

 

 

32번 줄부터는 코루틴이다

일단 캐릭터에게 할당한 이름이 있기 때문에 theOrder.PreLoadCharacter을 작성해준다

그뒤 theOrder.NotMove()를 호출해 준다

 

그리고 우리는 DialogueManager에서 the.Order.NotMove()를 실행하게 했는데 이제 이 부분을 지워주고 Event1에서 조작하게 한다

필자가 보여준 스샷의 64번째 줄이다

그리고 당연히 우리가 OrderManager을 불러오는 함수도 정지해준다

45번 줄과 56번 줄이다

 

Event1으로 다시 돌아와서

ShowDialogue(dialogue_1) 을 실행하고 캐릭터 움직임을 어떻게 할지 작성해준다

 

그뒤 큐가 다 완료될때까지 기다리고

ShowDialogue(dialogue_2)가 실행되게 한다

그뒤 WaitUntil로 리턴문을 작성 종료해준다

 

이제 빈 오브젝트에 Event1을 넣어주고 표지판에서 애니메이션을 실행하게 한다

 

 

이제 완성이 됬다

 

ps.

이번 강좌는 정말 쉬어가기네요

대사창에서 시간을 너무 잡아먹어서...

글을 읽으신 분들은 모르실 수 있는데 전에 올린 대사창은 한 일주일 공부한 것 같습니다

'쯔꾸르식 유니티 게임 공부' 카테고리의 다른 글

16.날씨효과  (0) 2025.02.04
15.페이드 & 플레시 연출  (0) 2025.01.24
13.대화시스템  (0) 2025.01.21
12.NPC 충돌방지(Box콜라이더 이동)  (0) 2025.01.16
11.이벤트 캐릭터 이동명령 이벤트  (0) 2025.01.15