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.
Related
So basically im creating a space sandbox game on mobile where you can create your own universe. At the start of the game you can choose your rocket. Every rocket has its own Camera, Player and Spawner attached to it. Not the nicest solution but it works. After the player chooses his rocket, I destroy the spawners on the inactives ones, so they dont work.
My problem is when exiting the scene and choosing a different rocket and repeating the process, the SpawningManager with all the references to all Spawners lost the references to them. Even though I reloaded the scene all references are still lost.
Sorry if this was hard to follow but it was hard to explain.
Here is a part of the code that destroys the spawners(represented by colors)
if (BlueSelected == true)
{
Destroy(RedSpawner);
Destroy(OrangeSpawner);
Destroy(YellowSpawner);
Destroy(GreenSpawner);
}
And a part of one of the planet spawner(represented by colors)
{
public Transform SpawnPointBlue, SpawnPointRed, SpawnPointOrange, SpawnPointYellow;
public GameObject Mercury;
// Checks if the Spawner is greater than null (There or not) and Instantiates the Object at the Players Position
public void SpawnMercury()
{
if(SpawnPointBlue != null)
{
Instantiate(Mercury, SpawnPointBlue.position, SpawnPointBlue.rotation);
}
if(SpawnPointRed != null)
{
Instantiate(Mercury, SpawnPointRed.position, SpawnPointRed.rotation);
}
if(SpawnPointOrange != null)
{
Instantiate(Mercury, SpawnPointOrange.position, SpawnPointOrange.rotation);
}
if(SpawnPointYellow != null)
{
Instantiate(Mercury, SpawnPointYellow.position, SpawnPointYellow.rotation);
}
If I understood well, your SpawnerManager is in "don't destroy on load" and keep existing between scenes. When you start your game you have referenced manually the spawners to the manager and everything is fine then when you go to another scene and come back where the spawners should be, there is no more references into the manager ?
If so, this seams normal to me, the references between scenes are not supported and when a scene is unloaded, the references disappear.
If I misunderstood something I would be glad to dig for the solution a bit
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);
}
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 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.)
Ok so I have this coroutine :
IEnumerator ShowCharTraits()
{
while(!hasPlayerChosen)
{
yield return null;
traitPanel.SetActive(true);
}
hasPlayerChosen = false;
traitPanel.SetActive(false);
// Debug.Log("Got called! job done");
}
It's being called like this from the awake method in my GameManager:
players = GameObject.FindGameObjectsWithTag("Player");
foreach (GameObject g in players)
{
ui_Controller.StartShowCharTraits();
g.GetComponent<PlayerToken>().isTurn = false;
}
StartShowCharTraits() is a simple method that does this :
public void StartShowCharTraits()
{
StartCoroutine("ShowCharTraits");
}
Now, I have checked the tags, no null reference exception, actually no errors or warnings are being thrown. If i load the scene in the editor and then play it everything works fine. traitPanel.SetActive(true); get called and my panel shows up. However when I load my scene from another scene using SceneManager.LoadScene(1); the above mentioned line is never reached. Any ideas why this is happening ?
Say you want to have one central place that is "like a singleton" in a Unity project. Example,
SoundEffects
LapTimer
Scores
SocialMediaConnections
All you do is this.
make your script SoundEffects.cs
recall that every Unity project must have a "preload" scene. (it's impossible to not have one)
in the preload scene, have a empty game object called "holder". make sure it is marked "DontDestroyOnLoad"
attach SoundEffects.cs to that holder
you're done.
there's just nothing more to it.
you're finished.
it's "just that simple"
So, any particular script, which happens to be attached to any particular object, in any particular scene, may need to access "SoundEffects"...
To do so, simply do this in Awake:
SoundEffects soundEffects = Object.FindObjectOfType<SoundEffects>();
then just use soundEffects anywhere in that script, for example soundEffects.PlayBoom(13) etc etc.
So in Awake()
Laps laps = Object.FindObjectOfType<Laps>();
Social social = Object.FindObjectOfType<Social>();
AI ai = Object.FindObjectOfType<AI>();
or whatever.
Unity is simple. Incredibly simple. It's just that easy.
write your script, LapTimer.cs or whatever
put it on a holder object in your preload scene (where else could it be?)
there's no "3", that's all there is. It's just that ridiculously simple.
Note that...
In the early days of Unity, someone unfortunately mentioned "singletons" on a QA board somewhere. (You can't have "singletons" in an ECS system, it's meaningless.) At the time, this led to huge discussions about how you can make a "singleton-like thingy" in Unity, which is piling confusion on confusion. Unfortunately from that day to this, you get people learning Unity, who see "singleton" mentioned here and there on the net, and it leads to endless confusion.
Once again, note that the idea of "managers" is just impossibly simple in Unity - explained above. It's trivial. It just couldn't be easier.
Note, above I mention you might want syntactic candy to avoid the incredible chore of typing Laps laps = Object.FindObjectOfType<Laps>();
There are very unfortunately no macros in Unity/c# so you need another way.
All you do is use a "Grid" script http://answers.unity3d.com/answers/1124859/view.html which has been popular for years in Unity.
But honestly, it's so simple to use Scores scores = Object.FindObjectOfType<Scores>(); that I usually just do that nowadays.
Ok how do I explain this. I have a singleton that acts as a data holder. While developing the scene with the game manager I had attached the singleton to the gamemanger object that hold a bunch of scripts. Now when I made the main menu I ofc added my singleton to it so I can carry info to the game scene and because of this my whole game manger object was being deleted. This is the culprit from the DataHolder :
void Awake()
{
if (instance == null)
instance = this;
else if (instance != this)
Destroy(gameObject);//This right here.
DontDestroyOnLoad(gameObject);
}
So I changed that line to Destroy(gameObject.GetComponent(instance.GetType()));