Quick question.
I have been looking around for days now, but somehow I can't get this to work.
I want to duplicate a Node box by a c# script to a content container [see image].
What is the best way to accomplish something like this in Unity and C#?
As I understand correct; this can be done with the Instantiate function right?
// get gameobject
public GameObject listpanel;
// Start is called before the first frame update
void Start()
{
// find tag
listpanel = GameObject.Find("listpanel");
// duplicate tag
GameObject duplicate = Instantiate(listpanel);
// set panel not active
//listpanel.SetActive(!listpanel.activeSelf);
}
Anybody has an idea of what I am doing wrong here.
Help would be highly appreciated.
update: This ends in no errors at all at the console; it seems to work, but nothing shows up.
Wesley
If you could share any errors that are in your console, it would help us debug.
For what I can see, if you are finding by tag, the FindGameObjectsWithTag method should be used instead of Find. This will be returned as an array.
Also, the Instantiate method has a number of parameters, where the 4th parameter would state what parent object it would be attached to.
Here is an example of instantiating a prefab located in the "Resources" folder of the Assets.
The prefab is instantiated as a child of another existing object.
void Start()
{
//State what to instantiate, where, and the rotation
GameObject nodeobject = (GameObject)Resources.Load("mynodeobject");
Vector3 position = new Vector3(0,0,0);
Quaternion rotation = Quaternion.Euler(0,270,0);
//State the parent object
GameObject parentobject = GameObject.Find("ParentObject");
//Instantiate the prefab
Instantiate(nodeobject, position, rotation, parentobject.transform);
}
Related
Looking to get an instance of this game object so I can successfully use .enabled to hide it in a scene.
PlayPortalLoginButton loginButton = gameObject.GetComponent<PlayPortalLoginButton>();
Fairly new to C# and I believe I am close to achieving my goal with the line above. What needs changed? Want to understand how to correctly do this.
Here is one way you could find a component on a GameObject in the scene, where "PortalLoginButton" is the name of the GameObject as seen in the editor:
var loginButton = GameObject.Find("PortalLoginButton");
loginButton.enabled = false;
However, GameObject.Find("...") searches the name of every GameObject in the scene, and this is not usually the best way to reference a GameObject since it is not very efficient. So make sure not to use GameObject.Find("...") or similar function calls in the Update() function because it will execute every frame and slow your game down. If the GameObject is not instantiated while the game is running, it is usually better to make a global reference to any GameObject or Component that you use in your script and then drag-and-drop the GameObject with the Component you are looking for into the field in the editor. Alternatively, you can use GameObject.Find("...") in the Start() or Awake() functions to store a reference to the GameObject that you are looking for, so that the search only happens once at the start of your game.
Here is an example of how to store the reference in global field (it will show up in the editor and you can drag-and-drop the GameObject into it). The differences between using a public field vs a private field are explained in the comments (you can decide on using public or private):
// By default, private fields are not viewable in the editor,
// but the [SerializeField] attribute, placed before
// the field declaration, allows them to be visible.
[SerializeField]
private GameObject loginButtonPrivateReference;
// If you need to access loginButton from another script,
// you can make it a public field.
// Public fields are viewable in the editor by default.
public GameObject loginButtonPublicReference;
Here is an example of how you can use GameObject.Find("...") in the Awake() function:
private GameObject loginButton;
private void Awake() {
loginButton = GameObject.Find("PortalLoginButton");
}
If you need to search for GameObjects in your scene by type or by tag name, see the GameObject documentation here for more information. Searching by type is less efficient and searching by tag is more efficient than searching by name because type searches check each component on each GameObject, and tag searches search only an organized GameObject subset.
GameObject button;
void Start() {
button = GameObject.Find ("yourButtom");
}
void SomeEvent() {
button.SetActive(false);
}
I think you have to help to you
There are several ways to get access to a gameObject in a script depending on exactly which gameObject you are trying to get.
If you are trying to access a GameObject of a behavior in the behavior script then simply using gameObject should suffice since that is the gameObject that behavior is attached to.
Accessing a script that is attached to another GameObject is where it can be tricky. For scenes such as a MainMenu, there is nothing wrong with giving it a public reference as an example:
public PlayPortalLoginButton loginButton;
void setLoginState(bool activate) {
loginButton.enabled = activate;
}
With this example you would just drag and drop the gameObject with the PlayPortalLoginButton script on your manager script, the script that would control whether it is enabled or not.
If you need a more modular approach to it for example in a gameplay scene where you are populating objects at run time the approach you can take is:
PlayPortalLoginButton loginButton;
void setLoginState(bool activate) {
if(loginButton == null)
{
loginButton = FindObjectOfType<PlayPortalLoginButton>();
}
// Requires the correct version of .net otherwise you can reuse the check above...
loginButton?.enabled = activate;
}
In the above script if you needed to gameObject of loginButton, now you can access it through loginButton.gameObject.
There are some more examples you could use and other approaches however I feel the above should suffice if for a menu.
I will also mention I am avoiding example of GameObject.Find and GameObject.FindGameObjectsWithTag as those are more prone to error. They will only work if your name or tag are correctly marked, if you rename them for any reason then your scripts will fail to find the Object, and this can cause an issue with troubleshooting.
Using FindObjectOfType, you are less likely to have an error, and if you remove that script type these scripts will populate an error indicating the script no longer exists. When refactoring, if you right click on the behaviors name and use the rename option it will automatically update references to the script throughout your code.
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Instantiate(Resources.Load("Objects/Level"), transform.position, Quaternion.identity);
}
}
This is my code. I have an object named Level.obj inside of a folder named "Objects" inside of my Assets. I attempt to spawn it on top of the parent object of this script with Resources.Load("Object/Level"). I believe this code itself is correct because the console returns with "The Object you want to instantiate is null." upon pressing the spacebar. What's probably wrong is my parameters, specifically how I attempted to find the object. I have also tried Assets/Objects/Level as opposed to what's above.
Add a public field public GameObject myPrefab; to your monobehavior.
Set it in the editor by selecting your gameobject and using the inspector.
Instantiate it like Instantiate(myPrefab, transform.position, Quaternion.identity);
You only need Resources.Load if your asset doesn't exist at compile time. And like the documentation says, Resources.Load needs the asset to be in the Resources folder.
https://docs.unity3d.com/ScriptReference/Resources.Load.html
I never used Resources.Load() so you may try to achieve something different, but what I do to "spawn" objects is to make them into a prefab (just drag/drop your object to your assets). Then declare a public GameObject field on your script, drag/drop the prefab in it in the inspector and then Instantiate it like you did.
Hope it helped !
I am trying to instantiate a coin prefab that appears when an enemy dies.
To initially get a reference to the prefab, I retrieved it using its tag:
private GameObject coinSpawn;
Start(){
coinSpawn = GameObject.FindGameObjectWithTag("xxx");
}
Now when the enemy dies, I call Instantiate() as follows:
Instantiate(coinSpawn, transform.position, Quaternion.identity);
However, when I was playing the game and an enemy died, nothing was spawned and I got this error:
ArgumentException: The Object you want to instantiate is null.
I do not understand what I did wrong - I confirmed that I have properly tagged the prefab which I want to instantiate.
One more thing is that I want to do this without making a Resources folder. Is that possible?
Unfortunately, GameObject.FindGameObjectWithTag() only retrieves active GameObjects with the given tag that already exist in the current scene. It sounds like you're trying to use this method to retrieve a reference to a prefab object in your Assets folder, which is something it can't do. As a result, the method is returning null and assigning it to coinSpawn, leading to the error when you try to use coinSpawn later.
You likely need the Resources.Load() method, to which you can supply a path to an object in your Assets folder. Just use that in place of GameObject.FindGameObjectWithTag():
private GameObject coinSpawn;
Start(){
coinSpawn = Resources.Load("path_to_prefab") as GameObject;
}
And yes - you will have to use the name of the prefab instead of its tag to identify it, but I don't think that should pose any problems. (If it does, please update your question accordingly with an explanation.)
Hope this helps! Let me know if you have any questions.
I'm pretty new to Unity3D and C# so I'm not entirely sure what I'm doing wrong in the following scenario.
In Unity3D I'm attempting to get the value of a variable (target) that is updated when the player moves close enough to the enemy that the script changes target from null to 'enemy' and gets the position and so on and so forth.
The turret that has a script on it for auto-targetting is a child to the main player gameobject.
Whenever I use the following:
targettingScript target;
target = gameObject.GetComponent<targettingScript>();
// or---
target = gameObject.GetComponentInChildren<targettingScript>();
...I can then test with a debug.log that it does pull "null" as it should at start up, but it doesn't seem to update when the turret finds a target and changes target from null.
I've read a few forum posts in various areas that some say you can't do this (pass data from a child component script to another gameobject that is instantiated (IE a missile firing after targetting is completed and then doing a homing-missile style of tracking) and others said that they did a check through all the levels of the gameObject till they found what they wanted, but I'm not understanding what that really means.
My questions are, 1 - is it possible to relay a variable from a child gameobject's component to another instantiated gameobject
2 - if so, how?
I apologize if this is a rather simple concept, but I'm not sure how to troubleshoot it.
I'm going to build a new scene and try various gameObjects and child objects and see what I can muster and if I find anything useful I will post it here.
In the mean time, thank you all for your time in reviewing my question.
sure,
since you instantiate the object run time, you should keep track of it,
public GameObject target;
public void Update() {
// if we dont have a target (find it).
if(target == null) {
target = GameObject.Find("Player");
}
// if we found the target take some health each frame.
if(target != null) {
playerhealth = player.GetComponent<PlayerHealth>();
playerhealth.health--;
}
}
you can of course also add a distance detector to the find.
if(target != null)
if(Vector3.distance(transform.position, target.transform.position) < 5) {
// target in range
} else {
// to far away ignore it.
target = null;
}
The best thing to do when you are instansiating gameobjects runtime you have to keep track of them if you are going to reference them later on, so create a manager that does this, create a empty gameobject, add a MgrScript to it, and have other objects call it as MgrScript.SpawnEnemy() that way we can reference the enemy's from an array or something like that.
If you dont use a manager and your scene is simple and small you can always use tags to reference the gameobjects, since it a bad idea to reference by name when you have a large and complex scene, because you will most likely reference the wrong item.
I'd like some help with the following issue. I'm making a simple game where you have a character running and he has to jump over obstacles coming at him.
And I'm currently stuck when it comes to creating GameObjects and randomly generating them within the game scene at run time.
I've written a class to help accomplish this:
using UnityEngine;
using System.Collections;
public class randomObstacles : MonoBehaviour {
public GameObject myCube;
public Vector3 spawnLocation = new Vector3(0,2,0);
// Use this for initialization
void Start () {
GameObject SpawnLocation = (GameObject)Instantiate(myCube, spawnLocation, Quaternion.identity);
}
// Update is called once per frame
void Update () {
}
}
The above code is what I wrote to simply create Objects, one after the other. But when I run the game, it comes up empty -_- !
Can anyone please tell me where am going wrong, and from the look of it my code doesn't seem to do what I am hoping to achieve :(
I've attached the above script into an empty GameObject as I saw in a tutorial from the Unity Community forum, but that did not help either.
(I've looked around and it seems like no one has come across such an issue - I could bee wrong)
It would seem that your myCube variable is the root of your problems, having tested it in a scene of my own. By subsituting
(GameObject)Instantiate(myCube, ...
with
(GameObject)Instantiate(GameObject.CreatePrimitive(PrimitiveType.Cube), ...
I was able to produce a cube at (0,2,0) with no qualms. Perhaps your myCube GameObject is missing a Mesh Renderer, in which case it would appear in the Hierarchy during runtime even though it would not appear visible in Game View. Perhaps you are not assigning it in the Inspector before you run the game, in which case the myCube variable would refer to null and thus not be created. Additionally, though you may be assigning the GameObject you instantiate to SpawnLocation, it is an unused local variable (something MonoDevelop or your code editor should notify you of). Make sure you either provide a reference to a myCube GameObject in the Inspector before runtime or through script referencing to a loaded prefab/GameObject during runtime. It would also be helpful to provide a fallback (say, to PrimitiveType.Cube perhaps?), which will make your code more robust and able to handle errors in referencing should they arise.
Regardless, in order to achieve the functionality you have described, first make sure yo have properly prepared whatever you would desire myCube to be. Also, for future posterity, you may want to initialize your spawnLocation in the Start routine, and assign the variable coordinates by substituting Random.value * yourValueCeiling in for each random coordinate you would like myCube to spawn on. You could even go as far to make a helper method externalized and thus independent from the start routine, such that you will not have to have a hundred instances of a single script to create a hundred instances of what you need; rather, you can call the method through a single script, and save yourself trouble in this way. If you would so appreciate it, here is my implementation of your objective, hope this helps!
using UnityEngine;
using System.Collections;
public class randomObstacles : MonoBehaviour {
public Vector3 spawnLocation;
public GameObject myCube;
// Use this for initialization
void Start () {
if (myCube != true) {
Debug.Log("myCube not set");
myCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
}
if (myCube.renderer.enabled == false) {
Debug.Log("myCube not rendered");
myCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
}
CreateCube();
}
// Update is called once per frame
void Update () {
}
void CreateCube() {
spawnLocation = new Vector3(0, Random.value * 10, 0);
Instantiate(myCube, spawnLocation, Quaternion.identity);
}
}
It may be worth pointing out that you're creating your object in the Start method, which means your code will only run once: from the name of your class, I'd assume you want to create more than one object using this code.
If you move the code into Update you'll create one object per frame, which is most likely too many. My guess would be that you want something like a coroutine that will run on a random interval, and then spawn cubes repeatedly over time, something like this:
void Start () {
StartCoroutine("SpawnObjects");
}
IEnumerator SpawnObjects()
{
while (keepAddingObjects) // a boolean - could just be "true" or could be controlled elsewhere
{
GameObject SpawnLocation = (GameObject)Instantiate(myCube, spawnLocation, Quaternion.identity);
float delay = Random.Range(1f, 5f); // adjust this to set frequency of obstacles
yield return new WaitForSeconds(delay);
}
}
Taken from my own code in a game that auto generate mazes:
public class Cell
{
private GameObject instance;
public void CreateVisual()
{
// Load a GameObject that exist inside the "Resources" folder.
GameObject prefab = (GameObject)Resources.Load("Models/Walls/3W1");
// Create an instance of the prefab
instance = (GameObject)GameObject.Instantiate(prefab);
instance.transform.position = myPosition;
}
}
I think the part you are missing is the Resources.Load() method.