ArgumentException: The prefab you want to instantiate is null - unity3d

I'm getting an error and I don't know why. From the error I can see that there is something wrong with line 12, I think.
The script is larger but is not needed to solve the problem.
But if you really need it, you can ask for it.
Here is the code:
if(RandomInt==2) {
var randomNumberB = Random.Range(3,5);
for(var b = 0; b < randomNumberB; b++) {
var xCoB = childVector3.x + Random.Range(0,10);
var zCoB = childVector3.z + Random.Range(0,10);
var randomRotationB = Quaternion.Euler(0,Random.Range(0,360),0);
var chancheB = Random.Range(0,2);
if(chancheB == 0) {
var bushC = Instantiate(bushes[Random.Range(0,bushes.length)], Vector3(xCoB, childVector3.y, zCoB), randomRotationB);
bushC.transform.name = "bush";
} else {
Instantiate(cactus, Vector3(xCoB, childVector3.y, zCoB), randomRotationB).transform.name = "cactus";
}
}
}

Make cactus a prefab.
Then make a public variable:
public GameObject cactus;
Then drag and drop the prefab into the script variable via de Editor. Then you can instantiate.
if(cactus != null)
{
GameObject g = Instantiate(cactus, new Vector3(xCoB, childVector3.y, zCoB), randomRotation) as GameObject;
g.name = "cactus";
}

it is easy if you have prefabs sitting in the root Resources folder. It is different if you want them to be in a subfolder of Resources. You will need to create a "Prefabs" folder within.
Since you are using Javascript
Given a prefab named "Your Prefab.prefab" within Assets/Resources:
var NewGameObject : GameObject = Resources.Load("Your Prefab"),Vector3.zero,Quaternion.identity);
This will allow you to have a reference to that prefab, loaded into memory.
If you wish to contain a prefab or more within a folder in Assets/Resources you must do the following:
2a. Create a folder named "Prefabs" within Assets/Resources.
2b. Create your folder there (e.g. "Resources/Prefabs/Your Prefab Folder");
2c. Given a prefab named "Your Prefab.prefab":
var NewGameObject : GameObject = Resources.Load("Prefabs/Your SubFolder/Your Prefab"),Vector3.zero,Quaternion.identity);
Notes:
Don't forget to remove the ".prefab" extension.
The Unity manual states that you can load assets from Resources without supplying a path with folder names. Certainly in regards to prefabs (and javascript?) that does not seem to be true (Unity 4.6).

Related

Sprites added to Unity SpriteLibraryAsset programmatically doesn't appear in asset

