대안에 대한 내용은 마지막에 넣어놨습니다.
이전 글에서 유니티 에디터에서 '파일 다얄로그'를 열어 파일을 선택하는 것을 했습니다.
문제는 유니티 에디터에서만 쓸 수 있다는 것이죠 ㅡ,.ㅡ;;;
그래서 검색해 보니 스크립트로 구현하는 방법이 있네요.
'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