Accessing container gameObject from component gameObject - c#

I created a GameObject and named it "sensor". I then added a BoxCollider and a script (script_sensor) to sensor.
Then I created another GameObject and named it "taxi". I added a script (script_taxi) to taxi and created a public Collider2D in the script.
Then I assigned the sensor GameObject to taxi's public Collider2D.
And now, i want to access script_taxi from script_sensor.
Basically, How can i access script_taxi (Box 1 on the image), from script_sensor (Box 2)?
Check the image to understand better.
Ps: When i spam taxi prefabs, every sensor object should be able to find it's own container gameobject(taxi).

If you want to access script_taxi from script_sensor, you need some type of reference to script_taxi inside script_sensor. You can then use GetComponent. You could also use a variation of GameObject.Find, however these calls can be expensive.
public class script_sensor : MonoBehavior {
[SerializeField]
private GameObject taxi;
private script_taxi taxiScript;
void Start() {
taxiScript = taxi.GetComponent<script_taxi>();
}
}
Also it is recommended to follow C# naming conventions.
script_sensor => Sensor
script_taxi => Taxi
public Collider2D col; => [SerializeField] private Collider2D col;

Or with GameObject.Find() to find the taxi GameObject like this:
script_taxi taxi;
void Awake()
{
taxi = GameObject.FindWith("taxi").GetComponent<script_taxi>();
}

Related

Assign gameObject of a script via another script?

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;
}

Can someone explain how i can just call for ridgedbody2d with this code?

so I have a script calling from another class, I'm wondering how I can write this to only destroy the ridgedbody 2d. I know that it will keep the sprite in scene which is what I'm looking for.
private void OnTriggerEnter2D(Collider2D other)
{
DamageDealer damageDealer = other.gameObject.GetComponent<DamageDealer>();
health -= damageDealer.GetDamage();
}
If you pass in a Component reference to Destroy it will only destroy the according component but keep the rest of the GameObject untouched
The object obj will be destroyed now or if a time is specified t seconds from now. If obj is a Component it will remove the component from the GameObject and destroy it. If obj is a GameObject it will destroy the GameObject, all its components and all transform children of the GameObject.
Destroy(damageDealer.GetComponnet<Rigidbody2D>());
If you do this quite often it might be better to store this reference already in Awake of the DamageDealer component and later pass it on like
public class DamageDealer : MonoBehaviour
{
// if possible already reference this via the Inspector
[SerializeField] private Rigidbody2D rigidbody;
// This is a read-only property returning the value of rigidbody
public Rigidbody2D Rigidbody => rigidbody;
private void Awake()
{
if(!rigidbody) rigidbody = GetComponnet<Rigidbody2D>();
...
}
...
}
then later you can simply do
Destroy(damageDealer.Rigidbody);

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>();

How to call a public static variable from another class, change its value and then check that its changed from its original class [duplicate]

So im trying to change a variable in another script by touching a cube.
Current setup
1x Player
1x Enemy
Each with their own script Enemy_Stats & Character_Stats
As you can see in this little snippet it's quite a workaround to access the variable from another script.
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Enemy")
{
collision.gameObject.GetComponent<Enemy_Stats>().Health =
collision.gameObject.GetComponent<Enemy_Stats>().Health
- gameObject.GetComponent<Character_Stats>().AttackDamage;
if (collision.gameObject.GetComponent<Enemy_Stats>().Health <= 0)
{
Destroy(collision.gameObject);
}
}
}
Iam new to Unity, but isn't there a way to just refer it with something like:
collision.Health?
How to access variables/functions from another Class. The variable or function you want to access or called must be public not private.
public class ScriptA : MonoBehaviour{
public int playerScore = 0;
void Start()
{
}
public void doSomething()
{
}
}
Access variable playerScore in ScriptA from ScriptB. First, find the GameObject that the script or component is attached to with the GameObject.Find function then use the GetComponent function to retrieve that script or component that is attached to it.
public class ScriptB : MonoBehaviour{
ScriptA scriptInstance = null;
void Start()
{
GameObject tempObj = GameObject.Find("NameOfGameObjectScriptAIsAttachedTo");
scriptInstance = tempObj.GetComponent<ScriptA>();
//Access playerScore variable from ScriptA
scriptInstance.playerScore = 5;
//Call doSomething() function from ScriptA
scriptInstance.doSomething();
}
}
No since Health is not part of the collision object, but Enemy_Stats. You can cache a Component (that's what Enemy_Stats is) if you use it multiple times to save you some typing (and some performance, but that is rather marginal for this example). Also you can cache "known" components like in this case Player_Stats. You can do this e.g. in Start or with a public variable and the inspector.
What you should probably do though is to make the enemy be responsible for his life and not the player, so move the Destroy-part to Enemy_Stats (into the Health property to be exact).
The first thing to make this shorter (and eventually faster) would be to store this: gameObject.GetComponent<Character_Stats>() on Start() in a private variable (you should avoid calling GetComponent on a frequent basis if you can avoid it).
For the Health variable, a way of avoiding GetComponent calls could be caching: you create a Dictionary<GameObject, Enemy_Stats> and read from that as soon as this gameobject collided once
At the very beginning i mean in Awake() method you can find a game-object with tag
and get it's Heath after that in Collision() method you should just decrease the health but, here the condition is there is only one enemy and only one player.

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