Advertisement
  1. Code
  2. Workflow

Gestión procesal de recursos en Unity

Scroll to top
Read Time: 9 min

() translation by (you can also view the original English article)

Anteriormente, vimos cómo agregar tus propias herramientas al editor de Unity; ahora, en este breve tutorial, te presentaré el manejo de los recursos por script en Unity. Administraremos rutas, crearemos archivos prefabricados, generaremos una textura y la guardaremos en una imagen. Finalmente también crearemos un archivo de material que usa la imagen generada, y todo esto se hará mediante código.


Vista previa del resultado final 

Echemos un vistazo al resultado final hacia el que trabajaremos:

Material with a texture assigned.

Paso 1: Configurar el proyecto

Crea un proyecto vacío; no usaremos nada sofisticado aquí, por lo que no deberíamos molestarnos en importar nada en absoluto. Una vez hecho esto, crea un script en el editor. Unity nos permitirá usar sus clases de editor solo si colocamos nuestro script en una carpeta llamada Editor. Dado que eso aún no existe en nuestro proyecto, debemos crearla.

Editor folder created in the project view.

Ahora creemos un script dentro de él.

Editor script in our folder.

Paso 2: Agregar un elemento de menú

Limpiemos nuestro script. Aparte de la funcionalidad básica, también queremos poder utilizar las clases del editor. Necesitamos usar UnityEditor y la clase de nuestro script debería extender la clase Editor en lugar de MonoBehaviour como lo hacen los objetos normales del juego.

1
using UnityEngine;
2
using System.Collections;
3
using UnityEditor;
4
5
public class Examples : Editor 
6
{
7
}

En nuestra primera función trabajaremos con prefabricados, llamémoslo PrefabRoutine.

1
public class Examples : Editor 
2
{
3
	void PrefabRoutine()
4
	{
5
	}
6
}

Para ejecutar fácilmente esta función desde el editor, agreguemos como MenuItem.

1
public class Examples : Editor 
2
{
3
	[MenuItem ("Examples/Prefab Routine")]
4
	void PrefabRoutine()
5
	{
6
	}
7
}

Aparte de hacerle saber a la unidad que queremos que esta función sea ejecutable desde "Examples->Prefab Routine", también necesitamos hacer que esta función sea estática.

1
public class Examples : Editor 
2
{
3
	[MenuItem ("Examples/Prefab Routine")]
4
	static void PrefabRoutine()
5
	{
6
	}
7
}

Si vuelves al editor ahora (y actualizas el menú), notarás que hay un nuevo menú llamado Examples.

Menu item added to the unity editor.

Si seleccionas Prefab Routine, no sucederá nada ya que nuestra función está vacía.


Paso 3: Crear una carpeta

Para dar forma a nuestro proyecto de la manera que queremos, necesitamos saber cómo crear carpetas para poder mover cosas. Crear una carpeta a partir del script es muy sencillo, todo lo que tenemos que hacer es dejar que unity sepa dónde debe colocarse la carpeta. Para crear una carpeta necesitamos usar la clase AssetDatabase.

1
[MenuItem ("Examples/Prefab Routine")]
2
static void PrefabRoutine()
3
{
4
	AssetDatabase.CreateFolder("Assets", "Prefab Folder");
5
}

"Assets" es el nombre de la carpeta principal del directorio que queremos crear. En nuestro caso, es la carpeta principal del proyecto donde se importan/crean todos nuestros recursos.

Ten en cuenta que también puedes utilizar la clase .NET Directory. Esto también te permitirá eliminar, mover o acceder a los archivos de los directorios. Para usar esta clase, debes usar System.IO.

Cada vez que selecciones Prefab Routine en el editor, se debe crear una nueva carpeta y estar visible en la vista del proyecto.

Folders created in our script.

Paso 4: Crear un prefabricado

Para crear un prefabricado necesitamos llamar a EditorUtility.CreateEmptyPrefab(). La función toma la ruta del prefabricado como argumento.

1
[MenuItem ("Examples/Prefab Routine")]
2
static void PrefabRoutine()
3
{
4
	AssetDatabase.CreateFolder("Assets", "Prefab Folder");
5
	
6
	Object prefab = EditorUtility.CreateEmptyPrefab("Assets/Prefab Folder/obj.prefab");
7
}

¡No te olvides de la extensión! Además, después de crear el archivo, debemos llamar a AssetDatabase.Refresh(), para que Unity pueda verlo.

1
[MenuItem ("Examples/Prefab Routine")]
2
static void PrefabRoutine()
3
{
4
	AssetDatabase.CreateFolder("Assets", "Prefab Folder");
5
	
6
	Object prefab = EditorUtility.CreateEmptyPrefab("Assets/Prefab Folder/obj.prefab");
7
	
8
	AssetDatabase.Refresh();
9
}

Si dejamos una ruta constante como argumento, cada vez que seleccionamos nuestra rutina, un nuevo prefabricado vacío reemplazará al anterior. Asignemos cada prefabricado a una carpeta separada para contrarrestar eso. Para hacer esto, necesitamos guardar la carpeta creada más recientemente en una cadena para poder usarla como un argumento de ruta más adelante. La función CreateFolder devuelve un GUID, que básicamente es el ID del archivo (o directorio). Hay una función que obtiene la ruta si enviamos este ID. Se llama GUIDToAssetPath; usémoslo para obtener la ruta de nuestra carpeta.

