Assign gameObject of a script via another script? - c#

How do I assign a gameObject of one script through another script's gameObject? For example;
Script_1
public class Script_1 : MonoBehaviour
{
public OVRScript OVR;
}
Script_2
public class Script_2 : MonoBehaviour
{
private Script_1 src_1;
public GameObject Front;
void Start()
{
src_1 = (Script_1) GameObject.FindObjectOfType(typeof(Script_1));
src_1.GetComponent<OVRScript >().OVR = Front //I am facing problem here
}
}
Both GameObjects "OVR" and "Front" contain the OVRScript

src_1.GetComponent<OVRScript>().OVR = Front.GetComponent<OVRScript>().OVR;

I don't know or see the OVRScript class but isn't OVR rather a member of Script_1?
And then you would want to use GetComponent on the Front in order to get a component attached to it.
// If possible rather drag your Script_1 in here directly via the Inspector
[SeializeField] private Script_1 src_1;
void Start()
{
// Now I would use find only as fallback
if(!scr_1) src_1 = GameObject.FindObjectOfType<Script_1>();
// then you want to assign the OVR field of the 'src_1' of type 'Script_1'
// and not use 'src_1.GetComponent<OVRScript>()' which would return
// the reference of an 'OVRScript' component attached to the same GameObject as the Script_1
//
// And you want to fill it with the reference of an 'OVRScript' attached to 'Front'
src_1.OVR = Front.GetComponent<OVRScript>();
}
(see [SerializeField])
It would be even better if you directly define
public OVRScript Front;
now if you drag in a GameObject it a) is checked if this GameObject actually has a OVRScript attached, otherwise you can't drop it and b) instead of the GameObject reference already the OVRScript reference is serialized and stored so there is no need for GetComponent anymore:
[SeializeField] private Script_1 src_1;
public OVRScript Front;
void Start()
{
// Now I would use find only as fallback
if(!scr_1) src_1 = GameObject.FindObjectOfType<Script_1>();
src_1.OVR = Front;
}

Related

Create a reference to a gameobject based on a raycast hit

I want to create a reference to an instance of a game object based on if a raycast hits a specific game object. In this case, its called "resource". Once I have click the gameobject I want to create an object of type ResourceSource that holds all variables and methods of that specific gameObject.
E.g i click the gameobject. A varaible is created
ResourceSource resource = hit.collider.gameObject.GetComponent<ResourceSource>();
Obviously, I cant just create a new object as that will just be a copy so if I make any changes to the gameobject the original won't be affected.
ResourceSource class
public class ResourceSource : MonoBehaviour
{
public ResourceType type;
public int quantity;
public UnityEvent onQuantityChange;
Cooldown cooldown;
public Vector3 GetPositon()
{
return gameObject.transform.position;
}
}
The method i want to create the reference
void CheckIfResource(RaycastHit hit)
{
if (hit.collider.gameObject.tag == "Resource")
{
//Want to create something like this
ResourceSource resourcePosition = hit.collider.gameObject.GetComponent<ResourceSource>();
}
}
Still somewhat new to unity so any help is appreciated :)
ResourceSource resource;
resource = hit.collider.gameObject.GetComponent<ResourceSource>();

GameObject in SerializedField - OverRide - Apply All: Prefab Doesn't Update

