PART 4 · 강의 3/3
에디터 스크립팅
EditorLevelLibrary로 레벨 자동화를 구현하고, Python 도구를 에디터 메뉴에 통합합니다
01
EditorLevelLibrary
레벨 액터 조작 자동화
Python - 레벨 액터 조작
import unreal
# 현재 레벨의 모든 액터
all_actors = unreal.EditorLevelLibrary.get_all_level_actors()
unreal.log(f"Total actors: {len(all_actors)}")
# 클래스별 필터링
static_meshes = unreal.EditorLevelLibrary.get_all_level_actors_of_class(
unreal.StaticMeshActor)
lights = unreal.EditorLevelLibrary.get_all_level_actors_of_class(
unreal.PointLight)
# 선택된 액터 가져오기
selected = unreal.EditorLevelLibrary.get_selected_level_actors()
# 액터 스폰
new_actor = unreal.EditorLevelLibrary.spawn_actor_from_class(
unreal.PointLight,
unreal.Vector(0, 0, 300),
unreal.Rotator(0, 0, 0))
# 액터 트랜스폼 설정
if new_actor:
new_actor.set_actor_location(
unreal.Vector(100, 200, 300), False, False)
new_actor.set_actor_rotation(
unreal.Rotator(0, 45, 0), False)
new_actor.set_actor_scale3d(
unreal.Vector(2, 2, 2))
new_actor.set_actor_label("MyPointLight")
# 액터 삭제
# unreal.EditorLevelLibrary.destroy_actor(actor)
02
레벨 자동 설정 스크립트
레벨 라이팅, 액터 배치, 프로퍼티 일괄 설정
Python - 레벨 라이팅 자동 설정
import unreal
def setup_basic_lighting():
"""기본 라이팅 설정 자동화"""
# 기존 라이트 검색 및 제거
existing_lights = (
unreal.EditorLevelLibrary.get_all_level_actors_of_class(
unreal.DirectionalLight))
for light in existing_lights:
unreal.EditorLevelLibrary.destroy_actor(light)
# Directional Light 배치
sun = unreal.EditorLevelLibrary.spawn_actor_from_class(
unreal.DirectionalLight,
unreal.Vector(0, 0, 500))
sun.set_actor_rotation(
unreal.Rotator(-50, -30, 0), False)
sun.set_actor_label("Sun_Directional")
# Light 컴포넌트 프로퍼티 설정
light_comp = sun.get_component_by_class(
unreal.DirectionalLightComponent)
if light_comp:
light_comp.set_editor_property("intensity", 5.0)
light_comp.set_editor_property("light_color",
unreal.Color(r=255, g=240, b=220))
# Sky Atmosphere
sky = unreal.EditorLevelLibrary.spawn_actor_from_class(
unreal.SkyAtmosphere,
unreal.Vector(0, 0, 0))
sky.set_actor_label("SkyAtmosphere")
# Sky Light
sky_light = unreal.EditorLevelLibrary.spawn_actor_from_class(
unreal.SkyLight,
unreal.Vector(0, 0, 200))
sky_light.set_actor_label("SkyLight")
unreal.log("Basic lighting setup complete!")
setup_basic_lighting()
Python - 액터 프로퍼티 일괄 변경
def set_all_meshes_mobility(mobility_type):
"""모든 Static Mesh 액터의 Mobility 일괄 변경"""
actors = unreal.EditorLevelLibrary.get_all_level_actors_of_class(
unreal.StaticMeshActor)
with unreal.ScopedSlowTask(
len(actors), "Setting mobility...") as task:
task.make_dialog(True)
for actor in actors:
if task.should_cancel():
break
task.enter_progress_frame(1)
root = actor.get_editor_property("root_component")
if root:
root.set_editor_property(
"mobility", mobility_type)
unreal.log(f"Updated {len(actors)} actors")
# 사용: 모두 Static으로
set_all_meshes_mobility(
unreal.ComponentMobility.STATIC)
03
Python + 에디터 메뉴 통합
Python 스크립트를 에디터 메뉴에 등록하기
Python - 커스텀 메뉴 구축
import unreal
def build_python_tools_menu():
"""Python 도구 전용 메뉴 구축"""
menus = unreal.ToolMenus.get()
# 메인 메뉴의 Tools 메뉴 확장
menu = menus.find_menu("LevelEditor.MainMenu.Tools")
if not menu:
unreal.log_error("Cannot find Tools menu")
return
# Python Tools 섹션 추가
section = menu.add_section("PythonTools", "Python Tools")
# 메뉴 항목들
tools = [
("AssetAudit", "Asset Audit",
"import asset_tools; asset_tools.run_audit()"),
("SetupLighting", "Setup Lighting",
"import level_tools; level_tools.setup_basic_lighting()"),
("BatchRename", "Batch Rename",
"import asset_tools; asset_tools.batch_rename()"),
("CleanUnused", "Clean Unused Assets",
"import asset_tools; asset_tools.clean_unused()"),
]
for name, label, command in tools:
entry = unreal.ToolMenuEntry(
name=name,
type=unreal.MultiBlockType.MENU_ENTRY)
entry.set_label(label)
entry.set_string_command(
unreal.ToolMenuStringCommandType.PYTHON,
"", command)
section.add_entry(entry)
menus.refresh_all_widgets()
unreal.log("Python tools menu registered")
build_python_tools_menu()
04
고급: 데이터 테이블과 외부 연동
CSV/JSON과 UE5 데이터 테이블 연동 자동화
Python - CSV에서 데이터 테이블 업데이트
import unreal
import csv
def import_csv_to_datatable(csv_path, table_path):
"""CSV 파일을 데이터 테이블에 임포트"""
# 데이터 테이블 로드
data_table = unreal.EditorAssetLibrary.load_asset(table_path)
if not data_table:
unreal.log_error(f"DataTable not found: {table_path}")
return
# CSV 읽기
with open(csv_path, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
rows = list(reader)
# CSV 파일을 임시 저장하고 리임포트
unreal.DataTableFunctionLibrary.fill_data_table_from_csv_file(
data_table, csv_path)
unreal.EditorAssetLibrary.save_loaded_asset(data_table)
unreal.log(f"Imported {len(rows)} rows to {table_path}")
def export_datatable_to_json(table_path, json_path):
"""데이터 테이블을 JSON으로 익스포트"""
data_table = unreal.EditorAssetLibrary.load_asset(table_path)
if not data_table:
return
json_string = unreal.DataTableFunctionLibrary\
.get_data_table_as_json_string(data_table)
with open(json_path, 'w', encoding='utf-8') as f:
f.write(json_string)
unreal.log(f"Exported to {json_path}")
외부 Python 패키지 사용
UE5 내장 Python 환경에 외부 패키지를 설치하려면 엔진의 Python 실행 파일로 pip를 사용합니다: Engine/Binaries/ThirdParty/Python3/Win64/python.exe -m pip install pandas
SUMMARY
핵심 요약
- EditorLevelLibrary로 레벨 액터의 검색, 스폰, 트랜스폼 수정, 삭제 등을 자동화합니다
- set_editor_property로 컴포넌트의 Mobility, Light Color 등 프로퍼티를 일괄 변경합니다
- ToolMenus를 Python에서 직접 조작하여 에디터 메뉴에 Python 도구를 통합합니다
- CSV/JSON과 DataTable의 양방향 연동으로 외부 데이터 파이프라인을 구축합니다
- 모든 배치 작업에 ScopedSlowTask를 사용하여 진행 바와 취소 기능을 제공합니다
PRACTICE
도전 과제
배운 내용을 직접 실습해보세요
실습 1: Python으로 레벨 Actor 조작
unreal.EditorLevelLibrary.get_selected_level_actors()로 선택된 Actor를 가져오고, 위치/회전/스케일을 일괄 수정하는 스크립트를 작성하세요. 모든 선택 Actor를 원점 기준으로 원형 배치하는 기능을 구현하세요.
실습 2: Python으로 에디터 UI 자동화
unreal.EditorUtilityLibrary를 활용하여 콘텐츠 브라우저 탐색, 에셋 선택, 프로퍼티 수정을 Python으로 자동화하세요. 특정 조건(텍스처 크기 > 2048)에 맞는 에셋을 찾아 리스트로 출력하는 검증 스크립트를 작성하세요.
심화 과제: 커스텀 Python 에디터 코맨드 시스템
자주 사용하는 에디터 작업을 Python 명령어로 등록하는 시스템을 구현하세요. unreal.register_slate_post_tick_callback으로 주기적 태스크를 등록하고, 커맨드 팔레트와 연동하여 이름으로 실행할 수 있는 명령 시스템을 만드세요.