제목 2단계입니다.
제목 2단계입니다.
제목 3단계입니다.
제목 3단계입니다.
제목 4단계입니다.
제목 4단계입니다.
- 리스트입니다.
- 이것도 리스트입니다.
- 리스트의 하위 리스트입니다.
- 이것도 하위 리스트임
- 다시 돌아갑시다.
title-stuck
title-stuck
title-stuck
title-stuck
title-strike
title-strike
title-strike
title-strike
Buttons
주제 버튼 가운데 정렬 주제 버튼 주제거꾸로버튼 일반 버튼 가운데 정렬 일반 버튼
새로운 버튼 테스트 내용물 테스트 menu_open
SectionBox
개발 편의 기능
개발 과정에서 발생하는 비효율적인 작업을 개선하고,
실무에 즉시 도입 가능한 기능을 구현하여 팀의 생산성을 끌어올릴 수 있습니다.
Attribute 기반의 자동 이벤트 바인딩 시스템
UIToolkit 환경에서, element class를 통해 이벤트를 자동으로 바인딩하는 기능을 구현하였습니다.
디자이너는 UI를 새로 만들거나 수정할 때, element class를 추가하면 즉시 기능을 적용할 수 있습니다.
프로그래머는 명시된 element class에 따라 Attribute를 선언하는 것으로, 추가적인 바인딩 작업을 진행하지 않아도 됩니다.
[ElementCommand("cmd--button--brush-tool")]
private static void SelectBrushTool(VisualElement target) => History.Log("브러쉬 도구를 선택하였음");
UQuery를 통해 가져온 VisualElement에 메서드를 등록하기 위해 Reflection을 사용하였으나,
초기화 시점에 단 한번 동작하여 UIBuilder 사용 시 성능 영향이 적도록 설계하였습니다.
추후 런타임 적용을 고려하여, Source Generator를 사용하는 방식으로 전환하더라도 복잡한 수정 과정 없이 사용할 수 있도록 설계하였습니다.
추가적인 메모리 할당을 방지할 수 있도록, 외부 변수 캡처 없이 static 메서드를 호출하는 static 람다 함수를 사용하는 방식으로 구현하였습니다.
CSV Utility
별도의 파싱 로직 작성 없이 CSV 데이터를 변환할 수 있는 유틸리티를 구현하였습니다.
이름 지정 방식과 열 인덱스 지정 방식을 지원하여 데이터 테이블의 헤더 수정에 유연하게 대응할 수 있도록 하였습니다.
public class Weapon
{
// 열 지정 방식
[CSVIndex(0)]
public string ItemCode;
// 이름 지정 방식
[CSVHeader("wpn_author")]
public string AuthorName;
public List<string> EnchantList;
public EquipSlotType SlotType; // enum
}
private UniTaskVoid Start()
{
Dictionary<string, Weapon> resultDictionary = new();
CSVUtility.TryFromText("text...", nameof(Weapon.ItemCode), out resultDictionary);
string resultText = string.Empty;
CSVUtility.TryToText(resultDictionary, out resultText);
}
기본 자료형(int, string) 외에도 사용자 정의 타입(클래스나 딕셔너리 리스트 같은 복합 자료형)을 처리하기 위해,
제네릭 기반의 추가 컨버터를 구현하여 사용할 수 있습니다.
동일한 타입이라도 상황에 따라 다른 파싱 규칙을 적용할 수 있습니다.
// 1. 사용자 정의 타입 처리를 위한 컨버터 구현
// CSVConverter<T>를 상속하여 구현
public class StatConverter : CSVConverter<StatInfo>
{
// 입력값: "HP:100|MP:50"
public override StatInfo Read(string value)
{
var stat = new StatInfo();
var parts = value.Split('|'); // 구분자 정의
stat.HP = int.Parse(parts[0].Split(':')[1]);
stat.MP = int.Parse(parts[1].Split(':')[1]);
return stat;
}
public override string Write(StatInfo value)
{
return $"HP:{value.HP}|MP:{value.MP}";
}
}
// 2. 사용자 정의 타입 컨버터 사용
public class MonsterData
{
[CSVIndex(0)]
public string ID;
// Attribute로 컨버터를 주입
[CSVConverter(typeof(StatConverter))]
public StatInfo BaseStat;
}
Naming Tool
지정된 네이밍 규칙에 따라 하이어라키와 프로젝트 에셋 파일명을 자동 변경해주는 에디터 기능을 구현하였습니다.
단순히 이름을 일괄 변경하는 것을 넘어, 에셋의 타입이나 컴포넌트 구성에 따라 우선순위를 지정하여
상황에 맞는 이름을 생성하도록 구현했습니다.
컴포넌트 기반 네이밍
게임 오브젝트에 부착된 컴포넌트를 분석하여 이름을 지정합니다.
단순히 컴포넌트명만 사용하는 것이 아니라, 내부 멤버 변수(참조 중인 메쉬, 재질 등)를 읽어와 이름에 반영할 수 있도록 구현하였습니다.
- 예) MeshRenderer 감지 → MeshFilter의 메쉬 이름 + Material 이름 조합 자동 생성
넘버링 시스템
유니티 엔진이 중복된 이름에 대해 부여하는 기본 넘버링 패턴을 감지하고, 이를 프로젝트 규약인 포맷으로 보정하는 기능을 구현했습니다.
또한 계층 구조 내의 자식 객체들을 대상으로 넘버링을 적용하는 기능을 추가하여, 복잡한 하이어라키 뷰의 시각적인 정돈을 도모하였습니다.
에셋 타입 기반 네이밍
선택된 에셋의 타입(Texture, AudioClip, Material 등)을 식별하여, 사전에 정의된 접두사 규칙을 자동으로 적용합니다. 정규표현식을 통해 공백이나 특수문자 등 사전 정의한 규칙에 어긋나는 문자가 포함된 경우 자동으로 제거하거나 지정된 문자로 치환하는 유효성 검사 로직이 있습니다.
확장을 고려한 구조
네이밍 로직을 추상 클래스로 정의하고 각 타입별(Light, Texture 등)로 상속받아 구현했습니다.
새로운 컴포넌트나 에셋 타입이 추가되더라도, 기존 코드를 수정할 필요 없이 새로운 네이밍 클래스를 추가하는 것으로 대응 가능한 구조를 설계했습니다.
에디터 확장 기능
개발 과정에서 발생하는 비효율적인 작업을 개선하고,
실무에 즉시 도입 가능한 기능을 구현하여 팀의 생산성을 끌어올릴 수 있습니다.
Attribute 기반의 자동 이벤트 바인딩 시스템
UIToolkit 환경에서, element class를 통해 이벤트를 자동으로 바인딩하는 기능을 구현하였습니다.
디자이너는 UI를 새로 만들거나 수정할 때, element class를 추가하면 즉시 기능을 적용할 수 있습니다.
프로그래머는 명시된 element class에 따라 Attribute를 선언하는 것으로, 추가적인 바인딩 작업을 진행하지 않아도 됩니다.
[ElementCommand("cmd--button--brush-tool")]
private static void SelectBrushTool(VisualElement target) => History.Log("브러쉬 도구를 선택하였음");
UQuery를 통해 가져온 VisualElement에 메서드를 등록하기 위해 Reflection을 사용하였으나,
초기화 시점에 단 한번 동작하여 UIBuilder 사용 시 성능 영향이 적도록 설계하였습니다.
추후 런타임 적용을 고려하여, Source Generator를 사용하는 방식으로 전환하더라도 복잡한 수정 과정 없이 사용할 수 있도록 설계하였습니다.
추가적인 메모리 할당을 방지할 수 있도록, 외부 변수 캡처 없이 static 메서드를 호출하는 static 람다 함수를 사용하는 방식으로 구현하였습니다.
CSV Utility
별도의 파싱 로직 작성 없이 CSV 데이터를 변환할 수 있는 유틸리티를 구현하였습니다.
이름 지정 방식과 열 인덱스 지정 방식을 지원하여 데이터 테이블의 헤더 수정에 유연하게 대응할 수 있도록 하였습니다.
public class Weapon
{
// 열 지정 방식
[CSVIndex(0)]
public string ItemCode;
// 이름 지정 방식
[CSVHeader("wpn_author")]
public string AuthorName;
public List<string> EnchantList;
public EquipSlotType SlotType; // enum
}
private UniTaskVoid Start()
{
Dictionary<string, Weapon> resultDictionary = new();
CSVUtility.TryFromText("text...", nameof(Weapon.ItemCode), out resultDictionary);
string resultText = string.Empty;
CSVUtility.TryToText(resultDictionary, out resultText);
}
기본 자료형(int, string) 외에도 사용자 정의 타입(클래스나 딕셔너리 리스트 같은 복합 자료형)을 처리하기 위해,
제네릭 기반의 추가 컨버터를 구현하여 사용할 수 있습니다.
동일한 타입이라도 상황에 따라 다른 파싱 규칙을 적용할 수 있습니다.
// 1. 사용자 정의 타입 처리를 위한 컨버터 구현
// CSVConverter<T>를 상속하여 구현
public class StatConverter : CSVConverter<StatInfo>
{
// 입력값: "HP:100|MP:50"
public override StatInfo Read(string value)
{
var stat = new StatInfo();
var parts = value.Split('|'); // 구분자 정의
stat.HP = int.Parse(parts[0].Split(':')[1]);
stat.MP = int.Parse(parts[1].Split(':')[1]);
return stat;
}
public override string Write(StatInfo value)
{
return $"HP:{value.HP}|MP:{value.MP}";
}
}
// 2. 사용자 정의 타입 컨버터 사용
public class MonsterData
{
[CSVIndex(0)]
public string ID;
// Attribute로 컨버터를 주입
[CSVConverter(typeof(StatConverter))]
public StatInfo BaseStat;
}
Naming Tool
지정된 네이밍 규칙에 따라 하이어라키와 프로젝트 에셋 파일명을 자동 변경해주는 에디터 기능을 구현하였습니다.
단순히 이름을 일괄 변경하는 것을 넘어, 에셋의 타입이나 컴포넌트 구성에 따라 우선순위를 지정하여
상황에 맞는 이름을 생성하도록 구현했습니다.
컴포넌트 기반 네이밍
게임 오브젝트에 부착된 컴포넌트를 분석하여 이름을 지정합니다.
단순히 컴포넌트명만 사용하는 것이 아니라, 내부 멤버 변수(참조 중인 메쉬, 재질 등)를 읽어와 이름에 반영할 수 있도록 구현하였습니다.
- 예) MeshRenderer 감지 → MeshFilter의 메쉬 이름 + Material 이름 조합 자동 생성
넘버링 시스템
유니티 엔진이 중복된 이름에 대해 부여하는 기본 넘버링 패턴을 감지하고, 이를 프로젝트 규약인 포맷으로 보정하는 기능을 구현했습니다.
또한 계층 구조 내의 자식 객체들을 대상으로 넘버링을 적용하는 기능을 추가하여, 복잡한 하이어라키 뷰의 시각적인 정돈을 도모하였습니다.
에셋 타입 기반 네이밍
선택된 에셋의 타입(Texture, AudioClip, Material 등)을 식별하여, 사전에 정의된 접두사 규칙을 자동으로 적용합니다. 정규표현식을 통해 공백이나 특수문자 등 사전 정의한 규칙에 어긋나는 문자가 포함된 경우 자동으로 제거하거나 지정된 문자로 치환하는 유효성 검사 로직이 있습니다.
확장을 고려한 구조
네이밍 로직을 추상 클래스로 정의하고 각 타입별(Light, Texture 등)로 상속받아 구현했습니다.
새로운 컴포넌트나 에셋 타입이 추가되더라도, 기존 코드를 수정할 필요 없이 새로운 네이밍 클래스를 추가하는 것으로 대응 가능한 구조를 설계했습니다.
Tables
|제목| |—| |테스트1|테스트2|테스트3| |테스트1|테스트2|테스트3| |테스트1|테스트2|테스트3|
| ets | ets | |
| ets | ets |