I added a script to my prefab. Then I put my prefab into my scene and drag/dropped the GameObjects into the appropriate fields within the inspector. I then clicked OverRides>>Apply All. (Which is common and I do this all of the time)
However, the game object I'm using for the Spawn Zone when the Game Object will be Instantiated will not apply to my Prefab. (The Prefab in the scene does have the Empty Game Object attached but not the main Prefab in the Project panel)
I'm using the same method that I use for Instantiating bullets but for some unknown reason the Project view prefab will say "None(GameObject)"
Here's the code:
[SerializeField]
private GameObject boss;
[SerializeField]
private float bossSpd;
[SerializeField]
private GameObject bossSpawnZone1; // This won't apply to my prefab in Project panel
private void Update()
{
if(startBoss == true)//StartBoss occurs when a GameObject is touched by player on another script. Just OnTriggerEnter2D set var to true
{
GetTheBoss();
}
}
void GetTheBoss()
{
Instantiate(boss, bossSpawnZone1.transform.position, Quaternion.identity);
startBoss = false;
}
I would include pics but I don't know how to upload them in here. Never used the IMG URL before. But trust me, I inserted the empty gameobject(SpawnZone) into the field. I also used the override to apply all. Yet the spawn zone field remains empty.
What I've tried:
1) Removing the script and re-adding it then filling the fields again.
2) Made the spawn zone public static and tried using GameObject.Find("PirateSpawnZone") in another script pertaining to the player.
3) Changing the variable name and saving the script.
4) Restarting Unity / Restarted computer completely then open Unity back up.
You can not have Scene references in a prefab. It is not possible. It only works for GameObject reference that are themselves a prefab living in the asset or references within one and the same prefab hierarchy.
However some workarounds exist
dependency injection
using dependency injection (e.g. Zenject)
ScriptableObject references
a ScriptableObject for setting the reference on scene start and referencing the ScriptableObject instead.
[CreateAssetMenu(filename = "new GameObjectReference", menuName = "ScriptableObject/GameObjectReference")]
public GameObjectReference : ScriptableObject
{
public GameObject value;
}
Create an Asset by right click in the Assets &rightarrow; Create &rightarrow; ScriptableObject &rightarrow; GameObjectReference
Then change your script field to
[SerializeField] private GameObjectReference bossSpawnZone1;
and everywhere where you use it use bossSpawnZone1.value instead.
This works now since the ScriptableObject instance itself lives in the Assets.
Then finally you need the setter component on the bossSpawnZone1 GameObject like
public GameObjectReferenceSetter : MonoBehaviour
{
[SerializeField] private GameObject scriptableAsset;
private void Awake()
{
scriptableAsset.value = gameObject;
}
}
Singleton pattern
having only the setter and making a public static reference (only works if there is only exactly one of those reference in the entire scene/game
public class SpawnZoneReference : MonoBehaviour
{
public static GameObject instance;
private void Awake ()
{
instance = gameObject;
}
}
And in your script instead use
Instantiate(boss, SpawnZoneReference.instance.transform.position, Quaternion.identity);
Or very similar using only a certain type like
public class BossSpawnZone : MonoBehaviour { }
On the GameObject and in your script do
bossSpawnZone1 = FindObjectOfType<BossSpawnZone>();

Instantiated prefab should call a function from the main script?

I want something like this.
ComponentTest.cs - This script is attached to a empty game object in the scene.
public class ComponentTest : MonoBehaviour {
public GameObject boxPrefab;
void Start () {
GameObject temp = Instantiate(boxPrefab, new Vector3(0,0,0), Quaternion.identity) as GameObject;
temp.GetComponent<PrefabBox> ().go = gameObject.GetComponent<ComponentTest>().Yes();
}
public void Yes(){
print("yes");
}
}
and PrefabBox.cs - This script is attached to the prefab.
public class PrefabBox : MonoBehaviour {
public GameObject go;
void Start () {
go ();
}
}
I get this as error:
The member `PrefabBox.go' cannot be used as method or delegate
First of all, the go object is declared as a GameObject but then you assign a function to it and then call it like a function.
It looks like you want Closures in which you can store functions to variables and call them in the way you do.
This post covers it: http://answers.unity3d.com/questions/494640/capturing-a-variable-in-a-closure-behaves-differen.html
Seems the data type needs to be Action but best to read up on it to grasp it properly.
Good luck.

Why is transform.parent null in Awake() and Start()?

I'm trying to get a reference to the GameObject that the script is attached to. Per docs transform.parent.gameObject is used for this but transform.parent is null in both Awake() and Start(). What do I need to do to get this working? This is probably a total noob question but Google didn't come up with a working answer so far.
using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour
{
private void Awake()
{
var obj = transform.parent;
Debug.Log(obj);
}
private void Start()
{
var obj = transform.parent;
Debug.Log(obj);
}
}
Nevermind! I'm an idiot! It shouldn't be parent but:
var obj = transform or var obj = transform.gameObject
since this script is part of the game object which it should refer to, not any parent. I had the strange assumption that a script is a child of a game object.
Transform.parent tells you what the parent of your current transform is. I.E. if GameObjectA is a child of GameObjectB, a script that accesses transform.gameObject in GameObjectB will return GameObjectA
What you're looking for, in fact, is just gameObject. This implicitly returns the gameObject your script is attached to.
Create two GameObjects in your scene.
Call one GameObjectA, and the other GameObjectB.
Attach this script to GameObjectB and then drag GameObjectB to be under GameObjectA in the hierarchy
public class ExampleBehaviour : MonoBehaviour {
void Awake () {
Debug.Log(gameObject.name); //Prints "GameObjectB" to the console
Debug.Log(transform.parent.name); //Prints "GameObjectA" to the console
}
}

How do I pass variable from one script to another C# Unity 2D?

For example I have a variable (public static float currentLife) in script "HealthBarGUI1" and I want to use this variable in another script.
How do I pass variable from one script to another C# Unity 2D?
You could do something like this, because currentLife is more related to the player than to the gui:
class Player {
private int currentLife = 100;
public int CurrentLife {
get { return currentLife; }
set { currentLife = value; }
}
}
And your HealthBar could access the currentLife in two ways.
1) Use a public variable from type GameObject where you just drag'n'drop your Player from the Hierarchy into the new field on your script component in the inspector.
class HealthBarGUI1 {
public GameObject player;
private Player playerScript;
void Start() {
playerScript = (Player)player.GetComponent(typeof(Player));
Debug.Log(playerscript.CurrentLife);
}
}
2) The automatic way is achieved through the use of find. It's a little slower but if not used too often, it's okay.
class HealthBarGUI1 {
private Player player;
void Start() {
player = (Player)GameObject.Find("NameOfYourPlayerObject").GetComponent(typeof(Player));
Debug.Log(player.CurrentLife);
}
}
I wouldn't make the currentLife variable of your player or any other creature static. That would mean, that all instances of such an object share the same currentLife. But I guess they all have their own life value, right?
In object orientation most variables should be private, for security and simplicity reasons. They can then be made accessible trough the use of getter and setter methods.
What I meant by the top sentence, is that you also would like to group things in oop in a very natural way. The player has a life value? Write into the player class! Afterwards you can make the value accessible for other objects.
Sources:
https://www.youtube.com/watch?v=46ZjAwBF2T8
http://docs.unity3d.com/Documentation/ScriptReference/GameObject.Find.html
http://docs.unity3d.com/Documentation/ScriptReference/GameObject.GetComponent.html
You can just access it with:
HealthBarGUI1.currentLife
I'm assuming that HealthBarGUI1 is the name of your MonoBehaviour script.
If your variable is not static and the 2 scripts are located on the same GameObject you can do something like this:
gameObject.GetComponent<HealthBarGUI1>().varname;
//Drag your object that includes the HealthBarGUI1 script to yourSceondObject place in the inspector.
public GameObject yourSecondObject;
class yourScript{
//Declare your var and set it to your var from the second script.
float Name = yourSecondObject.GetComponent<HealthBarGUI1>().currentLife;
}
TRY THIS!
//Drag your object that includes the HealthBarGUI1 script to yourSceondObject place in the inspector.
public GameObject yourSecondObject;
class yourScript{
//Declare your var and set it to your var from the second script.
float Name = yourSecondObject.GetComponent<HealthBarGUI1>().currentLife;

Categories