How to control the placement of GameObject in a scene programmatically in Unity - unity3d

I have created a code file in Unity and assigned it to an empty GameObject I have placed in the scene:
var obj = new GameObject("Sample");
obj.transform.position = new Vector3(0, 0, 0);
var text = obj.AddComponent<TextMesh>();
text.text = "Hello world";
When I run the scene, I can see the text. And that is my problem: I did not specify anywhere in code to add obj to the scene, but it gets placed automatically apparently.
This can be a problem if I want to introduce an object later than instantiation time.
What am I doing wrong? How can this be achieved? What are the patterns/best-practices here?

Immediate fix:
Use obj.SetActive(false) to temporarily disable the object and then use obj.SetActive(true) when you need the object to be active.
Other solutions / best practices:
Create the object you desire in the scene, save it as a prefab (prefabricated object) and then only instantiate it when you need it. Here's a link for further reading into the prefab system. https://docs.unity3d.com/Manual/Prefabs.html
Object pooling is typically used when you will have a bunch of the same objects (like lasers, bullets, etc). Watching this video may be of help: https://www.youtube.com/watch?v=tdSmKaJvCoA

Related

Change motion using script in Unity Editor

Hi how do we change motion in an AnimatorController using script in Unity Editor?
The red highlight is the one I'd like to change, but using script
My use case is to copy animations from one object, process the animation e.g. adding offset rotation, then add to another object. Since my object has many child objects, I need to create a script to automate this.
Changing the AnimatorController via editor scripts is always quite tricky!
First of all you need to have your AnimationClip from somewhere
// somewhere get the AnimationClip from
var clip = new AnimationClip();
Then you will have to cast the runtimeAnimatorController to an AnimatorController which is only available in the Editor! (put using UnityEditor; at the top of the script!)
var controller = (AnimatorController)animator.runtimeAnimatorController;
Now you can get all its information. In your case you can probably use the default layer (layers[0]) and its stateMachine and according to your image retrieve the defaultState:
var state = controller.layers[0].stateMachine.defaultState;
or find it using Linq FirstOrdefault (put using System.Linq; at the top of the script) like e.g.
var state = controller.layers[0].stateMachine.states.FirstOrDefault(s => s.state.name.Equals("SwimmingAnim")).state;
if (state == null)
{
Debug.LogError("Couldn't get the state!");
return;
}
Finally assign the AnimationClip to this state using SetStateEffectiveMotion
controller.SetStateEffectiveMotion(state, clip);
Note however that even though you can write individual animation curves for an animation clip using SetCurve unfortunately it is not possible to read them properly so it will be very difficult to do what you want
copy animations from one object, process the animation e.g. adding offset rotation, then add to another object.
You will have to go through AnimationUtility.GetCurveBindings which gets quite complex ;)
Good Luck!

Unity3D Text not changing after being set in Start()

