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 16 replies, 4 voices, and was last updated 1 month, 4 weeks ago by
Terence.
-
AuthorPosts
-
December 4, 2023 at 10:07 pm #12506
Phú Lê
ParticipantI 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 #12507Terence
KeymasterHi 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 #12508Phú Lê
ParticipantNo, 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 #12509Terence
KeymasterIt 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
(); 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
andtarget
objects all still exist.December 4, 2023 at 11:28 pm #12510Phú Lê
ParticipantHere you are:
https://imgur.com/X2n4s2i
Thank you for your time sir!December 5, 2023 at 12:56 am #12511Terence
KeymasterAh, 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.December 6, 2023 at 11:21 pm #12523Phú Lê
ParticipantSorry 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 #12542Terence
KeymasterI 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 #12544Phú Lê
Participantwow this time it works perfectly. Thank you very much for you endless support. Appreciated!
December 7, 2023 at 9:53 pm #12546Terence
KeymasterGlad you managed to fix this.
January 17, 2024 at 7:34 pm #13112Kai
ParticipantHi 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/vdMGsKJJanuary 17, 2024 at 8:26 pm #13113Terence
KeymasterKai, 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 #13114Kai
ParticipantHi, Terence
1. The subsequence hits did not spawn anything in the hierachy. However, the first hit did
2. No errors in my consoleJanuary 17, 2024 at 10:54 pm #13115Terence
KeymasterI 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 #13116Kai
ParticipantYou were right, the GeneratingFloatingText function was the problem.
I rewrite my code same as the video and it worked, thank you very much sir -
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: