En este tutorial, aprenderás cómo crear un juego 2D móvil con C # y Unity. Aprovecharemos el Dolby Audio Plugin for Unity para mejorar la experiencia auditiva del juego. El objetivo del juego es simple: llegar al otro lado del nivel mientras evitas a los enemigos y recolectas monedas..
En este tutorial, aprenderás los siguientes aspectos del desarrollo del juego Unity:
Abre Unity y selecciona Nuevo proyecto desde el Expediente Menú para abrir el nuevo cuadro de diálogo del proyecto. Indica a Unity dónde quieres guardar el proyecto y configuraConfigurar valores predeterminados para: menú desplegable para 2D.
En el siguiente paso, se presenta la interfaz de usuario de Unity. Configure el proyecto para el desarrollo móvil seleccionando Configuraciones de compilación desde el Expediente menú y seleccione Androide como la plataforma de destino.
Ya que estamos a punto de crear un juego en 2D, lo primero que debemos hacer después de seleccionar la plataforma de destino es elegir el tamaño de la ilustración que usaremos en el juego. Debido a que Android es una plataforma abierta, hay una amplia gama de dispositivos, resoluciones de pantalla y densidades de píxeles disponibles en el mercado actual. Algunos de los más comunes son:
Aunque nos enfocaremos en la plataforma Android en este tutorial, puedes usar el mismo código para apuntar a cualquiera de las otras plataformas que admite Unity.
Dependiendo de los dispositivos a los que te dirijas, es posible que tengas que convertir la ilustración del juego al tamaño y densidad de píxeles recomendados. Puedes hacer esto en tu editor de imágenes favorito. He usado el Ajustar el tamaño ... función bajo el Herramientas menú en OS X's Avance solicitud.
Antes de comenzar, asegúrese de hacer clic en el 2D botón en el Escena panel. También puede modificar la resolución que se muestra en el Juego panel.
La interfaz de nuestro juego será sencilla. La captura de pantalla de arriba te da una idea de la ilustración que usaremos y cómo se verá la interfaz final del juego. Puede encontrar la ilustración de este tutorial en los archivos de origen de este tutorial.
Puede usar uno de los tres lenguajes de programación cuando usa Unity, C #, UnityScript, una variación de JavaScript y Boo. Cada uno de estos lenguajes de programación tiene sus pros y sus contras y depende de usted decidir cuál prefiere. Mi preferencia personal va al lenguaje de programación C #, por lo que es el lenguaje que usaré en este tutorial..
Si decide utilizar otro lenguaje de programación, asegúrese de consultar la Referencia de guiones de Unity para ver ejemplos..
Unity ha creado un nombre por ser una excelente plataforma para crear juegos en 3D para varias plataformas, como Xbox 360 de Microsoft, PS3 de Sony, Wii de Nintendo, la web y varias plataformas móviles..
Si bien siempre ha sido posible usar Unity para el desarrollo de juegos en 2D, no fue hasta el lanzamiento de Unity 4.3 que incluyó el soporte nativo en 2D. Aprenderemos cómo trabajar con imágenes como sprites en lugar de texturas en los siguientes pasos.
Usaré una serie de sonidos para crear una gran experiencia auditiva para el juego. Los efectos de sonido utilizados en este tutorial se obtuvieron de as3sfxr y PlayOnLoop.
Antes de comenzar la codificación, debemos agregar nuestros activos al proyecto de Unity. Puedes hacer esto de varias maneras:
Después de completar este paso, debería ver los activos en el proyecto de su proyecto. Bienes carpeta en el Proyecto panel.
Estamos listos para crear la escena de nuestro juego arrastrando objetos a la Jerarquía o Escena panel.
Comience arrastrando y soltando el fondo en el Jerarquía panel. Debería aparecer automáticamente en el Escena panel.
Porque el Escena El panel está configurado para mostrar una vista 2D, notará que al seleccionar Cámara principal en el Jerarquía muestra una vista previa de lo que la cámara va a mostrar. También puedes ver esto en el Juego ver. Para hacer visible toda la escena, cambia la tamaño valor de la Cámara principal a 1.58 en el Inspector panel.
El piso se usa para evitar que nuestro personaje principal se caiga una vez que hemos agregado física al juego. Arrástrelo desde el Bienes Carpeta y posiciónelo en la escena como se muestra abajo..
Para hacer que el piso detecte cuando el personaje lo está tocando, necesitamos agregar un componente, un Box Collider 2D para ser preciso.
Selecciona el suelo en la escena, abre el Inspector panel, y haga clic en Agregar componente. De la lista de componentes, seleccione Box Collider 2D desde el Física 2D sección.
Usaremos botones para controlar a nuestro personaje principal en el juego. Arrastre y coloque el botón de salto en el Escena y agrega un Círculo Collider2D componente como se muestra en el paso anterior.
Para reproducir un sonido cuando el personaje salta, primero debemos adjuntarlo al botón de salto. Selecciónelo de la Jerarquía o Escena ver, haga clic en el Agregar componente botón en el Inspector panel, y seleccione Fuente de audio en el Audio sección.
Desmarcar Jugar en Awake y haga clic en el pequeño punto a la derecha, debajo del icono del engranaje, para seleccionar el sonido que queremos reproducir cuando el jugador toque el botón. En el siguiente paso, implementaremos la lógica para reproducir el sonido cuando el jugador toque el botón.
Vamos a crear el guión que controlará nuestro personaje. Seleccione el botón de salto y haga clic en el Agregar componente botón en el Inspector panel. Seleccionar Nueva secuencia de comandos y nombrarlo Saltar. No te olvides de cambiar el idioma a C #.
Abra el archivo recién creado y agregue el siguiente fragmento de código.
utilizando UnityEngine; utilizando System.Collections; Clase pública Jump: MonoBehaviour public float jumpForce; héroe de GameObject privado; // se utiliza para hacer referencia a nuestro personaje (héroe) en la escena // Use esto para la inicialización void Start () hero = GameObject.Find ("Hero"); // obtiene el objeto del juego del héroe // Se llama a la actualización una vez por fotograma nula Actualización () / * Compruebe si el usuario está tocando el botón en el dispositivo * / if (Application.platform == RuntimePlatform.Android) if ( Input.touchCount> 0) if (Input.GetTouch (0) .phase == TouchPhase.Began) CheckTouch (Input.GetTouch (0) .position, "comenzó"); // función creada a continuación else if (Input.GetTouch (0) .phase == TouchPhase.Ended) CheckTouch (Input.GetTouch (0) .position, "finalizado"); / * Comprueba si el usuario toca el botón en el Editor, cambia el valor de OSXEditor si estás en Windows * / if (Application.platform == RuntimePlatform.OSXEditor) if (Input.GetMouseButtonDown (0)) CheckTouch (Input.mousePosition, "comenzó"); if (Input.GetMouseButtonUp (0)) CheckTouch (Input.mousePosition, "finalizado"); anular CheckTouch (Vector3 pos, fase de cadena) / * Obtener el punto de la pantalla donde el usuario está tocando * / Vector3 wp = Camera.main.ScreenToWorldPoint (pos); Vector2 touchPos = nuevo Vector2 (wp.x, wp.y); Collider2D hit = Physics2D.OverlapPoint (touchPos); / * si se toca el botón ... * / if (hit.gameObject.name == "JumpButton" && hit && phase == "comenzó") hero.rigidbody2D.AddForce (nuevo Vector2 (0f, jumpForce)); // Agregar fuerza de salto a hero audio.Play (); // reproducir audio adjunto a este objeto del juego (sonido de salto)
El fragmento de código puede parecer desalentador, pero en realidad es bastante sencillo. Primero obtenemos una referencia a la héroe
objeto, una instancia de la GameObject
clase, así que podemos usarlo más tarde. Luego detectamos si el usuario está tocando el botón de salto y, si lo están, agregamos una fuerza a la héroe
objeto. Por último, pero no menos importante, reproducimos el sonido de salto cuando se pulsa el botón de salto.
Los pasos para agregar e implementar los botones de movimiento, izquierdo y derecho, son muy similares. Comience colocando los botones en la escena y agregue un Circle Collider 2D a cada botón como hicimos con el botón de salto.
Cree un nuevo script, adjúntelo al botón izquierdo y asígnele un nombre Mover hacia la izquierda. Reemplace su contenido con el siguiente fragmento de código, que contiene el Mover hacia la izquierda
método.
utilizando UnityEngine; utilizando System.Collections; clase pública MoveLeft: MonoBehaviour public Vector3 moveSpeed = new Vector3 (); movimiento bool privado = falso; escena privada de GameObject []; // conjunto de objetos del juego que conforman la escena privada GameObject bg; // Use esto para la inicialización void Start () scene = GameObject.FindGameObjectsWithTag ("Moveable"); // Objetos de juego con etiqueta movible bg = GameObject.Find ("Background"); // Fondo del juego // Se llama a Update una vez por fotograma nula Update () / * Detect touch * / if (Application.platform == RuntimePlatform.Android) if (Input.touchCount> 0) if (Input.GetTouch (0) .phase == TouchPhase.Began) CheckTouch (Input.GetTouch (0) .position, "comenzó"); else if (Input.GetTouch (0) .phase == TouchPhase.Ended) CheckTouch (Input.GetTouch (0) .position, "finalizado"); if (Application.platform == RuntimePlatform.OSXEditor) if (Input.GetMouseButtonDown (0)) CheckTouch (Input.mousePosition, "comenzó"); if (Input.GetMouseButtonUp (0)) CheckTouch (Input.mousePosition, "finalizado"); // Mover si se presiona el botón si (moviendo && bg.transform.position.x < 4.82f) for (int i = 0; i < scene.Length; i++) if (scene [i] != null) scene [i].transform.position += moveSpeed; void CheckTouch(Vector3 pos, string phase) Vector3 wp = Camera.main.ScreenToWorldPoint(pos); Vector2 touchPos = new Vector2(wp.x, wp.y); Collider2D hit = Physics2D.OverlapPoint(touchPos); if (hit.gameObject.name == "LeftButton" && hit && phase == "began") moving = true; if (hit.gameObject.name == "LeftButton" && hit && phase == "ended") moving = false;
En este script, creamos una matriz de los elementos etiquetados como Movible
-Los etiquetaremos más adelante en este tutorial, para que sea más fácil moverlos todos a la vez. Para mover los elementos, primero verificamos si se toca el botón y cambiamos la posición usando Velocidad de movimiento
en el Actualizar
función. Es tan simple como eso.
Cree otro script, adjúntelo al botón derecho y asígnele un nombre Mover a la derecha. Este script contiene el Mover a la derecha
método y su implementación es similar a la de la Mover hacia la izquierda
Método que vimos hace un momento. Cambiamos la dirección del movimiento sustituyendo += mover velocidad
con -= mover velocidad
. Esto moverá la escena en la dirección opuesta..
En el Mover a la derecha script, también verificamos si el jugador ha completado el nivel.
utilizando UnityEngine; utilizando System.Collections; clase pública MoveRight: MonoBehaviour public Vector3 moveSpeed = new Vector3 (); movimiento bool privado = falso; escena privada de GameObject []; GameObject privado bg; audioClip público completoSonido; botones privados de GameObject []; privado GameObject completeText; bool privado terminó = falso; fuente pública goodDog; // Use esto para la inicialización void Start () scene = GameObject.FindGameObjectsWithTag ("Moveable"); bg = GameObject.Find ("Background"); buttons = GameObject.FindGameObjectsWithTag ("Buttons"); // Se llama a Update una vez por fotograma nula Update () if (Application.platform == RuntimePlatform.Android) if (Input.touchCount> 0) if (Input.GetTouch (0) .phase == TouchPhase.Began ) CheckTouch (Input.GetTouch (0) .position, "comenzó"); else if (Input.GetTouch (0) .phase == TouchPhase.Ended) CheckTouch (Input.GetTouch (0) .position, "finalizado"); if (Application.platform == RuntimePlatform.OSXEditor) if (Input.GetMouseButtonDown (0)) CheckTouch (Input.mousePosition, "comenzó"); if (Input.GetMouseButtonUp (0)) CheckTouch (Input.mousePosition, "finalizado"); // Mover si se presiona el botón && la etapa no finaliza si (se mueve && bg.transform.position.x> -4.8f) para (int i = 0; i < scene.Length; i++) if (scene [i] != null) scene [i].transform.position -= moveSpeed; // Stage Completed if (bg.transform.position.x <= -4.8f && ended == false) Alert("complete"); void CheckTouch(Vector3 pos, string phase) Vector3 wp = Camera.main.ScreenToWorldPoint(pos); Vector2 touchPos = new Vector2(wp.x, wp.y); Collider2D hit = Physics2D.OverlapPoint(touchPos); if (hit.gameObject.name == "RightButton" && hit && phase == "began") moving = true; if (hit.gameObject.name == "RightButton" && hit && phase == "ended") moving = false; public void Alert(string action) ended = true; completeText = new GameObject(); completeText.AddComponent("GUIText"); completeText.guiText.font = goodDog; completeText.guiText.fontSize = 50; completeText.guiText.color = new Color(255, 0, 0); if (action == "complete") AudioSource.PlayClipAtPoint(completeSound, transform.position); completeText.guiText.text = "Level Complete!"; completeText.guiText.transform.position = new Vector3(0.24f, 0.88f, 0); else completeText.guiText.text = "Game Over"; completeText.guiText.transform.position = new Vector3(0.36f, 0.88f, 0); bg.GetComponent().Stop(); for(int i = 0; i < buttons.Length; i++) buttons[i].renderer.enabled = false; Invoke("restart", 2); void restart() Application.LoadLevel(Application.loadedLevel);
los Alerta
La función crea y muestra un mensaje al jugador y reproduce el sonido adjunto al sprite de fondo. Para que esto funcione, agregue el sonido correspondiente al sprite de fondo como vimos anteriormente en este tutorial. También ocultamos los botones y reiniciamos el juego con un retraso de dos segundos..
Usaremos una hoja de sprites para el resto de los elementos del juego. Unity tiene un editor de sprites que facilita el uso de sprites. La obra de arte utilizada en este tutorial se obtuvo de OpenGameArt.org.
Importe la obra, selecciónela de la Bienes panel, y cambiar el Modo Sprite opción a Múltiple en el Inspector panel.
Abre el Editor de Sprite Al hacer clic en el botón de abajo y seleccionar Rebanada> Automático.
Con la hoja de sprites cortada y lista para usar, haz clic en la flecha que aparece cuando la hoja de sprites está seleccionada y elige el sprite para el héroe, el personaje principal de nuestro juego. Colócalo en la escena y agrega un Colisionador 2D componente de ello.
Para detectar una colisión con nuestro héroe, al menos uno de los objetos en colisión debe tener un RigidBody 2D componente adjunto a él. Para agregar uno a nuestro héroe, seleccione Agregar componente en el Inspector panel, seguido de Física 2D > RigidBody 2D.
Comprobar el Ángulo fijo cuadro para evitar que el héroe gire si se produce una colisión.
Cuando nuestro héroe es golpeado por un enemigo, reproducimos otro sonido para dar retroalimentación al jugador. Si alguna vez has jugado a Super Mario Bros., entonces probablemente sabrás qué efecto estamos buscando. Para lograr esto, primero necesitamos agregar el sonido. Selecciónelo de la Jerarquía o Escena ver, haga clic en el Agregar componente botón en el Inspector panel, y seleccione Fuente de audio en el Audio sección.
Los detalles del componente de audio se mostrarán en la Panel de inspectores. Haga clic en el punto debajo del icono de engranaje y seleccione golpear sonar.
Como en muchos juegos de plataformas 2D tradicionales, puedes recolectar monedas en nuestro juego. Debido a que usaremos este objeto varias veces en el juego, lo convertiremos en un Casa prefabricada Una vez que hemos añadido todos los componentes necesarios..
Arrastra la moneda de la Bienes carpeta y añadir una Collider2D Como vimos en los pasos anteriores..
Tocamos un sonido cada vez que nuestro héroe recoge una moneda. Añadir un Fuente de audio componente como vimos hace un momento y seleccione el acuñar Sonido de los activos del proyecto..
Adjuntar este sencillo script a la moneda. Detecta cuándo chocan la moneda y el héroe. La moneda se destruye y se reproduce un sonido para indicar que la moneda ha sido recogida por el héroe..
utilizando UnityEngine; utilizando System.Collections; GrabCoin de clase pública: MonoBehaviour void OnTriggerEnter2D (Collider2D other) if (other.gameObject.name == "Hero") audio.Play (); Destroy (gameObject.collider2D); gameObject.renderer.enabled = false; Destroy (gameObject, 0.47f); // Destruye el objeto -después- el sonido reproducido
Con todos los componentes en su lugar, arrastre la moneda desde el Jerarquía panel para el Bienes panel para convertirlo en un Casa prefabricada. Notarás que el texto se vuelve azul indicando que ahora es un Prefab..
No olvidemos a los enemigos del juego. Arrastra la obra de arte para el enemigo desde el Bienes carpeta y añadir dos Colisionador 2D componentes como se muestra en la captura de pantalla a continuación.
Los colisionadores tienen un tamaño reducido para evitar que el héroe choque con ambos colisionadores a la vez. Cambiar la configuración de cada uno. Colisionador 2D componente como abajo.
El primer colisionador en el panel es el colisionador más alto que hemos agregado al enemigo. Detectará si el héroe salta sobre el enemigo y lo destruye. La lógica para esta acción se muestra en el siguiente script.
Marcamos el segundo colisionador como disparador marcando la casilla marcada Es gatillo. Detecta cuando el enemigo se topa con el héroe o viceversa. Cuando eso sucede, el jugador pierde el juego..
La secuencia de comandos adjunta al enemigo se muestra a continuación e implementa la lógica que acabamos de discutir. Como puedes ver, el enemigo se mueve hacia la izquierda en cada cuadro y la secuencia de comandos detecta cuando el héroe salta sobre el enemigo o cuando el héroe se encuentra con el enemigo..
utilizando UnityEngine; utilizando System.Collections; enemigo público de clase: MonoBehaviour public Vector3 moveSpeed; AudioClip público hitSound; juego público de alerta de objetoBridge; // Use esto para la inicialización void Start () // Update se llama una vez por fotograma void Update () transform.position - = moveSpeed; // Mueve al enemigo a la izquierda void OnCollisionEnter2D (Collision2D other) // Hero salta sobre el enemigo if (other.gameObject.name == "Hero") AudioSource.PlayClipAtPoint (hitSound, transform.position); Destroy (gameObject); void OnTriggerEnter2D (Collider2D otro) // heroe golpea el lado del enemigo if (other.gameObject.name == "Hero") other.gameObject.audio.Play (); // Play audio Destroy (other.gameObject.collider2D); // Eliminar colisionador para evitar la reproducción de audio other.gameObject.renderer.enabled = false; // Hacer que el objeto sea invisible Destroy (other.gameObject, 0.626f); // Destruye el objeto cuando el audio termina de reproducirse, destruirlo antes hará que el audio deje de alertBridge.GetComponent (). Alert ("gameover");
Los ladrillos se utilizan como plataformas. El héroe puede saltar sobre los ladrillos para evitar enemigos y recoger monedas. Arrastre la obra de arte de ladrillo de la Bienes panel y añadir un Colisionador 2D componente a ella No te olvides de convertirlo en un Casa prefabricada, Porque se utilizará bastante en el juego..
Usaremos un sprite para mostrar la línea final del nivel. Arrástrelo desde el Bienes panel para el Escena como se muestra en la captura de pantalla de abajo.
Mejoremos la experiencia auditiva de nuestro juego utilizando el Dolby Audio Plugin for Unity. Sin embargo, primero déjame explicarte por qué deberías usar el complemento de audio Dolby y cómo mejorará tu juego..
Dolby Digital Plus es una solución de audio avanzada integrada en muchos dispositivos móviles, incluidas las tabletas. Las aplicaciones móviles pueden aprovechar las capacidades de Dolby Digital Plus a través de API. Algunos de los beneficios incluyen la optimización de audio, la maximización de volumen y la nivelación de volumen. Dolby ha hecho que su API esté disponible para varias plataformas, incluyendo Android y Kindle Fire. En nuestro juego, aprovecharemos el complemento de Dolby Audio para Unity..
Tenga en cuenta que el complemento para Unity es de uso gratuito y muy fácil de integrar. En otras palabras, no hay razón para no incluirlo en tu próximo juego..
Comience por descargar el plugin de Dolby's Unity. Puede descargarlo desde Unity Asset Store o directamente desde el sitio web del desarrollador de Dolby. Si elige la última opción, cree una cuenta gratuita para descargar el complemento o inicie sesión si ya tiene una cuenta de desarrollador Dolby. Extraiga el paquete y copie la versión que necesita Activos> Complementos> Android. Así de fácil es instalar el plugin para Unity..
Cree un nuevo script y adjúntelo a un objeto que siempre esté presente en el juego, como el fondo o la cámara. Nombra el guion Dolby y rellénelo con el siguiente fragmento de código.
utilizando UnityEngine; utilizando System.Collections; utilizando System.Runtime.InteropServices; // Nos permite usar DLLImport public class Dolby: MonoBehaviour private GameObject debugText; Fuente pública arial; / * Funciones del complemento de importación * / [DllImport ("DSPlugin")] public static extern bool isAvailable (); [DllImport ("DSPlugin")] public static extern int initialize (); [DllImport ("DSPlugin")] public static extern int setProfile (int profileid); [DllImport ("DSPlugin")] public static extern int suspendSession (); [DllImport ("DSPlugin")] public static extern int restartSession (); [DllImport ("DSPlugin")] public static extern void release (); // Use esto para la inicialización void Start () / * Campo de texto creado para comentarios * / debugText = new GameObject (); debugText.AddComponent ("GUIText"); debugText.guiText.font = arial; debugText.guiText.fontSize = 14; debugText.guiText.color = nuevo Color (255, 0, 0); debugText.transform.position = nuevo Vector3 (0, 1, 0); / * Inicializar Dolby si está disponible * / if (isAvailable ()) Invoke (Init, 0.1f); // Espere 100 ms para asegurarse de que el servicio Dolby esté habilitado else debugText.guiText.text = "Dolby Sound no disponible"; void Init () debugText.guiText.text = "Dolby Sound Available"; setProfile (2); / * Establecer perfil en "Juego" * / initialize (); void OnApplicationPause () suspendSession (); // El sonido Dolby se detiene si la aplicación cambia o está en pausa void OnApplicationFocus () restartSession (); // Reiniciar el sonido Dolby si la aplicación está activa void OnApplicationQuit () release (); // Detiene Dolby Sound completamente
Estoy seguro de que estás de acuerdo en que es muy fácil integrar Dolby Audio API en tu juego. Primero creamos un debugText
objeto, que es de tipo GameObject
, para recibir comentarios del dispositivo. Luego importamos las funciones necesarias definidas por Dolby Audio API e inicializamos Dolby Audio API si el dispositivo del usuario lo admite..
Para asegurarnos de que el servicio Dolby esté habilitado, esperamos brevemente (0.1s) antes de llamar al inicializar()
método. Si no hacemos esto, existe la posibilidad de que reciba un -1
error, que puede suceder cuando intenta activar Dolby cuando se establece el servicio.
Dolby también ha incluido funciones para suspender y reiniciar el sonido cuando sea necesario, lo cual es útil cuando cambiamos a otra aplicación y no necesitamos la mejora de sonido. Esto es importante para conservar la energía de la batería y otros recursos del dispositivo. También podemos detener la mejora de sonido completamente invocando lanzamiento
como lo hacemos en OnApplicationQuit
.
Es hora de probar el juego. Pulsa Comando-P para jugar el juego en Unity. Si todo funciona como se espera, estás listo para los pasos finales..
Cuando estés satisfecho con tu juego, es hora de seleccionar Configuraciones de compilación desde el Expediente menú y haga clic en el Ajustes del jugador botón. Esto debería mostrar el Ajustes del jugador en el Inspector Panel donde puede configurar los parámetros para su aplicación..
Estas configuraciones son específicas de la aplicación e incluyen el creador o la compañía, la resolución de la aplicación, el modo de visualización, etc. Estas configuraciones dependen de los dispositivos a los que te dirijas y las tiendas o mercados en los que publicará tu juego.
Con los gráficos que creaste anteriormente, ahora puedes crear un bonito icono y una imagen de bienvenida para tu juego. Unity le muestra los tamaños requeridos, que dependen de la plataforma para la que está construyendo..
Una vez que su proyecto esté correctamente configurado, es hora de volver a visitar el Configuraciones de compilación y haga clic en el Construir botón. Eso es todo lo que se necesita para construir tu juego para prueba y / o distribución.
En este tutorial, hemos aprendido sobre el nuevo Dolby Audio Plugin para Unity, hojas de sprites, controles, detección de colisiones y otros aspectos del desarrollo de juegos que utilizan Unity. Te animo a experimentar con el resultado y personalizar el juego para que sea tuyo. Espero que te haya gustado este tutorial y te haya resultado útil..