Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

WorldToScreenPoint errors during collisions

Discussion in 'Scripting' started by Stonewood1612, Nov 15, 2014.

  1. Stonewood1612

    Stonewood1612

    Joined:
    Sep 15, 2014
    Posts:
    32
    Hey all,

    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.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4.  
    5. public class DestroyProjectile : MonoBehaviour {
    6.  
    7.     public int projectileDamage;
    8.     GameObject hitObject;
    9.     EnemyGeneral enemyGeneral;
    10.     TurretGeneral turretGeneral;
    11.     public GameObject impactEffect;
    12.     public int projectileLifeTime = 10;
    13.  
    14.     Vector3 impactPos;
    15.     Vector2 textPos;
    16.  
    17.     DmgIndicator dmgIndicator;
    18.  
    19.     void Start (){
    20.    
    21.         dmgIndicator = GameObject.FindGameObjectWithTag("GameController").GetComponent<DmgIndicator>();
    22.    
    23.     }
    24.  
    25.     void OnCollisionEnter (Collision collision)
    26.     {
    27.  
    28.         if(collision.gameObject.tag == "Enemy"){
    29.  
    30.             hitObject = collision.gameObject;
    31.             Debug.Log ("enemy hit");
    32.  
    33.             enemyGeneral = hitObject.GetComponent<EnemyGeneral>() ;
    34.             enemyGeneral.currentEnemyHealth -= projectileDamage;
    35.  
    36.             Instantiate(impactEffect, transform.position, Quaternion.identity);
    37.            
    38.             Destroy(gameObject);
    39.  
    40.             impactPos = collision.transform.position;
    41.  
    42.             textPos = Camera.current.WorldToScreenPoint(impactPos); //error points at this line
    43.             dmgIndicator.PopUpDmg(projectileDamage, textPos);
    44.  
    45.  
    46.         }
    Any ideas to reduce the chance of errors?
     
  2. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    At which line does the null reference exception happen in this script?
     
  3. Stonewood1612

    Stonewood1612

    Joined:
    Sep 15, 2014
    Posts:
    32
    Did you scroll down my script? I marked the line with a comment ;)

    edit: line 42 in this case
     
  4. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Yes, of course! Or maybe not ;)

    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.
     
  5. Stonewood1612

    Stonewood1612

    Joined:
    Sep 15, 2014
    Posts:
    32
    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 :rolleyes:) , 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.
     
  6. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    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.
     
  7. Stonewood1612

    Stonewood1612

    Joined:
    Sep 15, 2014
    Posts:
    32
    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.
     
  8. ThermalFusion

    ThermalFusion

    Joined:
    May 1, 2011
    Posts:
    906
    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.
     
  9. ThermalFusion

    ThermalFusion

    Joined:
    May 1, 2011
    Posts:
    906
    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.
    http://docs.unity3d.com/ScriptReference/Camera-main.html

    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.
    http://docs.unity3d.com/ScriptReference/Camera-current.html

    As you can tell, Camera.current should not be used in OnCollisionEnter.
     
  10. Stonewood1612

    Stonewood1612

    Joined:
    Sep 15, 2014
    Posts:
    32
    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.)