In this tutorial I describe how to save and load data from text and XML files. The data I store is three-dimensional points into the mixed reality environment in which you can insert to list with gesture event air tap.
Add the GameObject “Camera”, Gaze and from the gestures air tap event which described in the guide “Gaze and Gestures on HoloLens“.
Create three GameObjects with Box Collider to use as buttons. With “Start Recording” tile you can start recording new three-dimensional points in the space with the use of air tap, with “Save Points” tile you can save the points in the text and XML file, with “Load Points” you can load the points from text and XML files. These GameObjects have a script for the OnSelect event.
OnSelectSave.cs file
void OnSelect()
{
#if WINDOWS_UWP
CRUDManager.Instance.SavePins();
#endif
}
OnSelectRecord.cs file
void OnSelect()
{
CRUDManager.Instance.RecordCursorPins();
}
OnSelect.cs file
void OnSelect()
{
CRUDManager.Instance.LoadPins();
}
public class Pin {
public float posX { get; set; }
public float posY { get; set; }
public float posZ { get; set; }
}
Add a GameObject named “Manager” and add into to GameObject the scripts, GazeGestureManager.cs, CRUDManager.cs in which there is a code that records and loads the data from the text and XML file, TextMessage.cs in which display the list of three-dimensional points in GameObject “Border”. Also add the spatial mapping to select every surface from the real world.
CRUDManager.cs file
public class CRUDManager : MonoBehaviour
{
public static CRUDManager Instance { get; private set; }
public GameObject cursor;
public GameObject recordMessage;
private bool isrecording = false;
private List<Pin> pins = new List<Pin>();
private static string fileNameXML = "pins.xml";
private static string fileNameTXT = "pins.txt";
#if WINDOWS_UWP
private StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
private static string filePathXML = Path.Combine(ApplicationData.Current.LocalFolder.Path, fileNameXML);
private static string filePathTXT = Path.Combine(ApplicationData.Current.LocalFolder.Path, fileNameTXT);
#endif
void Awake()
{
Instance = this;
}
#region Record
public void RecordCursorPins()
{
isrecording = !isrecording;
if (isrecording)
{
pins.Clear();
InvokeRepeating("AddPins", 2f, 2f);
recordMessage.GetComponent<TextMesh>().text = "Stop Recording";
}
else
{
CancelInvoke("AddPins");
recordMessage.GetComponent<TextMesh>().text = "Start Recording";
}
}
private void AddPins()
{
pins.Add(new Pin { posX = cursor.transform.position.x, posY = cursor.transform.position.y, posZ = cursor.transform.position.z });
}
#endregion
#region Save
#if WINDOWS_UWP
public async void SavePins()
{
if (isrecording || pins.Count == 0)
{
TextMessage.Instance.ChangeTextMessage_Border("Try to record pins.");
return;
}
//await WriteTXTToLocalStorage(); //Save to TXT file
}
public async Task WriteXMLToLocalStorage()
{
XmlSerializer serializer = new XmlSerializer(typeof(List));
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
if (File.Exists(filePathXML))
File.Delete(filePathXML);
StorageFile storageFile = await storageFolder.CreateFileAsync(fileNameXML);
using (FileStream fs = new FileStream(storageFile.Path, FileMode.Create))
{
serializer.Serialize(fs, pins);
}
}
public async Task WriteTXTToLocalStorage()
{
XmlSerializer serializer = new XmlSerializer(typeof(List));
if (File.Exists(filePathTXT))
File.Delete(filePathTXT);
StorageFile storageFile = await storageFolder.CreateFileAsync(fileNameTXT);
StringBuilder builder = new StringBuilder();
for (int i = 0; i < pins.Count; i++)
{
builder.Append(string.Format("{0} {1} {2}", pins[i].posX.ToString("n5"), pins[i].posY.ToString("n5"), pins[i].posZ.ToString("n5"))).AppendLine();
}
//await FileIO.WriteTextAsync(storageFile, builder.ToString());
}
#endif
#endregion
#region Load
public void LoadPins()
{
#if WINDOWS_UWP
if (isrecording || pins.Count == 0)
{
TextMessage.Instance.ChangeTextMessage_Border("Try to record pins.");
return;
}
if (!File.Exists(filePathXML))
{
TextMessage.Instance.ChangeTextMessage_Border("XML file does not exist.");
return;
}
List savedPins = ReadXMLFromLocalStorage();
string pinMessage = string.Empty;
for(int i = 0; i < savedPins.Count; i++)
{
pinMessage = string.Format("{0} {1} {2}{3}", savedPins[i].posX.ToString("n5"), savedPins[i].posY.ToString("n5"), savedPins[i].posZ.ToString("n5"), Environment.NewLine);
}
//pinMessage = LoadTXTFromLocalStorage().Result; //Load TXT file
TextMessage.Instance.ChangeTextMessage_Border(pinMessage);
#endif
}
#if WINDOWS_UWP
public List ReadXMLFromLocalStorage()
{
List savedPins;
XmlSerializer serializer = new XmlSerializer(typeof(List));
using (FileStream fs = new FileStream(filePathXML, FileMode.Open, FileAccess.Read))
{
savedPins = (List)serializer.Deserialize(fs);
}
return (savedPins != null)? savedPins : new List();
}
public async Task LoadTXTFromLocalStorage()
{
StorageFile storageFile = await storageFolder.GetFileAsync(fileNameTXT);
return await FileIO.ReadTextAsync(storageFile);
}
#endif
#endregion
}
TextMessage.cs file
public class TextMessage : MonoBehaviour {
public static TextMessage Instance { get; private set; }
public GameObject textMessageBorderGmObj;
void Awake()
{
Instance = this;
}
public void ChangeTextMessage_Border(string textMessage)
{
textMessageBorderGmObj.GetComponent<TextMesh>().text = textMessage;
}
}
You can find this sample and download it from github to this link https://github.com/gntakakis/Hololens-CRUD-TXT-XML-Storage-Unity