() 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:

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.

Ahora creemos un script dentro de él.

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.

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.

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.

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.

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.

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.

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.

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!