대안에 대한 내용은 마지막에 넣어놨습니다.
이전 글에서 유니티 에디터에서 '파일 다얄로그'를 열어 파일을 선택하는 것을 했습니다.
문제는 유니티 에디터에서만 쓸 수 있다는 것이죠 ㅡ,.ㅡ;;;
그래서 검색해 보니 스크립트로 구현하는 방법이 있네요.
'ImprovedFileBrowser'라는 스크립트입니다.
(참고 : unify community - ImprovedFileBrowser )
설명이 워낙 잘되어 있어서 전체 코드를 넣겠습니다.
이것은 픽스된 코드가 적용된 코드입니다.
using UnityEngine; using System; using System.IO; using System.Collections.Generic; /* File browser for selecting files or folders at runtime. */ public enum FileBrowserType { File, Directory } public class FileBrowser { // Called when the user clicks cancel or select public delegate void FinishedCallback(string path); // Defaults to working directory public string CurrentDirectory { get { return m_currentDirectory; } set { SetNewDirectory(value); SwitchDirectoryNow(); } } protected string m_currentDirectory; // Optional pattern for filtering selectable files/folders. See: // http://msdn.microsoft.com/en-us/library/wz42302f(v=VS.90).aspx // and // http://msdn.microsoft.com/en-us/library/6ff71z1w(v=VS.90).aspx public string SelectionPattern { get { return m_filePattern; } set { m_filePattern = value; ReadDirectoryContents(); } } protected string m_filePattern; // Optional image for directories public Texture2D DirectoryImage { get { return m_directoryImage; } set { m_directoryImage = value; BuildContent(); } } protected Texture2D m_directoryImage; // Optional image for files public Texture2D FileImage { get { return m_fileImage; } set { m_fileImage = value; BuildContent(); } } protected Texture2D m_fileImage; // Browser type. Defaults to File, but can be set to Folder public FileBrowserType BrowserType { get { return m_browserType; } set { m_browserType = value; ReadDirectoryContents(); } } protected FileBrowserType m_browserType; protected string m_newDirectory; protected string[] m_currentDirectoryParts; protected string[] m_files; protected GUIContent[] m_filesWithImages; protected int m_selectedFile; protected string[] m_nonMatchingFiles; protected GUIContent[] m_nonMatchingFilesWithImages; protected int m_selectedNonMatchingDirectory; protected string[] m_directories; protected GUIContent[] m_directoriesWithImages; protected int m_selectedDirectory; protected string[] m_nonMatchingDirectories; protected GUIContent[] m_nonMatchingDirectoriesWithImages; protected bool m_currentDirectoryMatches; protected GUIStyle CentredText { get { if (m_centredText == null) { m_centredText = new GUIStyle(GUI.skin.label); m_centredText.alignment = TextAnchor.MiddleLeft; m_centredText.fixedHeight = GUI.skin.button.fixedHeight; } return m_centredText; } } protected GUIStyle m_centredText; protected string m_name; protected Rect m_screenRect; protected Vector2 m_scrollPosition; protected FinishedCallback m_callback; // Browsers need at least a rect, name and callback public FileBrowser(Rect screenRect, string name, FinishedCallback callback) { m_name = name; m_screenRect = screenRect; m_browserType = FileBrowserType.File; m_callback = callback; SetNewDirectory(Directory.GetCurrentDirectory()); SwitchDirectoryNow(); } protected void SetNewDirectory(string directory) { m_newDirectory = directory; } protected void SwitchDirectoryNow() { if (m_newDirectory == null || m_currentDirectory == m_newDirectory) { return; } m_currentDirectory = m_newDirectory; m_scrollPosition = Vector2.zero; m_selectedDirectory = m_selectedNonMatchingDirectory = m_selectedFile = -1; ReadDirectoryContents(); } protected void ReadDirectoryContents() { if (m_currentDirectory == "/") { m_currentDirectoryParts = new string[] { "" }; m_currentDirectoryMatches = false; } else { m_currentDirectoryParts = m_currentDirectory.Split(Path.DirectorySeparatorChar); if (SelectionPattern != null) { string directoryName = Path.GetDirectoryName(m_currentDirectory); string[] generation = new string[0]; if (directoryName != null) { //This is new: generation should be an empty array for the root directory. //directoryName will be null if it's a root directory generation = Directory.GetDirectories( directoryName, SelectionPattern); } m_currentDirectoryMatches = Array.IndexOf(generation, m_currentDirectory) >= 0; } else { m_currentDirectoryMatches = false; } } if (BrowserType == FileBrowserType.File || SelectionPattern == null) { m_directories = Directory.GetDirectories(m_currentDirectory); m_nonMatchingDirectories = new string[0]; } else { m_directories = Directory.GetDirectories(m_currentDirectory, SelectionPattern); var nonMatchingDirectories = new List<string>(); foreach (string directoryPath in Directory.GetDirectories(m_currentDirectory)) { if (Array.IndexOf(m_directories, directoryPath) < 0) { nonMatchingDirectories.Add(directoryPath); } } m_nonMatchingDirectories = nonMatchingDirectories.ToArray(); for (int i = 0; i < m_nonMatchingDirectories.Length; ++i) { int lastSeparator = m_nonMatchingDirectories[i].LastIndexOf(Path.DirectorySeparatorChar); m_nonMatchingDirectories[i] = m_nonMatchingDirectories[i].Substring(lastSeparator + 1); } Array.Sort(m_nonMatchingDirectories); } for (int i = 0; i < m_directories.Length; ++i) { m_directories[i] = m_directories[i].Substring(m_directories[i].LastIndexOf(Path.DirectorySeparatorChar) + 1); } if (BrowserType == FileBrowserType.Directory || SelectionPattern == null) { m_files = Directory.GetFiles(m_currentDirectory); m_nonMatchingFiles = new string[0]; } else { m_files = Directory.GetFiles(m_currentDirectory, SelectionPattern); var nonMatchingFiles = new List<string>(); foreach (string filePath in Directory.GetFiles(m_currentDirectory)) { if (Array.IndexOf(m_files, filePath) < 0) { nonMatchingFiles.Add(filePath); } } m_nonMatchingFiles = nonMatchingFiles.ToArray(); for (int i = 0; i < m_nonMatchingFiles.Length; ++i) { m_nonMatchingFiles[i] = Path.GetFileName(m_nonMatchingFiles[i]); } Array.Sort(m_nonMatchingFiles); } for (int i = 0; i < m_files.Length; ++i) { m_files[i] = Path.GetFileName(m_files[i]); } Array.Sort(m_files); BuildContent(); m_newDirectory = null; } protected void BuildContent() { m_directoriesWithImages = new GUIContent[m_directories.Length]; for (int i = 0; i < m_directoriesWithImages.Length; ++i) { m_directoriesWithImages[i] = new GUIContent(m_directories[i], DirectoryImage); } m_nonMatchingDirectoriesWithImages = new GUIContent[m_nonMatchingDirectories.Length]; for (int i = 0; i < m_nonMatchingDirectoriesWithImages.Length; ++i) { m_nonMatchingDirectoriesWithImages[i] = new GUIContent(m_nonMatchingDirectories[i], DirectoryImage); } m_filesWithImages = new GUIContent[m_files.Length]; for (int i = 0; i < m_filesWithImages.Length; ++i) { m_filesWithImages[i] = new GUIContent(m_files[i], FileImage); } m_nonMatchingFilesWithImages = new GUIContent[m_nonMatchingFiles.Length]; for (int i = 0; i < m_nonMatchingFilesWithImages.Length; ++i) { m_nonMatchingFilesWithImages[i] = new GUIContent(m_nonMatchingFiles[i], FileImage); } } public void OnGUI() { GUILayout.BeginArea( m_screenRect, m_name, GUI.skin.window ); GUILayout.BeginHorizontal(); for (int parentIndex = 0; parentIndex < m_currentDirectoryParts.Length; ++parentIndex) { if (parentIndex == m_currentDirectoryParts.Length - 1) { GUILayout.Label(m_currentDirectoryParts[parentIndex], CentredText); } else if (GUILayout.Button(m_currentDirectoryParts[parentIndex])) { string parentDirectoryName = m_currentDirectory; for (int i = m_currentDirectoryParts.Length - 1; i > parentIndex; --i) { parentDirectoryName = Path.GetDirectoryName(parentDirectoryName); } SetNewDirectory(parentDirectoryName); } } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); m_scrollPosition = GUILayout.BeginScrollView( m_scrollPosition, false, true, GUI.skin.horizontalScrollbar, GUI.skin.verticalScrollbar, GUI.skin.box ); m_selectedDirectory = GUILayoutx.SelectionList( m_selectedDirectory, m_directoriesWithImages, DirectoryDoubleClickCallback ); if (m_selectedDirectory > -1) { m_selectedFile = m_selectedNonMatchingDirectory = -1; } m_selectedNonMatchingDirectory = GUILayoutx.SelectionList( m_selectedNonMatchingDirectory, m_nonMatchingDirectoriesWithImages, NonMatchingDirectoryDoubleClickCallback ); if (m_selectedNonMatchingDirectory > -1) { m_selectedDirectory = m_selectedFile = -1; } GUI.enabled = BrowserType == FileBrowserType.File; m_selectedFile = GUILayoutx.SelectionList( m_selectedFile, m_filesWithImages, FileDoubleClickCallback ); GUI.enabled = true; if (m_selectedFile > -1) { m_selectedDirectory = m_selectedNonMatchingDirectory = -1; } GUI.enabled = false; GUILayoutx.SelectionList( -1, m_nonMatchingFilesWithImages ); GUI.enabled = true; GUILayout.EndScrollView(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Cancel", GUILayout.Width(50))) { m_callback(null); } if (BrowserType == FileBrowserType.File) { GUI.enabled = m_selectedFile > -1; } else { if (SelectionPattern == null) { GUI.enabled = m_selectedDirectory > -1; } else { GUI.enabled = m_selectedDirectory > -1 || ( m_currentDirectoryMatches && m_selectedNonMatchingDirectory == -1 && m_selectedFile == -1 ); } } if (GUILayout.Button("Select", GUILayout.Width(50))) { if (BrowserType == FileBrowserType.File) { m_callback(Path.Combine(m_currentDirectory, m_files[m_selectedFile])); } else { if (m_selectedDirectory > -1) { m_callback(Path.Combine(m_currentDirectory, m_directories[m_selectedDirectory])); } else { m_callback(m_currentDirectory); } } } GUI.enabled = true; GUILayout.EndHorizontal(); GUILayout.EndArea(); if (Event.current.type == EventType.Repaint) { SwitchDirectoryNow(); } } protected void FileDoubleClickCallback(int i) { if (BrowserType == FileBrowserType.File) { m_callback(Path.Combine(m_currentDirectory, m_files[i])); } } protected void DirectoryDoubleClickCallback(int i) { SetNewDirectory(Path.Combine(m_currentDirectory, m_directories[i])); } protected void NonMatchingDirectoryDoubleClickCallback(int i) { SetNewDirectory(Path.Combine(m_currentDirectory, m_nonMatchingDirectories[i])); } }
(참고 : unify community - ImprovedFileBrowser )
위 코드를 빌드하면 'GUILayoutx'가 없다는 에러가 납니다.
'ImprovedSelectionList'라는 것을 추가해주어야 한다고 합니다.
(참고 : unify community - ImprovedSelectionList )
using UnityEngine; public class GUILayoutx { public delegate void DoubleClickCallback(int index); public static int SelectionList(int selected, GUIContent[] list) { //return SelectionList(selected, list, "List Item", null); return SelectionList(selected, list, "Label", null); } public static int SelectionList(int selected, GUIContent[] list, GUIStyle elementStyle) { return SelectionList(selected, list, elementStyle, null); } public static int SelectionList(int selected, GUIContent[] list, DoubleClickCallback callback) { //return SelectionList(selected, list, "List Item", callback); return SelectionList(selected, list, "Label", callback); } public static int SelectionList(int selected, GUIContent[] list, GUIStyle elementStyle, DoubleClickCallback callback) { for (int i = 0; i < list.Length; ++i) { Rect elementRect = GUILayoutUtility.GetRect(list[i], elementStyle); bool hover = elementRect.Contains(Event.current.mousePosition); if (hover && Event.current.type == EventType.MouseDown) { selected = i; Event.current.Use(); } else if (hover && callback != null && Event.current.type == EventType.MouseUp && Event.current.clickCount == 2) { callback(i); Event.current.Use(); } else if (Event.current.type == EventType.repaint) { elementStyle.Draw(elementRect, list[i], hover, false, i == selected, false); } } return selected; } public static int SelectionList(int selected, string[] list) { //return SelectionList(selected, list, "List Item", null); return SelectionList(selected, list, "Label", null); } public static int SelectionList(int selected, string[] list, GUIStyle elementStyle) { return SelectionList(selected, list, elementStyle, null); } public static int SelectionList(int selected, string[] list, DoubleClickCallback callback) { //return SelectionList(selected, list, "List Item", callback); return SelectionList(selected, list, "Label", callback); } public static int SelectionList(int selected, string[] list, GUIStyle elementStyle, DoubleClickCallback callback) { for (int i = 0; i < list.Length; ++i) { Rect elementRect = GUILayoutUtility.GetRect(new GUIContent(list[i]), elementStyle); bool hover = elementRect.Contains(Event.current.mousePosition); if (hover && Event.current.type == EventType.MouseDown && Event.current.clickCount == 1) // added " && Event.current.clickCount == 1" { selected = i; Event.current.Use(); } else if (hover && callback != null && Event.current.type == EventType.MouseDown && Event.current.clickCount == 2) //Changed from MouseUp to MouseDown { Debug.Log("Works !"); callback(i); Event.current.Use(); } else if (Event.current.type == EventType.repaint) { elementStyle.Draw(elementRect, list[i], hover, false, i == selected, false); } } return selected; } }
(참고 : unify community - ImprovedSelectionList )
"List Item"이 없어서 경고가 나옵니다.
( "Unable to find style 'List Item' in skin 'GameSkin' Layout" )
이 경고 때문에 "Label"로 변경합니다.
스크립트를 설명하는 페이지에 샘플도 잘 나와 있으니 그대로 따라 해 봅시다.
using UnityEngine; public class TextFileFinder : MonoBehaviour { protected string m_textPath; protected FileBrowser m_fileBrowser; [SerializeField] protected Texture2D m_directoryImage, m_fileImage; public Texture2D texture; public GameObject m_goCube; void Start() { m_goCube = GameObject.Find("Cube"); } protected void OnGUI() { if (m_fileBrowser != null) { m_fileBrowser.OnGUI(); } else { OnGUIMain(); } } protected void OnGUIMain() { GUILayout.BeginHorizontal(); GUILayout.Label("Text File", GUILayout.Width(100)); GUILayout.FlexibleSpace(); GUILayout.Label(m_textPath ?? "none selected"); if (GUILayout.Button("...", GUILayout.ExpandWidth(false))) { m_fileBrowser = new FileBrowser( new Rect(10, 10, 600, 300), "Choose Text File", FileSelectedCallback ); //m_fileBrowser.SelectionPattern = "*.png"; m_fileBrowser.SelectionPattern = "*.txt"; m_fileBrowser.DirectoryImage = m_directoryImage; m_fileBrowser.FileImage = m_fileImage; } GUILayout.EndHorizontal(); } protected void FileSelectedCallback(string path) { m_fileBrowser = null; /* if (path.Length != 0) { WWW www = new WWW("file://" + path); texture = new Texture2D(64, 64); www.LoadImageIntoTexture(texture); m_goCube.renderer.material.mainTexture = texture; }*/ m_textPath = path; } }
(참고 : unify community - ImprovedFileBrowser )
제가 테스트용으로 사용한 큐브에 텍스쳐를 바꾸는 코드가 주석처리 되어 있습니다.
주석을 풀어 사용해 보세요.
메인카메라에 스크립트를 추가하고 테스트해 봅시다.
(참고로 웹에서는 동작하지 않습니다.)
잘 동작하네요 ㅎㅎㅎ
당연하게도 웹에서는 동작하지 않습니다.
우분투에서는 테스트해 봤는데 잘됩니다.
- 2023-10-05 추가
지금 날짜 기준으로 이 포스팅의 스크립트는 유지보수가 되지 않는 것으로 보입니다.
다른 스크립트를 이용할 것을 권장합니다.
다른 유니티 파일 브라우저 프로젝트
참고 : github - UnitySimpleFileBrowser, UnityStandaloneFileBrowser