I have a large room with tends of thousands of nested objects. I tried to select a group of objects that represents a single object out of hundreds. This was originally a sketchup file that got turned into a prefab variant and added to the scene.
using UnityEngine;
using System.Collections;
using UnityEditor;
public class CreatePrefab : MonoBehaviour
{
[MenuItem("Extras/Create Prefab From Selection")]
static void DoCreatePrefab()
{
Transform[] transforms = Selection.transforms;
foreach (Transform t in transforms)
{
GameObject prefab = PrefabUtility.CreatePrefab("Assets/Prefabs/" + t.gameObject.name +
".prefab", t.gameObject, ReplacePrefabOptions.ReplaceNameBased);
}
}
}
So I am trying to iterate through the selection and turn them each into prefabs. Its pretty ridiculous because there is close to 100,000 objects in total and everything, like nuts, bolts, rods that make up a chair are individual gameobjects.
I am trying to use GPU instancing to reduce framerate but this imported model needs to be converted into prefab somehow. I am trying to extract meaningful objects that repeat (ex. chairs) as individual chair prefabs but the problem is:
I don't know how to first combine/fuse the objects that make up a chair
If I am able to select a chair I need to be able to convert it into a chair prefab.
I have to basically repeat this process for each object that repeats excessively (ex. chairs, desks)
I get this error message from unity: can't save part of a prefab instance as a prefab,
How can I group the individual parts that make up a chair and turn it into a prefab?
Unity can neither handle that many objects nor a hierarchy this deep! (a nice article on Unity's own website about this). Thus you will never end up with good performance this way. You'll have to reduce and combine the objects in a dedicated software (usually 3D modeling software) and import those objects to unity.
The same requirement as your. Unity hasn't provided such a method to save a nested prefab modification, but can be achieved by a trick.
The solutions is:
Instantiate another nested prefab by PrefabUtility.InstantiatePrefab
Modify that new GameObject of the prefab
Save the modification by PrefabUtility.SaveAsPrefabAssetAndConnect
And because the gameobject hierarchy is a reference, the saved modification will also affect the nested prefab.
Here is the code:
var prefabPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(goInScene);
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
var anotherGo = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
// Do the same modification of the nestedGo to anotherGo
PrefabUtility.SaveAsPrefabAssetAndConnect(anotherGo, prefabPath, InteractionMode.AutomatedAction); // This save will affect all prefab in Scene!
DestroyImmediate(anotherGo);
Related
I'm spawning a prefab on MotherSpawner gameObject and I want to spawn that prefab again on positionWhereObjectSpawn gameObject.
What I'm planning to do is get the position of positionWhereObjectSpawn gameobject using GameObject.Find, then spawn on that position, but they say it's inefficient.
What's the efficient way to do this?
Something like this should work:
var posGo = GameObject.Find("positionwhereobjectspawn");
Instantiate(myPrefab, posGo.transform.position, posGo.transform.rotation);
One thing that's inefficient here is the GameObject.Find. If you do it at every spawn, yes, it is inefficient. If you find it once and simply place it into a variable in your class to be used later, it's efficient. Like so:
GameObject posGo;
Start() {
posGo = GameObject.Find("positionwhereobjectspawn");
}
Update() {
if(Input.GetKeyDown(KeyCode.SPACE)) {
Instantiate(myPrefab, posGo.transform.position, posGo.transform.rotation);
}
}
Next step to improve efficiency is to get rid of the Instantiate and use an object pool. You create game objects in advance, hide them, and use them when needed. For that, you should Google unity object pooling and use one of the options.
If this is static and you wont change the number of spawns you can do is make public fields and store the Transform of both the spots where you want to spawn a prefab just by making 2 public Transform fields OR if you want to increase the number of spawns you can simply store these positions in a collection and use that to spawn objects, and yea Gameobject.Find is inefficient, this method searches through your whole hierarchy so think how much time will it take to look through everything.
currently I am working on a Equipment system that will Instantiate Game objects into the scene from a list, prior to this I was not using a Instantiation system with just keeping the Game Objects Active in the scene at all time.
Now with Instantiating the Game Object(Prefab) I am running into the error of Loosing the References when I instantiate them, I have looked at various other articles before such as this Discussion here:
However I am looking at alternative ways other than using Tags as this system may use a large amount of tags decreasing game performance overtime, would anyone know different methods as to saving references from a scene into a prefab?
So as this is a new system I am really just looking for suggestions on how to save references of scene game-objects into a prefab, as my old system was just holding the game objects active in the scene and not actually instantiating them, once again I would love to hear different types of methods, something more than just using Tags.
The References im trying to save are three Transform Elements from a script attached to my Prefab they are the following
public Transform camPos;
public Transform aimLocation;
public Transform crosshairLocation;
Currently I am just dragging and dropping the gameobjects from the scene into the public fields in the script
Since this will be a major system I would like to not want to use tags for this system. But it is definitely a Valid option I am just looking for other methods for saving references of scene game-objects into a prefab When Instantiating the prefab into the scene,
Thank you for taking the time to read and any suggestions would be greatly Appreciated!
Any Questions Just Ask!
You can not save scene references in prefabs, for obvious reasons (what happens if you instantiate that prefab into another scene?). Your prefab needs to discover the objects it needs after it's instantiated. I'm not a huge fan of the tag system in Unity (or any other system that uses strings as identifiers, too much room for error). I'd recommend you take any of these three approaches:
Make the transforms you need (cam pos, aim location, etc.) singletons if there's ever only going to be one of each. You'd make a script class specifically for each one, make that class a singleton, and put it on the game objects. Then, after your prefab is instantiated, you can do something like this: camPos = CamPos.Instance.transform; You can read up on the singleton pattern here.
If there's going to be more than one of each, group all related objects into a single hierarchy (that is, make them all the child of a single game object). For example, if there are going to be many characters and each is going to have a separate aim location, you can make aim location a child of the character game object. Then, in your prefab (take care to make the prefab a child of the same root game object as well), you can do something along these lines: camPos = transform.root.GetComponentInChildren<CamPos>().transform; Better yet, you can have a component that has references to all such objects, and attach one to the root game object. Then, you can do: camPos = transform.root.GetComponent<ReferenceRepository>().CamPos;
Initialize the prefabs when they're instantiated. For example, say you have a player class that instantiates a weapon and already has a reference to the camPos. You can do it like this: var weapon = Instantiate<Weapon>(myWeaponPrefab); weapon.CamPos = camPos; Note however that when you assign public fields this way, they will only be accessible once Start is called. In other words, they won't be available in Awake.
That said, I don't think making stuff like aim location and crosshair location separate objects is a very good idea anyway. You should have a player/human/pawn class, and that class can provide this information to other objects that need it.
I have a 3D game that is generated randomly when you hit play. The thing is that objects don't generate with collision and characters start moving through walls. What is the necessary code for an object to be generated with collision in C# ?
Ok if I have read your question correctly, you are auto generating random meshes for you game but they do not yet have colliders on them. To generate a collider for an object in c# see the following example:
using UnityEngine;
using System.Collections;
public class AddComponentExample : MonoBehaviour
{
void Start( )
{
SphereCollider sc = gameObject.AddComponent<SphereCollider> as SphereCollider;
}
}
You need to add a collider component to the gameobject you are generating. The one you choose depends on the mesh you created, so if you are generating cube meshes choose a box collider.
If you are creating your own meshes instead of primitives that are more complex then you can apply a "MeshCollider". But be warned if you are creating your own mesh at run time you may get some unusual artefacts.
Hope that helps
I have multiple enemies that move toward the player. I am trying to stop them from merging into each other, i.e maintain some type of minimum distance between each other. What I'm trying is this (from unity3d forums):
enemy1.transform.position = (enemy1.transform.position -
enemy2.transform.position).normalized * distance + enemy2.transform.position;
However, when I have >= 3 enemies they still seem to bunch up even when I apply this to every enemy combination.
I need a better method as this one does not work and does not scale.
What you do around your enemy prefab is place a quad box which in effect is a trigger element, then on you script for the enemy you set that if another enemy (using tag types, I imagine) comes within touching of the quad box then to run appropriate code to stop the enemy getting closer in and to prevent the enemy actually overlapping with this trigger box.
Your code you example in your question looks like it is referencing the enemy units specifically rather than as instance entitites which is very probably a bad way of coding, as you're finding, it's very inflexible dealing with not-specifically-named reference entities.
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
private Transform otherEntity;
public float distance = 50.0f;
private Transform thisEntity;
void OnTriggerEnter(Collider other)
{
otherEntity = other.GetComponent<Transform>();
thisEntity = GetComponent<Transform>();
thisEntity.position = (thisEntity.position - otherEntity.position).normalized * distance + otherEntity.position;
}
}
I have not tested the above code but using the code you reference the values for the transform are loaded from the Game Component for the referenced entities, as this has changed ALOT in Unity since release of version 5.1 and your source for your code was an answer given in 2012!!
thisEntity is the object that the script is attached to, typically one of the enemy. The otherEntity is the object that comes within the quad trigger (please remember the quad needs to be referenced as a trigger element.
The values of the Entity variables need to be set once the trigger is entered, so that it always effects the correct other element.
(I may be totally wrong with my methodology but I hope this helps.)
I am doing some calculation with meshes in unity and adding MeshCollider's to calculate pathfinding. Some meshes that are generated are very big and splits meshes into 2 or more 'mesh parts'. I set MeshCollider like so:
testRoom = GameObject.Find("testroom");
MeshFilter[] _filters = testRoom.GetComponentsInChildren<MeshFilter>();
foreach (MeshFilter _filter in _filters)
{
_verts.AddRange(_filter.mesh.vertices);
_triangles.AddRange(_filter.mesh.triangles);
testRoom.AddComponent<MeshCollider>();
testRoom.GetComponent<MeshCollider>().sharedMesh = _filter.mesh;
}
This obviously dont work with several meshparts since the Collider gets overwritten. Since the mesh is to big I cannot merge the meshes together and set a collider, right? When I use the Generate Colliders box in unity it works fine but I want a programmable solution since I am to generate the meshes at runtime.
Does anyone know how to make a single collider for the big mesh that is split into several parts due to having to many vertices?
Here is a picture of the mesh (as requested) It might look abit strange but it's (part of) an office building. I made the mesh myself using a Tango tablet. I diddnt include a tango tag because I did not think how the mesh looked would affect the answer.
I dont fully understand your situation, to be honest, but if you need a collider that will cover complex object created from script you still can add it to each object separately at runtime, right? So instead of
testRoom.AddComponent<MeshCollider>();
testRoom.GetComponent<MeshCollider>().sharedMesh = _filter.mesh;
you can do
var collider = _filter.gameObject.AddComponent<MeshCollider>();
collider.sharedMesh = _filter.mesh;
You cant add more than one MeshFilter component to a gameObject anyway, so any filter you get from testRoom.GetComponentsInChildren() is attached to a different object. Therefore you can add new collider to each one of them individually.
You can of course add the colliders at runtime as you are already doing. This will give you very heavy and poor performance solution that will work but slow. Normal practice in this case would be modelling lowpoly version of that mesh you will use as a collider.
Another solution if your objects aren't too complex would be box colliders. You would need to grab renderer.bounds
http://docs.unity3d.com/ScriptReference/Renderer-bounds.html
and create new box collider with that bounds
http://docs.unity3d.com/ScriptReference/Collider-bounds.html
Hope that make sense