유니티 : https://github.com/Unity-Technologies/2d-renderer-samples?utm_source=chatgpt.com

최신화가 안되어서. 최신화 할 겸 만들었습니다.

수정한 샘플 : https://github.com/MinByungGil/2d-renderer-samples

 

UNITY 2D RENDERER

씬으로 배우는 Unity 2D 조명과 화면 표현

Unity의 2D 조명은 빛 하나만 배치해서 완성하지 않습니다. 빛의 종류, 대상 레이어, 표면 방향, 재질, 후처리를 함께 설계합니다.

Unity 6 URP 2D Renderer 10개 샘플 씬 주니어 개발자용
이 글은 기술 용어를 화면 변화와 연결해 설명합니다. 먼저 결과를 보고, 다음에 Inspector 설정을 확인하세요.

핵심 요약

01

한 장면, 한 가지 질문

각 씬은 하나의 렌더링 개념을 집중해서 보여 줍니다.

02

빛을 기능으로 확장

기본 조명을 Normal Map, Mask, Shadow, 후처리와 연결합니다.

03

한 번에 하나씩 비교

설정 하나만 바꾸고 화면 변화의 원인을 확인합니다.

이 글의 목표

배우는 내용

2D Light가 화면에 영향을 주는 과정을 이해합니다. 각 씬의 목적과 관찰 포인트도 함께 확인합니다.

얻는 결과

필요한 샘플 씬을 직접 고릅니다. 조명, 그림자, 재질, 카메라 설정을 비교하며 문제 원인을 찾습니다.

목차

프로젝트 결과물

이 프로젝트는 실행 가능한 씬 10개와 공유 기반 폴더 1개를 제공합니다. 각 씬은 독립적으로 열어 확인합니다.

 

Lights

빛의 종류, 표면 반응, 적용 범위를 비교합니다. 3개 씬을 제공합니다.

Shadows

하나의 그림자와 여러 그림자의 합성을 비교합니다. 2개 씬을 제공합니다.

Post Processing

Volume과 Bloom으로 최종 화면 분위기를 바꿉니다. 1개 씬을 제공합니다.

Shader Graph

재질 노드로 스프라이트 색상 흐름을 바꿉니다. 1개 씬을 제공합니다.

Pixel Perfect Camera

스프라이트, Tilemap, UI의 픽셀 표현을 비교합니다. 3개 씬을 제공합니다.

Common

URP Asset, 2D Renderer Data, 스프라이트와 Volume 설정을 공유합니다.

추천 학습 순서

  1. Common에서 공유 설정과 에셋 위치를 확인합니다.
  2. Lights에서 빛의 종류와 표면 반응을 살펴봅니다.
  3. Shadows에서 빛과 그림자의 관계를 비교합니다.
  4. Post Processing에서 화면 효과를 추가합니다.
  5. Shader Graph에서 재질 표현을 바꿉니다.
  6. Pixel Perfect Camera에서 최종 화면과 UI를 확인합니다.
2D 조명을 읽는 다섯 가지 질문

Inspector에서 아래 순서로 질문하면 빛 문제를 빠르게 좁힐 수 있습니다.

어떤 Light인가?
어디에 비추는가?
표면 방향이 있는가?
어떻게 합치는가?
최종 효과를 더하는가?

폴더별 씬 상세 설명

Common/

Common/은 실행 씬을 모아 둔 폴더가 아닙니다. 다른 씬이 함께 사용하는 렌더링 설정과 시각 에셋을 보관합니다.

Render Pipeline

URP Asset과 2D Renderer Data를 보관합니다.

Sprites

스프라이트, Normal Map, 외곽선, 쿠키를 보관합니다.

Volume Profile

여러 씬이 참고하는 화면 효과 설정을 보관합니다.

공유 원칙

공유 설정이 여러 씬의 기본 렌더링 흐름을 결정합니다.

Lights/

이 폴더는 2D Light를 세 단계로 설명합니다. 빛의 모양, 표면 반응, 조명 대상을 차례로 살펴봅니다.

01

1 Light Types

Assets/Samples/2D Renderer/Lights/1 Light Types.unity

요약

다섯 종류의 2D Light가 빛의 모양과 범위를 바꾸는 방식을 비교합니다.

목적

Global, Parametric, Freeform, Point, Sprite Light 2D를 한 화면에서 살펴봅니다.

결과물

배경과 스프라이트에 다섯 종류의 조명을 배치한 비교 씬입니다.

사용하면 할 수 있는 것

장면 목적에 맞는 Light 종류를 고르고 위치, 색, 강도를 조절합니다.

상세 설명

Global Light 2D는 넓은 영역에 기본 밝기를 만듭니다. Parametric Light 2D는 정해진 도형으로 빛을 만듭니다.

Freeform Light 2D는 점을 움직여 빛의 모양을 직접 만듭니다. Point Light 2D는 중심에서 사방으로 빛을 퍼뜨립니다.

Sprite Light 2D는 이미지 형태를 빛의 무늬로 사용합니다. 같은 스프라이트도 빛의 위치와 범위에 따라 다르게 보입니다.

추천 실험
  1. 각 Light를 하나씩 끄며 역할을 확인합니다.
  2. Light 위치를 바꾸며 조명 영역을 비교합니다.
  3. 색과 강도를 차례로 바꾸며 화면 변화를 기록합니다.
02

2 Normal Map

Assets/Samples/2D Renderer/Lights/2 Normal Map.unity

요약

Normal Map이 표면 방향을 알려 주고 조명이 명암을 계산합니다.

목적

Normal Map을 연결한 스프라이트와 일반 스프라이트의 차이를 비교합니다.

결과물

GlowRocks B와 배경에 Freeform Light를 비추는 비교 씬입니다.

사용하면 할 수 있는 것

2D 그림에 표면 명암과 입체감을 추가하는 방법을 이해합니다.

상세 설명

Normal Map은 표면이 어느 방향을 향하는지 색으로 저장합니다. 2D Light는 그 방향 정보를 사용해 밝기와 명암을 계산합니다.

빛을 움직이면 표면의 밝은 부분과 어두운 부분도 움직입니다. Normal Map을 끄면 표면 반응이 단순해집니다.

관련 텍스처는 Common/Sprites/GlowRocks B_n.png입니다. 같은 Light를 Normal Map 사용 전후에 비춰 결과를 비교하세요.

03

3 Masks

Assets/Samples/2D Renderer/Lights/3 Masks.unity

요약

Light Mask는 빛의 대상을 고릅니다. Blend Style은 빛의 합성 방식을 고릅니다.

목적

배경과 오브젝트에 서로 다른 조명을 적용하는 방법을 비교합니다.

결과물

Global Light 2D, Key Light, Rim Light를 한 씬에 배치합니다.

사용하면 할 수 있는 것

Sorting Layer별 조명과 주 조명, 외곽 조명을 설계합니다.

상세 설명

Global Light 2DBackground 레이어를 비춥니다. Key LightRim LightSpace Junk 레이어를 비춥니다.

Light Inspector의 Apply To Sorting Layers가 조명 대상을 고릅니다. 오브젝트가 빛 영역 안에 있어도 레이어가 다르면 빛을 받지 않습니다.

Key Light는 기본 합성을 사용합니다. Rim Light는 두 번째 Rim Blend Style을 사용해 오브젝트 외곽을 강조합니다.

Rim Light는 외곽선을 자동으로 그리지 않습니다. 대상 레이어, 조명 영역, 보조 텍스처를 모두 확인해야 합니다.

추천 실험
  1. Global, Key, Rim Light를 차례로 끕니다.
  2. Key Light의 대상 Sorting Layer를 해제합니다.
  3. Rim Light의 Blend Style을 바꾸고 결과를 비교합니다.

Shadows/

이 폴더는 빛이 만드는 어두운 영역을 설명합니다. 하나의 그림자부터 여러 그림자의 합성까지 비교합니다.

04

1 Shadows

Assets/Samples/2D Renderer/Shadows/1 Shadows.unity

요약

하나의 2D Light와 Shadow Caster가 만드는 기본 그림자를 살펴봅니다.

목적

빛과 오브젝트의 위치가 그림자 방향과 길이에 미치는 영향을 확인합니다.

결과물

Rock과 Parametric Light가 만드는 단일 그림자 씬입니다.

사용하면 할 수 있는 것

Shadow Caster를 연결하고 그림자 경계를 비교합니다.

상세 설명

Shadow Caster는 스프라이트가 그림자를 만드는 경계를 정의합니다. 빛과 Rock의 상대 위치가 그림자 방향을 결정합니다.

빛과 Rock 사이의 거리는 그림자 길이에 영향을 줍니다. Light와 Rock을 옮기며 그림자 변화를 관찰하세요.

05

2 Shadow Composite

Assets/Samples/2D Renderer/Shadows/2 Shadow Composite.unity

요약

여러 Rock 오브젝트가 만든 그림자를 하나의 빛 아래에서 합칩니다.

목적

그림자 영역이 겹칠 때 최종 화면이 달라지는 과정을 확인합니다.

결과물

여러 Rock과 Shadow Caster를 배치한 합성 그림자 씬입니다.

사용하면 할 수 있는 것

오브젝트 배치로 그림자 모양을 바꾸고 각 기여도를 확인합니다.

상세 설명

여러 Rock의 그림자 영역이 겹치면 최종 그림자 모양도 달라집니다. Rock과 Light의 위치를 한 번에 하나씩 바꾸세요.

개별 Shadow Caster를 끄면 해당 Rock의 기여를 확인할 수 있습니다. 이 씬은 그림자를 조명 결과의 조각으로 이해하도록 돕습니다.

Post Processing/

이 폴더는 조명 결과에 화면 효과를 추가하는 방법을 설명합니다.

06

1 Post Processing

Assets/Samples/2D Renderer/Post Processing/1 Post Processing.unity

요약

Volume이 2D 조명 장면에 후처리 효과를 추가합니다.

목적

Bloom이 밝은 영역과 전체 화면 분위기를 바꾸는 과정을 확인합니다.

결과물

GlowRocks B와 조명 영역에 Bloom Profile을 적용한 씬입니다.

사용하면 할 수 있는 것

조명과 후처리의 역할을 나누고 화면 분위기를 설계합니다.

상세 설명

2D Light는 장면 안의 빛과 색을 만듭니다. Post Processing은 완성된 화면에 추가 효과를 계산합니다.

Profiles/Bloom Profile.asset은 Bloom 설정을 담습니다. Bloom은 밝은 영역 주변에 부드러운 빛 번짐을 만듭니다.

먼저 Volume 효과를 끕니다. 다음에 Bloom을 켜고 같은 장면을 비교합니다. 마지막으로 효과 강도를 조절합니다.

Shader Graph/

이 폴더는 재질이 화면 색을 바꾸는 과정을 설명합니다.

07

1 Shader Graph

Assets/Samples/2D Renderer/Shader Graph/1 Shader Graph.unity

요약

Shader Graph 재질이 2D Lit Sprite의 색상 표현을 바꿉니다.

목적

기본 재질과 색상 반전 재질의 차이를 비교합니다.

결과물

RockInvert Color 재질을 연결한 비교 씬입니다.

사용하면 할 수 있는 것

노드를 연결해 재질 색상 흐름을 만들고 조명과 함께 비교합니다.

상세 설명

Shader Graph는 코드를 직접 작성하지 않고 재질 흐름을 구성합니다. Invert Color 그래프는 입력 색상의 반대 색상을 출력합니다.

2D Lit Sprite는 재질과 조명 결과를 함께 화면에 그립니다. 따라서 같은 조명도 재질에 따라 다른 색을 보여 줍니다.

Materials/Invert Color.matShader Graphs/Invert Color.shadergraph를 차례로 확인하세요.

Pixel Perfect Camera/

이 폴더는 화면을 픽셀 격자에 맞추는 방법을 비교합니다. 조명보다 카메라, 스프라이트, 타일, UI 표현을 다룹니다.

08

1 SpriteRenderer Examples

Assets/Samples/2D Renderer/Pixel Perfect Camera/1 SpriteRenderer/1 SpriteRenderer Examples.unity

요약

SpriteRenderer 이동 사례를 두 카메라로 비교합니다.

목적

오브젝트 이동 방식이 픽셀 정합과 화면 가장자리에 미치는 영향을 확인합니다.

결과물

정지, 부모 이동, 애니메이션, 물리, 스크립트 이동 사례를 배치합니다.

사용하면 할 수 있는 것

일반 카메라와 Pixel Perfect Camera의 차이를 설명합니다.

상세 설명

장면은 Stationary, Animated, Physically Controlled 같은 사례를 제공합니다. 각 사례는 서로 다른 이동 방식을 보여 줍니다.

화면의 Pixel Perfect 토글로 두 카메라를 전환합니다. 정지 오브젝트와 이동 오브젝트의 가장자리를 차례로 비교하세요.

09

2 Tilemap Examples

Assets/Samples/2D Renderer/Pixel Perfect Camera/2 Tilemap/2 Tilemap Examples.unity

요약

Dungeon과 애니메이션 Water Tilemap을 두 카메라로 비교합니다.

목적

타일 경계와 카메라 이동이 픽셀 정합에 미치는 영향을 확인합니다.

결과물

던전, 물 타일, 로봇 캐릭터를 배치한 이동형 비교 씬입니다.

사용하면 할 수 있는 것

타일 경계, 카메라 추적, Rule Tile 결과를 함께 관찰합니다.

상세 설명

Dungeon은 Rule Tile로 만든 던전 타일을 보여 줍니다. Water는 애니메이션 타일로 만든 물 표현을 보여 줍니다.

실행 중 방향키로 로봇 캐릭터를 움직입니다. Pixel Perfect 토글로 카메라를 바꾸고 타일 경계를 비교하세요.

10

3 UI Scaling Example

Assets/Samples/2D Renderer/Pixel Perfect Camera/3 UI Scaling Example/3 UI Scaling Example.unity

요약

기준 해상도에 맞춰 카메라와 UI 크기를 비교합니다.

목적

화면 크기와 종횡비가 UI 배치에 미치는 영향을 확인합니다.

결과물

기준 해상도 320 x 180과 Screen Space - Camera UI를 사용하는 씬입니다.

사용하면 할 수 있는 것

UI 크기, Crop Frame, Custom Canvas Scaler의 역할을 비교합니다.

상세 설명

Game 뷰의 해상도와 종횡비를 바꾸며 UI를 비교합니다. Canvas의 기존 Canvas Scaler를 끄고 Custom Canvas Scaler를 확인합니다.

Pixel Perfect Camera의 Crop Frame X/Y 설정도 함께 살펴봅니다. Screen Space - Camera 조건에서 UI 배치와 잘림을 비교하세요.

장면을 확인하는 실험 규칙

기본 화면을 먼저 확인합니다.
관찰할 오브젝트와 Light를 고릅니다.
설정 하나만 바꿉니다.
변경 전후 화면을 비교합니다.
바꾼 값과 결과를 기록합니다.
같은 해상도와 종횡비를 유지합니다.

빛이 보이지 않을 때 확인할 순서

  1. 스프라이트의 Sorting Layer를 확인합니다.
  2. Light의 Apply To Sorting Layers를 확인합니다.
  3. Light가 오브젝트를 실제로 덮는지 확인합니다.
  4. Light의 Intensity가 0에 가깝지 않은지 확인합니다.
  5. 스프라이트가 2D Renderer용 재질과 셰이더를 사용하는지 확인합니다.
검증 안내: 이 글은 저장소 문서와 현재 에셋 구조를 기준으로 작성했습니다. Unity 컴파일과 10개 씬의 최종 Play Mode 검증은 별도로 확인해야 합니다.

용어 사전

2D Light2D 그림과 배경을 밝히는 조명 요소입니다.
Normal Map표면 방향을 저장해 명암 계산을 돕는 이미지입니다.
Light Mask빛이 영향을 줄 Sorting Layer를 고르는 필터입니다.
Sorting Layer스프라이트를 화면에 그리는 그룹 순서입니다.
Blend Style여러 빛을 최종 색에 섞는 방식입니다.
Shadow Caster오브젝트가 그림자를 만들 영역을 정의합니다.
Volume화면 효과 설정을 모아 관리하는 영역입니다.
Bloom밝은 부분 주변에 빛 번짐을 추가하는 효과입니다.
Shader Graph노드를 연결해 재질 표현을 만드는 도구입니다.
Pixel Perfect Camera픽셀 단위 표현을 유지하도록 화면을 계산하는 카메라입니다.

'Unity > 이론' 카테고리의 다른 글

