동적으로 채우는 글자는 본 만큼 램에 쌓인다
Esc

    동적으로 채우는 글자는 본 만큼 램에 쌓인다

    –UnityUIuGUI

    게임 안의 글자는 대부분 정해져 있습니다. 버튼 문구, 설명, 퀘스트 이름은 만드는 쪽이 정합니다. 그런데 채팅, 유저 이름, 길드 이름, 외부에서 받아 오는 공지 는 무슨 글자가 나올지 미리 알 수 없습니다.

    Unity 는 이런 글자를 실행 중에 굽습니다. 화면에 처음 나온 글자를 그때 만들어서 글자 텍스처에 붙입니다. 영어권 게임에서는 별일이 아닙니다. 알파벳과 숫자, 기호를 다 합쳐도 백 자가 안 됩니다. 한글과 중국어에서는 이야기가 달라집니다.

    새 글자가 들어오면 벌어지는 일

    채팅 한 줄이 들어왔을 때 반갑습니다 :) 아틀라스에 있는 글자인가 있으면 그대로 그립니다 없으면 그 자리에서 굽고 빈 칸에 붙입니다 그 프레임이 잠깐 걸립니다 빈 칸이 없으면 가득 참 1 장 가득 참 2 장 새 장 3 장 빈 칸이 다 차면 같은 크기의 장이 하나 더 생깁니다. 1024 × 1024 한 장이 1 MB 입니다. 한 번 들어간 글자는 화면에서 사라져도 그 자리에 남아 있습니다. 지우는 것은 게임 쪽에서 따로 시켜야 합니다.
    처음 보는 글자는 그 자리에서 구워 붙이고, 자리가 없으면 장을 하나 더 만듭니다.

    한 번 구운 글자는 텍스처 안에 자리를 하나 차지합니다. 자리가 다 차면 같은 크기의 텍스처를 한 장 더 만듭니다. 글자가 늘어난 만큼 텍스처도 늘어납니다.

    • 처음 보는 글자가 나온 프레임에는 굽는 시간이 듭니다. 긴 문장이 한꺼번에 들어오면 그 프레임만 눈에 띄게 걸립니다
    • 텍스처는 한 픽셀에 한 바이트 를 씁니다. 1024 × 1024 한 장이 1 MB 입니다
    • 글자를 화면에서 치워도 그 자리는 그대로 남습니다

    한글과 중국어는 자릿수가 다릅니다

    한글은 현대 글자를 다 세면 11,172 자이고, 많이 쓰는 완성형만 추려도 2,350 자입니다. 중국어는 표준 상용 한자가 3,500 자, 일본어 상용 한자가 2,136 자입니다. 채팅에 몇 백 명이 몇 시간 떠들면 그 언어의 상용 글자는 거의 다 한 번씩 나옵니다.

    그러니까 채팅이 있는 게임에서 동적으로 굽는 방식은 “그 언어의 글자를 거의 다 텍스처에 올려 두는 것” 과 같은 말이 됩니다. 굽는 크기를 키울수록 한 장에 들어가는 글자가 확 줄어드는 것도 위에서 보이실 겁니다.

    채팅창은 두 부분입니다

    길드원1 같이 사냥 가실 분 길드원2 저요 저요 길드원3 5분만 기다려 주세요 나 바로 갈게요 메시지를 입력하세요 1. 지나간 대화 목록 글자를 그리는 컴포넌트가 줄마다 하나씩 (Text 또는 TextMeshPro) 새 글자가 계속 들어오는 쪽입니다 2. 내가 치는 입력칸 InputField 입니다. 안의 글자를 Text 가 그리면 Text 기반, TextMeshPro 가 그리면 TMP_InputField 둘이 같은 폰트를 쓰면 글자는 같은 텍스처에 쌓입니다. 한쪽만 바꾸면 반만 바뀝니다.
    채팅창은 지나간 대화 목록과 입력칸 두 부분입니다.
    • 지나간 대화 목록 은 글자를 그리는 컴포넌트가 줄마다 하나씩 놓인 것입니다. 새 글자가 계속 들어오는 쪽이 여기입니다
    • 내가 치는 입력칸 은 InputField 입니다. 안의 글자를 Text 가 그리면 Text 기반 InputField, TextMeshPro 가 그리면 TMP_InputField 입니다
    • 둘이 같은 폰트를 쓰면 글자도 같은 텍스처에 쌓입니다. 목록만 Text 기반으로 바꾸고 입력칸을 TMP 로 두면, 사람이 직접 친 글자는 TMP 쪽에 그대로 남습니다
    • 그래서 “채팅은 Text 기반으로” 라고 할 때는 목록과 입력칸을 같이 말하는 것입니다

    쌓이는 쪽과 버리는 쪽

    1분 5분 10분 20분 채팅을 계속 보고 있을 때 글자 텍스처가 차지하는 자리 본 글자가 전부 남아 있어서 계속 늘어납니다. 비우라고 시키기 전까지는 줄지 않습니다. 비우면 그 뒤에 나오는 글자를 다시 굽습니다.
    본 글자가 그대로 쌓입니다.
    1분 5분 10분 20분 채팅을 계속 보고 있을 때 글자 텍스처가 차지하는 자리 텍스처를 다시 만들 때 최근에 쓴 글자만 남기고 버립니다. 그래서 오래 켜 둬도 화면에 보이는 양만큼에서 맴돕니다. 대신 다시 만들 때 그 폰트의 글자를 전부 다시 그립니다.
    다시 만들 때 최근에 쓴 글자만 남깁니다.

    여기서 두 컴포넌트가 갈립니다.

    • TextMeshPro 로 그리면 동적 아틀라스가 본 글자를 계속 들고 있습니다. 비우라고 시키기 전까지 줄지 않습니다. 대신 한 번 구운 글자는 다시 구울 일이 없어서 그 뒤로는 빠릅니다
    • Text 컴포넌트(TextMeshPro 가 나오기 전부터 있던 것)로 그리면, 그 폰트의 텍스처를 다시 만들 때 최근에 쓴 글자만 남기고 버립니다. 문서에도 “텍스처를 다시 만들면 지난 프레임에 쓰인 글자만 들어 있다” 고 적혀 있습니다. 그래서 오래 켜 둬도 화면에 보이는 양에서 맴돕니다
    • 대신 Text 쪽은 텍스처를 다시 만들 때마다 그 폰트를 쓰는 글자를 전부 다시 그립니다. 채팅이 빠르게 흐르면 이쪽이 자주 일어납니다

    채팅만 Text 기반으로 만드는 이유가 이것입니다. 대화 목록은 Text 로, 입력칸은 Text 기반 InputField 로 두면 화면에 보이는 몇 줄만 글자 텍스처에 남고 지나간 대화의 글자는 알아서 버려집니다. 나머지 화면은 TextMeshPro 로 두고 채팅만 다르게 가도 됩니다.

    그대로 TextMeshPro 로 가려면

    채팅까지 TextMeshPro 로 만들 수도 있습니다. 대신 쌓이는 것을 관리해야 합니다.

    • 주기적으로 비웁니다. 채팅창을 닫을 때, 마을을 벗어날 때처럼 끊기는 지점에서 동적으로 채운 글자를 지웁니다. 지운 뒤 처음 나오는 글자는 다시 굽습니다
    • 굽는 크기를 작게 잡습니다. 채팅 글자는 작으니 큰 크기로 구울 이유가 없습니다. 위의 그림에서 크기를 낮추면 한 장에 들어가는 글자가 몇 배로 늘어납니다
    • 자주 쓰는 글자는 미리 구워 둡니다. 한글 완성형처럼 흔한 범위를 미리 구운 폰트를 기본으로 두고, 거기 없는 글자만 동적으로 받게 합니다
    • 빌드에 굽힌 글자가 딸려 가지 않게 합니다. 에디터에서 테스트하며 채워진 글자가 그대로 빌드에 들어가면 쓰지도 않는 텍스처가 같이 나갑니다

    장이 여러 개면 그리기도 갈립니다

    글자 텍스처가 두 장, 세 장으로 늘어나면 서로 다른 장에 있는 글자는 한 번에 못 그립니다. 한 줄짜리 채팅에 장이 다른 글자가 섞여 있으면 그 줄을 나눠 그립니다. 메모리만 늘어나는 것이 아니라 그리는 횟수도 같이 늘어납니다.

    빠져 있는 글자를 다른 폰트에서 찾아 오는 경우에도 같습니다. 그 폰트는 자기 텍스처를 따로 들고 있습니다. 이모지처럼 다른 폰트에서 오는 글자가 섞이면 그 줄은 나눠 그려집니다.

    정할 것들

    항목 정해 줄 것
    지원 언어 한국어만인지, 중국어와 일본어도 받는지. 언어마다 글자 수가 다릅니다
    채팅 표시 한 화면에 몇 줄까지 보이는지, 지난 대화를 얼마나 남기는지
    이름 길이 유저 이름과 길드 이름의 최대 글자 수
    글자 크기 채팅에 쓰는 크기가 몇 종류인지. 종류가 적을수록 텍스처가 작습니다
    이모지 쓸 수 있는지, 쓴다면 어느 범위까지인지
    비우는 지점 채팅창을 닫을 때처럼 글자 텍스처를 정리해도 되는 순간

    정리

    • 나올 글자를 미리 모르는 화면은 글자를 실행 중에 굽고, 그만큼 텍스처가 늘어납니다
    • 한 픽셀에 한 바이트라 1024 × 1024 한 장이 1 MB 입니다. 자리가 차면 같은 크기로 한 장이 더 생깁니다
    • 한글과 중국어는 상용 글자만 수천 자입니다. 채팅이 오래 흐르면 그 언어의 글자가 거의 다 올라옵니다
    • 채팅창은 지나간 대화 목록과 입력칸 두 부분이고, 목록은 글자 컴포넌트, 입력칸은 InputField 입니다
    • TextMeshPro 로 그리면 본 글자를 계속 들고 있고, Text 로 그리면 텍스처를 다시 만들 때 최근에 쓴 글자만 남깁니다
    • 그래서 채팅은 목록과 입력칸을 같이 Text 기반으로 두거나, TextMeshPro 로 두되 비우는 지점과 굽는 크기를 정해 둡니다
    • 텍스처가 여러 장이면 서로 다른 장의 글자는 한 번에 못 그립니다. 다른 폰트에서 받아 오는 글자도 마찬가지입니다