I’m continuing cleaning up some of my scripts, and I’m little stuck at a part that sometimes causes nullreference errors. I’d like to fix them, but it seems like I can’t find how, I’ve tried many things.
So this script is for a projectile, which is destroyed and deals damage on impact. When it hits an enemy, it also displays a number on the screen showing how much damage it did. DmgIndicator is another script that creates these number pop-ups, but needs a 2d position on the screen for where the number needs to appear. So in this script, after a collision, I use WorldToScreenPoint to turn the 3d impact location into a 2d position. That part sometimes causes errors, in fact about 15% of the projectiles cause this error, which is a lot. When I use pause on error, I can see in the debug inspector that the projectile, at the moment of the collision, properly does damage, and receives the impactpos, but the textpos is still at 0,0. I’ve tried changing the colliders, speed of the projectile, the order of the code in the script (which actually properly destroys the projectile now, instead of having it bounce off), but that doesn’t seem to make a difference.
using UnityEngine;
using System.Collections;
public class DestroyProjectile : MonoBehaviour {
public int projectileDamage;
GameObject hitObject;
EnemyGeneral enemyGeneral;
TurretGeneral turretGeneral;
public GameObject impactEffect;
public int projectileLifeTime = 10;
Vector3 impactPos;
Vector2 textPos;
DmgIndicator dmgIndicator;
void Start (){
dmgIndicator = GameObject.FindGameObjectWithTag("GameController").GetComponent<DmgIndicator>();
}
void OnCollisionEnter (Collision collision)
{
if(collision.gameObject.tag == "Enemy"){
hitObject = collision.gameObject;
Debug.Log ("enemy hit");
enemyGeneral = hitObject.GetComponent<EnemyGeneral>() ;
enemyGeneral.currentEnemyHealth -= projectileDamage;
Instantiate(impactEffect, transform.position, Quaternion.identity);
Destroy(gameObject);
impactPos = collision.transform.position;
textPos = Camera.current.WorldToScreenPoint(impactPos); //error points at this line
dmgIndicator.PopUpDmg(projectileDamage, textPos);
}
You can’t use Camera.current in a context where the camera is not known. If a collision happens, Unity hasn’t a current camera. You need to get the camera somehow else, e.g. by using a manager script.
I"m using camera.current because I have quite a few cameras which you can cycle trough.
The thing is, it works 85% of the time (I guess you also didn’t fully read my explanation ) , and I make sure I only have only one camera component active in the scene.
So the camera is known, but not always? I guess I could try to use a manger script, but I want to know if it would the correct solution.
I guess I read the explanation. It doesn’t matter at the end of the day how often it works, it is pretty clear that Camera.current is not always set. You can solve that by making sure you have the reference to the current camera somewhere else, like in a manager class. This will most likely solve it in the remaining 15%. If not, there is an issue that you are not properly setting the camera.
Alright fixed it by adding some public camera variable that updates every time the camera switches to an existing script. Not a single error anymore. You have my thanks.
Though caching your own Camera is better for performance, you were probably wishing to use Camera.main rather than Camera.current.
Main gets you the first active camera tagged maincamera.
Current gives you the current camera being rendered to during the special Camera callback messages like OnPreRender etc.
Scissored from the manual:
Camera.main:
The first enabled camera tagged “MainCamera” (Read Only).
Returns null if there is no such camera in the scene.
Camera.current:
The camera we are currently rendering with, for low-level render control only (Read Only).
Most of the time you will want to use Camera.main instead. Use this function only when implementing one of the following events: MonoBehaviour.OnRenderImage, MonoBehaviour.OnPreRender, MonoBehaviour.OnPostRender.
As you can tell, Camera.current should not be used in OnCollisionEnter.
Does it grab the component or the gameobject? Since most of my cameras are tagged MainCamera, yet they can’t be disabled, the camera component is switched on and off when switching. I’m wasn’t sure if it grabbed the component, so that’s why I didn’t use Camera.main at first.
Anyway, I’m not really worried about perf, and it might be useful to have that data about which camera is being used stored. It doesn’t really matter now, I’ll look at optimizing when the game is near completion. (Which it is nowhere close to, when I make some more progress, I’ll make a thread in the wip projects forum.)