1
[MenuItem ("Examples/Prefab Routine")]
2
static void PrefabRoutine()
3
{
4
	string path = AssetDatabase.GUIDToAssetPath(AssetDatabase.CreateFolder("Assets", "Prefab Folder"));
5
	
6
	Object prefab = EditorUtility.CreateEmptyPrefab("Assets/Prefab Folder/obj.prefab");
7
	
8
	AssetDatabase.Refresh();
9
}

Ahora usemos path para dirigir los prefabricados que vamos a crear a la carpeta creada más recientemente.

1
[MenuItem ("Examples/Prefab Routine")]
2
static void PrefabRoutine()
3
{
4
	string path = AssetDatabase.GUIDToAssetPath(AssetDatabase.CreateFolder("Assets", "Prefab Folder"));
5
	
6
	Object prefab = EditorUtility.CreateEmptyPrefab(path + "/obj.prefab");
7
	
8
	AssetDatabase.Refresh();
9
}

Puedes probar si los objetos prefabricados vacíos creados están empaquetados en carpetas ahora.

Prefabs in the folders.

Paso 5: Configurar el prefabricado

Si creas un objeto prefabricado, probablemente no quieras dejarlo vacío porque en ese caso es bastante inútil. Configuremos nuestro prefabricado si hay algún objeto de juego seleccionado mientras se ejecuta nuestra rutina. Realizaremos el prefabricado del objeto seleccionado. Para obtener el objeto seleccionado actualmente, podemos usar la clase Selection que tiene una referencia a él. Para configurar el prefabricado, debemos llamar a ReplacePrefab().

1
[MenuItem ("Examples/Prefab Routine")]
2
static void PrefabRoutine()
3
{
4
	string path = AssetDatabase.GUIDToAssetPath(AssetDatabase.CreateFolder("Assets", "Prefab Folder"));
5
	
6
	Object prefab = EditorUtility.CreateEmptyPrefab(path + "/obj.prefab");
7
	
8
	AssetDatabase.Refresh();
9
	
10
	if (Selection.activeObject)
11
		EditorUtility.ReplacePrefab(Selection.activeGameObject, prefab);
12
}

Si ejecutas la rutina con cualquier objeto de juego seleccionado ahora, notarás que el prefabricado creado se configura automáticamente.

Prefab set to the selected object.

Eso es todo, hemos creado una rutina personalizada para la creación de elementos prefabricados, no es muy útil, pero deberías poder saber cómo hacerlo ahora si hay una necesidad de tal cosa en tu proyecto.

Al final, también quiero mencionar que AssetDatabase también te permite mover recursos, moverlos a la papelera o eliminarlos llamando a AssetDatabase.MoveAsset(), AssetDatabase.MoveAssetToTrash() y AssetDatabase.DeleteAsset() respectivamente. El resto de la funcionalidad se puede encontrar en la página de referencia del script AssetDatabase.


Paso 6: Agregar otro elemento de menú

Vayamos a otro ejemplo, esta vez crearemos una textura y un material mediante programación. Llamemos a este elemento de menú Material Routine.

1
[MenuItem ("Examples/Prefab Routine")]
2
static void PrefabRoutine()
3
{
4
	string path = AssetDatabase.GUIDToAssetPath(AssetDatabase.CreateFolder("Assets", "Prefab Folder"));
5
	
6
	Object prefab = EditorUtility.CreateEmptyPrefab(path + "/obj.prefab");
7
	
8
	AssetDatabase.Refresh();
9
	
10
	if (Selection.activeObject)
11
		EditorUtility.ReplacePrefab(Selection.activeGameObject, prefab);
12
}
13
14
[MenuItem ("Examples/Material Routine")]
15
static void MaterialRoutine()
16
{
17
}

Ahora tenemos dos elementos para elegir en el menú Examples.


Paso 7: Crear una textura

Creemos una Texture2D y establezcamos su tamaño en (256, 256) para este ejemplo.

1
[MenuItem ("Examples/Material Routine")]
2
static void MaterialRoutine()
3
{
4
	Texture2D tex = new Texture2D(256, 256);
5
}

Ahora no deberíamos dejar que todos esos píxeles se desperdicien, así que configuremos los píxeles de la textura de acuerdo con algún tipo de fórmula pensada. Para eso, necesitaremos dos bucles for para pasar por cada píxel. Para establecer el color de cada píxel, debemos llamar a SetPixel(), que toma la posición del píxel en una textura y su color como argumentos.

1
[MenuItem ("Examples/Material Routine")]
2
static void MaterialRoutine()
3
{
4
	Texture2D tex = new Texture2D(256, 256);
5
	
6
	for (int y = 0; y < 256; ++y)
7
	{
8
		for (int x = 0; x < 256; ++x)
9
			tex.SetPixel(x, y, new Color());
10
	}
11
}