Unity Learn 정식 오픈  (0) 2022.09.02
Unity 6.6 Dictionary 직렬화 쉽게 이해하기
💡 한 줄 요약
Unity 6.6은 Dictionary<TKey, TValue>를 직접 저장합니다. Inspector에서도 Key와 Value를 바로 편집할 수 있습니다.
핵심 요약
[SerializeField]를 붙이면 Dictionary를 Unity가 직렬화합니다.
Inspector에서 Key와 Value를 직접 수정할 수 있습니다.
List 두 개로 Dictionary를 흉내 낼 필요가 줄었습니다.
필드 타입은 Dictionary<TKey, TValue>를 사용합니다.
public Dictionary도 [SerializeField]를 붙입니다.
목표
Unity 6.6에서 Dictionary를 Inspector 데이터로 사용하는 방법을 알아봅니다.
지원 범위와 주의사항도 함께 확인합니다.
결과물
using System.Collections.Generic;
using UnityEngine;
 
public class Inventory : MonoBehaviour
{
[SerializeField]
private Dictionary<string, int> itemCounts = new();
}
Inspector에서는 Key와 Value를 표 형태로 편집합니다.
Key
Value
Potion
5
Sword
1
결과물로 얻을 수 있는 기대
Key 기반 데이터를 Inspector에서 바로 관리할 수 있습니다.
ScriptableObject 데이터 작성도 더 단순해집니다.
별도 SerializableDictionary와 변환 코드도 줄일 수 있습니다.
상세 설명
1. 무엇이 달라졌나
기존 Unity는 일반적인 Dictionary를 기본 직렬화하지 못했습니다.
개발자는 List 두 개나 커스텀 직렬화 코드를 자주 사용했습니다.
Unity 6.6은 Dictionary<TKey, TValue>를 직접 직렬화합니다.
Inspector도 Dictionary 전용 편집 기능을 제공합니다.
2. Dictionary에는 [SerializeField]를 붙인다
[SerializeField]
private Dictionary<string, int> itemCounts = new();
Unity가 Dictionary를 저장하도록 필드에 속성을 지정합니다.
3. Inspector 표시 순서와 실제 순서는 다르다
Inspector는 Key 기준으로 정렬해서 보여줄 수 있습니다.
하지만 화면 순서와 실제 직렬화 순서는 다를 수 있습니다.
실제 데이터는 항목을 추가한 순서를 유지합니다.
4. 사용할 수 있는 Key와 Value
int, float, bool, string
enum
Vector2, Vector3, Color
[Serializable] 클래스와 struct
UnityEngine.Object 파생 타입
기본형부터 Unity 타입과 직렬화 가능한 커스텀 타입까지 사용할 수 있습니다.
5. Value에는 List와 배열도 사용할 수 있다
[SerializeField]
private Dictionary<int, List<int>> stageRewards = new();
반대로 Key에는 List나 배열을 사용할 수 없습니다.
// 지원하지 않음
Dictionary<List<int>, int>
6. List나 배열 안에 Dictionary를 직접 넣지 않는다
List<Dictionary<string, int>>
Dictionary<string, int>[]
필요하면 Dictionary를 직렬화 가능한 타입으로 감쌉니다.
[System.Serializable]
public class ItemTable
{
[SerializeField]
public Dictionary<string, int> items = new();
}
 
[SerializeField]
private List<ItemTable> tables = new();
7. 커스텀 타입을 Key로 쓸 때 주의한다
커스텀 class는 기본적으로 객체 참조를 비교합니다.
필드 값이 같아도 다른 객체라면 다른 Key로 판단할 수 있습니다.
EqualsGetHashCode 구현을 권장합니다.
값 타입은 IEquatable<T> 구현도 유용합니다.
8. 중복 Key는 Inspector에서 확인한다
Inspector에는 중복 Key가 잠시 표시될 수 있습니다.
런타임 Dictionary는 동일한 Key를 두 개 저장하지 못합니다.
9. null Key도 주의한다
null Key는 런타임 Dictionary에 정상 항목으로 들어가지 않습니다.
Inspector에서 비어 있는 Key를 발견하면 먼저 수정하세요.
10. Inspector 표시를 꾸밀 수 있다
[SerializeField]
[DictionaryDisplay(
keyLabel = "Item",
valueLabel = "Drop Chance",
keyColumnFraction = 0.6f)]
private Dictionary<string, float> drops = new();
열 이름과 Key 영역 비율을 직접 지정할 수 있습니다.
11. Prefab에서는 순서 변경을 조심한다
Prefab Instance는 Dictionary 항목별 Override를 지원합니다.
Unity는 내부 직렬화 위치를 기준으로 Override를 기록합니다.
항목을 추가하거나 삭제하면 Override 위치가 달라질 수 있습니다.
Prefab Dictionary를 수정한 뒤 Instance Override를 다시 확인하세요.
12. 실전에서 어디에 쓰면 좋은가
아이템 ID → 보유 개수
몬스터 ID → 능력치
스테이지 번호 → 보상 목록
사운드 이름 → AudioClip
캐릭터 타입 → Prefab
설정 이름 → ScriptableObject
[SerializeField]
private Dictionary<string, AudioClip> sounds = new();
 
public AudioClip GetSound(string id)
{
return sounds.TryGetValue(id, out var clip) ? clip : null;
}
DictionaryDisplay로 Inspector 표시 꾸미기
같은 Dictionary 타입에 공통 표시 규칙도 지정할 수 있습니다.
using System.Collections.Generic;
using UnityEngine;
 
[assembly: DictionaryDisplayForType(
typeof(Dictionary<string, SkillLevel>),
layout = DictionaryLayout.OneColumnWithValueVisible,
keyLabel = "Skill",
valueLabel = "Level")]
 
[System.Serializable]
public struct SkillLevel
{
public int rank;
public float bonus;
}
 
public class Character : MonoBehaviour
{
[SerializeField]
private Dictionary<int, Dictionary<string, SkillLevel>> skillsPerTier = new();
}
 
