Mostrar el daño en pantalla con un texto que sube y desaparece aporta claridad inmediata al jugador. Aquí verás cómo crear un damage number reutilizable en Unity: configura el UI Text, muévelo en Update, destrúyelo tras unos segundos e instáncialo desde el arma para cada golpe. Todo con C# y buenas prácticas de prefab.
¿Cómo crear y configurar el texto de daño en Unity UI?
Para reutilizar un mismo asset en múltiples casos (daño, curación, impacto al protagonista), se parte de un prefab con un componente de texto. El script expone variables públicas para ajustar velocidad, valor y referencia al UI Text desde el editor.
¿Qué variables públicas necesitas?
damageSpeed: velocidad a la que sube el texto.
damagePoints: valor numérico a mostrar.
damageText: referencia al componente Text de UnityEngine.UI.
No es necesario Start: se asigna todo desde el inspector.
¿Cómo se actualiza el contenido y la posición en Update?
El texto se construye con damagePoints.ToString().
El movimiento vertical usa Time.deltaTime para suavidad.
Los ejes x y z se mantienen, solo cambia y.
No hay físicas: se modifica transform.position directamente.
¿Cómo destruir el prefab tras un tiempo con un script simple?
Para evitar acumular objetos en la jerarquía, se destruye el texto tras unos segundos con un script mínimo. Así se mantiene el rendimiento y se limpia la interfaz automáticamente.
usingUnityEngine;publicclassDestroyAfterTime:MonoBehaviour{publicfloat timeToDestroy;// por ejemplo 1.5fvoidUpdate(){ timeToDestroy -= Time.deltaTime;if(timeToDestroy <=0f){Destroy(gameObject);}}}
Añade el script al prefab del daño.
Configura timeToDestroy en el inspector.
Verás desaparecer el objeto de la jerarquía al cumplirse el tiempo.
Usa Apply All para propagar cambios al prefab padre cuando veas marcas en el inspector.
¿Cómo instanciar el prefab desde el arma y pasar el valor de daño?
El responsable de crear el texto al golpear es el script del arma, por ejemplo WeaponDamage. Se instancia el prefab en el punto de impacto y se inyecta el daño actual del arma.
¿Dónde asignar y cómo evitar rotaciones?
Declara una variable pública GameObject damageNumber en el arma.
Arrastra el prefab al campo correspondiente en la swing zone.
Instancia en la posición del hitPoint con Quaternion.Euler(Vector3.zero) para evitar texto inclinado.
Almacena el clon para editar su componente DamageNumber.
Muy interesante la mecánica de mostrar los puntos de daño:
!!
Se puede usar Destroy(gameobject, 1.5f) para destruir el damageNumber despues de 1.5 segundos.
usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;usingUnityEngine.UI;publicclassDamageNumber:MonoBehaviour{publicfloat damagePoints;[SerializeField]float damageSpeed;[SerializeField]Text damageText;privatevoidStart(){Destroy(gameObject,1.5f);}// Update is called once per framevoidUpdate(){ damageText.text = damagePoints.ToString();this.transform.position =newVector3(this.transform.position.x,this.transform.position.y + damageSpeed * Time.deltaTime,this.transform.position.z);}}
Tal cual, inentendible lo de crear un script para destruir un gameObject 🤔
Alguien puede ayudarme? Estaba practicando y de repente el sprite de mi personaje se duplicó en la pantalla. Lo raro es q no se lo puede manipular de ninguna forma, no se puede clickear, ni borrar, y no parece estar vinculado con ningún código... Alguien sabe cómo resolver esto?
Hice el mismo procedimiento para el daño hacia el jugador y no aparece, la funcionalidad del canvas es correcta pero no la esta instanciando en el juego :( que puedo revisar:
Código DamageWeapon
private void OnTriggerEnter2D(Collider2D collision2D) {
//Si coliciona con el Jugador o con el Enemigo
if(collision2D.gameObject.tag.Equals("Enemy") || collision2D.gameObject.tag.Equals("Player")){
Debug.Log("Colisiono enemigo o player"); collision2D.gameObject.GetComponent<HealthManager>().DamageCharacter(damage);//Instanciar el prefab Blood en el punto del HitPoint del playerInstantiate(hurtAnimation,hitPoint.transform.position, hitPoint.transform.rotation);Debug.Log("Obtiene la instancia cloneDamageNamber");//Obtener la instancia del impacto, la función Quaternion.Euler para que no se rote el textovar cloneDamageNamber =(GameObject)Instantiate(damageNumber, hitPoint.transform.position,Quaternion.Euler(Vector3.zero));Debug.Log("Asigna damagePoints del script DamageNumber");//Carga la información en el script de DamageNumber en el damagePoints cloneDamageNamber.GetComponent<DamageNumber>().damagePoints= damage;}}
Dejo como otro aporte, cambie la creación del texto a la clase HealthManager para que se instancie ni bien se recibe daño.
La misma cambia de color según quien se ve afectado
publicclassHealthManager:MonoBehaviour{[Header("Configuration")]public int maxHealth;public int currentHealth;publicGameObject damageTextNumber;SpriteRenderer _renderer;privatevoidAwake(){ _renderer =GetComponent<SpriteRenderer>();}// Start is called before the first frame updatevoidStart(){ currentHealth = maxHealth;}// Update is called once per framevoidUpdate(){if(currentHealth <=0){ gameObject.SetActive(false);}}publicvoidDamageCharacter(int damage){ currentHealth -= damage;StartCoroutine(HitEffect(_renderer));ShowDamageNumber(damage);}publicvoidUpdateMaxHealth(int newMaxHealth){ maxHealth = newMaxHealth; currentHealth = maxHealth;}publicIEnumeratorHitEffect(SpriteRenderer _renderer){if(_renderer !=null){ _renderer.color=Color.red;yieldreturnnewWaitForSeconds(0.2f); _renderer.color=Color.white;}elseDebug.LogError("Hay un null en el HitEffect");}publicvoidShowDamageNumber(int damage){GameObject damageText =Instantiate(damageTextNumber,this.transform.position,Quaternion.Euler(Vector3.zero))asGameObject;//I don't want text to get rotated. That why I used Euler damageText.GetComponent<DamageNumber>().damagePoints= damage;//Change Text Color depends if is a Player or an Enemyif(this.gameObject.CompareTag("Player")){ damageText.GetComponentInChildren<Text>().color=Color.red;}elseif(this.gameObject.CompareTag("Enemy")){ damageText.GetComponentInChildren<Text>().color=Color.yellow;}Destroy(damageText, 5f);}}
Dejo el código por si alguien quiere hacer que el texto haga un desvanecimiento en vez de desaparecer de una.
publicclassDamageNumber:MonoBehaviour{[Header("Configuration")]public float damageSpeed;public float damagePoints;public float fadeOutSpeed;publicText damageText;privateCanvasGroup _canvasGroup;privatevoidAwake(){ _canvasGroup =GetComponent<CanvasGroup>();}privatevoidStart(){StartCoroutine(FadeOut());}// Update is called once per framevoidUpdate(){ damageText.text= damagePoints.ToString();this.transform.position=newVector2(this.transform.position.x,this.transform.position.y+ damageSpeed *Time.deltaTime);}publicIEnumeratorFadeOut(){yieldreturnnewWaitForSeconds(0.4f);if(_canvasGroup !=null&& fadeOutSpeed !=0){while(_canvasGroup.alpha>0){ _canvasGroup.alpha=Mathf.Lerp(_canvasGroup.alpha,0,Time.deltaTime* fadeOutSpeed);yieldreturnnewWaitForSeconds(0.01f);}}}}