- Home /
Troubles with accessing other variables in other scripts on other Gameobjects
Hi, as the title suggests I am having troubles with accessing other variables in other scripts on other GameObjects. I have a player script for the health of my player(playerShield) and another script for enemy damage(EnemyScript). What I would like to happen is when the player hits the enemy collider the player takes damage. But the reverse happens, the player doesn't take any damage and it comes up with this error: NullReferenceException: Object reference not set to an instance of an object EnemyScript.Damage () (at Assets/Scripts/AI/EnemyScript.cs:73).
When I click on the error it directs me to line 73 on the EnemyScript.
Here is my EnemyScript:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class EnemyScript : MonoBehaviour
{
public float enemyShield;
public DestroyRange destroyRadius;
public PlayerShield shieldValue;
public GameObject player;
public Text EnemyHealth;
public GameObject enemy;
public bool random = true;
public bool damage = false;
public bool textTrigger = true;
public float damageAmount;
void Awake ()
{
if(random == true)
{
enemyShield = Random.Range( 0.1f, 6.0f );
}
shieldValue = GetComponent<PlayerShield>();
destroyRadius = GetComponent<DestroyRange>();
Debug.Log("Enemy Spawned!!!");
}
// Update is called once per frame
void Update ()
{
if(textTrigger == true)
{
EnemyHealth.text = enemyShield.ToString();
}
enemyShield = Mathf.Round(enemyShield * 10f) / 10f;
}
private GameObject GetGameObject()
{
return gameObject;
}
void OnTriggerEnter2D(Collider2D other)
{
Debug.Log("Enemy Hit!!!");
if(other.CompareTag("Player"))
{
Debug.Log("Enemy Hit Player!!!");
if(damage == true)
{
Debug.Log("Damage = true");
Invoke("Damage", 0.1f);
}
if(other.gameObject.GetComponent<PlayerShield>().shieldValue > enemyShield)
{
Destroy(enemy);
Debug.Log("Enemy Destroyed!!!");
}
}
}
void Damage()
{
Debug.Log("Damage invoked!!");
transform.Find("Player").GetComponent<PlayerShield>().shieldValue = transform.Find("Player").GetComponent<PlayerShield>().shieldValue - damageAmount;
Invoke("DamageTrue", 3.0f);
Debug.LogError("ERROR: Damage Invoke didn't Cancel.");
}
void DamageTrue()
{
damage = false;
CancelInvoke("Damage");
CancelInvoke("DamageTrue");
}
}
And here is the PlayerShield script:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using Image=UnityEngine.UI.Image;
public class PlayerShield : MonoBehaviour
{
public float maxShields = 5.0f;
public float shieldValue = 1.0f;
public float powerUpValue = 0.1f;
public float enemyPowerUpValue;
public float pHealth;
public bool objective;
public Image Healthbar;
public Text shieldNumber;
public EnemyScript enemyShield;
public EnemyScript damage;
public void start()
{
objective = false;
shieldValue = 1.0f;
enemyShield = GetComponent<EnemyScript>();
damage = GetComponent<EnemyScript>();
}
void Update()
{
if(shieldValue == 5.0f)
{
objective = true;
Debug.Log("shieldValue = 5.0f");
}
pHealth = shieldValue / maxShields;
Healthbar.fillAmount = pHealth;
shieldNumber.text = shieldValue.ToString();
if(shieldValue > maxShields)
{
shieldValue = maxShields;
}
if(shieldValue <= 0)
{
Invoke("Respawn", 0.1f);
}
shieldValue = Mathf.Round(shieldValue * 10f) / 10f;
}
void OnTriggerEnter2D(Collider2D other)
{
if(other.CompareTag("PowerUp"))
{
shieldValue = shieldValue + powerUpValue;
Debug.Log("you got a power UP!");
}
if(other.CompareTag("Enemy"))
{
if(other.gameObject.GetComponent<EnemyScript>().enemyShield > shieldValue)
{
if(other.gameObject.GetComponent<EnemyScript>().damage == false)
{
Invoke("Respawn", 0.1f);
Debug.Log("Player Destroyed!!!");
}
}
if(other.gameObject.GetComponent<EnemyScript>().enemyShield < shieldValue)
{
shieldValue = shieldValue + enemyPowerUpValue;
}
}
}
void Respawn()
{
Application.LoadLevel(Application.loadedLevel);
}
}
Any form of help is greatly appreciated and thankyou in advance.
In what context do I put that code in? I tried replacing this: void Damage() { Debug.Log("Damage invoked!!");
transform.Find("Player").GetComponent<PlayerShield>().shieldValue = transform.Find("Player").GetComponent<PlayerShield>().shieldValue - damageAmount;
Invoke("DamageTrue", 3.0f);
Debug.LogError("ERROR: Damage Invoke didn't Cancel.");
}
with this:
void Damage()
{
Debug.Log("Damage invoked!!");
FindObjectOfType<"PlayerShield">()."shieldValue" = FindObjectOfType<"playerShield">()."shieldValue" - damageAmount;
Invoke("DamageTrue", 3.0f);
Debug.LogError("ERROR: Damage Invoke didn't Cancel.");
}
but it comes up with this error: Assets/Scripts/AI/EnemyScript.cs(77,35): error CS1525: Unexpected symbol `)'
Answer by bobisgod234 · Apr 24, 2017 at 02:31 AM
transform.find will only find objects that are a child of that transform, and I doubt that the player is a child of a component called "EnemyScript". Use GameObject.Find instead of transform.find
I would also suggest breaking up the problematic line to make it easier to debug.
GameObject.Find("Player").GetComponent<PlayerShield>().shieldValue = GameObject.Find("Player").GetComponent<PlayerShield>().shieldValue - damageAmount;
Would become:
GameObject player = GameObject.Find("Player");
PlayerShield playerShield = player.GetComponent<PlayerShield>();
playerShield.shieldValue -= damageAmmount;
However, Gameobject.find is very slow, and I would strongly suggest comming up with some other solution to getting player scripts e.g. by using the player's collider2d.
Thank you so much it worked although with one side effect, the damage is doubled but I can work around that by halving the damage amount.
Answer by LoneWolfSwat · Apr 25, 2017 at 02:37 PM
Your error is: The game can't find the player's script. You can fix this in your enemy script: Add a new float variable: "ShieldValue"
//this must be updated every frame (So put it on Update function)
ShieldValue = GameObject.FindObjectOfType<PlayerShield>().shieldValue;
//this can't be updated every frame, so this must be on your OnTriggerEnter2D funtion.
GameObject.FindObjectOfType<PlayerShield>().shieldValue = ShieldValue -= damageAmount;
Instead of what you've done:
transform.Find("Player").GetComponent<PlayerShield>().shieldValue =transform.Find("Player").GetComponent<PlayerShield>().shieldValue - damageAmount;
Answer by sdclark79 · Apr 24, 2017 at 07:52 AM
Your problem is the lower-case transform.Find you are using. First, lower-case transform refers to the transform of the current object (upper-case Transform would mean another object). You should be using GameObject.Find (not to be confused with gameObject, which again would refer to your current object). So line73 in your first script should be something like:
GameObject.Find("Player").GetComponent<YourComponent>();
Answer by Eno-Khaon · Apr 24, 2017 at 02:53 AM
You're likely seeing a problem with your use of "Transform.Find()" -- More specifically, the problem is that you're using it at all in this case. Transform.Find() is intended to search for children of your GameObject's Transform. Since you're looking for a different GameObject entirely, you would normally use something like "GameObject.Find()" or "GameObject.FindWithTag()" instead.
However, that's not actually a solution to the problem. That simply mitigates the symptoms.
The real problem comes from not making use of information you have available.
Let's use "OnTriggerEnter2D()" as an example. When it's called, it's passing through more information (Namely, Collider2D other). You check whether it's the player that you hit, then you attempt to damage the player... and throw out all the useful information you had in the process.
void OnTriggerEnter2D(Collider2D other)
{
// ...
if(other.CompareTag("Player"))
{
PlayerShield playerShield = other.GetComponent<PlayerShield>();
// Just to be sure, verify that it exists
if(playerShield != null)
{
DamagePlayer(player, damageAmount);
}
else
{
Debug.LogError("ERROR: Target with tag \"Player\" does not have PlayerShield attached to it.");
}
}
// ...
}
public void DamagePlayer(PlayerShield player, float damageAmount)
{
player.shieldValue -= damageAmount;
}
Additionally, the way your Awake() function is set up, your player and enemies have inner conflicts. They look to themselves in lines such as...
enemyShield = GetComponent<EnemyScript>();
... rather than getting information about another GameObject. With everything arranged more cleanly, however, you won't need those at all, since you get up-to-date information from OnTriggerEnter2D().
Further notes: To improve the flow of damage being dealt, you might consider converting health/shield values into Properties. That way, you can check immediately upon dealing damage whether they're dead.
For example, in the PlayerShield script...
private float _shieldValue = 1.0f;
public float shieldValue
{
get
{
return _shieldValue;
}
set
{
_shieldValue = value;
if(_shieldValue <= 0.0f)
{
// You are dead.
Respawn();
}
}
}
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Change the alpha of a gameobject with multiple childs 1 Answer
HoloLens - Smooth Rotation doesn't work 0 Answers
Setting gameobject to null 1 Answer