public class AbilityBook : MonoBehaviour
{
[SerializeField]
private Dictionary<string, SkillLevel> learnedSkills = new();
}
주의사항
Dictionary마다 [SerializeField]가 필요합니다.
[SerializeReference]를 Dictionary 필드에 직접 붙일 수 없습니다.
Inspector 다중 객체 편집은 지원하지 않습니다.
Inspector 검색과 필터 기능은 없습니다.
Prefab Override와 순서 변경을 함께 사용할 때 주의합니다.
결론
Unity 6.6의 Dictionary 직렬화는 데이터 작성 방식을 크게 단순화합니다.
단순한 Key-Value 데이터라면 별도 SerializableDictionary부터 만들 필요가 없습니다.
먼저 [SerializeField] Dictionary<TKey, TValue>를 검토하면 됩니다.

Unity MCP 기능 요약

Unity 개발 작업에서의 일반적인 사용 빈도를 기준으로 활용도를 평가했습니다.

Assets

MCP 이름 기능 설명 활용도
AssetGeneration_GenerateAsset 이미지·텍스처 등의 에셋 생성 ★★★★☆
AssetGeneration_GetModels 에셋 생성에 사용할 AI 모델 조회 ★★☆☆☆
AssetGeneration_ConvertSprite 이미지를 Unity Sprite로 변환 ★★★★☆
AssetGeneration_ConvertToMaterial 생성 결과물을 Material로 변환 ★★★☆☆
AssetGeneration_ConvertToTexture 생성 결과물을 Texture로 변환 ★★★★☆
AssetGeneration_CreateAnimation 이미지나 에셋을 이용해 애니메이션 생성 ★★★☆☆
AssetGeneration_EditAnimation 생성된 애니메이션 수정 ★★★☆☆
AssetGeneration_GetComposition 에셋 생성 작업의 구성·결과 정보 조회 ★★☆☆☆
AssetGeneration_ManageInterrupted 중단된 에셋 생성 작업 확인·재개 ★★☆☆☆
AudioClip_Edit AudioClip 자르기 등 오디오 편집 ★★★☆☆
FindProjectAssets 프로젝트에서 조건에 맞는 에셋 검색 ★★★★★
ManageShader Shader 생성·수정·조회 ★★★★☆

Core

MCP 이름 기능 설명 활용도
RunCommand Unity Editor 명령이나 등록된 작업 실행 ★★★★★
ApplyTextEdits 코드·텍스트 파일에 부분 수정 적용 ★★★★★
CreateScript 새로운 C# 스크립트 생성 ★★★★★
DeleteScript 기존 스크립트 삭제 ★★☆☆☆
FindInFile 프로젝트 파일 내부 문자열 검색 ★★★★★
GetSha 파일 또는 프로젝트 상태 비교용 해시 조회 ★☆☆☆☆
ImportExternalModel 외부 3D 모델을 Unity 프로젝트로 가져오기 ★★★☆☆
ListResources 접근할 수 있는 Unity 리소스 목록 조회 ★★★★☆
ManageAsset 에셋 생성·이동·이름 변경·삭제·속성 관리 ★★★★★
ManageEditor 플레이·정지·일시정지 등 Editor 제어 ★★★★★
ManageGameObject GameObject와 컴포넌트 생성·수정·삭제 ★★★★★
ManageMenuItem Unity 메뉴 항목 조회·실행 ★★★☆☆
ManageScene Scene 생성·열기·저장 및 구조 관리 ★★★★★
ManageScript 스크립트 생성·조회·수정 통합 관리 ★★★★★
ManageScript_capabilities 지원되는 스크립트 작업 기능 조회 ★★☆☆☆
ReadResource Unity 프로젝트 리소스 내용 읽기 ★★★★☆
ScriptApplyEdits C# 스크립트에 구조화된 코드 수정 적용 ★★★★★
ValidateScript C# 스크립트 문법·컴파일 상태 검사 ★★★★★

Debug & Diagnostics

MCP 이름 기능 설명 활용도
GetConsoleLogs Unity Console의 로그·경고·오류 조회 ★★★★★
Profiler_GetBottomUpSampleTree 하위 호출부터 병목 원인을 역추적 ★★★☆☆
Profiler_GetCounterSummary CPU·메모리 등 선택한 카운터 요약 ★★★★☆
Profiler_GetCounterTable 프레임별 프로파일러 카운터 조회 ★★★☆☆
Profiler_GetFrameGcAllocations 특정 프레임의 GC 할당 원인 분석 ★★★★★
Profiler_GetFrameRangeGcAllocations 여러 프레임의 GC 할당 변화 분석 ★★★★★
Profiler_GetFrameRangeTopTimeSummary 지정 구간에서 시간이 많이 든 작업 요약 ★★★★★
Profiler_GetFrameSelfTimes 특정 프레임의 함수별 Self Time 조회 ★★★★☆
Profiler_GetFrameTopTimeSamples 특정 프레임의 주요 병목 샘플 조회 ★★★★★
Profiler_GetOverallGcAllocations 전체 프로파일링 구간의 GC 할당 요약 ★★★★☆
Profiler_GetRelatedSamplesTree 선택한 샘플과 연결된 호출 관계 조회 ★★★☆☆
Profiler_GetSampleGcAllocations 특정 샘플의 GC 할당량 조회 ★★★★☆
Profiler_GetSampleGcAllocationSummary 특정 샘플의 GC 할당 결과 요약 ★★★★☆
Profiler_GetSampleTimeSummary 선택한 함수·샘플의 실행시간 요약 ★★★★★
Profiler_GetSampleTimeSummary (variant) 조건 또는 범위를 지정한 실행시간 요약 ★★★★☆
ReadConsole Unity Console의 현재 출력 내용 읽기 ★★★★★

Editor

