I've a game. I should save the game whenever end user exit.
how to know where to save? because If I save the game to the under C://Users/.. path what happens if user uses Android or IOS? what is the solution for this problem?
You should use Application.persistentDataPath method.
This value is a directory path where you can store data that you want
to be kept between runs. When you publish on iOS and Android,
persistentDataPath points to a public directory on the device. Files
in this location are not erased by app updates. The files can still be
erased by users directly.
When you build the Unity application, a GUID is generated that is
based on the Bundle Identifier. This GUID is part of
persistentDataPath. If you keep the same Bundle Identifier in future
versions, the application keeps accessing the same location on every
update.
using UnityEngine;
public class Info : MonoBehaviour
{
void Start()
{
Debug.Log(Application.persistentDataPath);
}
}
Use application data folder which changes depending on platform.
//Attach this script to a GameObject
//This script outputs the Application’s path to the Console
//Run this on the target device to find the application data path for the platform
using UnityEngine;
public class Example : MonoBehaviour
{
string m_Path;
void Start()
{
//Get the path of the Game data folder
m_Path = Application.dataPath;
//Output the Game data path to the console
Debug.Log("dataPath : " + m_Path);
}
}
Read more about it here at source
There is structure or class and on it base will be better to creating objects and writing its in file.
[System.Serialisable]
public class AAA{
public string Name = "";
public int iNum = 0;
public double dNum = 0.0;
public float fNum = 0f;
int[] array;
// Here may be any types of datas and arrays and lists too.
}
AAA aaa = new AAA(); // Creating object which will be serialis of datas.
// Initialisation our object:
aaa.Name = "sdfsf";
aaa.iNum = 100;
string path = "Record.txt"
#if UNITY_ANDROID && !UNITY_EDITOR
path = Path.Combine(Application.persistentDataPath, path);
#else
path = Path.Combine(Application.dataPath, path);
#endif
// Writing datas in file - format JSON:
string toJson = JsonUtility.ToJson(aaa, true);
File.WriteAllText(path, toJson);
// reading datas from file with JSON architecture and serialis.. it in object:
string fromjson = File.ReadAllText(path);
AAA result = JsonUtility.FromJson<AAA>(fromjson);
I have a desktop application that I have made on Unity and I want to take a screenshot of my current view in the application using a C# script attached to the main camera. Please help.
I have browsed other code snippets that I found on this platform and nothing seemed to help.
You can use CaptureScreenshot.
public class ScreenCapture : MonoBehaviour
{
//here you can set the folder you want to use,
//IMPORTANT - use "#" before the string, because this is a verbatim string
//IMPORTANT - the folder must exists
string pathToYourFile = #"C:\Screenshots\";
//this is the name of the file
string fileName = "filename";
//this is the file type
string fileType = ".png";
private int CurrentScreenshot { get => PlayerPrefs.GetInt("ScreenShot"); set => PlayerPrefs.SetInt("ScreenShot", value); }
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
UnityEngine.ScreenCapture.CaptureScreenshot(pathToYourFile + fileName + CurrentScreenshot + fileType);
CurrentScreenshot++;
}
}
}
A few notes.
I used a verbatim string to define your folder
The folder where you store the screenshot must exist (if you want to create it in the script you can follow this answer)
AFTER COMMENT REQUEST - 1: If you do not set the folder the file will be saved in the default directory of the application (that changes based on the system - you can check it from Application.dataPath)
AFTER COMMENT REQUEST - 2: If you use the same path and filename the file will be overriden, so I added a way to let you save multiple screenshots, also in different sessions using PlayerPrefs.
You can use CaptureScreenshot method as answered above but it might be confusing for you if you are new to unity. It stores your captures image in a filepath which you should pass to CaptureScreenshot method as parameter for example
public class ScreenShotManager : MonoBehaviour {
const string FilePath = #"C:\Users\UserName\Desktop\ScreenShots";
public void CaptureScreenShot() {
ScreenCapture.CaptureScreenshot(FilePath);
}
void Update(){
if(Input.GetKeyDown(Keycode.C))
CaptureScreenShot();
}
this code shows that if you press 'c' key on keyboard it would be captured what main camera is rendering at that moment and stored in that file path
I'm storing materials paths in .plist in Unity and rendering them in my objects at runtime. Code looks like this:
public static Dictionary<string, object> uiElements = (Dictionary<string, object>)Plist.readPlist("Assets/EditUI.plist");
foreach (string key in User.purchasedItems.Keys)
{
GameObject tmpObj = (GameObject)Instantiate(Resources.Load(key) ,position ,Quaternion.identity);
tmpObj.transform.localScale = Vector3.one;
tmpObj.SetActive(true);
}
It's working fine in Unity editor, but when I made iOS build (Xcode project), nothing is being loaded. Everything is empty. I couldn't figure out whether the problem is with plist path or loading on runtime. Something related to custom plist is also posted here with no solution:
http://answers.unity3d.com/questions/468667/custom-plist-file-not-added-to-ios-project.html
You'll need to use Unity's iOS Scripting API to add the file to the Xcode project. Create a PostProcessBuild script that does something like this:
[PostProcessBuild]
public static void OnPostProcessBuild(BuildTarget buildTarget, string path)
{
// Go get pbxproj file
string projPath = path + "/Unity-iPhone.xcodeproj/project.pbxproj";
// PBXProject class represents a project build settings file,
// here is how to read that in.
PBXProject proj = new PBXProject ();
proj.ReadFromFile (projPath);
// This is the Xcode target in the generated project
string target = proj.TargetGuidByName ("Unity-iPhone");
// Copy plist from the project folder to the build folder
FileUtil.CopyFileOrDirectory ("Assets/EditUI.plist", path + "/EditUI.plist");
proj.AddFileToBuild (target, proj.AddFile("EditUI.plist", "EditUI.plist"));
// Write PBXProject object back to the file
proj.WriteToFile (projPath);
}
I know that Directory.CreateDirectory actually creates parents, so how can I STOP this from happening? i.e. is there a mode that I can utilise like a stricter way of doing so, the reason is that I have a watch program watching the parent top tree dir and it goes beserk if Directory.CreateDirectory makes more than one dir at a time.
Is there an equivalent to Directory.CreateDirectory which will NOT make parents?
Do you understand what for you need such method? It seems like you don't want to create all folders needed to create your target folder, like: C:\this\is\your\path\TargetFolder
In this case you can just do the following:
const string path = #"C:\this\is\your\path";
if (Directory.Exists(path))
{
Directory.CreateDirectory(Path.Combine(path, "TargetDirectory"));
}
If you have other purpose for that method, please help us to understand which one
List<string> missingDirectories = null;
private void MakeParents(string path)
{
missingDirectories = new List<string>();
missingDirectories.Add(path);
parentDir(path);
missingDirectories = missingDirectories.OrderBy(x => x.Length).ToList<string>();
foreach (string directory in missingDirectories)
{
Directory.CreateDirectory(directory);
}
}
private void parentDir(string path)
{
string newPath = path.Substring(0, path.LastIndexOf(Path.DirectorySeparatorChar));
if (!Directory.Exists(newPath))
{
missingDirectories.Add(newPath);
parentDir(newPath);
}
}
this does it, the issue is that if you want to "gently" roll up the paths one dir at a time making them, something like this is the only way you can do it :/
One option would be to do System.IO.Directory.GetParent() a few times. Is there a more graceful way of travelling a few folders up from where the executing assembly resides?
What I am trying to do is find a text file that resides one folder above the application folder. But the assembly itself is inside the bin, which is a few folders deep in the application folder.
Other simple way is to do this:
string path = #"C:\Folder1\Folder2\Folder3\Folder4";
string newPath = Path.GetFullPath(Path.Combine(path, #"..\..\"));
Note This goes two levels up. The result would be:
newPath = #"C:\Folder1\Folder2\";
Additional Note
Path.GetFullPath normalizes the final result based on what environment your code is running on windows/mac/mobile/...
if c:\folder1\folder2\folder3\bin is the path then the following code will return the path base folder of bin folder
//string directory=System.IO.Directory.GetParent(Environment.CurrentDirectory).ToString());
string directory=System.IO.Directory.GetParent(Environment.CurrentDirectory).ToString();
ie,c:\folder1\folder2\folder3
if you want folder2 path then you can get the directory by
string directory = System.IO.Directory.GetParent(System.IO.Directory.GetParent(Environment.CurrentDirectory).ToString()).ToString();
then you will get path as c:\folder1\folder2\
You can use ..\path to go one level up, ..\..\path to go two levels up from path.
You can use Path class too.
C# Path class
This is what worked best for me:
string parentOfStartupPath = Path.GetFullPath(Path.Combine(Application.StartupPath, #"../"));
Getting the 'right' path wasn't the problem, adding '../' obviously does that, but after that, the given string isn't usable, because it will just add the '../' at the end.
Surrounding it with Path.GetFullPath() will give you the absolute path, making it usable.
public static string AppRootDirectory()
{
string _BaseDirectory = AppDomain.CurrentDomain.BaseDirectory;
return Path.GetFullPath(Path.Combine(_BaseDirectory, #"..\..\"));
}
Maybe you could use a function if you want to declare the number of levels and put it into a function?
private String GetParents(Int32 noOfLevels, String currentpath)
{
String path = "";
for(int i=0; i< noOfLevels; i++)
{
path += #"..\";
}
path += currentpath;
return path;
}
And you could call it like this:
String path = this.GetParents(4, currentpath);
C#
string upTwoDir = Path.GetFullPath(Path.Combine(System.AppContext.BaseDirectory, #"..\..\"));
The following method searches a file beginning with the application startup path (*.exe folder). If the file is not found there, the parent folders are searched until either the file is found or the root folder has been reached. null is returned if the file was not found.
public static FileInfo FindApplicationFile(string fileName)
{
string startPath = Path.Combine(Application.StartupPath, fileName);
FileInfo file = new FileInfo(startPath);
while (!file.Exists) {
if (file.Directory.Parent == null) {
return null;
}
DirectoryInfo parentDir = file.Directory.Parent;
file = new FileInfo(Path.Combine(parentDir.FullName, file.Name));
}
return file;
}
Note: Application.StartupPath is usually used in WinForms applications, but it works in console applications as well; however, you will have to set a reference to the System.Windows.Forms assembly. You can replace Application.StartupPath by
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) if you prefer.
I use this strategy to find configuration and resource files. This allows me to share them for multiple applications or for Debug and Release versions of an application by placing them in a common parent folder.
Hiding a looped call to Directory.GetParent(path) inside an static method is the way to go.
Messing around with ".." and Path.Combine will ultimately lead to bugs related to the operation system or simply fail due to mix up between relative paths and absolute paths.
public static class PathUtils
{
public static string MoveUp(string path, int noOfLevels)
{
string parentPath = path.TrimEnd(new[] { '/', '\\' });
for (int i=0; i< noOfLevels; i++)
{
parentPath = Directory.GetParent(parentPath ).ToString();
}
return parentPath;
}
}
this may help
string parentOfStartupPath = Path.GetFullPath(Path.Combine(Application.StartupPath, #"../../")) + "Orders.xml";
if (File.Exists(parentOfStartupPath))
{
// file found
}
If you know the folder you want to navigate to, find the index of it then substring.
var ind = Directory.GetCurrentDirectory().ToString().IndexOf("Folderame");
string productFolder = Directory.GetCurrentDirectory().ToString().Substring(0, ind);
I have some virtual directories and I cannot use Directory methods. So, I made a simple split/join function for those interested. Not as safe though.
var splitResult = filePath.Split(new[] {'/', '\\'}, StringSplitOptions.RemoveEmptyEntries);
var newFilePath = Path.Combine(filePath.Take(splitResult.Length - 1).ToArray());
So, if you want to move 4 up, you just need to change the 1 to 4 and add some checks to avoid exceptions.
Path parsing via System.IO.Directory.GetParent is possible, but would require to run same function multiple times.
Slightly simpler approach is to threat path as a normal string, split it by path separator, take out what is not necessary and then recombine string back.
var upperDir = String.Join(Path.DirectorySeparatorChar, dir.Split(Path.DirectorySeparatorChar).SkipLast(2));
Of course you can replace 2 with amount of levels you need to jump up.
Notice also that this function call to Path.GetFullPath (other answers in here) will query whether path exists using file system. Using basic string operation does not require any file system operations.