Acessing another script weird error

I have this in my code:

    void OnTriggerEnter(Collider other)
    {

        DamageController otherS = (DamageController)other.GetComponent(typeof(DamageController));
        otherS.HealthUp();
        
        RespawnManager _instance = FindObjectOfType(typeof(RespawnManager)) as RespawnManager;
        _instance.AddRespawnItem(_prefabIndex, _thisTransform.position, timeToRespawn, Time.time);
		Kill();
    }

Everything works, the health get power up, the object get Killed, everything works very well.
BUT, I always get this error in the console:

NullReferenceException: Object reference not set to an instance of an object
HealthPack.OnTriggerEnter (UnityEngine.Collider other) (at Assets/Sticks Carnage/Scripts/Collectible/HealthPack.cs:37)

This is the line of code:

 otherS.HealthUp();

I searched many times in the forum, and the answers, and in Google, and I dont found how to resolve this issue.

Someone knows what to do to stop this happening?

If I get about 20 errors like this, my other scripts stop working. Then, I need to resolve this.
And, is only this the error, no one other.

I would think that you are not assigning the health pack in the inspector.

This script is in the healthpack prefab, and the HealthUP() function is on the DamageController that is attached to the players.
I would think that you dont understood my problem.

What is your code on line 37?

Do you really read my first post?

what is otherS? Did you forget to define it?

Hard to say without seeing your hierarchy, but I gather its not actually finding the object based on the transform the collider is attached to. Defensive programming would look something like…

DamageController otherS = (DamageController)other.GetComponent(typeof(DamageController));
if(otherS != null)
{
//do stuff
}
else Debug.Log(“couldnt find it”);

If you see couldnt find it, you know its not attached to the same transform as the collider.

I would throw in some debugging code to make sure you have the right transform to start

Debug.Log(other.transform.name);

I would then look at doing a more comprehensive search to see if you can actually find it…

other.transform.root.GetComponentInChildren( … );

There is the problem, because all works. The function on my character is executed. Then, finding the right script it is.
If not, it will not add health to the right player. The unique weird thing, is that all works, but shows that message error.

Someone?

You’re sure its always a player colliding with the healthbox?

The only logical answer is the thing you think is colliding is not the thing actually colliding…

maybe its spawning another healthbox in the same spot and its triggering.

without more information, youre not going to get an answer

I agree with JamesLeeNZ. Your script works because your trigger is colliding with your health box and runs your code fine, but it must also be colliding with something else (perhaps you have multiple colliders on your object?). If you do not check that otherS != null before you call otherS.HealthUp();, then you’re going to get that message if ANYTHING but your health box collides with the trigger because it can’t find DamageController on the colliding object.

DamageController otherS = (DamageController)other.GetComponent(typeof(DamageController));
 if(otherS == null) return;

Also, don’t forget Object.Destroy() does not happen immediately. (I assume Kill() issues this command.) According to the docs “Actual object destruction is always delayed until after the current Update loop, but will always be done before rendering.” There is the remote possibility that your OnTriggerEnter may be called multiple times before destruction takes place if it collides with many colliders in the same update. (I actually use this effect to allow a bullet to hit multiple stacked enemies at once before it dies.) You might want to add a boolean value to prevent that from happening:

private bool alive = true;

void OnTriggerEnter(Collider other) {
    if(!alive) return; // skip out if colliding after already destroyed
    
    DamageController otherS = (DamageController)other.GetComponent(typeof(DamageController));
    if(otherS == null) return;
    
    otherS.HealthUp();
    ...
    Kill();
}

private void Kill() {
   alive = false;
   ...
}

If you absolutely need to destroy something instantly, you must use Object.DestroyImmediate() instead. (The docs warn it should only be used in the editor, but it does work in-game too.)

OEEE, solved the problem. Thank you very much for the “light”!
In the physics, I’m controlling to just the characters and the healthpack to collide.
Changed from OnTriggerEnter to OnTriggerStay;
Filtered if the tag of the collider gameobject is a player or an enemy/bot;
Putted the logic that you guys said;

void OnTriggerStay(Collider other)
    {
		if(other.gameObject.tag == "Player" || other.gameObject.tag == "Enemy"){
			DamageController otherS = (DamageController)other.GetComponent(typeof(DamageController));
		
			if(otherS != null)
			{
			    otherS.HealthUp();
        		RespawnManager _instance = FindObjectOfType(typeof(RespawnManager)) as RespawnManager;
        		_instance.AddRespawnItem(_prefabIndex, _thisTransform.position, timeToRespawn, Time.time);
		        Kill();
			}
			else Debug.Log("couldnt find it");
		}
    }

The error stopped, and all works very well!
Thanks again!

About the Kill(), it is a function of my object pool manager. It dont destroy the item, just deactive it.

How I change the name of this thread to [SOLVED]?

This little text made me understand what was happening. My characters have 2 colliders, one in the head and another character controller.

Glad you got it figured out!

I don’t think you can. You can edit the first post and add SOLVED to the top or something. That’s usually what I do.

One more thing, calling FindObjectOfType is very slow as it mentions in the docs. The docs suggest using a Singleton pattern. The way I do it is to create a manager class that contains static fields with references to my other managers. I access all my managers by typing GameManager.objectManager.DoSomething(); My setup isn’t really super optimal since I did it a long time ago when I was less experienced, but I have one gameobject in the world with all my manager scripts attached to it. The main one, GameManager gets all the others by running GetComponent on Awake and filling the static fields. Running this on awake caused me a lot of issues with script execution order, but since I did this they added the ability to customize your script execution order in the editor so its easy now. I didn’t really need for most of my managers to be MonoBehaviours so I could have just made them regular classes and instanced them directly in GameManager, but if you want to drag and drop things into variables on your managers and they’re already MonoBehaviours, this setup might work well.)

@guavaman you’re the man!
I’m using echo17’s Swarm Object Manager, and he uses singleton to the Main Monobehavior. But I dont figured out in use it.
I will try this.

Living and learning. :slight_smile:
Thank you very much again!

(http://forum.unity3d.com/threads/99361-Swarm-Object-Manager)