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으로 주기적 태스크를 등록하고, 커맨드 팔레트와 연동하여 이름으로 실행할 수 있는 명령 시스템을 만드세요.