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);
}
Related
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'll start with the errors themselves. The first is : Assertion failed on expression: 'm_UncompressedBlocksOffsets[blockInd] <= from + dstPos && m_UncompressedBlocksOffsets[blockInd] + uncompressedBlockSize >= from + dstPos' UnityEngine.AssetBundle:LoadFromFile(String)
Followed by : Failed to decompress data for the AssetBundle 'D:/Unity/projects/PQv0.10/Assets/AssetBundles/spritesbundle'. UnityEngine.AssetBundle:LoadFromFile(String)
I've always just used the resources folder for my projects but my current project has outgrown what that method can accommodate. So I'm trying to offload assets (in this case 5000 or so sprites)into an assetbundle and load them as needed at runtime. I figured I could just get a reference to the assetbundle and then call assetbundle.LoadAsset(assetname), substituting my old Resources.Load calls. Here's my attempt at making the assetbundle reference that keeps erroring:
AssetBundle sprites;
void loadSprites()
{
sprites = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/spritesbundle"); // " + bundleName);
if (!sprites) {
Debug.Log("failed to load assetbundle");
}
}
For due diligence, here's also the code I used to create that assetbundle. It simple searches my project for png's and packs them into the assetbundle:
public static void SaveSpecificAssets()
{
AssetBundleBuild build = new AssetBundleBuild();
build.assetBundleName = "spritesBundle";
string[] files = AssetDatabase.GetAllAssetPaths();
List<string> validFiles = new List<string>();
foreach (string file in files)
{
if (file.EndsWith(".png")) validFiles.Add(file);
}
build.assetNames = validFiles.ToArray();
BuildPipeline.BuildAssetBundles("Assets/AssetBundles", new AssetBundleBuild[1] { build }, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
}
The assetbundle builds without errors and appears in the directory where it should be. I have no indication that it's faulty other than the errors I get when trying to load it. The manifest it generates contains appropriate items so I think it's working as intended at least.If I'm missing any relevant information, please point it out and I'll try to provide it.
this is the test coroutine I used in place of loadSprites() for testing if it made a difference:
IEnumerator testLoader()
{
WWW www = WWW.LoadFromCacheOrDownload("file:///" + Application.dataPath + "/AssetBundles/spritesbundle", 1);
yield return www;
sprites = www.assetBundle;
}
Try this, for all the PNG's in your project folder, select them all and add them to an AssetBundle via the Editor, Then just build using
BuildPipeline.BuildAssetBundles("Assets/AssetBundles",BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
Then try to load the bundles and see if it shows an error.
Also, look into the Manifest to see if all the files you intended are listed
I'm adding a custom create action for a ScriptableObject like this:
[MenuItem("Assets/Create/FlowEngine/Character")]
private static void CreateCharacter()
{
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
string assetPath = path + "/New Character.asset";
FlowEngineCharacterData character = ScriptableObject.CreateInstance<FlowEngineCharacterData>();
AssetDatabase.CreateAsset(character, assetPath);
AssetDatabase.SaveAssets();
Selection.activeObject = character;
}
This works exactly as expected, but there is one difference between this and all of the built in Assets. When you create those it automatically starts in rename 'mode'.
The only thing I can find to do with renaming the assets is a method which directly renames the asset rather than starting the UI rename operation.
Is there any way I can replicate this behavior?
I've found an answer for this tucked away in one of the other namespaces:
[MenuItem("Assets/Create/FlowEngine/Character")]
private static void CreateCharacter()
{
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
string assetPath = path + "/New Character.asset";
FlowEngineCharacterData character = ScriptableObject.CreateInstance<FlowEngineCharacterData>();
ProjectWindowUtil.CreateAsset(character, assetPath);
}
Note that is ProjectWindowUtil rather than AssetDatabase. Using that starts the create operation off in 'rename mode'.
(Before I jump into the nitty-gritty, I want to set the context: I'm trying to load a WPF frame with the contents of an .html file that I'm including in my project as a resource.)
I create a new WPF Application; I add a new folder called 'foofiles' to the project, and I add a couple of files (page1.foo and page2.foo) to that folder.
For each newly added .foo file, I right-click on it, go to "Properties," and set the Build Action to 'Resource,' and the Copy To Output Directory to "Copy always."
I want to be able to access those files both in XAML:
<Frame x:Name="bar" Source="/foofiles/page1.foo"/>
And in procedural code:
private void someFunc()
{
bar.Source = new Uri("/foofiles/page1.foo");
}
But I just can't figure out why this doesn't work -- I get a "Format of the URI could not be determined."
In the code-behind, I tried doing this:
private void someFunc()
{
bar.Source = new Uri("pack://application:,,,/foofiles/page1.foo");
}
which didn't throw an exception, but my main window crashed.
In my thinking, if I add a file of any type to my project, and if I mark it as "Resource" in "Build Action," I should be able to use that file per my examples above. Also, I would like to use that file like this:
private void someOtherFunc()
{
System.IO.StreamReader reader = new System.IO.StreamReader("/foofiles/page1.foo");
string bar = reader.ReadToEnd();
}
Any help would be appreciated... thanks in advance!
Try adding the component-part to your Pack URI like this
pack://application:,,,/AssemblyName;component/ResourceName
where AssemblyName is the name of your assembly. So for your case, the following statement should work:
bar.Source = new Uri("pack://application:,,,/AssemblyName;component/foofiles/page1.foo");
More practically, try the relative pack uri notation:
bar.Source = new Uri("AssemblyName;component/foofiles/page1.foo", UriKind.Relative));
For stream reading resources use
var streamResourceInfo = Application.GetResourceStream(uri);
using (var stream = streamResourceInfo.Stream)
{
// do fancy stuff with stream
}
I got a programm that generates .resx resource files. Those resource files are used in other projects, that isnt in the same solution as the project that generates the resource files.
I wonder now, if its possible to generate a designer.cs file from the resource file, so that you can access the resources directly without using the resxresourcereader.
Open the resx file and on its toolbar there's an Access Modifier menu. Set this to Public. This will generate a *.Designer.cs file.
Right click on the Resources.resx and select "Run Custom Tool".
If the file is added to a Visual Studio Project you have to set the Custom Tool property of the .resx file to ResXFileCodeGenerator. Then will VS automatically create the needed designer file.
In one project I made a T4 script that scans the folder within the project for all images and let create a corresponding ressource file at a click.
Here is the needed part out of the T4 script:
var rootPath = Path.GetDirectoryName(this.Host.TemplateFile);
var imagesPath = Path.Combine(rootPath, "Images");
var resourcesPath = Path.Combine(rootPath, "Resources");
var pictures = Directory.GetFiles(imagesPath, "*.png", SearchOption.AllDirectories);
EnvDTE.DTE dte = (EnvDTE.DTE)((IServiceProvider)this.Host)
.GetService(typeof(EnvDTE.DTE));
EnvDTE.Projects projects = dte.Solution.Projects;
EnvDTE.Project iconProject = projects.Cast<EnvDTE.Project>().Where(p => p.Name == "Icons").Single();
EnvDTE.ProjectItem resourcesFolder = iconProject.ProjectItems.Cast<EnvDTE.ProjectItem>().Where(item => item.Name == "Resources").Single();
// Delete all existing resource files to avoid any conflicts.
foreach (var item in resourcesFolder.ProjectItems.Cast<EnvDTE.ProjectItem>())
{
item.Delete();
}
// Create the needed .resx file fore each picture.
foreach (var picture in pictures)
{
var resourceFilename = Path.GetFileNameWithoutExtension(picture) + ".resx";
var resourceFilePath = Path.Combine(resourcesPath, resourceFilename);
using (var writer = new ResXResourceWriter(resourceFilePath))
{
foreach (var picture in picturesByBitmapCollection)
{
writer.AddResource(picture.PictureName, new ResXFileRef(picture, typeof(Bitmap).AssemblyQualifiedName));
}
}
}
// Add the .resx file to the project and set the CustomTool property.
foreach (var resourceFile in Directory.GetFiles(resourcesPath, "*.resx"))
{
var createdItem = resourcesFolder.Collection.AddFromFile(resourceFile);
var allProperties = createdItem.Properties.Cast<EnvDTE.Property>().ToList();
createdItem.Properties.Item("CustomTool").Value = "ResXFileCodeGenerator";
}
I have flattened the above code a little bit, cause in my real solution i use a custom class for each picture instead of the simple filename to also support the same filename in different sub folders (by using a part of the folder structure for the namespace generation). But for a first shot the above should help you.
You can also do this in code:
(Taken from here: msdn)
StreamWriter sw = new StreamWriter(#".\DemoResources.cs");
string[] errors = null;
CSharpCodeProvider provider = new CSharpCodeProvider();
CodeCompileUnit code = StronglyTypedResourceBuilder.Create("Demo.resx", "DemoResources",
"DemoApp", provider,
false, out errors);
if (errors.Length > 0)
foreach (var error in errors)
Console.WriteLine(error);
provider.GenerateCodeFromCompileUnit(code, sw, new CodeGeneratorOptions());
sw.Close();
You need to reference system.design.dll
This also worked for me: double click and open the resx file, add a dummy resource, click save. the .designer.cs file is generated.
If you deleted it or added it to .gitignore because you thought you didn't need it. this is how you regenerate the file.
Go to the Access modifier and change it from (Public/Internal) to "No Code Generation"
Now put it back to Public/Internal.
VS will regenerate the Designer file for you.