Assessing variables from other scripts using an accessor seems inelegant. Please explain.

As near as I can tell based on this reference…
Referencing non static variables from another script? C#
… the following code below is how I have to access variables ( members public or private ) from one script via another script.

Notice that I make another class inside my EnemyControl script to access the health from EnemyControl, even though health is public. Also I have to set my accessor method “updateHealth” to static to resolve a compiler error (An object reference is required to access non-static member).

My question is, is this the correct way to do this? It seems a little cludgy/hacky.

Here’s my calling code…

    // detect collisions
 	void OnCollisionEnter(Collision collision) 
	{
    	if (collision.gameObject.name == "Enemy")
		{
			// add to score
			HudManager.addToScore(10);
			
			// modify enemy health
			Accessor enemyScript = collision.gameObject.GetComponent<Accessor>();
			Accessor.updateHealth(-1, collision.gameObject);
			
			// kill off bullet
			Destroy (this.gameObject);
			
		}
	}

Here’s the accessor code.

using UnityEngine;
using System.Collections;

public class EnemyControl : MonoBehaviour {
	
	public int health = 100;

	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
		
	}
	
	
	
}

public class Accessor : MonoBehaviour {
	
    // update health
	public static void updateHealth( int val, GameObject which )
	{
		which.GetComponent<EnemyControl>().health -= val;
		Debug.Log ("Enemy takes a hit");
	}
}

As an aside, HudManager.addToScore() was done using static members and declaring the method static as well. I was okay with this because HudManager is a singleton but I need EnemyControl to work on instances of the enemies as they spawn. Here’s the HudManager code anyway… ( for the sake of search engines this code shows how to fire projectiles at the enemy and detect collisions with the enemy ) I’m also using NGUI for the HUDs.

using UnityEngine;
using System.Collections;

public class HudManager : MonoBehaviour {
	
	public static int ammo = 256;
	public float bulletSpeed = 11;
	public static int score = 1;
	public GameObject projectile;
	
	private static UIBaseLabel ammoText;
	private static UIBaseLabel scoreText;
	
	
	
	// Use this for initialization
	void Start () {
		
		// initial update UI
		ammoText = GameObject.Find ("AmmoLabel").GetComponent<UIBaseLabel>();
		ammoText.text = "Ammo:" + ammo;
		
		// initial update UI
		scoreText = GameObject.Find ("ScoreLabel").GetComponent<UIBaseLabel>();
		scoreText.text = "Score:" + score;
	}
	
	// Update is called once per frame
	void Update () {
		
		// check for firing
		if (Input.GetMouseButtonDown(0))
		{
			// reduce ammo counter
			if ( ammo > 0)
			{
				ammo -= 1;
			
				// update ammo counter
				ammoText.text = "Ammo:" + ammo;
				
				// Instantiate the projectile at the position and rotation of this transform
			    GameObject gunNozzle = GameObject.Find("Nozzle");
				GameObject clone = Instantiate(projectile, gunNozzle.transform.position, gunNozzle.transform.rotation) as GameObject;
		    	
				// Add force to the cloned object in the object's forward direction
			    clone.gameObject.AddComponent<Rigidbody>();
			    clone.rigidbody.mass = 0.1f;
			    clone.rigidbody.useGravity = false;
			    clone.rigidbody.AddForce(clone.transform.forward * bulletSpeed);
			    
				// attach script
			    clone.gameObject.AddComponent("projectileController");
			}
		}
	
	}
	public static void addToScore(int val)
	{
		// increment score by amount
		score += val;
		
		// update UI
		scoreText.text = "Score:" + score;
	}
}

Why the “Accessor” class? Why not just put UpdateHealth() inside your EnemyControl class? UpdateHealth would not be static inside of the EnemyControlClass, and it would be tied to the instance of the class (and therefore the game object). Then you could do something like:

EnemyControl enemyScript = collision.gameObject.GetComponent<EnemyControl>();
if (enemyScript != null)
    enemyScript.updateHealth(-1);

Thanks for you help. Aww - man, now I understand. When I did this yesterday as you explained it gave me the error “An object reference is required to access non-static member”.

It was because I called it explicitly…
EnemyControl.updateHealth(-1);
… which is not allowed (not sure why).

So theoretically the HudManager should work the same. Now I get it :smiley:

This the object reference that is needed to access a non-static member…

HudManager hudScript = GameObject.Find(“Player”).GetComponent(); because HudManager is sitting on Player.

So then I can call…
hudScript.addToScore(10);

All sorted and now I understand - except, why do they have to be referenced and not be able to be called explicitly?

Actually I think I understand now. All scripts tend to be put on an instance of an object, so you need to reference the component attached to that object to get the actual instance of the script. The only way for something to be accessed directly, ie HudManager.addToScore is to make it singleton and make all the method static.