I am creating a Unity Editor script which takes a texture, slices it (this part works) and adds these sprites to a selected SpriteLibraryAsset:
foreach(var currentGroup in selectedDefinitionFile.Groups)
{
for (int i = 1; i <= currentGroup.Item2; i++) {
var rects = dataProvider.GetSpriteRects();
var targetName = String.Format("{0}-{1}", currentGroup.Item1, i);
var sprite = (Sprite)allSprites.Where(x => x.name == targetName).First();
spriteLibraryToPopulate.AddCategoryLabel(sprite, currentGroup.Item1, i.ToString());
}
}
// None of these do anything
spriteLibraryToPopulate.SetDirty();
EditorUtility.SetDirty(spriteLibraryToPopulate);
AssetDatabase.SaveAssets();
AssetDatabase.SaveAssetIfDirty(new UnityEditor.GUID(AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(spriteLibraryToPopulate))));
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(spriteLibraryToPopulate));
AssetDatabase.Refresh();
UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty();
If I run this script multiple times and stop on a breakpoint, I can see in Visual Studio that the sprites are being added as expected to the in-memory object. However, when I examine the Sprite Library asset, both in the editor and in the asset file using Notepad++, none of them appear.
Reimporting via the menu in the editor does nothing as well.
Investigation with a debugger shows that internally, Unity uses the class SpriteLibrarySourceAsset when importing a .spriteLib asset and creates the SpriteLibraryAsset I have access to in my scripts. I haven't been able to find how to go the other way.
I finally was able to achieve what I intended using reflection to call some internal Unity APIs.
// Perform your modification to the sprite library before this
// The logic to transform the SpriteLibraryAsset to the internal representation works on the selected objects.
Selection.objects = new UnityEngine.Object[]
{
spriteLibraryToPopulate
};
var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(spriteLibraryToPopulate)) as SpriteLibrarySourceAssetImporter;
var saveMethod = typeof(SpriteLibrarySourceAssetImporter).GetMethod("ConvertToSourceAsset", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
saveMethod.Invoke(null, null);
var rootPath = Path.Join(AssetDatabase.GetAssetPath(spriteLibraryToPopulate), "..");
// The save logic creates a differently named instance of the asset, so we copy the data from our newly created one into the original
File.Copy(Path.Join(rootPath, string.Format("{0} 1.spriteLib", spriteLibraryToPopulate.name)),
Path.Join(rootPath, string.Format("{0}.spriteLib", spriteLibraryToPopulate.name)), true);
// Get rid of the extra asset and its associated meta file.
File.Delete(Path.Join(rootPath, string.Format("{0} 1.spriteLib", spriteLibraryToPopulate.name)));
File.Delete(Path.Join(rootPath, string.Format("{0} 1.spriteLib.meta", spriteLibraryToPopulate.name)));
At the end, the library should be selected in the Unity Editor. If you try and click away, it will be marked dirty and Unity will prompt you to save or revert; it appears to me that both have the same result.

How can i load asset bundle which don't know the name of asset?

I want to load and instantiate asset from my asset bundle, but in unity 5.+ i can do it with code like this:
Note: my assetbundle have one asset inside itself, like:
AssetBundle myLoadedAssetBundle;
public string path;
void Start()
{
LoadAssetBundle(path);
}
void LoadAssetBundle(string bundleUrl)
{
myLoadedAssetBundle = AssetBundle.LoadFromFile(bundleUrl);
Debug.Log(myLoadedAssetBundle == null ? "Faild To Load" : "Succesfully Loaded!");
Debug.Log(myLoadedAssetBundle.mainAsset.name);
Instantiate(myLoadedAssetBundle.mainAsset);
}
}
actually even i use
Debug.Log(myLoadedAssetBundle.mainAsset.name);
to log name of mainasset of my assetbundle!
but in unity after 5+ , they say mainasset is obsolete.
my questions is:
1- How can i load asset bundle which don't know the name of asset?
2- How Instantiate or assign sprite which loaded of assetbundle ?
According to the AssetBundle documentation, there is now the ability to call GetAllAssetNames() to return a list of all asset names in a bundle as a string array. You can load the assets from the bundle via a for loop with those asset names.
Alternatively, if you are guaranteeing to only have 1 asset per bundle you can simply grab the string at index 0 (not recommended).
Additionally, you can load the assets without knowing the names by using LoadAllAssets() which returns an array of the specific type (in your case you would specify Sprite).
You could try something like this: (Note - You will need to know your directory path to each asset, here, I'll make some stuff up as an example)
private List<GameObject> assetBundle = new List<GameObject>();
private GameObject asset1 = Resources.Load("Weapon1") as GameObject;
private GameObject asset2 = Resources.Load("Weapon2") as GameObject;
private GameObject asset3 = Resources.Load("Weapon3") as GameObject;
private void Start()
{
assetBundle.Add(asset1);
assetBundle.Add(asset2);
assetBundle.Add(asset3);
}
Now you can access them from the list by element whenever you wish. However, I'm not 100% certain that Resources.Load() will work for what you're trying to do. I am about 65% - 70% though so I answered. Hope it helps!
Here's my solution,
IEnumerator LoadBundleFromDir(string bundleUrl)
{
//which type of asset i want load
GameObject model;
AssetBundleCreateRequest bundleRequest = AssetBundle.LoadFromFileAsync(bundleUrl);
yield return bundleRequest;
AssetBundle localeAssetBundle = bundleRequest.assetBundle;
Object[] allBundles = localeAssetBundle.LoadAllAssets();
foreach (Object item in allBundles)
{
if (item.GetType() == typeof(GameObject))
{
AssetBundleRequest assetRequest = localeAssetBundle.LoadAssetAsync<GameObject>(item.name);
yield return assetRequest;
model = assetRequest.asset as GameObject;
localeAssetBundle.Unload(false);
break;
}
}
}

Cant instantiate multi-sprite

I can't seem to load a sprite runtime.
I have a main grid object, on the grid I have a TerrainDrawer component.
The code for the script :
void Start()
{
Sprite[] myFruit = Resources.LoadAll<Sprite>("Sprites/multisprite");
foreach(var sprite in myFruit)
{
print("sprite : " + sprite.name);
}
/*var spritePath = "Sprites/225835_hyptosis_tile-art-batch-1";
//GameObject go = new GameObject();*/
SpriteRenderer renderer = gameObject.AddComponent<SpriteRenderer>();
renderer.sprite = myFruit[0];
//renderer.sprite = Resources.Load(spritePath , typeof(Sprite)) as Sprite;
}
The sprite that I'm wanting to use:
When I start up my game, I get this error :
IndexOutOfRangeException: Index was outside the bounds of the array.
TerrainDrawer.Start () (at Assets/Scripts/TerrainDrawer.cs:21)
I have a strong feeling that my problem is with the path to the sprite, but now matter what I try, I can't get it loaded up.
Any advice?
To load from Resources in code there must exist a folder named Resources with that sprite in it. You are basically loading in an empty array and that is why you get an out of range error.
Take a look at this page from the docs.
Hope this helps!

Unable to get new unity particle system code working post update

I used to have the following particle system that worked.
// In the inspector I drag in the leaf particle system.
public ParticleSystem LeafStormParticleSystem;
private IEnumerator activate(float ActivateFor) {
//Change number of particles to 150
LeafStormParticleSystem.maxParticles = 150;
// LeafStormParticleSystem.
var newEmission = LeafStormParticleSystem.emission;
var rate = newEmission.rate;
rate.constantMin = 20;
rate.constantMax = 21;
newEmission.rate = rate;
Now as you can probably tell, this simple increases the number of particles. Now, this used to work and probably doesn't because of the new particle system I keep reading about.
However on this new particle system I have a question and issues getting it to work.
Issue
Correct me if i'm wrong but the particle system is defined as follows
void Start()
{
ParticleSystem ps = GetComponent<ParticleSystem>();
var main = ps.main;
main.startDelay = 5.0f;
main.startLifetime = 2.0f;
}
Now if I have 3 particle systems, how do I specify which one i'm referring to? Since I cant define it as public and drag the particle system to it in the editor anymore?
Issue B
Now i tried following what unity said in their forums and did the following
ParticleSystem ps = GetComponent<ParticleSystem>();
var main = ps.main;
main.maxParticles = 150;
// LeafStormParticleSystem.maxParticles = 150;
do not create your own module instances, get them from a ParticleSystem instance UnityEngine.ParticleSystem+MainModule.set_maxParticle
Any help with Issues A and B will be appreciated.
Thank you
Issue A
Only one ParticleSystem component can be attached to any one GameObject at a time. Sub-ParticleSystems must therefore be attached to separate GameObjects too (generally children of the GameObject holding the first ParticleSystem), which can be dropped directly onto public fields.
public ParticleSystem LeafStormParticleSystem;
void Start ()
{
if (LeafStormParticleSystem != null)
{
var main = LeafStormParticleSystem.main;
main.maxParticles = 150;
}
}
Issue B
Your code looks fine, however a critical part of the error message was missing; NullReferenceException which is telling you that a reference in your code is equal to NULL. In your case, that reference would be the ps variable used to store the ParticleSystem reference, which is either a consequence of not attaching this script to the GameObject holding your ParticleSystem or simply that you have no ParticleSystem attached at all. In either case, make sure both script and ParticleSystem are attached to the same GameObject and check your references like so;
void Start ()
{
ParticleSystem ps = GetComponent<ParticleSystem>();
if (ps != null)
{
var main = ps.main;
main.maxParticles = 150;
}
}

How to add gameobjects via script in the hierarchy in edit mode?

I would like to create a menu item that can build a game object with children and components.
I can't use prefabs for the whole objects because I need that the children are separate prefabs.
You can use something like this:
[MenuItem("YOUR_MENU_NAME/YOUR_SUBMENU_NAME/YOUR_METHOD_NAME %&n")]
static void CreateAPrefab()
{
//Parent
GameObject prefab = (GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath<Object>("Assets/Prefabs/TestPrefab.prefab"));
prefab.name = "TestPrefab";
if(Selection.activeTransform != null)
{
prefab.transform.SetParent(Selection.activeTransform, false);
}
prefab.transform.localPosition = Vector3.zero;
prefab.transform.localEulerAngles = Vector3.zero;
prefab.transform.localScale = Vector3.one;
//Child 1
GameObject prefabChild1 = (GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath<Object>("Assets/Prefabs/TestPrefabChild1.prefab"));
prefabChild1.name = "TestPrefabChild";
prefabChild1.transform.SetParent(prefab.transform, false);
prefabChild1.transform.localPosition = Vector3.zero;
prefabChild1.transform.localEulerAngles = Vector3.zero;
prefabChild1.transform.localScale = Vector3.one;
//Child2...
//...
Selection.activeGameObject = prefab;
}
Don't forget to include using UnityEditor; and to either place the script in an Editor/ folder or use #if UNITY_EDITOR / #endif around the parts using the editor methods. Also I added a shortcut to the MenuItem using %&n (Ctrl + Alt + N).
If you need to change the prefabs that compose the instantiated object, you can try to retrieve them all in your project (maybe be and heavy operation depending on your project) as they did here and display a kind of checklist where you select the prefabs needed as children inside an EditorWindow.