MCP 이름 기능 설명 활용도
Camera_Capture 게임 카메라의 현재 화면 캡처 ★★★★☆
SceneView_Capture2DScene Scene View를 2D 화면으로 캡처 ★★★★☆
SceneView_CaptureMultiAngleSceneView Scene을 여러 각도에서 캡처 ★★★☆☆
GetProjectData Unity 버전·렌더 파이프라인 등 프로젝트 정보 조회 ★★★★★
GetUserGuidelines 프로젝트에 설정된 사용자 작업 지침 조회 ★★★★☆
PackageManager_ExecuteAction Unity 패키지 설치·제거·업데이트 실행 ★★★★☆
PackageManager_GetData 설치된 패키지와 사용 가능한 버전 조회 ★★★★☆
활용도: 일반적인 Unity 프로젝트에서 AI 에이전트가 실제 개발 작업에 사용하는 빈도 기준

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

github copilot과 Unity MCP 연결(Claude Code 도 비슷)  (0) 2026.05.25
Unity MCP Tools 설명  (0) 2026.05.24

Unity uGUI Safe Area로 안전한 모바일 UI 만들기

한 줄 소개: 모바일 기기의 노치, 둥근 모서리, 시스템 제스처 영역을 피해 UI를 배치하는 uGUI Safe Area 적용법입니다.

목표

노치나 화면 모서리 때문에 버튼, HUD, 상단 바가 가려지지 않도록 필수 UI를 안전 영역 안에 배치합니다.

해상도와 화면 방향이 바뀌어도 같은 UI 구조가 자동으로 대응하도록 구성합니다.

 

유니티 : 6.6
패키지 버전: uGUI 2.6.0 (패키지 매니저에서 설치)
날짜: 2026년 3월 30일

(오랜기간 직접 개발해서 썼는데 드디어 지원. 울고 싶다. )

결과

UI가 다양한 모바일 화면에서 잘리지 않고 안정적으로 표시됩니다.

핵심 요약

  • Safe Area 컴포넌트는 기기가 알려 주는 Screen.safeArea를 기준으로 RectTransform의 앵커를 조정합니다.
  • 해상도나 화면 방향이 바뀌면 안전 영역도 런타임에 다시 반영됩니다.
  • 배경처럼 화면 끝까지 보여야 하는 요소는 Safe Area 밖에 두고, 버튼과 HUD처럼 반드시 보여야 하는 요소만 안에 둡니다.
  • 한쪽 노치 때문에 UI가 치우치면 Center Horizontally 또는 Center Vertically를 사용합니다.

적용 방법

1. 전용 루트 오브젝트 만들기

Canvas 아래에 화면 전체를 채우는 SafeAreaRoot를 만들고 Safe Area 컴포넌트를 추가합니다.

 

빨간색은 SafeArea

파란색은 TopBar

중앙.

초록색은 BottomBar

빨간색은 SafeArea

SafeAreaTestCanvas.zip
0.10MB

2. 필수 UI를 자식으로 이동하기

화면에서 반드시 보여야 하는 버튼, 텍스트, HUD를 SafeAreaRoot 아래에 둡니다.

전체 화면을 채울 배경과 장식 이미지는 Canvas 바로 아래에 유지합니다.

3. Inspector 설정하기

  1. Reference Orientation을 UI를 제작한 기준 방향으로 설정합니다.
  2. Edges에서 안전 영역을 적용할 위·오른쪽·아래·왼쪽 가장자리를 선택합니다.
  3. 가로 화면에서 한쪽 노치 때문에 UI가 치우치면 Center Horizontally를 켭니다.
  4. 위아래 여백이 비대칭이라면 Center Vertically를 켭니다.

참고 자료

 

----

 

 

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

RectTransformUtility  (0) 2023.03.14
CalculateRelativeRectTransformBounds  (1) 2021.08.04
텍스트 배경크기조절. ContentSizeFitter  (0) 2021.08.04
글자수에 따라 배경의 크기가 자동으로 커지는 효과  (0) 2020.08.11
팁 정리  (0) 2019.10.30

기본 / 생성

옵션뜻입력 예시

Enabled 자동 생성 여부 true
Rate 초당 생성 개수 20
Lifetime 파티클 생존 시간 1 ~ 2
TimeScale 파티클 시간 배율 1

외형

옵션뜻입력 예시

Texture 파티클 이미지 rbxassetid://123
Size 수명에 따른 크기 변화 0 → 2 → 0
Squash 가로/세로 눌림·늘림 0 → 1
Color 수명에 따른 색 변화 흰색 → 파랑
Transparency 수명에 따른 투명도 1 → 0 → 1
Brightness 파티클 밝기 1
LightEmission 자체 발광 느낌 0.8
LightInfluence 주변 조명의 영향 0
ZOffset 화면상 앞뒤 렌더 위치 0.1

이동

옵션뜻입력 예시

Speed 처음 이동 속도 5 ~ 10
Acceleration 생성 후 계속 받는 가속도 0, 10, 0
Drag 이동 감속 정도 3
VelocityInheritance 부모 이동속도 상속 비율 0.5
LockedToPart 생성 후에도 부모를 따라갈지 false
WindAffectsDrag 월드 바람 영향 여부 true

방출 방향

옵션뜻입력 예시

EmissionDirection 기본 방출 방향 Top
SpreadAngle 방출되는 퍼짐 각도 30, 30

EmissionDirection

Top
Bottom
Front
Back
Left
Right

회전

옵션뜻입력 예시

Rotation 생성될 때 시작 회전각 0 ~ 360
RotSpeed 초당 회전 속도 -90 ~ 90

파티클 방향

옵션뜻입력 예시

Orientation 파티클 이미지가 바라보는 방향 FacingCamera

Orientation

FacingCamera              카메라를 바라봄
FacingCameraWorldUp       세로 방향을 유지하며 카메라를 봄
VelocityParallel          이동 방향과 평행
VelocityPerpendicular     이동 방향과 수직

