ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 유니티 2D - 말하는 NPC 만들기, 최적화
    쾌락없는 책임 (공부)/Unity 2021. 5. 19. 20:05
    반응형

    <참고 영상>

     

    <코드>

     

    JangHanjun/GameMakers_Study

    Contribute to JangHanjun/GameMakers_Study development by creating an account on GitHub.

    github.com

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using TMPro;
    
    public class ChatSystem : MonoBehaviour{
    
        public Queue<string> sentences;
        public TextMeshPro text;
        public GameObject quad;
        string s;
        float textW;
        public void Ondialogue(string[] lines, Transform pos){
            transform.position = pos.position;
            sentences = new Queue<string>();
            sentences.Clear();
    
            // foreach(var line in lines){
            //     sentences.Enqueue(line);
            // }
            for(int i = 0; i < lines.Length; i++){
                sentences.Enqueue(lines[i]);
            }
            StartCoroutine(Talk(pos));
        }
    
        IEnumerator Talk(Transform quadPos){
            yield return null;
    
            while(sentences.Count > 0) {
                text.text = sentences.Dequeue();
    
                // 말풍선(quad) 크기 지정
                textW = text.preferredWidth;
                textW = (textW > 3.5f) ? 3.5f : textW + 1;
                quad.transform.localScale = new Vector2(textW, text.preferredHeight + 0.3f);
    
                transform.position = new Vector2(quadPos.position.x, quadPos.position.y + text.preferredHeight/2);
    
                yield return new WaitForSeconds(3f);
            }
    
            NpcDialogueMananger.NpcTalkEnd(this);
        }
    }
    

     

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class NpcDialogueMananger : MonoBehaviour{
        public static NpcDialogueMananger chatInstance;
        [SerializeField]
        GameObject quadPrefab;
        Queue<ChatSystem> chatPool = new Queue<ChatSystem>();
    
        private void Awake() {
            chatInstance = this;
            InitChatPool(3);
        }
    
        private void InitChatPool(int count){
            for(int i = 0; i < count; i++){
                chatPool.Enqueue(CreateQuad());
            }
        }
    
        private ChatSystem CreateQuad(){
            var obj = Instantiate(quadPrefab).GetComponent<ChatSystem>();
            obj.gameObject.SetActive(false);
            obj.transform.SetParent(transform);
    
            return obj;
        }
    
        public static ChatSystem NpcTalk(GameObject npc){
            var quad = chatInstance.chatPool.Dequeue();
            quad.gameObject.SetActive(true);
            quad.transform.SetParent(npc.transform);
            return quad;
        }
    
        public static void NpcTalkEnd(ChatSystem quad){
            quad.gameObject.SetActive(false);
            quad.transform.SetParent(chatInstance.transform);
            chatInstance.chatPool.Enqueue(quad);
        }
    }
    

     

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class NpcMovement : MonoBehaviour{
        public string[] sentences;
        public Transform chatTransform;
        public GameObject chatBox;
        Vector3 dir;
        RaycastHit2D rayHit;
        public bool talking;
        public int moveRand;
        Rigidbody2D rigid;
        SpriteRenderer sr;
        
    
        private void Start() {
            rigid = GetComponent<Rigidbody2D>();
            sr = GetComponent<SpriteRenderer>();
            StartCoroutine(walk());
        }
    
        private void FixedUpdate() {
            rigid.velocity = new Vector2(moveRand, rigid.velocity.y);
    
            if(moveRand > 0){
                sr.flipX = true;
                dir = Vector3.right;
            }
            else{
                sr.flipX = false;
                dir = Vector3.left;
            }
    
            rayHit = Physics2D.Raycast(rigid.position, dir, 1.5f, LayerMask.GetMask("Ground"));   
            if(rayHit){
                moveRand *= -1;
                Debug.Log("방향전환");
            }
            
        }
    
        IEnumerator walk(){
            moveRand = Random.Range(-1, 2);
            
            yield return new WaitForSeconds(2f);
            StartCoroutine(walk());
        }
        public void Talk(){
            talking = true;
            ChatSystem go = NpcDialogueMananger.NpcTalk(gameObject);
            go.GetComponent<ChatSystem>().Ondialogue(sentences, chatTransform);
            Invoke("Init", 8f);
        }
    
        private void OnTriggerEnter2D(Collider2D other) {
            if(other.CompareTag("Player") && talking == false){
                Talk();
            }
        }
    
        void Init(){
            talking = false;
        }
    }
    

     

    <설명>

     말풍선 프리팹과 코드는 위 영상과 비슷하게 되어 있습니다. 대신 2가지 사항들을 추가해서 개선을 했습니다.

     

    1. foreach -> for

     유니티에서 foreach를 사용할 경우 GC가 24바이트를 먹기 때문에 for로 변경을 했습니다. 이를 통해서 GC호출시 렉을 줄일 수 있었습니다.

     

    2. 채팅 풀을 만들어 실행

     Instantiate, Destroy를 영상에서 사용했는데 2번째 코드인 NpcDialogueManager를 만들어서 싱글톤으로 선언을 한 뒤 이 오브젝트 풀에서 가져오고 반환하는 식으로 만들었습니다.

     

     그 외에는 NPC에 움직임을 추가해 벽에 충돌하지 않게 했으며 플레이어가 근처에 오면 OnTriggerEnter2D를 통해서 말풍선을 가져오는 함수를 실행했습니다. 또한 플레이어가 콜라이더 경계선을 오가면 한번에 여러개의 말풍선을 불러오게 되니 bool변수와 invoke를 통해서 텀을 줬습니다.

     

    반응형

    댓글

Designed by Tistory.