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.

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;

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.

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

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