생성 영역 Shape

옵션뜻입력 예시

Shape 파티클 생성 영역 모양 Sphere
ShapeStyle 영역 내부/표면 생성 Volume
ShapeInOut 안쪽/바깥쪽 방출 Outward
ShapePartial Shape 일부만 사용 0.5

Shape

Box
Sphere
Cylinder
Disc

ShapeStyle

Volume     내부 전체에서 생성
Surface    표면에서만 생성

ShapeInOut

Outward     바깥쪽으로
Inward      안쪽으로
InAndOut    양쪽 랜덤

Flipbook 애니메이션

옵션뜻입력 예시

FlipbookLayout 스프라이트 프레임 배열 Grid4x4
FlipbookSizeX Custom 가로 프레임 수 4
FlipbookSizeY Custom 세로 프레임 수 4
FlipbookFramerate 애니메이션 FPS 12
FlipbookMode 애니메이션 재생 방식 Loop
FlipbookStartRandom 랜덤 프레임부터 시작 true
FlipbookBlendFrames 프레임 사이 부드럽게 보간 true

FlipbookLayout

None
Grid2x2
Grid4x4
Grid8x8
Custom

FlipbookMode

Loop       반복
OneShot    한 번 재생
PingPong   정방향 → 역방향 반복
Random     랜덤

거의 안 쓰는 옵션

옵션뜻입력 예시

LocalTransparencyModifier 로컬 투명도 추가 보정 0
VelocitySpread 구형 퍼짐 옵션, Deprecated 사용 안 함
FlipbookIncompatible Flipbook 사용 불가 상태 확인 읽기용

가장 자주 쓰는 핵심만 뽑으면

Rate                초당 생성량              20
Lifetime            생존시간                 1 ~ 2
Size                크기 변화                0 → 2 → 0
Transparency        투명도 변화              1 → 0 → 1
Speed               초기 속도                5 ~ 10
Acceleration        가속도                   0, 10, 0
Drag                감속                     3
EmissionDirection   방출 방향                Top
SpreadAngle         퍼짐 각도                30, 30
Rotation            시작 회전                0 ~ 360
RotSpeed            회전 속도                -90 ~ 90
Color               색 변화                  흰색 → 파랑
Texture             이미지                   rbxassetid://123

 

트레일 텍스쳐 옵션정리

'로블록스' 카테고리의 다른 글

데이터 저장소 4.(캐싱)  (0) 2026.07.30
데이터 저장소. 3 (버전)  (0) 2026.07.30
데이터 저장소. 2 (웹페이지에서 접근)  (0) 2026.07.30
데이터 저장소. 1 ( 기본 )  (0) 2026.07.30
카메라 변경  (0) 2026.07.26

캐싱

성능을 개선하고 서버에 대한 요청 수를 줄이기 위해 데이터 저장소의 데이터를 임시로 저장하는 데 캐싱을 사용하세요. 예를 들어, 게임은 데이터의 복사본을 캐시하여 데이터 저장소에 다른 호출을 할 필요 없이 빠르게 접근할 수 있습니다.

 

실제 구현은?

Roblox 데이터 저장소(DataStore)에서 GetAsync(), SetAsync(), UpdateAsync(), IncrementAsync(), RemoveAsync() 등의 작업 명령어를 호출하면, 기본적으로 엔진 차원에서 4초간의 로컬 캐싱이 자동으로 작동합니다.

따라서 개발자가 별도의 캐시 시스템을 구현하지 않아도 데이터 저장소를 사용하는 것만으로 캐싱이 자연스럽게 적용됩니다.

캐싱 비활성화 

local ok = pcall(function()
    store:UpdateAsync(key, transform)
end)

if not ok then
    local options = Instance.new("DataStoreGetOptions")
    options.UseCache = false

    local success, value = pcall(function()
        return store:GetAsync(key, options)
    end)

    if success then
        -- 캐시된 상태가 아닌 백엔드 상태에 따라 결정
    end
end

'로블록스' 카테고리의 다른 글

파티클  (0) 2026.08.22
데이터 저장소. 3 (버전)  (0) 2026.07.30
데이터 저장소. 2 (웹페이지에서 접근)  (0) 2026.07.30
데이터 저장소. 1 ( 기본 )  (0) 2026.07.30
카메라 변경  (0) 2026.07.26

1. 버전이 생성되는 기준 (하루 1회)

  • UTC 기준 하루 첫 쓰기 시점: 특정 데이터(키)를 SetAsync(), UpdateAsync(), IncrementAsync()로 처음 변경할 때, 그 시점의 이전 데이터가 백업 버전으로 저장됩니다.
  • 같은 날 추가 변경 시: 같은 UTC 날짜(24시간) 안에서 랭킹이나 점수가 10번, 100번 변경되어 계속 업데이트되더라도, 이전 데이터를 덮어쓸 뿐 매번 새 백업 버전이 생기지는 않습니다.

2. 이전 데이터 복구 (백업)

  • 만약 플레이어의 데이터가 손상되거나 버그가 발생하면, ListVersionsAsync()로 해당 날짜에 저장된 백업 목록을 조회하고, GetVersionAsync()로 해당 시점의 데이터를 가져와 복구할 수 있습니다.
  • 이 백업 버전 데이터는 30일 동안 보관된 후 자동으로 삭제됩니다.

특정 유저 데이터가 깨졌다면

