티스토리 뷰

🎨/Unity

[Unity] NPC와 대화하기 (1)

eungding 2022. 2. 17. 13:30
반응형

[Unity] NPC와 충돌감지하기 에서 이어집니다. 

 

⭐️ 목표 ⭐️ 

1. NPC와 플레이어가 만나면 대화창 (DialogPanel) 이 활성화 되도록한다.

2. 텍스트를 한글자씩 타이핑하는 효과를 낸다 with 코루틴 


 

[1]  NPC와 플레이어가 만나면 DialogPanel 이 활성화 되도록

 

 대충 이미지와 텍스트를 자식으로 넣어둔 Panel을 만들었고 

 

 

Panel 의 태그를 DialogPanel 이라고 해놨습니다. 

그리고 Panel을 비활성화 해뒀습니다. 

 

 

그리고 NPCAreaController 에서 

충돌을 감지한 대상이 Player라면 DialogPanel을 활성화시키는 코드를 작성해줬습니다. 

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

public class NPCAreaController : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag == "Player")
        {
            GameObject panel = GameObject.FindWithTag("DialogPanel");
            if (panel == null)
            {
                return;
            }

            panel.SetActive(true);
        };
    }
}

 

저는 FindWithTag 를 사용해주었는데요! 

Find 처럼 게임오브젝트의 이름으로 찾는 메소드도 있습니다. 

 

근데 FindWithTag 랑 Find 모두 활성화된 오브젝트만 찾을 수 있다고 합니다!  

비활성화된 오브젝트를 찾고 싶은 경우, 활성화된 부모를 찾아서 자식을 찾는 형식으로 접근해야한다고 하네요 (참고: 비활성화 된 GameObject찾기)

 

 

그래서 스크립트의 onTriggerEnter 메소드를 아래와 같이 수정해줘야합니다. 

private void OnTriggerEnter(Collider other)
{
    if (other.gameObject.tag == "Player")
    {
        GameObject panel = GameObject.FindWithTag("Canvas").transform.Find("DialogPanel").gameObject;
        if (panel == null)
        {
            return;
        }

        panel.SetActive(true);
    };
}

 

근데 Swift의 옵셔널 체이닝이랑 다르게

C#은 GameObject.FindWithTag("Canvas") 에서 실패하면 panel이 null로 할당되는게 아니라 NullReferenceException이 납니다.  그렇다고 게임이 종료되지는 않고 콘솔에만 찍히더라구요! 

 

null 체크를 어디까지 해야되는 지 모르겠는데,,, 크래쉬는 안나니까 우선 이 정도만 하려고 합니다. 

(사실 transform.Find("Panel") 부분도 null 체크 해줘야될 것 같아요) 

private void OnTriggerEnter(Collider other)
{
    if (other.gameObject.tag == "Player")
    {
        GameObject canvas = GameObject.FindWithTag("Canvas");

        if (canvas == null)
        {
            return;
        }


        Transform transform = canvas.transform; // The Transform Attached to this GameObject
        GameObject panel = transform.Find("Panel").gameObject;

        if (panel == null)
        {
            return;
        }

        panel.SetActive(true);
    };
}

 

아무튼 NPC Area에 들어가면 Panel 이 활성화 잘 됩니다.

 

 

 

조이스틱이 거슬려서 내리고 싶다! 고 하면 현재 구조가 이렇게 되어있으니

JoySticsk를 비활성화 시키는 코드를 함께 추가해주면 됩니다. 

 

 

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag == "Player")
        {
            GameObject canvas = GameObject.FindWithTag("Canvas");

            if (canvas == null)
            {
                return;
            }


            Transform transform = canvas.transform; // The Transform Attached to this GameObject
            GameObject joysticksCanvas = transform.Find("UI_Canvas_StarterAssetsInputs_Joysticks").gameObject;
            GameObject panel = transform.Find("Panel").gameObject;

            if (joysticksCanvas == null || panel == null)
            {
                return;
            }

            joysticksCanvas.SetActive(false);
            panel.SetActive(true);
        };
    }

 

 

 

[2] 타이핑 되는 텍스트로 만들기

 

