Files

7.4 KiB

Studio 모듈 가이드

Studio는 3D 씬 에디터 애플리케이션입니다. 3D 오브젝트 배치, Transform 편집, Undo/Redo, 파일 저장/내보내기 기능을 제공합니다.


모듈 구조

Studio/
├── StudioAppMain.cs           # 앱 진입점
├── StudioAppContext.cs        # 앱 레벨 DI 컨텍스트
├── StudioSceneMain.cs         # 씬 초기화
├── StudioSceneContext.cs      # 씬 레벨 DI 컨텍스트
├── StudioSideTabBar.cs        # 사이드 탭 바
├── Config/
│   ├── StudioAppConfig.cs     # 앱 설정
│   ├── StudioConstants.cs     # 상수
│   ├── Setting.cs             # 사용자 설정 (그리드, 스냅)
│   └── Library.cs             # 에셋 라이브러리
├── Command/                   # Command 패턴 (Undo/Redo)
│   ├── TransformChangeCommand.cs
│   ├── PropertyChangeCommand.cs
│   ├── EditDeleteCommand.cs
│   ├── EditDuplicateCommand.cs
│   ├── EditCreatePlaneCommand.cs
│   ├── EditUndoCommand.cs
│   ├── EditRedoCommand.cs
│   ├── FileNewCommand.cs
│   ├── FileOpenCommand.cs
│   ├── FileSaveCommand.cs
│   └── FileExport*.cs
├── Manager/
│   ├── UndoRedoManager.cs     # Undo/Redo 히스토리
│   ├── StageObjectManager.cs  # 스테이지 오브젝트 관리
│   ├── SelectionManager.cs    # 선택 상태 관리
│   ├── SelectionInputHandler.cs
│   ├── ShortcutManager.cs     # 단축키 관리
│   └── GizmoUndoBridge.cs     # RTGizmo ↔ Undo 연동
├── Modal/
│   └── Settings/              # 설정 모달
├── Tab/
│   ├── StudioSideTabBarHierarchy.cs  # 계층 탭
│   └── StudioSideTabBarAccordion.cs  # 아코디언 탭
└── UI/
    └── Buttons/               # UI 버튼 컴포넌트

핵심 시스템

1. 앱 진입점 (StudioAppMain)

namespace UVC.Studio
{
    [DefaultExecutionOrder(100)]
    public class StudioAppMain : SingletonApp<StudioAppMain>
    {
        public Action Initialized;

        protected override async void Init()
        {
            Log4netCodeConfigurator.Setup();
            UILoading.Show();

            RTG.get.initialized += OnRTGInit;

            await SettupConfigAsync();
            Initialized?.Invoke();
        }

        private async void OnRTGInit()
        {
            // RTGizmo 초기화
            RTGizmos.get.CreateViewGizmo(RTCamera.get.settings.targetCamera);

            // Setting 서비스에서 그리드/스냅 설정 적용
            Setting setting = InjectorAppContext.Instance.Get<Setting>();
            RTGrid.get.settings.cellSize = new Vector3(
                setting.Data.general.gridSize, ...);
            RTGizmos.get.skin.globalGizmoStyle.positionSnap =
                setting.Data.general.snapPosition;
        }
    }
}

2. Undo/Redo 시스템

UndoRedoManager

public class UndoRedoManager : SingletonScene<UndoRedoManager>
{
    private readonly Stack<IUndoableCommand> _undoStack = new();
    private readonly Stack<IUndoableCommand> _redoStack = new();

    public event Action? OnHistoryChanged;
    public event Action<IUndoableCommand>? OnUndo;
    public event Action<IUndoableCommand>? OnRedo;

    public bool CanUndo => _undoStack.Count > 0;
    public bool CanRedo => _redoStack.Count > 0;

    // Command 실행 및 히스토리 기록
    public void ExecuteCommand(IUndoableCommand command, object? parameter = null);

    // 이미 실행된 Command를 히스토리에만 기록 (RTGizmo 연동)
    public void RecordCommand(IUndoableCommand command);