개발자가 직접 구현해야 하는 부분

  1. 복구 스크립트 
    • 복구할 플레이어의 Key(예: User_12345)를 지정합니다.
    • ListVersionsAsync()를 호출하여 과거 저장된 버전 목록(시간대별 백업 목록)을 가져옵니다.
    • 복구하고자 하는 특정 시간대의 버전을 선택합니다.
    • GetVersionAsync()로 해당 버전의 데이터를 읽어옵니다.
    • 읽어온 옛날 데이터를 SetAsync()로 현재 최신 데이터 위치에 덮어씌웁니다.
  2. 예시)
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("PlayerData")

local function rollbackPlayerData(userId, targetDateTime)
    local key = "User_" .. userId
    
    -- 1. 지정한 시간(targetDateTime) 이전의 가장 가까운 버전 목록 조회
    local success, pages = pcall(function()
        return playerDataStore:ListVersionsAsync(
            key, 
            Enum.SortDirection.Descending, 
            nil, 
            targetDateTime.UnixTimestampMillis
        )
    end)
    
    if success then
        local items = pages:GetCurrentPage()
        if #items > 0 then
            local targetVersion = items[1].Version -- 가장 가까운 과거 버전 번호
            
            -- 2. 해당 버전의 데이터값 읽어오기
            local getSuccess, oldData = pcall(function()
                return playerDataStore:GetVersionAsync(key, targetVersion)
            end)
            
            -- 3. 읽어온 옛날 데이터로 현재 데이터 덮어쓰기 (복구 실행)
            if getSuccess and oldData then
                playerDataStore:SetAsync(key, oldData)
                print(userId .. "번 유저 데이터 복구 완료!")
            end
        end
    end
end

'로블록스' 카테고리의 다른 글

파티클  (0) 2026.08.22
데이터 저장소 4.(캐싱)  (0) 2026.07.30
데이터 저장소. 2 (웹페이지에서 접근)  (0) 2026.07.30
데이터 저장소. 1 ( 기본 )  (0) 2026.07.30
카메라 변경  (0) 2026.07.26

위치

  1. 로블록스 대시보드
  2. 작품
  3. 해당 체험(게임)
  4. 데이터 저장소 관리자

 

'로블록스' 카테고리의 다른 글

데이터 저장소 4.(캐싱)  (0) 2026.07.30
데이터 저장소. 3 (버전)  (0) 2026.07.30
데이터 저장소. 1 ( 기본 )  (0) 2026.07.30
카메라 변경  (0) 2026.07.26
Roblox Tool 장착과 재장전 아이콘 변경  (0) 2026.07.26

데이터 저장소 접근

local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")

데이터 생성

local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")
local success, errorMessage = pcall(function()
	gameStore:SetAsync("User_1234", 50)
end)
if not success then
	print(errorMessage)
end

데이터 업데이트

local DataStoreService = game:GetService("DataStoreService")
local nicknameStore = DataStoreService:GetDataStore("Nicknames")
local function makeNameUpper(currentName)
	local nameUpper = string.upper(currentName)
	return nameUpper
end
local success, updatedName = pcall(function()
	return nicknameStore:UpdateAsync("User_1234", makeNameUpper)
end)
if success then
	print("대문자 이름:", updatedName)
end

SetAsync()와 UpdateAsync()의 차이점 

항목 SetAsync() UpdateAsync()
기본 동작 덮어쓰기 (Overwrite) 읽은 후 갱신 (Read-then-Write)
처리 속도 빠름 상대적으로 느림
호출 제한 쓰기 제한만 적용 읽기 및 쓰기 제한 모두 적용
동시성 안전성 데이터 덮어쓰기 위험 존재 안전함 (데이터 일관성 보장)
권장 용도 단순 데이터 저장, 초기 데이터 생성 재화 변경, 멀티 서버 데이터 처리

데이터 읽기

local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")
local success, currentGame = pcall(function()
	return gameStore:GetAsync("User_1234")
end)
if success then
	print(currentGame)
end

데이터 증가

local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")
local success, newGame = pcall(function()
	return gameStore:IncrementAsync("Player_1234", 1)
end)
if success then
	print(newGame)
end

데이터 제거

local DataStoreService = game:GetService("DataStoreService")
local nicknameStore = DataStoreService:GetDataStore("Nicknames")
local success, removedValue = pcall(function()
	return nicknameStore:RemoveAsync("User_1234")
end)
if success then
	print(removedValue)
end

메타데이터

메타데이터 및 UserID를 함께 저장하기

local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")
local setOptions = Instance.new("DataStoreSetOptions")
setOptions:SetMetadata({["GameElement"] = "Fire"})
local success, errorMessage = pcall(function()
    gameStore:SetAsync("User_1234", 50, {1234}, setOptions)
end)
if not success then
    print(errorMessage)
end

데이터와 메타데이터 함께 조회하기

local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")
local success, currentGame, keyInfo = pcall(function()
    return gameStore:GetAsync("User_1234")
end)
if success then
    print(currentGame)
    print(keyInfo.Version)
    print(keyInfo.CreatedTime)
    print(keyInfo.UpdatedTime)
    print(keyInfo:GetUserIds())
    print(keyInfo:GetMetadata())
end

메타데이터와 UserID를 유지하며 데이터 업데이트하기

local DataStoreService = game:GetService("DataStoreService")
local nicknameStore = DataStoreService:GetDataStore("Nicknames")
local function makeNameUpper(currentName, keyInfo)
    local nameUpper = string.upper(currentName)
    local userIDs = keyInfo:GetUserIds()
    local metadata = keyInfo:GetMetadata()
    return nameUpper, userIDs, metadata
end

local success, updatedName, keyInfo = pcall(function()
    return nicknameStore:UpdateAsync("User_1234", makeNameUpper)
end)
if success then
    print(updatedName)
    print(keyInfo.Version)
    print(keyInfo.CreatedTime)
    print(keyInfo.UpdatedTime)
    print(keyInfo:GetUserIds())
    print(keyInfo:GetMetadata())
end

 

+ Recent posts