I have a Canvas (World Space Render mode) with a Text and a Button component displayed in a tridimensional space (it's a VR app). The canvas instantiated at runtime using a prefab.
I get a reference to the Text object using:
_codeTextLabel = canvasPrefab.transform.Find("CodeTextLabel").gameObject.GetComponent<Text>();
I want to update the text at run-time using:
void Update()
{
_codeTextLabel.text = _codeText;
}
where _codeText is just a variable I update based on specific events.
The problem is that the Text gets updated only the first time, but if I try to change the variable nothing happens. I have tried several combinations and also the method _codeTextLabel.SetAllDirty() but it doesn't work.
The only way to update the text is to re-instantiate the prefab.
Are you instantiating your prefab before setting the values. If you are storing the _codeTextLabel reference before instantiating then your reference will point to the prefab not the runtime object. I can't see the rest of your code, so I can't say for sure. (I would have asked as a comment, but as I'm new I don't have the reputation to do so)
edit: I did a test to try and recreate your problem. I made the following script and it appears to work as expected. CanvasPrefab is a worldspace canvas with a UnityEngine.UI.Text component attached. (The script is attached on an empty game object in the scene btw)
public class ChangeText : MonoBehaviour
{
public GameObject CanvasPrefab;
private GameObject runtimeCanvas;
public string runtimeText = "something";
private Text textRef;
// Start is called before the first frame update
void Start()
{
runtimeCanvas = GameObject.Instantiate(CanvasPrefab);
textRef = runtimeCanvas.GetComponentInChildren<Text>();
}
// Update is called once per frame
void Update()
{
textRef.text = runtimeText;
}
}
as long as you did something wrong, It works absolutely so I guess there are several cases
Failed to do "_codeTextLabel = canvasPrefab.transform.Find("CodeTextLabel").gameObject.GetComponent();"
'_codeTextLabel' lost reference from 'GameObject.
Doesn't change runtimeText' change at all
Subscription of events failed I mean, your updating scripts doesn't get proper event to update that text.
Without codes, this is only thing I can guess for yours so please check above I hope there is case among above.

Can I programatically load scenes in the Unity editor?

I'm using the A* pathfinding algorithm for my 2D game (from my understanding, Unity Nav Meshes don't work in 2D). I would like to be able to pre-calculate navigation grids for all of my scenes, and save them in resource files that can be loaded whenever the player enters a new scene. Rather than having to remember to click "calculate" for every scene -- and remember to recalculate all of my scenes if I make a change to my navigation grids -- I want to be able to programatically have the Unity Editor iterate though each scene and calculate the grids.
Is there a way to create a command in the Unity editor that will iteratively open each scene in the editor and run a method on a MonoBehaviour that's in the scene? Alternatively, is there another way to accomplish what I'm trying to do?
Yes you can!
In editmode you can't use SceneManager but have to use the EditorSceneManager.
First of all you need the scenes you want to iterate.
Could be e.g. a public static field with a list of SceneAsset in the Inspector where you simply reference the scenes
public static List<SceneAsset> Scenes = new List<SceneAsset>();
or you could get them by script e.g. for only use the scenes added to the build settings using EditorBuildSettings.scenes
List<EditorBuildSettingsScene> Scenes = EditorBuildSettings.scenes;
For both you can get a list of the scene paths e.g. using LinQ Select (this is basically a kind of shortcut for a foreach loop) and AssetDatabase.GetAssetPath like
List<string> scenePaths = Scenes.Select(scene => AssetDatabase.GetAssetPath(scene)).ToList();
for the EditorBuildSettingsScene from EditorBuildSettings.scenes you can also simply use
List<string> scenePaths = Scenes.Select(scene => scene.path).ToList();
Now you can iterate over them all and do your stuff by using EditorSceneManager.OpenScene, EditorSceneManager.SaveScene and EditorSceneManager.CloseScene (and if you need it AssetDatabase.SaveAssets)
foreach(string scenePath in scenePaths)
{
// Open a scene e.g. in single mode
var currentScene = EditorSceneManager.OpenScene(scenePath);
/* Do your calculation for currentScene */
// Don't know if it makes changes to your scenes .. if not you can probably skip this
EditorSceneManager.SaveScene(currentScene);
// Finally Close and remove the scene
EditorSceneManager.CloseScene(currentScene, true);
}
// you might be doing changes to an asset you want to save when done
AssetDatabase.SaveAssets();
Before starting you should probably ask to save the current open scene(s) using EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo
if(EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
{
// Saved => the foreach loop here
}
else
{
// aborted => do nothing
}
Than in order to finally start that method the simplest would be to add a [MenuItem]
public static class Calculation
{
[MenuItem("YourMenu/RunCalculation")]
public static void RunCalculation()
{
// all the before mentioned snippets here
// depending how exactly you want to do it
}
}
This will add a new menu YourMenu with one entry RunCalculation to the top menubar of the Unity Editor.
Note:
Since this uses a lot of types (EditorSceneManager etc) that only exist in the UnityEditor namespace you should either place the whole script in an Editor folder (so it is ignored in the final build) or use pre-processors like
#if UNITY_EDITOR
// ... code here
#endif
so in the build the code is also ignored.
Note that I'm assuming so far you also did your calculation in editmode. The thing is if this calculation relies somewhere aon any Start or Awake method you have to call it manually from that editorscript before running the calculation.

Unity clone objects don't include scripts

Does anybody know how can I include scripts when my objects clone. In my game, I need to make that when my ball hit moving wall, then there is need to show new wall including my moving scripts. MY CASE: new wall is shown, but it is not moving.
Please help.
Kind regards
Well it is very easy.
First case: if you are using the prefab to instantiate, be sure to assign on the prefab your scripts.
Second case: if you are taking the template to instantiate directly from GameObject of wall, it should create the GameObject with exatly same scripts.
If it is still not moving, check in Inspector the cloned wall, if the scripts are enabled, and double check how the scripts work (maybe needs some initializing or whatever)
If your script is not on your prefab (for any reason), you can add via a script:
void CreateWall(){
GameObject obj = (GameObject)Instantiate(wallPrefab);
NewScript ns = obj.AddComponent<NewScript>();
}
The only advantage I could think about that way is that you can add specific components based on a specific situation. Say you want to add Script A if condition A or Script B if condition B:
void CreateWall(){
GameObject obj = (GameObject)Instantiate(wallPrefab);
switch(condition){
case A:
obj.AddComponent<ScriptA>();
break;
case B:
obj.AddComponent<ScriptB>();
break;
}
}

Unity GetComponent(GUIText) bug?

I have an issue with the GetComponent(GUIText) the error i get is
There is no 'GUIText' attached to the "#######COUNTER(Clone)" game object, but a script is trying to access it.
Here is my code:
var UItecxt = GameObject.Find("#######COUNTER(Clone)");
var txtconvert = UItecxt.GetComponent(GUIText);
print(txtconvert);
txtconvert.text = counternumb.ToString();
I HAVE a GUIText on my clone! What is the issue? Thanks!
Your problem is that there is no GameObject named "#######COUNTER(Clone)" cloned in the scene. Run my code below and you will notice.
var UItecxt = GameObject.Find("#######COUNTER(Clone)");
var txtconvert : GUIText;
if(UItecxt != null)
txtconvert = UItecxt.GetComponent(GUIText);
else
Debug.Log("There was no GameObject with the name '#######COUNTER(Clone)' in the scene");
To fix it just make sure you do have a GameObject with that name.
Your question is not detail enough to determine the problem.
Still, i assumed the gameobject that you mentioned should be a prefab that you instantiated.
Where you put or attach the sciprt? Make sure it is attached to the prefab that you instantiated.
Also, you can try use direct reference the component instead of using gameobject.Find.
It is easier for you to drag and drop element at the inspector.