    public void Undo();
    public void Redo();
    public void Clear();
}

TransformChangeCommand

public class TransformChangeCommand : IUndoableCommand
{
    public string Description { get; }

    // 생성자에서 Before 상태 캡처
    public TransformChangeCommand(Transform transform, string description = "객체 이동");
    public TransformChangeCommand(IEnumerable<Transform> transforms, string description);

    // 드래그 완료 후 After 상태 캡처
    public void CaptureAfterState();

    // 변경사항 확인
    public bool HasChanges();

    // Undo/Redo
    public void Undo(object? parameter = null);
    public void Redo();

    // 파괴된 객체 복구 (StageObject ID 기반)
    public bool TryResolveAllTransforms();
    public bool IsValid();
}

3. StageObjectManager

public class StageObjectManager
{
    // 오브젝트 등록/조회
    public void Register(StageObject obj);
    public StageObject? GetById(string id);
    public StageObject? GetByGameObject(GameObject go);
}

4. SelectionManager

public class SelectionManager
{
    public event Action<IReadOnlyList<GameObject>>? OnSelectionChanged;

    public IReadOnlyList<GameObject> SelectedObjects { get; }

    public void Select(GameObject obj);
    public void AddToSelection(GameObject obj);
    public void Deselect(GameObject obj);
    public void ClearSelection();
}

Command 패턴

IUndoableCommand 인터페이스

public interface IUndoableCommand
{
    string Description { get; }

    void Execute(object? parameter = null);
    void Undo(object? parameter = null);
    void Redo();

    // 병합 지원 (연속 드래그 등)
    bool CanMerge(IUndoableCommand other);
    void Merge(IUndoableCommand other);
}

Command 사용 예시

// Transform 변경 Command
var cmd = new TransformChangeCommand(selectedTransforms, "객체 이동");
// ... 드래그 완료 후 ...
cmd.CaptureAfterState();

if (cmd.HasChanges())
{
    UndoRedoManager.Instance.RecordCommand(cmd);
}

// Undo/Redo 실행
UndoRedoManager.Instance.Undo();
UndoRedoManager.Instance.Redo();

RTGizmo 연동

GizmoUndoBridge

RTGizmo의 드래그 이벤트를 Undo 시스템에 연결합니다.

// RTGizmo 드래그 시작 시
private TransformChangeCommand? _pendingCommand;

void OnGizmoDragStart(IEnumerable<Transform> targets)
{
    _pendingCommand = new TransformChangeCommand(targets, "Transform 변경");
}

// RTGizmo 드래그 완료 시
void OnGizmoDragEnd()
{
    if (_pendingCommand != null)
    {
        _pendingCommand.CaptureAfterState();
        if (_pendingCommand.HasChanges())
        {
            UndoRedoManager.Instance.RecordCommand(_pendingCommand);
        }
        _pendingCommand = null;
    }
}

파일 Command

Command 설명
FileNewCommand 새 프로젝트
FileOpenCommand 프로젝트 열기
FileSaveCommand 저장
FileSaveAsCommand 다른 이름으로 저장
FileInsertDbCommand DB에 삽입
FileExportLayoutCommand 레이아웃 내보내기
FileExportMetaCommand 메타데이터 내보내기
FileExportGltfCommand glTF 내보내기

설정 모달

Modal/Settings/
├── SettingModal.cs              # 설정 모달 메인
├── SettingGeneralTabContent.cs  # 일반 설정 탭
├── SettingDatabaseTabContent.cs # 데이터베이스 설정 탭
├── SettingShortcutTabContent.cs # 단축키 설정 탭
├── SettingOpenCommand.cs        # 설정 모달 열기 Command
└── SettingOpenCommandMono.cs    # MonoBehaviour 래퍼

의존성

  • RTGLite: Gizmo, Grid, Camera 제어
  • UVC 라이브러리: Core (DI, Singleton), UI, Data
  • UniTask: 비동기 처리