저는 이 유튜브 영상을 참고해줬습니다. 

 

 

# DialogController 만들기

DialogController를 만들고 Panel에 붙여줍니다. 

 

그리고 Text를 에디터에서 주입받울 수 있게 해주려고 dialogText를 추가했어요

Text 타입을 사용하려면 UnityEngine.UI를 임포트 해야합니다.

 

위에서 처럼 Find로 자식을 찾을 수 도 있지만, 이 방법이 더 간단하고 깔끔해서 이렇게 해볼게요! 

 

 

그리고 유니티 에디터로 돌아가보면 

이렇게 Text 를 주입받을 수 있는 필드가 생긴 것을 볼 수 있습니다.

 

 

DialogText를 필드에 넣어줍니다. 

 

 

DialogText는 이거에요! 

 

 

그리고 게임플레이하고 콘솔을 보면 우리가 만든 스크립트가 필드에 넣어준 텍스트에 잘 접근하고 있는 것을 확인할 수 있습니다.

 

 

 

# 코루틴 살펴보기 

그리고 코드를 작성하려면 코루틴에 대해서 알아야합니다.

간단히 정리하자면..! 

 

- 시간이 지남에 따라 점진적으로 업데이트 되어야하는 애니메이션, 이벤트를 작업해야할 때, 

update 함수 (매 프레임 마다 호출됨) 보다 코루틴(coroutine)을 사용하는 것이 더 편하다. 

 

- 코루틴은 실행을 일시 중지하고 Unity에 제어 권한을 반환한 후 다음 프레임에서 중단했던 위치에서 계속할 수 있는 함수다.

- 코루틴은 IEnumerator 반환 타입과 body 어딘가에 yield 반환문이 포함된 함수다. 

- yield return null 라인은 실행이 일시 중지되고 다음 프레임에서 다시 시작되는 지점이다. 

- 기본적으로 코루틴은 프레임이 생성된 후 다시 시작되지만 WaitForSeconds를 사용하여 시간 지연을 도입할 수 있다.

 

- 코루틴을 사용하려면  StartCoroutine 함수를 사용해야한다. 

StopCoroutine과 StopAllCoroutines를 사용하여 코루틴을 중지할 수 있다.
SetActive(false)로 인해 연결된 게임 오브젝트가 비활성화될 때에도 코루틴이 중지된다.  

 

 

# 코루틴 테스트해보기

DialogController를 아래와 같이 작성하고 게임플레이를 해볼까요?

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

public class DialogController : MonoBehaviour
{
    public Text dialogText;

    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(Typing(dialogText.text));
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    IEnumerator Typing(string text)
    {
        foreach (char letter in text.ToCharArray())
        {
            print(letter);
            yield return new WaitForSeconds(1f);
        } 
    }
}

 

그럼 1초마다 한글 자씩 프린트가 잘되는 것을 볼 수 있습니다.

 

 

 

# 타이핑 스크립트 작성하기

이제 드디어 타이핑하는 코드를 작성해봅시다. 

Start에서 현재 dialogText를 empty로 만들어주고

하드코딩한 샘플텍스트를 0.1초 간격으로 나오게 하는 코드 입니다. 

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

public class DialogController : MonoBehaviour
{
    public Text dialogText;

    // Start is called before the first frame update
    void Start()
    {
        dialogText.text = "";
        string sampleText = "안녕하세요 지니지니테스트님,\n반갑습니다 룰루라라";
        StartCoroutine(Typing(sampleText));
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    IEnumerator Typing(string text)
    {
        foreach (char letter in text.ToCharArray())
        {
            dialogText.text += letter;
            yield return new WaitForSeconds(0.1f);
        }
    }
}

 

 

 

 

 

반응형

'🎨 > Unity' 카테고리의 다른 글

[Unity] NPC와 대화하기 (2)  (0) 2022.02.18
[Unity] Xcode Simulator로 빌드하기  (0) 2022.02.17
[Unity] NPC와 충돌감지하기  (0) 2022.02.17
[Unity] Canvas 와 UI 오브젝트  (0) 2022.02.17
[Unity] Skybox  (0) 2022.02.10
댓글