printf("Hello world!\n");
보통 2D 게임을 만들 때, 렌더링 시 어떤 스프라이트를 참고하여 Draw 하게 되는데 이때 Drawcall이라는 것을 한 번 호출하게 된다. 근데 예를 들어 아래와 같이 그릴 것들이 많아서 참고해야 할 스프라이트 이미지가 n개라고 한다면? Drawcall도 n번 만큼 발생하게 되는 것이다.
Drawcall 이 많으면 게임 퍼포먼스가 안 좋아진다. 반대로 얘기하면 Drawcall이 적으면 게임 퍼포먼스가 좋아진다.
스프라이트 아틀라스를 이용하여 이 Drawcall을 줄여보도록 하자!
<기본 설정>
> 유니티6에서는 따로 설정을 하지 않아도 Sprite Atlas를 바로 사용할 수 있다. 아래처럼 바로 Create 할 수 있는데, 이전 버전에서는 Editor에서 어떤 설정을 하여야 저렇게 Create에서 Sprite Atlas 를 사용할 수 있었다라고 한다. (본인은 그땐 안 해봄ㅇㅇ;)
<Editor 설정>
> 보통 유니티6에서는 Sprite Atlas 모드가 V2 -> Enabled 로 되어 있을텐데, 혹시나 안 되어 있다면 체크해주자.
> V1,V2~ 이런 설정들이 있는데 간략하게 설명하자면 아래와 같다.
항목 | Sprite Atlas V1 | Sprite Atlas V2 |
출시 버전 | Unity 2017~2018 | Unity 2019.3 이상 |
관리 방식 | Built-in 방식 | ScriptableObject 기반 |
Addressable 호환 | 제한적 | 완전 지원 |
AssetBundle 연동 | 수동 조작 필요 | 자동 연동 가능 |
Atlas Packing | Editor에서 고정 방식 | Build 시점에 유연하게 변경 가능 |
API | SpriteAtlasUtility | SpriteAtlasManager 중심으로 개선 |
권장 여부 | 더 이상 권장되지 않음 | 현재 표준 방식 |
옵션 이름 | 사용되는 Sprite Atlas 버전 | 에디터에서 사용 |
Disabled | 없음 | 사용 안 함 |
Sprite Atlas V1 – Enabled For Builds | V1 (구버전) | 사용 안 함 |
Sprite Atlas V1 – Always Enabled | V1 (구버전) | 사용 |
Sprite Atlas V2 – Enabled | V2 (신버전) | 사용 |
Sprite Atlas V2 – Enabled For Builds | V2 (신버전) | 사용 안 함 |
*Sprite Atlas V2 - Enabled 쓰면 된다. (참고로 V1과 V2는 서로 호환되지 않음.)
실제 사용
기본적인 사용법은 아래와 같다.
- Assets 아래에 SpriteAltasses 같은 폴더를 하나 만든다. (굳이 안 만들어도 되기는 한데 관리상..)
- 폴더 내에서 마우스 오른쪽 클릭 -> Create -> 2D -> Sprite Atlas를 만든다.
- 만들어진 Sprite Altas 에 Sprites 를 추가한다.
- 실제 사용하는 곳에서 SpriteAtlas를 불러와 이미지 이름에 해당하는 Sprite를 불러온다.
<Sprites 들 넣기>
> Atlas 생성하였으면, Atlas를 클릭하여 Inspector 창을 보자. 그러면 저렇게 Objects for Packing 이라는게 있는데, 거기서 +를 눌러 스프라이트들을 추가할 수 있다.
- 팁 : 아래와 같이 폴더 자체를 통째로 넣을 수 있음.
- 주의점 : 아틀라스에 넣으려고 하는 Sprite 이미지들은 꼭 Sprite Mode를 Single로 해라... Mutiple로 되어 있으면 나중에 스프라이트 불러올 때 이름이 이상하게 되어 있어서 '이거 이름 맞는데 왜 안 불러와짐?ㅡㅡ' 하며 혈압 오를 수도 있다.
> 대충 스프라이트 낑겨 넣었으면 Atlas에서 Pack Preview 를 클릭하여 적용 완료하자.
> 그러면 아래 Preview에서 Atlas화 된 sprite가 보일 것이다.
> 아틀라스한 이미지가 이상한 방향으로 돌아가 있을 수가 있는데, 그럴 때는 위에서 Allow Rotation 옵션을 꺼주면된다. (* tight packing은 스프라이트의 실제 알파 영역만 기준으로 경계(Rect)를 잡아서 아틀라스에 최대한 촘촘하게 배치하는 방식 )
모드 | 설명 |
기본 (Tight Packing 꺼짐) | 이미지 외곽 전체를 네모로 잘라서 배열 |
ight Packing 켜짐 | 실제 픽셀이 있는 부분만 사용하여 더 촘촘히 배치 |
> 여기까지 되었으면 'Addressable' 도 체크해주자.
Addressble 해주면 여러 이점이 있는데, 아래와 같이 안 했을 때와 차이를 정리하였으니 참고 바란다.
항목 | Addressable 사용 | Addressable 미사용 |
✅ 로딩 방식 | Addressables.LoadAssetAsync<SpriteAtlas>("key") | Resources.Load<SpriteAtlas>("path") or Inspector 참조 |
✅ 로드 제어 | 비동기(async), 콜백/Task 지원 | 동기(synchronous), 즉시 반환 |
✅ 메모리 관리 | 명시적 Release() 가능 → 메모리 절약 | 자동 언로드 불가, 메모리 계속 점유 |
✅ 빌드 최적화 | 필요한 리소스만 번들화 (필요한 시점에 로드) | 전부 빌드에 포함 (Include in Build 체크됨) |
✅ 앱 실행 크기 | 최초 실행 시 가볍고 빠름 | 실행 크기 증가 가능성 ↑ |
✅ 유지보수성 | Key 기반으로 관리 → 디커플링 용이 | 경로 기반 → 경로/이름 변경 시 의존성 깨짐 |
✅ 에셋 번들 분리 배포 | 가능 (DLC, Patching 등) | 불가능 (모든 리소스 포함된 단일 빌드) |
❌ 초기 셋업 | 다소 복잡 (Profile, Group, 키 설정 필요) | 단순 (Resources 폴더 or 직접 참조) |
❌ 디버깅/테스트 | 로컬, Remote 빌드 구분 필요 | Unity Editor에서 바로 테스트 용이 |
❌ 런타임 관리 | 로드/해제 수동 관리 필요 | 자동 로드 & 해제 (하지만 예측 어려움) |
<본격 스프라이트 아틀라스 사용하기>
> 그러면 본격적으로 아틀라스를 사용해보자. 본인은 UIHelper라는 클래스를 통해서 Atlas를 캐싱하여 사용한다.
public class UIHelper
{
public SpriteAtlas _itemAtlas; //아틀라스 부분
public Dictionary<string, Sprite> _itemSpriteDict = new Dictionary<string, Sprite>();
public EnchantColorTable colorTable;
static UIHelper s_instance;
public static UIHelper Instance { get { Init(); return s_instance; } } //싱글톤
public Sprite GetItemSprite(string itemName)
{
if(_itemAtlas == null)
{
Debug.Log("UPHelper : atlas 아직 로딩 안됨!");
return null;
}
return _itemAtlas.GetSprite(itemName);
}
}
보면 _itemAtlas 라는 SpriteAtlas 가 있는데, SpriteAtlas를 먼저 게임 시작하는 곳(예를 들면 타이틀 화면에서 로비로 진입할 때?)에서 비동기로 로드해와야 한다. 어디서 할까 하다가 그냥 BaseScene (모든 Scene에서 달라붙어 있는 컴포넌트) 에서 하기로 하였다.
using System;
using System.Threading.Tasks;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;
using UnityEngine.U2D;
public class BaseScene : MonoBehaviour
{
private void Start()
{
Init();
}
protected virtual async void Init()
{
try
{
await LoadAtlas();
}
catch(Exception e)
{
Debug.Log($"Atlas load 실패 {e}");
}
}
async Task LoadAtlas()
{
var handle = Addressables.LoadAssetAsync<SpriteAtlas>("GameItems");
if (UIHelper.Instance._itemAtlas == null)
UIHelper.Instance._itemAtlas = await handle.Task;
if (UIHelper.Instance._itemAtlas == null)
Debug.LogError("Sprite Atlas GameItems 로딩 실패");
}
}
> 대충 이런 식으로 만들면 된다. Addressable이 아니었다라면 Resources.Load<SpriteAtlas>(경로) 형태로 불러와야 하는데, Addressable 을 체크하면 위처럼 그냥 키(이름)만 가지고도 불러올 수 있음ㅇㅇ;
> SpriteAtlas 이미지들을 다 불러왔으면 이제 실제 사용하면 되는데, 사용하는 곳에서 그냥 itemImage.sprite = UIHelper.Instance.GetItemSprite(itemName); 이런 식으로 호출하면 된다.
*ItemName은 실제 스프라이트 이미지의 이름이다. (string)
SpriteAtlas는 저장한 이미지들을 이미지 이름(순수 이름, .png 이런거 안 붙임.)을 key로 저장한다.
그래서 불러올 때도 이미지 이름으로만 불러와도 됨.
근데 본인은 이렇게 했는데 자꾸 안돼서 뭐가 문제인지 한 참 헤맸다. 결론은.. 아까도 얘기한 거긴 한데,
--->>>>> SPRITE ATLAS에 쓸 이미지들은 꼭 MULTIPLE 이 아니라, SINGLE로 해라. 두 번해라.
>> Mutiple 로 하면, 실제 이미지 이름이 abc 라고 한다면 abc로 저장되는게 아니고 abc_01, abc_02 이딴 식으로 저장 됨.(dunno y;)
'유니티' 카테고리의 다른 글
[유니티 최적화] Profiling (빌드 이후 메모리 사용량 등 확인 하기.) (0) | 2025.04.17 |
---|---|
[유니티] 모바일 디바이스 드래그 감도 조절 (0) | 2025.03.27 |
[유니티6/UI] 채팅창 구현하기 (ScrollView , InputField, Button) (0) | 2025.03.18 |
[유니티] 알림/경고 메시지를 띄워보자 (Notification Message, 코루틴) (0) | 2025.03.12 |
[유니티6] Android 버전으로 빌드하여 sdk 파일 추출하기. (0) | 2025.03.04 |