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
- This topic has 18 replies, 5 voices, and was last updated 2 weeks, 4 days ago by Terence.
-
AuthorPosts
-
December 4, 2023 at 10:07 pm #12506::
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&)"
December 4, 2023 at 10:16 pm #12507::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; ...
December 4, 2023 at 10:21 pm #12508::No, the editor says the error in this line: rect.position = referenceCamera.WorldToScreenPoint(target.position + new Vector3(0, yOffset));
December 4, 2023 at 10:53 pm #12509::It seems to be saying that the
rect
object no longer exists, hencerect.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<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; Debug.Log(rect + " | " + referenceCamera + " | " + target); rect.position = referenceCamera.WorldToScreenPoint(target.position); ...
I’m trying to check if the
rect
,referenceCamera
andtarget
objects all still exist.December 4, 2023 at 11:28 pm #12510December 5, 2023 at 12:56 am #12511::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<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); // 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.December 6, 2023 at 11:21 pm #12523::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!
December 6, 2023 at 11:32 pm #12542::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); }
December 7, 2023 at 12:43 am #12544::wow this time it works perfectly. Thank you very much for you endless support. Appreciated!
December 7, 2023 at 9:53 pm #12546January 17, 2024 at 7:34 pm #13112::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
January 17, 2024 at 8:26 pm #13113::Kai, can you check for the following:
- When the subsequent hits happen, do any Text GameObjects get spawned on the Hierarchy?
- Are there any errors in the Console?
January 17, 2024 at 10:09 pm #13114::Hi, Terence
- The subsequence hits did not spawn anything in the hierachy. However, the first hit did
- No errors in my console
January 17, 2024 at 10:54 pm #13115::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.
January 17, 2024 at 11:22 pm #13116 -
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: