Forum begins after the advertisement:


[Part 14] MissingReferenceException with floating text RectTransform

Home Forums Video Game Tutorial Series Creating a Rogue-like Shoot-em Up in Unity [Part 14] MissingReferenceException with floating text RectTransform

Viewing 15 posts - 1 through 15 (of 15 total)
  • Author
    Posts
  • #12506
    Phú Lê
    Participant

    I have followed the instructions from the tutorial but it seems there is an error like this.

    The damage text still appears but it shows error right away. Can you please tell me where it went wrong and how to fix this bug. Thanks a lot for your help!
    This is the error in text “MissingReferenceException:

    The object of type 'RectTransform' has been destroyed but you are still trying to access it.
    Your script should either check if it is null or you should not destroy the object.
    UnityEngine.Transform.set_position (UnityEngine.Vector3 value) (at <30adf90198bc4c4b83910c6fb1877998>:0)
    GameManager+<GenerateFloatingTextCoroutine>d__32.MoveNext () (at Assets/Scripts/GameManager.cs:134)
    UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <30adf90198bc4c4b83910c6fb1877998>:0)
    UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)"
    #12507
    Terence
    Keymaster

    Hi phule, is the error on this line?

        IEnumerator GenerateFloatingTextCoroutine(string text, Transform target, float duration = 1f, float speed = 50f)
        {
            // Start generating the floating text.
            GameObject textObj = new GameObject("Damage Floating Text");
            RectTransform rect = textObj.AddComponent<RectTransform>();
            TextMeshProUGUI tmPro = textObj.AddComponent<TextMeshProUGUI>();
            tmPro.text = text;
            ...
    #12508
    Phú Lê
    Participant

    No, the editor says the error in this line:
    rect.position = referenceCamera.WorldToScreenPoint(target.position + new Vector3(0, yOffset));

    #12509
    Terence
    Keymaster

    It seems to be saying that the rect object no longer exists, hence rect.position is not valid. But this doesn’t seem to be possible. Can you add the following lines and show me the Console?

    IEnumerator GenerateFloatingTextCoroutine(string text, Transform target, float duration = 1f, float speed = 50f)
    {
        // Start generating the floating text.
        GameObject textObj = new GameObject("Damage Floating Text");
        RectTransform rect = textObj.AddComponent();
        TextMeshProUGUI tmPro = textObj.AddComponent();
        tmPro.text = text;
        tmPro.horizontalAlignment = HorizontalAlignmentOptions.Center;
        tmPro.verticalAlignment = VerticalAlignmentOptions.Middle;
        tmPro.fontSize = textFontSize;
        if (textFont) tmPro.font = textFont;
        Debug.Log(rect + " | " + referenceCamera + " | " + target);
        rect.position = referenceCamera.WorldToScreenPoint(target.position);
        ...
    

    I’m trying to check if the rect, referenceCamera and target objects all still exist.

    #12510
    Phú Lê
    Participant

    Here you are:

    Thank you for your time sir!

    #12511
    Terence
    Keymaster

    Ah, I found the error. It’s a mistake in my code:

    IEnumerator GenerateFloatingTextCoroutine(string text, Transform target, float duration = 1f, float speed = 50f)
    {
        // Start generating the floating text.
        GameObject textObj = new GameObject("Damage Floating Text");
        RectTransform rect = textObj.AddComponent();
        TextMeshProUGUI tmPro = textObj.AddComponent();
        tmPro.text = text;
        tmPro.horizontalAlignment = HorizontalAlignmentOptions.Center;
        tmPro.verticalAlignment = VerticalAlignmentOptions.Middle;
        tmPro.fontSize = textFontSize;
        if (textFont) tmPro.font = textFont;
        rect.position = referenceCamera.WorldToScreenPoint(target.position);
    
        // Makes sure this is destroyed after the duration finishes.
        Destroy(textObj, duration);
    
        // Parent the generated text object to the canvas.
        textObj.transform.SetParent(instance.damageTextCanvas.transform);
    
        // Pan the text upwards and fade it away over time.
        WaitForEndOfFrame w = new WaitForEndOfFrame();
        float t = 0;
        float yOffset = 0;
        while(t < duration)
        {
            // Fade the text to the right alpha value.
            tmPro.color = new Color(tmPro.color.r, tmPro.color.g, tmPro.color.b, 1 - t / duration);
    
            // Pan the text upwards.
            yOffset += speed * Time.deltaTime;
            rect.position = referenceCamera.WorldToScreenPoint(target.position + new Vector3(0,yOffset));
    
            // Wait for a frame and update the time.
            yield return w;
            t += Time.deltaTime;
            // Fade the text to the right alpha value.
            tmPro.color = new Color(tmPro.color.r, tmPro.color.g, tmPro.color.b, 1 - t / duration);
    
            // Pan the text upwards.
            yOffset += speed * Time.deltaTime;
            rect.position = referenceCamera.WorldToScreenPoint(target.position + new Vector3(0,yOffset));
        }
    }

    Basically, the code to move the floating text runs for 1 extra frame after the text gets destroyed (because the code runs after the 1 frame delay (yield return w). We shift the code for animating the text up so that this doesn’t happen.

    #12523
    Phú Lê
    Participant

    Sorry for the late reply. Aften the modification in the code, it seems that the error message still appears but slower than the previous one (after the second text disappeared). This time it says the “Transform” is null, not “RectTransform”:

    This the the log in the console:

    MissingReferenceException: The object of type 'Transform' has been destroyed but you are still trying to access it.
    Your script should either check if it is null or you should not destroy the object.
    UnityEngine.Transform.get_position () (at <30adf90198bc4c4b83910c6fb1877998>:0)
    GameManager+<GenerateFloatingTextCoroutine>d__32.MoveNext () (at Assets/Scripts/GameManager.cs:134)
    UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <30adf90198bc4c4b83910c6fb1877998>:0)
    UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)"
    "Damage Floating Text (UnityEngine.RectTransform) | Main Camera (UnityEngine.Camera) | Bat(Clone) (UnityEngine.Transform)
    UnityEngine.Debug:Log (object)
    GameManager/<GenerateFloatingTextCoroutine>d__32:MoveNext () (at Assets/Scripts/GameManager.cs:121)
    UnityEngine.MonoBehaviour:StartCoroutine (System.Collections.IEnumerator)
    GameManager:GenerateFloatingText (string,UnityEngine.Transform,single,single) (at Assets/Scripts/GameManager.cs:108)
    EnemyStats:TakeDamage (single,UnityEngine.Vector2,single,single) (at Assets/Scripts/Enemy/EnemyStats.cs:58)
    ProjectileWeaponBehaviour:OnTriggerEnter2D (UnityEngine.Collider2D) (at Assets/Scripts/Weapons/ProjectileWeaponBehaviour.cs:86)

    Thank you for your time!

    #12542
    Terence
    Keymaster

    I suspect that this issue is caused when the enemy dies before the floating text expires, so target becomes null and causes the issue.

    rect.position = referenceCamera.WorldToScreenPoint(target.position + new Vector3(0,yOffset));

    To fix this, you can change the code this way:

    // Pan the text upwards.
    if(target) {
        yOffset += speed * Time.deltaTime;
        rect.position = referenceCamera.WorldToScreenPoint(target.position + new Vector3(0,yOffset));
    } else {
        // If target is dead, just pan up where the text is at.
        rect.position += new Vector3(0, speed * Time.deltaTime, 0);
    }
    #12544
    Phú Lê
    Participant

    wow this time it works perfectly. Thank you very much for you endless support. Appreciated!

    #12546
    Terence
    Keymaster

    Glad you managed to fix this.

    #13112
    Kai
    Participant

    Hi Terence, I followed up your code to fixed the MissingReferenceException error and ran the game without any further errors. However, I noticed my damage text only pop up once. I did call the GenerateFloatingText in EnemyStat.cs but I have no idea what caused this. Here is my code:

    GameManager.cs

    public static void GenerateFloatingText(string text, Transform target, float duration = 1f, float speed = 1f)
    {
        //If the canvas is not set, end the function so we don't generate the floating text
        if(!instance.damageTextCanvas)
        {
            return;
        }
    
        if(!instance.referenceCamera)
        {
            instance.referenceCamera = Camera.main;
            instance.StartCoroutine(instance.GenerateFloatingTextCoroutine(text, target, duration, speed));
        }
    }
    IEnumerator GenerateFloatingTextCoroutine(string text, Transform target, float duration = 1f, float speed = 50f)
    {
        //Start generating the floating text
        GameObject textObj = new GameObject("Damage Floating Text");
        RectTransform rect = textObj.AddComponent<RectTransform>();
        TextMeshProUGUI tmPro = textObj.AddComponent<TextMeshProUGUI>();
    
        tmPro.text = text;
        tmPro.horizontalAlignment = HorizontalAlignmentOptions.Center;
        tmPro.verticalAlignment = VerticalAlignmentOptions.Middle;
        tmPro.fontSize = textFontSize;
    
        if(textFont)
        {
            tmPro.font = textFont;
        }
        rect.position = referenceCamera.WorldToScreenPoint(target.position);
    
        //Make sure this is destroyed after the duration finishes
        Destroy(textObj, duration);
        //parent the genertated text object to the canvas
        textObj.transform.SetParent(instance.damageTextCanvas.transform);
        //Pan the text upwards and fade it overtime
        WaitForEndOfFrame w = new WaitForEndOfFrame();
        float t = 0;
        float yOffset = 0;
        while(t < duration)
        {
            //Fade the text to the right alpha value
            tmPro.color = new Color(tmPro.color.r, tmPro.color.g, tmPro.color.b, 1 - t / duration);
    
            //Pan the text upwards
            if(target)
            {
                yOffset += speed * Time.deltaTime;
                rect.position = referenceCamera.WorldToScreenPoint(target.position + new Vector3(0, yOffset));
            }
            else
            {
                rect.position += new Vector3(0, speed * Time.deltaTime, 0);
            }
            yield return w;
            t += Time.deltaTime;
        }
    
    }

    EnemyStats.cs

    public void TakeDamage(float dmg, Vector2 sourcePosition, float knockbackForce = 3f, float knockbackDuration = 0.1f)
     {
         currentHealth -= dmg;
         StartCoroutine(DamageFlash());
    
         //Create a pop-up text when enemy take damage
         if (dmg > 0)
         {
             GameManager.GenerateFloatingText(Mathf.FloorToInt(dmg).ToString(), transform);
         }
    
         //Apply knockback if it is not zero
         if(knockbackForce > 0)
         {
             //Get direction of knockback
             Vector2 dir = (Vector2)transform.position - sourcePosition;
             movement.Knockback(dir.normalized * knockbackForce, knockbackDuration);
         }
    
         if(currentHealth <= 0) 
         {
             Kill();
         }
     }
     //Coroutine for damage flash
     IEnumerator DamageFlash()
     {
         sr.color = damageColor;
         yield  return new WaitForSeconds(damageFlashDuration);
         sr.color = originalColor;
     }
     public void Kill()
     {
         StartCoroutine(KillFade());
     }
    
     IEnumerator KillFade()
     {
         //Wait for a sigle frame.
         WaitForEndOfFrame w = new WaitForEndOfFrame();
         float t = 0, origAlpha = sr.color.a;
         //This is a loop that fires every frame
         while (t < deathFadeTime)
         {
             yield return w;
             t += Time.deltaTime;
             //Set the color for the frame
             sr.color = new Color(sr.color.r, sr.color.g, sr.color.b, (1 - t / deathFadeTime) * origAlpha);
         }
    
         Destroy(gameObject);
     }

    Video:
    https://imgur.com/vdMGsKJ

    #13113
    Terence
    Keymaster

    Kai, can you check for the following:

    1. When the subsequent hits happen, do any Text GameObjects get spawned on the Hierarchy?
    2. Are there any errors in the Console?
    #13114
    Kai
    Participant

    Hi, Terence
    1. The subsequence hits did not spawn anything in the hierachy. However, the first hit did
    2. No errors in my console

    #13115
    Terence
    Keymaster

    I think your GenerateFloatingText() function is terminating early here:

    public static void GenerateFloatingText(string text, Transform target, float duration = 1f, float speed = 1f)
    {
        //If the canvas is not set, end the function so we don't generate the floating text
        if(!instance.damageTextCanvas)
        {
            return;
        }
    
        if(!instance.referenceCamera)
        {
            instance.referenceCamera = Camera.main;
            instance.StartCoroutine(instance.GenerateFloatingTextCoroutine(text, target, duration, speed));
        }
    }

    Can you check if your Damage Text Canvas continues to be assigned after the first call? It may have been destroyed by something in your code.

    #13116
    Kai
    Participant

    You were right, the GeneratingFloatingText function was the problem.
    I rewrite my code same as the video and it worked, thank you very much sir

Viewing 15 posts - 1 through 15 (of 15 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: