- Home /
Creating Assets On The Fly
I want to create an asset on the fly from a file system resource. I have a bunch of text files that are used as content in my game and I want to be replace/update the files prior to building without actually having to open Unity to do it. I thought I might accomplish this by using the command line features with an Editor script that used C# file IO to load my file system resources, create new assets, and then create a new AssetBundle.
The part I haven't figured out is how to create a TextAsset from a file. This appears to be done internally? Any pointers are appreciated.
Just to clarify, basically what I want to implement in my script is whatever code is being run with the progress bar when an asset is modified on the file system. I'm hoping this functionality is exposed in the scripting API.
Hi, I have a question here as I am creating a level editor, where in runtime some objects are created and scaled/moved/and a a world is built. Now i have to export/Save this so that another application will load for further use.
AssetBundle is a UnityEditor thing i can't use this as i need this work on runtime(Exe) I cant't use command line batch script coz the client/user might not have Unity(on top they need Pro).So this is not the way.
Is there any other way i can export the objects built with the all the proerties,physics and other components.??
Thanks in advance!
@RDx: This is not an answer, so don't post it as answer! I've converted it into a comment.
Also your question has nothing to do with the original question. Saving at runtime has been asked a lot on this Q&A site, so search for it.
There is no buildin way to save export assets at runtime. You have to find your own custom way. There are already packages that provides such features, but most of them aren't for free.
Answer by Ben 2 · Jan 22, 2010 at 04:33 AM
In the end I went with the Bash script below. This script takes a directory and creates an asset bundle with all the files in the directory. It does that by first creating a temporary Unity project in /tmp, then copying the files to Assets, then it creates a script in the Editor directory that uses BuildPipeline to create the AssetBundle. Anyway, usage is:
script.sh MyDirectoryToBundlify MyAssetBundle.unity3d
Just made it up earlier today, no guarantee there aren't bugs.
#!/bin/bash
UNITY_EXEC=/Applications/Unity/Unity.app/Contents/MacOS/Unity
if [ -z "$2" ]; then echo "You must provide a path to the bundle assets and a path to the resulting bundle."; exit 1; fi
export UNITY_ASSET_BUNDLE_PATH=${2}
CREATION_TIME=`date +%s` ASSET_BUNDLE_PROJECT_DIR=/tmp/AssetBundle-${CREATION_TIME}
echo "Creating temporary project."; ${UNITY_EXEC} -batchmode -quit -createProject ${ASSET_BUNDLE_PROJECT_DIR};
Copy the project assets from the source folder
cho "Copying resources from source folder to assets folder."; cd $1; cp -r . ${ASSET_BUNDLE_PROJECT_DIR}/Assets;
echo "Finding assets."; cd ${ASSET_BUNDLE_PROJECT_DIR}; ASSETS_TO_BUNDLE=`find Assets -type f -name "." | sed 's/^.\///g' | sed 's/^/assetPathsList.Add("/g' | sed 's/$/");/g'`
Copy the bundler script into the project
kdir ${ASSET_BUNDLE_PROJECT_DIR}/Assets/Editor/; cat > ${ASSET_BUNDLE_PROJECT_DIR}/Assets/Editor/AssetsBundler.cs assetPathsList = new List(); ${ASSETS_TO_BUNDLE};
ArrayList assetList = new ArrayList();
foreach(string assetPath in assetPathsList)
{
Debug.Log("Loading " + assetPath);
UnityEngine.Object[] assets = AssetDatabase.LoadAllAssetsAtPath(assetPath);
foreach(UnityEngine.Object asset in assets)
{
Debug.Log("Found asset: " + asset.name);
assetList.Add(asset);
}
}
UnityEngine.Object[] allAssets = (UnityEngine.Object[]) assetList.ToArray(typeof(UnityEngine.Object));
BuildPipeline.BuildAssetBundle(null, allAssets, "${UNITY_ASSET_BUNDLE_PATH}", BuildAssetBundleOptions.CompleteAssets);
}
} END
echo "Building the bundle."; ${UNITY_EXEC} -batchmode -quit -projectProject ${ASSET_BUNDLE_PROJECT_DIR} -executeMethod AssetsBundler.Bundle;
echo "Deleting temporary project."; rm -rf ${ASSET_BUNDLE_PROJECT_DIR};
Answer by Bampf · Jan 20, 2010 at 01:44 AM
Here is one way to do it that assumes the file is in the Resources directory of your project. This example looks for a file called "puzzles.txt".
StringReader reader = null;
TextAsset puzdata = (TextAsset)Resources.Load("puzzles", typeof(TextAsset)); // puzdata.text is a string containing the whole file. To read it line-by-line: reader = new StringReader(puzdata.text); if ( reader == null ) { Debug.Log("puzzles.txt not found or not readable"); } else { // Read each line from the file while ( (string txt = reader.ReadLine()) != null ) Debug.Log("-->" + txt); }
Note that this file (and everything in Resources) is being packaged with the rest of the game when Unity builds it.
I wrote on this topic in an article on my website, Reading Text Data Into a Unity Game. It describes other options as well. There are ways to read a textfile that is not packaged into the game. That would be preferred if (for example) you wanted to let modders edit the file without Unity or your source code.
The article is informative but it is the less detailed final section about Asset Bundles that concerns my question. I want the text file to reside somewhere on the file system (not necessarily in a Unity project) and then be read in by my script using C# File IO. The script would then convert the text files to TextAsset objects somehow and create an asset bundle using BuildPipeline.
Cool. $$anonymous$$aybe I'll link to this q&a from the article to help fill in that gap.
Answer by Ben 2 · Jan 20, 2010 at 08:39 PM
To solve my problem I wrote one script to load the files from the file system using C# System.IO and a class that extends AssetPostprocessor. By creating/copying my files from the file system to a location under the project directories the AssetPostProcessor is called. It collects the assets I'm interested in and then writes them out to a new AssetBundle using BuildPipeline.BuildAssetBundle. Here's a simplified version of each:
using UnityEngine; using UnityEditor; using System.Collections; using System.IO;
public class AssetBundleBuilder : ScriptableObject {
[MenuItem ("Custom/Create Asset")] static void CreateAsset() {
FileStream file = new FileStream("/Users/ben/AssetBundleSandbox/Assets/testFile.xml", FileMode.OpenOrCreate, FileAccess.Write); StreamWriter sw = new StreamWriter(file); sw.Write("Hello World"); sw.Close(); file.Close();
AssetDatabase.Refresh(ImportAssetOptions.Default);
}
}
using UnityEngine; using UnityEditor; using System.Collections;
public class CustomPostProcessor : AssetPostprocessor { public static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) { Object[] assetObjects = new Object[importedAssets.Length]; int assetIndex = 0;
foreach(string importedAsset in importedAssets) { Debug.Log("Postprocessing " + importedAsset + "!"); assetObjects[assetIndex] = AssetDatabase.LoadAssetAtPath(importedAsset, typeof(TextAsset)); }
bool buildSuccessful = BuildPipeline.BuildAssetBundle(null, assetObjects, "/tmp/TestAssetBundle.unity3d", BuildAssetBundleOptions.CompleteAssets); if(buildSuccessful) { Debug.Log("Success!"); } else { Debug.Log("Failed!");
} }
}
So I never end up having to create the assets directly but the end result is files outside of a Unity project are imported and then stored in an AssetBundle, which is what I needed.
Superb Ben Using your example above solved my problem of how to create and save text files from within unity for use as text assets. Thanks.
only problem with this one is that assetBundles are unity pro only and for a student in learning thats a bit over my budget ;)
so this solution only helps those with pro :(
$$anonymous$$inor change:
add assetIndex++; in foreach loop to avoid a nasty crash! :)
Answer by saurabh · Apr 29, 2011 at 12:31 PM
is it like i can change my prefab later on ??
can u mail me the entire pachage to test plz
Use comments if you have questions or comments to an answer! The Answer function is meant to give an answer to this question. Please read the FAQs. http://answers.unity3d.com/faq
Answer by drudiverse · May 19, 2014 at 06:40 PM
a mod of unitycoder's code and create prefab from selected code:
Note: edit the code to make assets and prefabs in different folders because they have same icons in unity and it will be confusing so make 2 subfolders in savedmesh folder for each.
using UnityEditor;
using UnityEngine;
/// <summary>
/// Creates a prefab from a selected game object.
/// </summary>
class CreatePrefabFromSelected
{
const string menuName = "GameObject/Create Prefab From Selected";
/// <summary>
/// Adds a menu named "Create Prefab From Selected" to the GameObject menu.
/// </summary>
[MenuItem(menuName)]
static void CreatePrefabMenu ()
{
var go = Selection.activeGameObject;
Mesh m1 = go.GetComponent<MeshFilter>().mesh;//update line1
AssetDatabase.CreateAsset(m1, "Assets/savedMesh/" + go.name +"_M" + ".asset"); // update line2
var prefab = EditorUtility.CreateEmptyPrefab("Assets/savedMesh/" + go.name + ".prefab");
EditorUtility.ReplacePrefab(go, prefab);
AssetDatabase.Refresh();
}
/// <summary>
/// Validates the menu.
/// The item will be disabled if no game object is selected.
/// </summary>
/// <returns>True if the menu item is valid.</returns>
[MenuItem(menuName, true)]
static bool ValidateCreatePrefabMenu ()
{
return Selection.activeGameObject != null;
}
}
Your answer
Follow this Question
Related Questions
Resources.FindObjectsOfTypeAll() doesn't return all Textures 2 Answers
GameObject permanent destruction from "Resources" in EditorWindow 0 Answers
Loading XML asset after build 0 Answers
Can't load prefabs from resources into an array 1 Answer
Manually changing between sprites in a spritesheet 0 Answers