네, LLM을 활용한 유니티 씬 파일(.unity) 파싱 및 분석은 충분히 가능합니다.
유니티 씬 파일은 기본적으로 텍스트 기반의 YAML(YAML Ain't Markup Language) 형식으로 저장되기 때문에 텍스트 문맥 이해 능력이 뛰어난 LLM이 구조를 파악하고 정보를 추출하기에 매우 적합합니다.
💡 LLM이 유니티 씬을 파싱하는 방법과 한계
* YAML 구조 해석: 유니티 씬 파일에는 GameObject, Transform, MonoBehaviour 등 다양한 컴포넌트 정보가 고유 ID(fileID, guid)와 함께 YAML 텍스트로 기록됩니다. LLM은 이 관계를 파악하여 특정 오브젝트의 위치나 연결된 스크립트를 찾아낼 수 있습니다.
* 추천하는 접근 방식 (하이브리드): 단, 몇만 줄이 넘어가는 거대한 씬 파일을 LLM에 날것(Raw text)으로 전부 집어넣으면 토큰 소모가 극심하고 환각(Hallucination)이 발생할 수 있습니다. 따라서 C# 스크립트나 Python으로 기본적인 YAML 파싱 레이어를 구축해 데이터를 정제한 뒤, 핵심 맥락만 LLM에 전달하는 방식이 가장 효율적입니다.
* 최신 트렌드 (MCP 활용): 최근에는 Unity 에디터와 LLM을 MCP(Model Context Protocol)로 연결하여, AI 에이전트가 실시간으로 씬 내부와 프리팹을 들여다보고 분석하게 만드는 도구들도 개발되고 있습니다.
🛠️ 실제 활용할 수 있는 유즈케이스
* 씬 내부 컴포넌트 분석: "이 씬에서 Light 컴포넌트가 붙은 오브젝트들의 정보와 그 값을 요약해줘" 같은 자연어 질의가 가능합니다.
* 잘못된 설정(버그) 추적:Missing 레퍼런스가 깨진 오브젝트나, 비정상적인 Scale 값(예: 0,0,0)을 가진 게임 오브젝트를 찾아내라고 명령할 수 있습니다.
* 씬 데이터 변경 및 자동화: 복잡한 YAML 규칙을 학습시켜 "특정 태그를 가진 오브젝트들의 Transform 값을 일괄 변경하는 YAML 코드를 작성해줘"와 같은 작업도 수행할 수 있습니다.
---
AI가 유니티 씬(Scene) 파일을 직접 분석하고 에디터 상에 캐릭터를 자동으로 배치하는 환경은 충분히 구현 가능하며, 최근 게임 개발 자동화에서 가장 주목받는 영역입니다.
이를 구현하려면 단순히 LLM에게 텍스트를 보여주는 것을 넘어, [AI 에이전트 <-> 매개체(데이터/API) <-> 유니티 에디터]가 실시간으로 소통하는 환경을 구축해야 합니다.
---
🏗️ AI 캐릭터 배치 환경 구축을 위한 3대 핵심 요소
1. 씬 데이터의 '경량 시각화' (AI가 이해할 수 있는 형태)
유니티 씬(.unity) 파일 전체를 LLM에 넣으면 토큰 낭비가 심합니다. 먼저 C# 스크립트를 통해 AI가 이해하기 쉬운 경량 데이터(JSON 등)나 프롬프트로 변환해야 합니다.
* 추출할 데이터: 지형의 크기(Bounding Box), 바닥(Floor) 오브젝트의 위치, 장애물(Obstacle) 위치, 현재 배치된 SpawnPoint 등.
* 텍스트 변환 예시:
"현재 씬의 크기는 50x50입니다. 바닥은 Y=0에 위치합니다. (X:10, Z:10) 위치에 커다란 바위 장애물이 있습니다. 여기에 전사 캐릭터 1명과 몬스터 3명을 자연스럽게 배치해 주세요."
2. 에디터 제어를 위한 AI 에이전트 프로토콜 (MCP)
최근 각광받는 MCP(Model Context Protocol)나 Websocket 서버를 활용하여, LLM이 유니티 에디터에 직접 명령을 내릴 수 있는 통로를 만듭니다.
* LLM에게 유니티 에디터 기능을 실행할 수 있는 '도구(Tools/Function Calling)'를 부여합니다.
* 예: SpawnCharacter(string characterType, float x, float y, float z)라는 함수를 LLM이 스스로 호출할 수 있게 만듭니다.
3. 배치 규칙(Constraint) 가이드라인 제공
AI가 엉뚱한 공중이나 벽 속에 캐릭터를 생성하지 않도록 레이캐스트(Raycast)나 네비메시(NavMesh) 정보를 활용하도록 유도해야 합니다.
* AI에게 좌표를 받으면, 유니티 내부에서 바닥으로 레이를 쏘아 정확한 Y축 고정 지점을 찾도록 시스템을 보완합니다.
---
🛠️ 실제 작동 프로세스 (Workflow)
```
[개발자 변수 입력]
"마을 광장에 상인 NPC 3명 배치해줘"
↓
[유니티 C# 에디터 스크립트]
광장 주변의 지형 및 장애물 좌표 정보를 JSON으로 파싱
↓
[LLM (AI 에이전트)]
JSON을 분석하여 겹치지 않는 최적의 NPC 배치 좌표(X, Y, Z) 계산
↓
[유니티 에디터 (Function Calling)]
AI가 계산한 좌표를 바탕으로 `Instantiate()` 함수를 실행해 프리팹 실시간 배치
```
---
🚀 추천하는 구현 시작 단계
이 환경을 처음부터 직접 만드는 것이 부담스럽다면, 다음과 같은 오픈소스 및 기술을 참고해 구현해 볼 수 있습니다.
Unity 내장 AI 도구 활용: 유니티가 공식 개발 중인 Unity Muse(Compositor 등)나 AI 에시스턴트 기능을 참고하면 자연어 명령으로 씬을 구성하는 환경을 미리 체험해 볼 수 있습니다.
직접 구현 시: Python Flask나 Node.js로 중간 서버를 두고, 유니티 에디터 스크립트에서 UnityWebRequest로 LLM API를 호출하는 방식이 가장 직관적이고 빠르게 프로토타입을 만들 수 있는 방법입니다.
---
로컬에서 구동하는 큐엔(Qwen) 2.5(특히 Qwen2.5-Coder 시리즈)는 현존하는 오픈소스 모델 중 코딩 및 구조화 데이터 해석 능력이 가장 뛰어나며, 유니티 씬(.unity) 및 컴포넌트 분석 작업을 훌륭하게 수행할 수 있습니다.
모델의 파라미터 크기(7B, 14B, 32B 등)와 컴퓨터 사양에 따라 성능 차이는 있지만, 핵심적인 분석 가능 범위는 다음과 같습니다.
---
1. 문맥 수용량 (Context Length): 최대 128K~256K 토큰 지원
* 어디까지 가능한가: Qwen 2.5는 기본적으로 128K(일부 버전은 256K)의 거대한 컨텍스트 창을 지원합니다. 이는 대략 A4 용지 50~100장 분량의 텍스트 혹은 수만 줄의 코드를 한 번에 프롬프트로 입력받을 수 있음을 의미합니다.
* 씬 파일 분석 적용: 오브젝트가 수십~수백 개 수준인 중소규모의 유니티 YAML 씬 파일은 파일 통째로 넘겨도 한 번에 완벽히 읽고 맥락을 파악할 수 있습니다.
2. YAML 데이터 분석 능력: 최상급
* 어디까지 가능한가: 유니티 씬은 특유의 GUID, fileID 구조를 가진 복잡한 YAML 포맷을 사용합니다. Qwen 2.5는 구조화된 데이터(JSON, YAML, XML 등)의 문법적 관계를 추적하는 능력이 매우 날카롭습니다.
* 실제 분석 가능한 항목:
* 상속 및 부모-자식 관계 추적: Transform 컴포넌트의 m_Father와 m_Children ID를 추적하여 씬의 하이hierarchy(계층 구조)를 스스로 재구성할 수 있습니다.
* 컴포넌트 매칭: 특정 GameObject에 어떤 MonoBehaviour(C# 스크립트)나 라이트, 콜라이더가 붙어있는지 ID를 매핑하여 찾아냅니다.
3. 구조화된 배치 좌표 연산 및 JSON 출력 (Agentic Coding)
* 어디까지 가능한가: Qwen 2.5는 수학적 추론(Math Reasoning)과 정확한 JSON 형식 출력(Structured Output) 능력이 강화되었습니다.
* 캐릭터 배치 적용: "빈 공간 좌표를 계산해서 JSON 배열로 반환해줘"라고 요청하면, 씬 내부 장애물 좌표를 피해 겹치지 않는 { "x": 10.5, "y": 0, "z": -3.2 } 형태의 정확한 포맷을 에러 없이 출력합니다. 유니티 스크립트가 이를 받아 그대로 Instantiate()에 밀어 넣기 아주 좋습니다.
---
⚠️ 로컬 구동 시 성능별 한계 (현실적인 제약)컴퓨터의 VRAM(그래픽카드 메모리) 사양에 따라 선택하는 모델 크기별 한계는 명확히 존재합니다.
모델 크기 (Qwen 2.5) 추천 VRAM 유니티 씬 분석 한계
7B (중소형) 8GB ~ 12GB 단일 방(Room)이나 소규모 스테이지 단위의 씬 분석 가능. 배치 규칙이 복잡해지면(조건 3개 이상) 가끔 좌표가 겹치는 실수 발생.
14B (중형) 16GB ~ 24GB 일반적인 던전, 마을 광장 규모 씬 분석 가능. hierarchy 관계 추적을 꽤 정확하게 수행함.
32B / 72B (대형) 24GB ~ 48GB+ 클라우드 모델(GPT-4o급)에 준하는 복잡한 공간 추론 가능. 장애물 밀도를 계산해 '전술적 배치'까지 지시 가능.
💡 성공적인 구현을 위한 팁Qwen 2.5가 아무리 똑똑해도 씬 파일의 m_LocalPosition이나 fileID 같은 날것의 YAML 텍스트를 그대로 읽게 하면 로컬 환경에서는 연산 속도가 느려집니다.
따라서 유니티에서 1차로 텍스트를 정제(예: 필요한 오브젝트 이름과 Collider 범위만 JSON으로 파싱)한 뒤 Qwen 2.5에 입력값으로 던져주는 '하이브리드 파싱' 방식을 사용하면, 7B 수준의 가벼운 로컬 모델로도 끊김 없이 실시간 캐릭터 배치 환경을 훌륭하게 굴릴 수 있습니다.
---
네, 맞습니다. 유니티는 기본적으로 에디터가 활성화되거나 포커스를 얻을 때, 백그라운드에서 변경된 파일(스크립트, 씬, 에셋 등)을 자동으로 감지하고 새로고침(Auto Refresh) 및 리컴파일을 수행합니다.
AI가 외부에서 씬 파일(.unity)을 수정하거나 JSON 데이터를 갱신하면, 유니티 에디터 화면을 클릭하는 순간 그 변경 사항이 즉시 화면에 반영됩니다.
다만, AI 에이전트 환경을 더 매끄럽게 구축하기 위해 꼭 알아두어야 할 핵심 설정과 한계점이 있습니다.
---
⚙️ 1. 자동 고침 관련 유니티 에디터 설정
이 기능은 유니티 설정에서 켜고 끌 수 있습니다. AI 자동화 툴을 만들 때 팀원들의 에디터 설정이 다르면 오작동할 수 있으므로 체크해 두어야 합니다.
* 설정 위치: Edit -> Preferences -> Asset Pipeline
* 핵심 옵션:
* Auto Refresh: 기본값은 On Demand 또는 Enabled입니다. Enabled로 되어 있어야 백그라운드 변경을 감지합니다.
* Directory Monitoring: 이 옵션이 켜져 있으면 유니티가 OS 레벨에서 파일 변경을 실시간으로 감지하므로 새로고침이 더 빨라집니다.
---
⚠️ 2. AI 캐릭터 배치 환경 구축 시 주의할 점 (한계와 해결책)
AI가 씬 파일을 직접 수정하고 유니티가 이를 자동 고침하게 만들 때, 두 가지 큰 걸림돌이 있습니다.
① 현재 열려 있는 씬은 자동 고침으로 바로 안 바뀔 수 있음
* 문제점: 유니티 에디터에 이미 열려 있는(Open) 씬 파일을 외부에서 AI가 메모장 고치듯 수정하면, 유니티는 메모리 상의 데이터가 유실되는 것을 막기 위해 씬을 자동으로 다시 로드하지 않거나 경고창을 띄웁니다.
* 해결책: AI가 씬(.unity)을 직접 건드리는 것보다, "AI는 spawn_config.json 같은 데이터 파일만 수정"하게 하고, 유니티 내부에서 AssetPostprocessor 스크립트를 짜두는 것이 훨씬 안전합니다. JSON이 바뀌면 유니티가 백그라운드 감지로 이를 알아채고, C# 코드가 즉시 씬 위에 캐릭터 프리팹을 생성(Instantiate)하게 만드는 방식입니다.
② 포커스를 주어야만 갱신되는 문제
* 문제점: 유니티가 백그라운드에 가만히 있으면 파일이 바뀌어도 감지만 하고 있다가, 개발자가 유니티 창을 '마우스로 클릭(Focus)'하는 순간 리컴파일과 새로고침을 시작합니다. 완벽한 실시간 자동화를 원하는 경우 이 미세한 딜레이가 답답할 수 있습니다.
* 해결책: 유니티가 백그라운드에 있어도 실시간으로 명령을 처리하게 하려면, 앞서 언급한 Websocket 서버나 MCP를 유니티 에디터 스크립트(EditorApplication.update)와 연동하여 창이 내려가 있어도 계속 데이터를 받아 동기화하도록 강제해야 합니다.
---
🛠️ 추천하는 AI 배치 워크플로우
따라서 가장 안정적인 구조는 다음과 같습니다.
* AI(Qwen 2.5)가 분석 후 배치 좌표가 담긴 character_placement.json 파일을 생성 및 갱신합니다.
* 유니티 에디터가 백그라운드에서 이 파일의 변경을 감지합니다.
* 유니티 내부의 에디터 스크립트가 JSON을 읽어와서 실시간으로 씬에 캐릭터를 배치하고 씬을 저장(EditorSceneManager.SaveScene)합니다.
이 방식은 유니티의 기본 백그라운드 갱신 기능을 안전하게 활용하면서도, 씬 파일이 꼬이는 문제를 완벽하게 방지할 수 있습니다.
---
두 가지 방식을 모두 활용하는 구조(하이브리드)는 AI의 자유도와 시스템의 안정성을 동시에 챙길 수 있는 가장 강력한 접근법입니다.
* JSON 방식: 실시간 배치, 빈 공간 좌표 연산, 프리팹 생성 등 동적이고 빠른 작업에 사용합니다.
* .unity 직접 수정 방식: 씬의 계층 구조(Hierarchy) 대대적 변경, 대규모 컴포넌트 일괄 수정 등 구조적 작업에 사용합니다.
이 두 가지를 유니티 백그라운드 자동 고침 기능과 연동하여 안전하게 구동할 수 있는 구체적인 구현 전략과 핵심 C# 코드를 정리해 드립니다.
---
⚙️ 1. JSON 변경 감지 및 자동 배치 (실시간 연동용)AI가 배치 좌표를 character_placement.json 파일로 내뱉으면, 유니티가 백그라운드에서 이를 감지해 즉시 씬에 프리팹을 배치하고 자동으로 씬을 저장하는 스크립트입니다.
Assets/Editor/AIPlacementWatcher.cs 경로로 저장하세요.
```csharp
using UnityEngine;
using UnityEditor;
using System.IO;
using UnityEditor.SceneManagement;
public class AIPlacementWatcher : AssetPostprocessor
{
// 에셋 파이프라인에서 파일 변경을 감지하는 함수
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
foreach (string str in importedAssets)
{
// AI가 내뱉은 JSON 파일 이름 매칭
if (str.EndsWith("character_placement.json"))
{
Debug.Log("[AI] 캐릭터 배치 데이터 변경 감지! 적용을 시작합니다.");
ApplyAIPositioning(str);
break;
}
}
}
static void ApplyAIPositioning(string assetPath)
{
string jsonText = File.ReadAllText(assetPath);
// AI가 준 JSON 파싱 (간단한 구조 가정)
AIPlacementData data = JsonUtility.FromJson(jsonText);
// 유니티 에디터 환경에서 프리팹 로드 및 배치
GameObject prefab = AssetDatabase.LoadAssetAtPath($"Assets/Prefabs/{data.characterName}.prefab");
if (prefab != null)
{
GameObject spawned = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
spawned.transform.position = new Vector3(data.x, data.y, data.z);
spawned.name = data.characterName + "_AI";
// 중요: 변경 사항을 씬에 기록하고 자동 저장
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene());
Debug.Log($"[AI] {data.characterName} 배치 완료 및 씬 자동 저장 성공.");
}
}
}
[System.Serializable]
public class AIPlacementData { public string characterName; public float x; public float y; public float z; }
```
🛠️ 2. .unity 파일 직접 수정 (대규모 구조 변경용)
AI(Qwen 2.5)가 유니티 씬(.unity) 파일을 텍스트로 직접 수정할 때 발생할 수 있는 "현재 열려 있는 씬과 메모리 충돌" 문제를 방지하는 워크플로우입니다.
⚠️ 핵심 우회 전략
유니티는 활성화된 씬 파일이 외부에서 바뀌면 파일이 깨지는 것을 막기 위해 로드를 거부하거나 경고를 끕니다. 이를 해결하려면 AI가 수정을 마친 후 유니티에게 "코드 명령으로 씬을 강제 리로드(Reload)"하라고 지시해야 합니다.
AI가 씬 파일을 직접 수정했다면, 유니티 에디터를 클릭했을 때 아래 스크립트가 작동하여 변경된 파일 버전을 메모리에 강제로 새로고침합니다.
```csharp
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
[InitializeOnLoad]
public class SceneRefreshWatcher
{
static SceneRefreshWatcher()
{
// 유니티 에디터가 백그라운드에 있다가 포커스를 얻을 때(활성화될 때) 호출됨
EditorApplication.focusChanged += OnFocusChanged;
}
static void OnFocusChanged(bool isFocused)
{
if (isFocused)
{
// 현재 열려있는 씬의 경로를 가져옴
string currentScenePath = EditorSceneManager.GetActiveScene().path;
// AI가 외부에서 .unity 파일을 수정했다면, 현재 메모리를 비우고 디스크의 파일로 강제 리로드
if (!string.IsNullOrEmpty(currentScenePath))
{
// 사용자에게 묻지 않고 현재 열린 씬을 디스크 버전으로 강제 동기화
EditorSceneManager.OpenScene(currentScenePath, OpenSceneMode.Single);
Debug.Log("[AI] 외부에서 수정된 .unity 씬 파일을 강제로 리로드했습니다.");
}
}
}
}
```
💡 큐엔 2.5(Qwen)를 위한 하이브리드 활용 팁
1. 대화 나눌 때 구분하기:
1. AI에게 명령할 때 "이번엔 씬 내부 전체 컴포넌트 ID 구조를 바꿔야 하니까 .unity 파일을 직접 수정해줘" 혹은 "단순 캐릭터 위치만 잡을 거니까 JSON 파일만 갱신해줘"라고 프롬프트 상에서 명확히 역할을 분담시키면 환각(Hallucination)율이 급격히 줄어듭니다.
2. 유니티 백그라운드 완전 자동화:
1. 만약 유니티 화면을 마우스로 클릭하지 않아도 AI가 수정하자마자 바로바로 반영되게 하고 싶다면, 위 코드들의 OnFocusChanged 대신 EditorApplication.update 델리게이트에 타이머를 등록하여 1~2초마다 외부 파일의 수정 시간(File.GetLastWriteTime)을 체크하는 방식으로 고도화할 수 있습니다.
두 가지 방식을 섞어 쓰시려는 만큼 시스템 구조가 흥미로워질 것 같습니다. 혹시 AI가 .unity 파일을 직접 건드릴 때 주로 어떤 컴포넌트나 값을 바꾸게 할 계획이신가요? (예: 메인 카메라 세팅 변경, 라이트맵 세팅 등) 그에 맞는 AI 프롬프트 가이드를 추가로 제안해 드릴 수 있습니다.
---
"다(모든 것)"를 처리하는 시스템이라면 AI 에이전트의 권한과 유니티 에디터의 자동화 수준을 극한으로 끌어올려야 합니다. AI가 단순 좌표 변경(JSON)부터 씬의 모든 물리적/구조적 속성(.unity 직접 수정)까지 자유자재로 다루려면, 앞서 다룬 마우스 클릭 기반의 감지로는 한계가 있습니다.
개발자가 유니티 창을 보지 않고 백그라운드에 내려놓아도 AI가 명령을 내리는 즉시 씬 파일 리로드, JSON 파싱, 컴포넌트 조작이 실시간으로 이루어지는 완전 자동화 백그라운드 루프 시스템이 필요합니다.
이를 위해 유니티 에디터가 백그라운드에서도 쉬지 않고 돌며 모든 변경 사항을 즉시 반영하는 '올인원(All-in-One) 에디터 프로세서'를 구축해야 합니다.
---
🚀 백그라운드 실시간 올인원 감지 시스템유니티가 포커스를 잃어도(Background) 매초마다 JSON과 .unity 파일의 변경 여부를 체크하여 자동으로 씬을 리로드하고 캐릭터를 배치하는 통합 마스터 스크립트입니다.설치 경로: Assets/Editor/AIAllInOneProcessor.cs
```csharp
using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;
using System.IO;
[InitializeOnLoad]
public class AIAllInOneProcessor
{
// 감지할 파일 경로 설정 (프로젝트 루트 폴더 기준)
private static readonly string jsonPath = "AI_Output/character_placement.json";
private static readonly string scenePath = "Assets/Scenes/MainScene.unity"; // 대상 씬 경로
private static System.DateTime lastJsonTime;
private static System.DateTime lastSceneTime;
private static float checkInterval = 1.0f; // 1초마다 파일 체크
private static float nextCheckTime = 0;
static AIAllInOneProcessor()
{
// 유니티가 백그라운드에 있어도 이 루프는 계속 실행됩니다.
EditorApplication.update += BackgroundUpdateLoop;
// 초기 파일 시간 기록
if (File.Exists(jsonPath)) lastJsonTime = File.GetLastWriteTime(jsonPath);
if (File.Exists(scenePath)) lastSceneTime = File.GetLastWriteTime(scenePath);
}
static void BackgroundUpdateLoop()
{
// 너무 자주 체크하면 프리징이 걸리므로 주기적으로 체크
if (Time.realtimeSinceStartup < nextCheckTime) return;
nextCheckTime = Time.realtimeSinceStartup + checkInterval;
// 1. AI가 .unity 파일(씬 구조 전체)을 직접 수정한 경우 감지
if (File.Exists(scenePath))
{
System.DateTime currentSceneTime = File.GetLastWriteTime(scenePath);
if (currentSceneTime > lastSceneTime)
{
lastSceneTime = currentSceneTime;
Debug.Log("[AI 시스템] 외부에서 .unity 씬 파일 변경 감지! 강제 리로드합니다.");
// 현재 활성화된 씬이 대상 씬이라면 묻지 않고 디스크 버전으로 강제 동기화
EditorApplication.delayCall += () => {
EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single);
};
return; // 씬이 리로드되므로 루프 탈출
}
}
// 2. AI가 JSON(동적 배치 데이터)을 수정한 경우 감지
if (File.Exists(jsonPath))
{
System.DateTime currentJsonTime = File.GetLastWriteTime(jsonPath);
if (currentJsonTime > lastJsonTime)
{
lastJsonTime = currentJsonTime;
Debug.Log("[AI 시스템] 외부에서 JSON 배치 데이터 변경 감지! 프리팹을 배치합니다.");
EditorApplication.delayCall += () => {
ApplyJsonPlacement(jsonPath);
};
}
}
}
static void ApplyJsonPlacement(string path)
{
string jsonText = File.ReadAllText(path);
AIPlacementData data = JsonUtility.FromJson(jsonText);
// 에셋 데이터베이스에서 프리팹 검색 및 생성
GameObject prefab = AssetDatabase.LoadAssetAtPath($"Assets/Prefabs/{data.characterName}.prefab");
if (prefab != null)
{
GameObject spawned = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
spawned.transform.position = new Vector3(data.x, data.y, data.z);
spawned.name = $"{data.characterName}_AI_Spawned";
// 씬을 Dirty 상태로 만들고 즉시 저장 (이 저장이 디스크에 .unity 파일을 업데이트함)
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene());
// 본인이 수정한 것으로 인해 씬 감지 루프가 오작동하는 것을 방지하기 위해 시간 동기화
lastSceneTime = File.GetLastWriteTime(scenePath);
Debug.Log($"[AI 시스템] {data.characterName} 배치 완료 및 씬 저장 성공.");
}
else
{
Debug.LogError($"[AI 시스템] Assets/Prefabs/{data.characterName}.prefab 을 찾을 수 없습니다.");
}
}
}
```
⚠️ '다' 처리하는 환경에서 반드시 켜야 할 유니티 설정
이 시스템이 백그라운드에서 끊김 없이 돌아가려면 유니티 자체의 '기장 제한'을 풀어주어야 합니다.
1. 백그라운드 실행 허용:
1. 유니티 메뉴에서 Edit -> Project Settings -> Player로 이동합니다.
2. Run In Background 옵션을 반드시 체크(True)해야 유니티 창이 내려가 있어도 AI의 명령을 감지하고 연산을 수행합니다.
2. 에디터 다운타임 방지:
1. Edit -> Preferences -> General에서 Interaction Mode를 확인하고, 에디터가 포커스를 잃었을 때 프레임레이트가 극단적으로 떨어지는 현상을 방지하기 위해 가급적 고성능을 유지하도록 컴퓨터 전원 관리를 설정해 줍니다.
---
🤖 큐엔 2.5(Qwen) 멀티태스킹 프롬프트 가이드모든 것을 제어하는 AI 에이전트(Qwen)에게는 자신이 어떤 모드로 파일을 수정해야 하는지 확실한 지침(Guidelines)을 주어야 에러가 나지 않습니다. Qwen 시스템 프롬프트(System Prompt)에 아래 내용을 주입하세요.
```text
[역할 정의]
너는 유니티 에디터를 제어하는 마스터 개발 에이전트이다. 너는 상황에 따라 두 가지 방식으로 환경을 제어할 수 있다.
1. [JSON 모드] (단순 캐릭터 배치, 월드 스폰, 빠른 좌표 연산)
- 목적: 프리팹을 특정 위치에 빠르게 스폰하거나 이동할 때 사용한다.
- 파일: `AI_Output/character_placement.json` 경로에만 결과물을 출력한다.
- 형식: 정확한 JSON 포맷 포맷만 출력하며, 절대 다른 설명 텍스트를 섞지 않는다.
2. [YAML 모드] (씬 전체 구조 변경, 컴포넌트 일괄 수정, 계층 구조 변경)
- 목적: 유니티 씬의 근본적인 컴포넌트 데이터(Light 세팅, 카메라 세팅, 태그 변경 등)를 대규모로 수정할 때 사용한다.
- 파일: `Assets/Scenes/MainScene.unity` 파일의 YAML 텍스트를 직접 수정하여 덮어쓴다.
- 주의: 유니티 특유의 GUID 및 fileID 관계(m_Father, m_Children)가 깨지지 않도록 수정한 블록 외의 다른 YAML 구조는 원본을 완벽히 유지해야 한다.
사용자의 명령이 '동적 배치'에 가까우면 1번 모드를, '구조적 편집'에 가까우면 2번 모드를 스스로 판단하여 수행하라.
```
이제 AI가 대규모 구조를 바꿀 때는 .unity 파일을 해킹하듯 직접 수정하고, 유니티 에디터는 이를 감지해 자동으로 화면을 새로고침할 것입니다. 반대로 캐릭터를 촘촘히 배치할 때는 JSON을 통해 유니티 내부 C# 엔진의 안전한 Instantiate 기능을 빌려 쓰게 됩니다.
---
네, JSON 데이터 연동과 .unity 씬 파일 직접 수정 방식을 동시에 다루는 통합 백그라운드 자동 고침 환경은 유니티 에디터 스크립팅과 AI 에이전트의 프롬프트 설계 조합으로 완벽하게 구현 가능합니다.
AI가 실시간 캐릭터 배치나 연산은 JSON으로 가볍게 처리하고, 컴포넌트 일괄 수정이나 계층 구조 변경은 .unity 파일 직접 수정으로 처리할 수 있도록, 유니티가 백그라운드에서 이를 자동으로 감지하고 새로고침하는 마스터 제어 환경을 구축하는 방법을 안내해 드립니다.
---
🚀 1. 백그라운드 통합 자동 고침 C# 스크립트
개발자가 유니티 창을 마우스로 클릭하지 않고 백그라운드에 내려놓아도, AI가 파일을 수정하는 즉시 감지하여 씬을 강제 리로드하거나 프리팹을 배치하는 통합 에디터 스크립트입니다.
설치 경로: Assets/Editor/AIAllInOneProcessor.cs
```csharp
using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;
using System.IO;
[InitializeOnLoad]
public class AIAllInOneProcessor
{
// 감지할 파일 경로 설정 (프로젝트 루트 폴더 기준)
private static readonly string jsonPath = "AI_Output/character_placement.json";
private static readonly string scenePath = "Assets/Scenes/MainScene.unity"; // 대상 씬 경로
private static System.DateTime lastJsonTime;
private static System.DateTime lastSceneTime;
private static float checkInterval = 1.0f; // 1초마다 파일 변경 체크
private static float nextCheckTime = 0;
static AIAllInOneProcessor()
{
// 유니티가 백그라운드에 있어도 이 루프는 에디터 상에서 계속 실행됩니다.
EditorApplication.update += BackgroundUpdateLoop;
// 초기 파일 시간 기록
if (File.Exists(jsonPath)) lastJsonTime = File.GetLastWriteTime(jsonPath);
if (File.Exists(scenePath)) lastSceneTime = File.GetLastWriteTime(scenePath);
}
static void BackgroundUpdateLoop()
{
if (Time.realtimeSinceStartup < nextCheckTime) return;
nextCheckTime = Time.realtimeSinceStartup + checkInterval;
// [방식 A] AI가 .unity 파일(씬 구조 전체)을 직접 수정한 경우 감지
if (File.Exists(scenePath))
{
System.DateTime currentSceneTime = File.GetLastWriteTime(scenePath);
if (currentSceneTime > lastSceneTime)
{
lastSceneTime = currentSceneTime;
Debug.Log("[AI 시스템] 외부에서 .unity 씬 파일 직접 수정 감지! 씬을 강제 리로드합니다.");
// 메인 스레드 안전을 위해 delayCall로 실행
EditorApplication.delayCall += () => {
EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single);
};
return;
}
}
// [방식 B] AI가 JSON(동적 배치 데이터)을 수정한 경우 감지
if (File.Exists(jsonPath))
{
System.DateTime currentJsonTime = File.GetLastWriteTime(jsonPath);
if (currentJsonTime > lastJsonTime)
{
lastJsonTime = currentJsonTime;
Debug.Log("[AI 시스템] 외부에서 JSON 배치 데이터 변경 감지! 프리팹을 배치합니다.");
EditorApplication.delayCall += () => {
ApplyJsonPlacement(jsonPath);
};
}
}
}
static void ApplyJsonPlacement(string path)
{
string jsonText = File.ReadAllText(path);
AIPlacementData data = JsonUtility.FromJson(jsonText);
GameObject prefab = AssetDatabase.LoadAssetAtPath($"Assets/Prefabs/{data.characterName}.prefab");
if (prefab != null)
{
GameObject spawned = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
spawned.transform.position = new Vector3(data.x, data.y, data.z);
spawned.name = $"{data.characterName}_AI_Spawned";
// 씬을 수정된 상태(Dirty)로 만들고 즉시 디스크에 저장
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene());
// 유니티가 스스로 수정한 파일 때문에 루프가 오작동하는 것을 방지하기 위해 시간 동기화
lastSceneTime = File.GetLastWriteTime(scenePath);
Debug.Log($"[AI 시스템] {data.characterName} 배치 완료 및 씬 저장 성공.");
}
else
{
Debug.LogError($"[AI 시스템] Assets/Prefabs/{data.characterName}.prefab 을 찾을 수 없습니다.");
}
}
}
[System.Serializable]
public class AIPlacementData { public string characterName; public float x; public float y; public float z; }
```
---
⚙️ 2. 이 환경이 멈추지 않고 돌아가기 위한 필수 유니티 설정
유니티는 기본적으로 백그라운드로 내려가면 연산을 멈추거나 프레임레이트를 극단적으로 낮춥니다. 이를 방지하려면 아래 두 설정을 반드시 활성화해야 합니다.
1. 백그라운드 실행 허용:
1. Edit -> Project Settings -> Player -> Resolution and Presentation 탭으로 이동합니다.
2. Run In Background 옵션을 체크(True)로 변경합니다.
2. 에셋 파이프라인 자동 새로고침 확인:
1. Edit -> Preferences -> Asset Pipeline에서 Auto Refresh가 Enabled로 되어 있는지 확인하여 외부 파일 변경 이벤트가 즉시 유니티 엔진에 전달되도록 합니다.
---
🤖 3. 큐엔 2.5(Qwen)를 위한 에이전트 가이드 프롬프트모든 권한을 가진 로컬 AI(Qwen 2.5)가 상황에 맞게 JSON과 YAML(.unity) 모드를 스스로 선택해서 작업할 수 있도록 시스템 프롬프트(System Prompt)에 규칙을 주입해야 효율이 극대화됩니다.
```text
너는 유니티 에디터를 완벽히 제어하는 자동화 개발 에이전트이다. 너는 지시에 따라 다음 두 가지 방식으로 환경을 제어할 수 있다.
1. [JSON 배치 모드]
- 목적: 새로운 캐릭터를 스폰하거나, 장애물을 피해서 특정 오브젝트의 위치를 바꿀 때 사용한다.
- 파일 출력: `AI_Output/character_placement.json` 경로에 데이터를 갱신한다.
- 특징: 가볍고 빠르며 유니티의 안전한 인스턴스화 기능을 이용한다. 다른 설명 없이 오직 순수 JSON 데이터만 출력하라.
2. [YAML 직접 수정 모드]
- 목적: 씬 내부 컴포넌트 전체 일괄 수정, 계층 구조(Hierarchy)의 대대적 변경, 조명(Light) 설정 등의 구조적 수정을 할 때 사용한다.
- 파일 출력: `Assets/Scenes/MainScene.unity` 파일의 YAML 텍스트를 직접 열어 수정 후 저장한다.
- 주의: 유니티의 고유 fileID 및 m_Father, m_Children 관계가 깨지면 씬 파일이 손상되므로, 수정하려는 컴포넌트 블록 외의 다른 YAML 구조는 원본을 완벽하게 보존해야 한다.
사용자의 요구사항이 '동적 캐릭터 배치'라면 1번 모드를, '전체적인 환경 및 컴포넌트 편집'이라면 2번 모드를 스스로 판단하여 수행하라.
```
이렇게 구성하면 AI가 대규모 구조를 수정할 때는 .unity 파일을 해킹하듯 텍스트 단위로 조작하고, 유니티 에디터는 이를 백그라운드에서 실시간으로 감지하여 자동으로 화면에 새 구조를 로드합니다. 반대로 캐릭터를 배치할 때는 안정적인 JSON 파일 파싱 레이어를 거치게 됩니다.
---
그럼 두 가지 모두 완벽히 작동하도록, JSON 데이터 구조에는 회전(Rotation)과 크기(Scale)를 포함하고, .unity 파일 직접 수정을 위해 실제 유니티 YAML 코드 분석 가이드까지 통합하여 제공해 드리겠습니다.
---
🎨 1. 확장된 JSON 배치 시스템 (위치 + 회전 + 크기)
AI가 캐릭터를 더욱 자연스럽게 배치할 수 있도록 Rotation과 Scale 정보를 추가한 완전한 C# 감지 스크립트입니다.
* 설치 경로: Assets/Editor/AIAllInOneProcessor.cs (기존 코드를 이 버전으로 덮어쓰시면 됩니다.)
```csharp
using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;
using System.IO;
[InitializeOnLoad]
public class AIAllInOneProcessor
{
private static readonly string jsonPath = "AI_Output/character_placement.json";
private static readonly string scenePath = "Assets/Scenes/MainScene.unity";
private static System.DateTime lastJsonTime;
private static System.DateTime lastSceneTime;
private static float checkInterval = 1.0f;
private static float nextCheckTime = 0;
static AIAllInOneProcessor()
{
EditorApplication.update += BackgroundUpdateLoop;
if (File.Exists(jsonPath)) lastJsonTime = File.GetLastWriteTime(jsonPath);
if (File.Exists(scenePath)) lastSceneTime = File.GetLastWriteTime(scenePath);
}
static void BackgroundUpdateLoop()
{
if (Time.realtimeSinceStartup < nextCheckTime) return;
nextCheckTime = Time.realtimeSinceStartup + checkInterval;
// [방식 A] .unity 파일 직접 수정 감지
if (File.Exists(scenePath))
{
System.DateTime currentSceneTime = File.GetLastWriteTime(scenePath);
if (currentSceneTime > lastSceneTime)
{
lastSceneTime = currentSceneTime;
Debug.Log("[AI 시스템] 외부에서 .unity 씬 파일 직접 수정 감지! 씬을 강제 리로드합니다.");
EditorApplication.delayCall += () => {
EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single);
};
return;
}
}
// [방식 B] JSON 배치 데이터 변경 감지 (확장 버전)
if (File.Exists(jsonPath))
{
System.DateTime currentJsonTime = File.GetLastWriteTime(jsonPath);
if (currentJsonTime > lastJsonTime)
{
lastJsonTime = currentJsonTime;
Debug.Log("[AI 시스템] 외부에서 JSON 배치 데이터 변경 감지! 프리팹을 정밀 배치합니다.");
EditorApplication.delayCall += () => { ApplyJsonPlacement(jsonPath); };
}
}
}
static void ApplyJsonPlacement(string path)
{
string jsonText = File.ReadAllText(path);
AIPlacementData data = JsonUtility.FromJson(jsonText);
GameObject prefab = AssetDatabase.LoadAssetAtPath($"Assets/Prefabs/{data.characterName}.prefab");
if (prefab != null)
{
GameObject spawned = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
// 위치(Position), 회전(Rotation), 크기(Scale) 정밀 적용
spawned.transform.position = new Vector3(data.posX, data.posY, data.posZ);
spawned.transform.rotation = Quaternion.Euler(data.rotX, data.rotY, data.rotZ);
spawned.transform.localScale = new Vector3(data.scaleX, data.scaleY, data.scaleZ);
spawned.name = $"{data.characterName}_AI_Spawned";
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene());
lastSceneTime = File.GetLastWriteTime(scenePath);
Debug.Log($"[AI 시스템] {data.characterName} 정밀 배치 및 씬 저장 성공.");
}
}
}
// 큐엔 2.5가 출력해야 하는 확장 JSON 매핑 클래스
[System.Serializable]
public class AIPlacementData
{
public string characterName;
public float posX; public float posY; public float posZ;
public float rotX; public float rotY; public float rotZ;
public float scaleX; public float scaleY; public float scaleZ;
}
```
🔍 2. .unity 파일 직접 수정을 위한 YAML 분석 가이드큐엔 2.5가 .unity 파일을 에러 없이 해킹·수정하게 하려면, 씬 파일 내부의 Transform(위치/회전/크기)과 Light(조명) 컴포넌트의 YAML 구조를 프롬프트에 예시로 제공해야 합니다. 유니티 씬 파일은 아래와 같은 규칙으로 기록됩니다.
① Transform 컴포넌트 YAML 구조 (AI 학습용)
```yaml
--- !u!4 &123456789
Transform:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 987654321} # 연결된 게임오브젝트 ID
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} # 쿼터니언 회전값값
m_LocalPosition: {x: 10, y: 0, z: -5} # 위치값
m_LocalScale: {x: 1, y: 1, z: 1} # 크기값
m_Children: []
m_Father: {fileID: 0}
```
② Light(조명) 컴포넌트 YAML 구조 (AI 학습용)
```yaml
--- !u!108 &11223344
Light:
m_ObjectHideFlags: 0
m_GameObject: {fileID: 987654321}
m_Enabled: 1
m_Type: 1 # 1은 Directional Light, 2는 Point Light 등
m_Color: {r: 1, g: 0.95, b: 0.8, a: 1} # 조명 색상 (RGBA)
m_Intensity: 1.5 # 조명 밝기
m_Range: 10
```
🤖 3. 큐엔 2.5(Qwen) 최종 마스터 시스템 프롬프트위의 확장된 JSON 구조와 YAML 규칙을 큐엔 2.5에게 주입하는 최종 프롬프트입니다. 이를 AI의 역할 정의(System Prompt)에 그대로 입력하세요.
```text
너는 유니티 에디터와 씬 환경을 완벽히 제어하는 자동화 AI 개발 에이전트이다.
너는 사용자의 명령에 따라 다음 두 가지 모드 중 가장 적합한 방식을 스스로 선택하여 파일을 갱신해야 한다.
1. [JSON 배치 모드] (캐릭터 배치, 오브젝트 조절 등 고속 작업)
- 목적: 새로운 캐릭터나 프리팹을 정밀한 위치, 회전, 크기로 배치할 때 사용한다.
- 파일 출력: 'AI_Output/character_placement.json' 경로에 아래 포맷으로만 작성한다. (설명 텍스트 절대 금지)
- 포맷 예시:
{
"characterName": "Warrior",
"posX": 12.5, "posY": 0.0, "posZ": -5.2,
"rotX": 0.0, "rotY": 180.0, "rotZ": 0.0,
"scaleX": 1.0, "scaleY": 1.0, "scaleZ": 1.0
}
2. [YAML 직접 수정 모드] (씬 전체 구조 변경, 라이트/카메라 세팅 등 대규모 작업)
- 목적: 씬 내부 컴포넌트(Light의 Intensity/Color, Transform의 좌표, 컴포넌트 활성화 여부 등)를 직접 조작할 때 사용한다.
- 파일 출력: 'Assets/Scenes/MainScene.unity' 파일의 텍스트를 직접 수정하여 덮어쓴다.
- 규칙: 유니티의 고유 오브젝트 ID(fileID, GUID) 및 부모 자식 관계(m_Father, m_Children)를 절대 임의로 새로 만들거나 깨뜨리지 말고, 타겟 컴포넌트의 값(m_LocalPosition, m_Intensity 등)만 정확히 변경하라.
명령을 받으면 어떤 모드를 사용할지 결정하고, 오직 해당 파일의 코드(또는 JSON)만 깔끔하게 출력하라.
```
이제 완벽한 하이브리드 환경이 갖춰졌습니다. AI가 JSON을 건드리면 유니티가 실시간으로 캐릭터를 예쁘게 정렬해 스폰하고, AI가 .unity 파일을 직접 건드리면 유니티가 감지하여 씬을 통째로 새로고침(Reload)하며 조명이나 씬 세팅을 즉시 바꿀 것입니다.
혹시 이 시스템을 바탕으로 처음으로 시도해보고 싶으신 구체적인 테스트 명령이 있으신가요? (예: "마을에 전사 캐릭터를 앞을 보게 배치해줘" 또는 "씬 전체 조명을 밤(어둡고 푸른색)으로 바꿔줘" 등) 명령에 맞는 AI 입력용 프롬프트 조합을 구성해 드릴 수 있습니다.
---
그럼 이 마스터 시스템이 제대로 작동하는지 검증하기 위해, JSON 정밀 배치와 YAML 씬 직접 수정 두 가지를 모두 아우르는 종합 테스트 명령용 프롬프트 세트를 준비했습니다.
로컬에서 구동 중인 큐엔 2.5(Qwen 2.5)에게 아래 프롬프트를 차례대로 입력하고, 유니티 에디터 화면이 백그라운드에서 실시간으로 바뀌는지 확인해 보세요!
---
🧪 1차 테스트: JSON 정밀 배치 (위치 + 회전 + 크기)
큐엔에게 보낼 명령:
"전사(Warrior) 캐릭터를 광장 중앙 근처인 (X:15.2, Y:0, Z:-8.4) 위치에 배치해줘. 캐릭터가 카메라를 등지고 앞을 바라보도록 Y축 회전값을 180도로 설정하고, 보스 캐릭터처럼 보이게 크기(Scale)를 모두 1.5배로 키워줘."
큐엔 2.5가 출력해야 할 결과물 (AI_Output/character_placement.json으로 저장):
```json
{
"characterName": "Warrior",
"posX": 15.2,
"posY": 0.0,
"posZ": -8.4,
"rotX": 0.0,
"rotY": 180.0,
"rotZ": 0.0,
"scaleX": 1.5,
"scaleY": 1.5,
"scaleZ": 1.5
}
```
* 결과 확인: 이 JSON 파일이 저장되는 순간, 유니티 에디터가 백그라운드에서 프리팹을 생성하고 1.5배 커진 전사를 180도 돌려 배치한 뒤 씬을 자동 저장합니다.
---
🪐 2차 테스트: .unity 직접 수정 (조명 세팅을 '밤'으로 변경)
큐엔에게 보낼 명령:
"현재 Assets/Scenes/MainScene.unity 파일을 읽고, 씬의 분위기를 어두운 '밤(Night)'으로 바꿔줘. 씬 내부의 Light 컴포넌트를 찾아서 밝기(m_Intensity)를 0.3으로 낮추고, 조명 색상(m_Color)을 차가운 푸른빛인 {r: 0.1, g: 0.15, b: 0.3, a: 1}으로 수정해줘."
큐엔 2.5가 출력해야 할 결과물 (Assets/Scenes/MainScene.unity에 덮어쓰기):
```yaml
# 유니티 씬 파일 내부의 Light 컴포넌트 부분을 AI가 아래처럼 수정함
--- !u!108 &11223344
Light:
m_ObjectHideFlags: 0
m_GameObject: {fileID: 987654321}
m_Enabled: 1
m_Type: 1
m_Color: {r: 0.1, g: 0.15, b: 0.3, a: 1} # AI가 푸른색으로 변경
m_Intensity: 0.3 # AI가 어둡게 변경
m_Range: 10
```
결과 확인: AI가 씬 텍스트를 수정해 저장하면, 유니티 백그라운드 루프가 이를 감지해 씬을 자동으로 리로드(Reload)합니다. 화면 전체가 어둡고 푸른 밤 환경으로 실시간 전환됩니다.
💡 큐엔 2.5 실행 환경 가이드 (최종 체크)
1. 유니티 프로젝트 폴더 안에 AI_Output 이라는 이름의 폴더를 미리 하나 생성해 두세요.
2. 유니티에서 Assets/Prefabs/ 경로에 Warrior 라는 이름의 프리팹(간단한 큐브나 캐릭터 모델)을 만들어 두세요.
3. 큐엔 2.5가 파일 시스템에 접근할 수 있도록 Python 스크립트나 AI 에이전트 실행 도구(예: Ollama, 웹 UI 등)와 연결하여 위 파일들을 읽고 쓸 수 있게 권한을 부여해 주시면 끝납니다.
---
로컬 환경에서 큐엔 2.5(Qwen 2.5-Coder)를 구동하고, 파이썬을 통해 유니티 파일들을 실제로 제어하는 통합 연동 코드입니다.
가장 대중적이고 가벼운 로컬 LLM 구동 툴인 Ollama API와 파이썬의 Pydantic 라이브러리를 활용하여, AI가 출력 포맷을 절대로 어기지 않도록 구조화된 출력(Structured Output) 기능으로 안전하게 설계했습니다.
---
🛠️ 1. 파이썬 환경 준비터미널을 열고 AI 연동 및 데이터 검증에 필요한 라이브러리를 먼저 설치해 주세요.
```bash
pip install ollama pydantic
```
🐍 2. AI 마스터 에이전트 파이썬 스크립트
유니티 프로젝트 루트 폴더(또는 바로 바깥 폴더)에 unity_ai_agent.py라는 이름으로 저장하고 실행하시면 됩니다. 이 코드가 큐엔 2.5를 호출하고 결과물을 유니티 파일 시스템에 직접 기록합니다.
```python
import os
import json
from ollama import Client # Ollama 공식 라이브러리 사용
from pydantic import BaseModel, Field
# ------------------------------------------------------------------
# [1] 데이터 구조 정의 (Qwen 2.5가 절대 틀리지 않게 포맷 강제)
# ------------------------------------------------------------------
class AIPlacementData(BaseModel):
characterName: str = Field(description="배치할 유니티 프리팹의 이름 (예: Warrior)")
posX: float = Field(description="X축 위치 좌표")
posY: float = Field(description="Y축 위치 좌표 (바닥 높이)")
posZ: float = Field(description="Z축 위치 좌표")
rotX: float = Field(description="X축 회전각")
rotY: float = Field(description="Y축 회전각 (바라보는 방향)")
rotZ: float = Field(description="Z축 회전각")
scaleX: float = Field(description="X축 크기 배율")
scaleY: float = Field(description="Y축 크기 배율")
scaleZ: float = Field(description="Z축 크기 배율")
# ------------------------------------------------------------------
# [2] 환경 설정 및 에이전트 클래스
# ------------------------------------------------------------------
class UnityAIAgent:
def __init__(self, unity_project_path):
self.project_path = unity_project_path
# JSON이 저장될 폴더 자동 생성
self.json_dir = os.path.join(unity_project_path, "AI_Output")
os.makedirs(self.json_dir, exist_ok=True)
self.json_file_path = os.path.join(self.json_dir, "character_placement.json")
self.scene_file_path = os.path.join(unity_project_path, "Assets/Scenes/MainScene.unity")
# 로컬 Ollama 클라이언트 초기화 (Qwen 2.5 사용)
self.client = Client(host='http://localhost:11434')
self.model_name = "qwen2.5-coder:7b" # 7b, 14b, 32b 등 본인의 모델명으로 매칭
# 방식 1: JSON 캐릭터 정밀 배치 명령 처리
def request_json_placement(self, user_command):
print(f"\n[AI] JSON 배치 요청 분석 중: '{user_command}'")
# Ollama의 Structured Output 기능을 사용하여 정확히 JSON만 받아냄
response = self.client.chat(
model=self.model_name,
messages=[
{"role": "system", "content": "너는 유니티 프리팹 배치 좌표를 계산하는 정밀 에이전트이다."},
{"role": "user", "content": user_command}
],
format=AIPlacementData.model_json_schema() # Pydantic 스키마 주입으로 포맷 강제
)
# 받은 JSON 텍스트를 파일로 저장
json_result = response['message']['content']
with open(self.json_file_path, "w", encoding="utf-8") as f:
f.write(json_result)
print(f"✅ JSON 데이터 갱신 완료 -> {self.json_file_path}")
print(json.dumps(json.loads(json_result), indent=2))
# 방식 2: .unity 씬 파일 직접 수정 명령 처리
def request_scene_modify(self, user_command):
print(f"\n[AI] 씬 파일 직접 수정 중: '{user_command}'")
if not os.path.exists(self.scene_file_path):
print(f"❌ 에러: 지정된 경로에 씬 파일이 없습니다 ({self.scene_file_path})")
return
# 원본 .unity 파일(YAML) 읽기
with open(self.scene_file_path, "r", encoding="utf-8") as f:
scene_raw_text = f.read()
# 큐엔 2.5에게 원본 파일과 함께 수정 명령 전달 (맥락 보존)
prompt = f"""
아래의 유니티 씬 파일(YAML) 데이터를 읽고, 사용자의 요구사항에 맞게 특정 컴포넌트 블록의 값만 정밀하게 수정해줘.
오브젝트의 ID(fileID)나 부모-자식 관계는 절대 건드리지 말고, 변경 요청이 들어온 값만 고쳐야 해.
출력은 다른 설명이나 마크다운 백틱(```) 없이, 오직 수정이 완료된 유니티 씬 파일의 전체 텍스트만 출력해라.
[사용자 요구사항]
{user_command}
[원본 씬 파일 데이터]
{scene_raw_text}
"""
response = self.client.generate(
model=self.model_name,
prompt=prompt,
options={"temperature": 0.1} # 환각 방지를 위해 온도를 낮춤
)
modified_scene_text = response['response'].strip()
# 수정본을 그대로 .unity 파일에 덮어쓰기
with open(self.scene_file_path, "w", encoding="utf-8") as f:
f.write(modified_scene_text)
print(f"✅ .unity 씬 파일 직접 수정 완료 -> {self.scene_file_path}")
# ------------------------------------------------------------------
# [3] 실제 에이전트 구동 및 테스트
# ------------------------------------------------------------------
if __name__ == "__main__":
# 자신의 유니티 프로젝트 폴더 경로를 여기에 적으세요.
UNITY_PROJECT_DIR = "C:/Users/Username/MyUnityProject"
agent = UnityAIAgent(unity_project_path=UNITY_PROJECT_DIR)
# [테스트 1] JSON 배치 실행
agent.request_json_placement(
"전사(Warrior) 캐릭터를 (X:15.2, Y:0, Z:-8.4) 위치에 배치해줘. "
"Y축 회전값은 180도, 크기(Scale)는 보스 몬스터처럼 전축 모두 1.5배로 키워줘."
)
# [테스트 2] .unity 파일 직접 수정 실행 (실제 씬 파일이 존재해야 정상 작동합니다)
# agent.request_scene_modify(
# "씬 내부의 Light 컴포넌트를 찾아서 밝기(m_Intensity)를 0.3으로 낮추고, "
# "색상(m_Color)을 차가운 푸른빛인 {r: 0.1, g: 0.15, b: 0.3, a: 1}으로 바꿔서 밤 분위기를 만들어줘."
# )
```
💡 연동 후 완벽하게 굴리는 루틴 구상
1. 이 파이썬 코드를 실행하면 AI_Output/character_placement.json 파일이 새로 생기거나, MainScene.unity 파일 텍스트가 바뀝니다.
2. 유니티 프로젝트를 켜두고 Run In Background 옵션을 켠 상태라면, 유니티는 백그라운드에서 우리가 아까 짜둔 C# 관찰자(AIAllInOneProcessor)를 통해 1초마다 이 파일들을 체크합니다.
3. 파이썬이 파일을 바꾸자마자 유니티 에디터 화면에 캐릭터가 척척 소폰되거나 조명이 즉시 밤으로 변하게 됩니다.
🛠️ Code Note & Usage
* Human + AI Collaboration: 여기 문서와 코드는 제가 전체적인 구조를 설계하고, Google AI를 달달 볶아가며(?) 생성한 코드 뭉치들 입니다.
* Free to Use: 제 노력이 담긴 문서와 코드이지만, 공부하시는 분들을 위해 누구나 자유롭게 가져가서 사용하실 수 있도록 공개합니다!
* ⚠️ Warning: 제 프로젝트에 맞춰 최적화된 코드이므로, 가져가서 쓰실 때는 본인의 환경에 맞게 버그나 에러를 꼭 한 번 더 확인(주의)하고 사용해 주세요.
코드를 사용할 때는 주의가 필요합니다.
2026년 7월 22일 수요일
네, LLM을 활용한 유니티 씬 파일(.unity) 파싱 및 분석은 충분히 가능합니다.
네, LLM을 활용한 유니티 씬 파일(.unity) 파싱 및 분석은 충분히 가능합니다.
네, LLM을 활용한 유니티 씬 파일(.unity) 파싱 및 분석은 충분히 가능합니다. 유니티 씬 파일은 기본적으로 텍스트 기반의 YAML(YAML Ain't Markup Language) ...
-
bool atob(const char * string) { if (!strcmp(string, "true")) return true; return false; }
-
Environment Variables: MAXSDKPATH=C:\Program Files (x86)\Autodesk\3ds Max 2010 SDK Sample source http://download.autodesk.com/media/...
-
/// CXXXView.cpp void CXXXView::OnInitialUpdate() { CView::OnInitialUpdate(); // TODO: Add your specialized code here and/or call the ...