Para asignar el color usaremos la función Mathf.Sin(). La clase Color se puede inicializar con tres flotantes, correspondientes a los componentes de color rojo, verde y azul, respectivamente. El valor máximo permitido es 1 y el mínimo es 0, por lo que la función Sin() se adapta perfectamente a nuestras necesidades.

1
for (int y = 0; y < 256; ++y)
2
{
3
	for (int x = 0; x < 256; ++x)
4
		tex.SetPixel(Mathf.Sin(x*y), Mathf.Sin(x*y), Mathf.Sin(x*y)));
5
}

No importa lo que enviemos a la función Sin(), pero para obtener algo más interesante, debemos dar un valor que cambie para cada píxel.


Paso 8: Crear una imagen

Ahora vamos a generar una imagen a partir de la textura que acabamos de crear. Dado que escribiremos en un archivo en modo binario, necesitamos usar System.IO, así que vamos a agregarlo al principio de nuestro script.

1
using UnityEngine;
2
using System.Collections;
3
using UnityEditor;
4
using System.IO;
5
6
public class Examples : Editor

Para guardar nuestra textura como una imagen PNG, primero debemos llamar a EncodeToPNG() que devolverá una matriz de bytes que contiene el archivo PNG.

1
for (int y = 0; y < 256; ++y)
2
{
3
	for (int x = 0; x < 256; ++x)
4
		tex.SetPixel(x, y, new Color(Mathf.Sin(x*y), Mathf.Sin(x*y), Mathf.Sin(x*y)));
5
}
6
7
byte[] pngData = tex.EncodeToPNG();

Ahora que tenemos nuestro pngData, podemos escribirlo en un archivo y crear una imagen PNG de esta manera.

1
byte[] pngData = tex.EncodeToPNG();
2
3
if(pngData != null)
4
	File.WriteAllBytes("Assets/texture.png", pngData);

Dado que creamos el archivo en una ruta constante, cada vez que ejecutamos MaterialRoutine(), la textura se sobrescribe.

Y como tenemos nuestra imagen, ya no necesitamos la textura generada, ya que de todos modos no hará referencia a una imagen. Vamos a destruirla.

1
byte[] pngData = tex.EncodeToPNG();
2
3
if(pngData != null)
4
	File.WriteAllBytes("Assets/texture.png", pngData);
5
	
6
DestroyImmediate(tex);

Además, debemos permitir que Unity actualice la vista del proyecto y las referencias de los archivos; para hacer eso, necesitamos llamar a AssetDatabase.Refresh().

1
byte[] pngData = tex.EncodeToPNG();
2
3
if(pngData != null)
4
	File.WriteAllBytes("Assets/texture.png", pngData);
5
	
6
DestroyImmediate(tex);
7
AssetDatabase.Refresh();

Probemos si la textura se crea cuando ejecutamos nuestra rutina.

The generated texture.

Paso 9: Crear un material

Tenemos una imagen y ahora podemos crear un material que la use como textura. Creemos un nuevo Material.

1
AssetDatabase.Refresh();
2
3
new Material(Shader.Find("Diffuse"));

El material creado utilizará un sombreador difuso. Para guardar este material en el archivo, podemos llamar a AssetDatabase.CreateAsset(). Esta función toma un recurso como primer argumento y la ruta como segundo.

1
AssetDatabase.Refresh();
2
3
AssetDatabase.CreateAsset(new Material(Shader.Find("Diffuse")), "Assets/New Material.mat");

Si ejecutas nuestra rutina ahora, verás que se crea el material.

Material without assigned texture.

Como puedes ver, todo es correcto, su nombre es New Material y usa sobras difusas, pero no tiene ninguna textura asignada.


Paso 10: Asignar la textura

Primero necesitamos obtener una referencia al material que acabamos de crear. Podemos obtener eso llamando a AssetDatabase.LoadAssetAtPath() que carga el recurso y devuelve su referencia.

1
AssetDatabase.CreateAsset(new Material(Shader.Find("Diffuse")), "Assets/New Material.mat");
2
		
3
Material material = (Material) (AssetDatabase.LoadAssetAtPath("Assets/New Material.mat",typeof(Material)));

Ahora asignemos nuestra textura generada como la textura principal del material. Podemos obtener la referencia de textura de la textura generada de la misma manera que obtuvimos la referencia de material.

1
Material material = (Material) (AssetDatabase.LoadAssetAtPath("Assets/New Material.mat",typeof(Material)));
2
material.mainTexture = (Texture2D) (AssetDatabase.LoadAssetAtPath("Assets/texture.png", typeof(Texture2D)));

Para ver los resultados, ejecuta el Material Routine.

Material with assigned texture.

Como puedes ver, el material tiene la textura asignada ahora.

Conclusión

Ese es el final de la introducción para administrar tus recursos mediante scripts. Si deseas ampliar tus conocimientos sobre el tema, puedes visitar la página de referencia de Clases del editor de Unity, en particular, vale la pena examinar la referencia del script AssetDatabase. Si necesitas trabajar a un nivel bajo, también debes leer los documentos en System.IO para obtener más información sobre sus clases y cómo puedes usarlas. ¡Gracias por tu tiempo!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.