Como reducir tamaño del build en Unity para mobiles

Sonido:

Al agregar archivo de audio para el proyecto en Unity, siempre usa puro sonidos en modo MONO, es decir que solo tiene un canal y por lo tanto se va escuchar exactamente igual como en el lado izquierdo y lado derecho. Ya que la mayoría de los celulares solo tienen una bocina y aunque tuvieran más de uno, suelen estar juntas y sonidos con efecto estereo se pierde. Si una persona juega tu juego y tiene audífonos puesto, simplemente se oirá igual en ambos lados, así que no habrá problema.

¿Porque? Bueno, un archivo de audio grabado en estéreo tiene el doble de información aunque sonara igual el sonido como en el lado izquierdo y lado derecho. Un ejemplo, una música de fondo puede pesar 4MB en modo estéreo y en modo Mono pesaría 2MB. El cual implica la mitad de espacio que usara en tu build final, mitad de RAM en uso, mitad en tiempo de carga solo de este archivo, con este espacio puedes ahora tener 2 canciones de la misma duración con la misma cantidad de recursos.

Para ahorrarse problemas sería mejor si pasáramos el archivo ya mono a Unity, pero si no, podemos indicarle a Unity que nos ayude con esta parte, al seleccionar el archivo de audio, hasta arriba tiene la opción de “Force to Mono” habilitamos y listo.

sonidos

Texturas e imágenes:

La primera regla al trabajar con texturas es siempre cuestionarnos si el tamaño de las texturas realmente son necesarias de ese tamaño, eso que quiere decir, ¿es necesario que la taza que solo sale en una vez en el primer nivel, es un adorno y su textura es de 512 x 512? Algo que le cuesta mucho a los desarrolladores es el sacrificar calidad. Siempre hay que hacer que tenga la mejor calidad los objetos que más serán vistos y con mayor frecuencia el usuario interactuara con ellos, de disminuimos y le reducimos calidad en proporción a lo frecuente y importante que es el objeto, regresando al ejemplo de la taza, si la taza solo sale una vez, su propósito es solamente de relleno y aparte el usuario nunca se acercara a este, podemos bajarle el tamaño de textura a unos 128 x 128 o inclusive a unos 64 x 64. Este tipo de objetos nunca los evalúes desde el Editor abarcando toda tu pestaña de escena. Siempre hazlo desde la perspectiva y distancia que tendrá la cámara en juego. ¿Que si te fijas muy bien, si se alcanza a notar? Ok, y el jugador por las mecánicas de tu juego, ¿tendrá que tener fija su mirada por donde estará la taza? Esto serán las cosas que tenemos que cuestionar y analizar para determinar la calidad de objeto ya sea Sprite o un modelo 3D.

“Generate MipMaps”: Esta opción esta al seleccionar imágenes que se usaran como Sprite. Este hay que deshabilitarlo cuando el sprite vaya ser usado en el UI o sabemos que no jugaremos con las escalas del sprite. ¿Porque? Bueno, esto es porque los MipMaps son copias de menor calidad que Unity genera de manera automática para que en caso de escalar, no tenga que calcular como se vería la imagen. El problema de esta opción es que crece un 30% del peso final de tus texturas. Nota, en objetos 3D esto siempre tiene que estar activado.

mipmap

Estos tips pueden ayudar mucho en el tamaño del build final como en el consumo de RAM del juego.

Consejos para aprender programación

Cuando uno se va metiendo en el mundo de programación, a veces es difícil meterse, ya que la programación es tan variado y siempre puedes encontrar algo nuevo que aprender. Pero entonces, ¿Como uno puede ingresar al mundo de la programación? Dejo aquí unos pequeños consejos, pero pueden guiar a cualquier programador.

Programa, programa y programa.

Una vez entendido que son variables, if, for, while, switch y funciones. Programa y programa, la verdad no hay mejor manera. Ponte un meta, uno básico por ejemplo es hacer una calculadora y avanza paso por paso, te topas con un problema o error, solucionarlo y avanza. A lo mejor puede tomarte 1 día,   2 o más la primera vez y no te sientas tonto por esto, estarás aprendiendo y así empezamos todos.

Divide tu meta en pasos.

Nunca trates de programar todo de un golpe, siempre hazlo por pequeños pasos y submetas. En el caso de una calculadora, ok, primero haz un botón, luego que imprima un “Hola” al presionar el botón, después duplicarlo y posicionar como seria los botones de la calculadora, seguido de que al presionar un botón de un numero este lo imprima, después que al presionar un segundo botón, ya se combine con lo que ya estaba escrito, después que si presiono otro botón como suma, obtener y almacenar el numero escrito. Así consecutivamente y probando en cada paso y solucionando problemas como surjan. Esto es más fácil de ir arreglando y a la larga más rápido.

Explícaselo al ‘Pato’.

Cuando no entiendas que sucede algo que no funcione correctamente, primero levántate, despéjate un rato, luego ve por un pato de bañera, un juguete que aun contengas o un peluche y explícale que hace tu código (No le digas tus problemas, explica que hace tu código línea por línea) aunque te sientas un tonto, te sorprenderá como al explicar un código puedes encontrar muchos errores desde lógica a dedo.

B75vnDaIgAAXGDV.jpg large

Lee teorías y algoritmos.

Nunca hay tiempo para programar de todo y tener experiencia en varios aspectos, pero es muy útil si lees teorías, algoritmos o técnicas que usaron otros para resolver problemas. Entender cuál es la teoría para llevar a cabo un problema, aunque no te enfrentes al mismo, tener mucha referencias, puedes usarlas para resolver otros problemas.

No tengas miedo de usar otros códigos y re usarlos.

La comunidad de programadores, es de los mejores ejemplos donde la ayuda mutua logra grandes cosas. Busca códigos en San Google, rehúsa los código que ya hayas usado. En la programación es mucho usar código ya existente para avanzar y resolver problemas, no hay nada de malo, es muy útil y además nadie sabe todo y menos en algo tan extenso como la programación. Eso sí, entiende aunque no sea línea por línea, pero si la lógica y concepto de lo que has copiados, porque muchas veces encontraras más que nada ejemplos, y tendrás que modificar para tus necesidades y unirlo a lo que ya tienes.

¿Pagina que recomiendo?

Yo recomiendo la pagina Code.org, el cual esta destinada a fomentar y enseñar desde entender como es la lógica que se requiere para llevar acabo a la programación a través de ejercicios que van con interfaces muy clic, arrastra y suelta, hasta pequeños códigos para darnos idea. Los cuales mientras estudias un lenguaje de programación recomiendo que prueben los tutoriales y juegos de Code.

Que es el Lerp y como usarlo correctamente

Lerp o Interpolaciòn lineal, es la linea continua que se genera entre un punto inicial y un punto final. Y se puede sacar cualquier punto de esta recta linea, solo necesitamos un porcentaje donde 0% es el punto inicial y 100% es el punto final. En otras palabras podemos obtener cualquier coordenadas que se encuentre entre estos 2 puntos.

LerpExample

NOTA: en programacion 0% – 100% se representa con 0 – 1

Esto en videojuegos se utiliza para hacer mover un objecto cuando deseamos que vaya de un punto A a un punto B. Pero generalmente suele usarse de una manera incorrecta. Codigo base en Unity: Ejemplo:


float Speed = 5f;
transform.position = Vector3.Lerp.html(transform.position, Destiny, Speed * Time.deltatime);

 

¿Porque es incorrecto esto? Bueno imaginemos que estoy en (0,0,0) y deseo ir a (10,0,0).

Frame 1: El Lerp me devolverá un punto entre el inicio y el final, más o menos como a 0.01f (Speed( que es 5f) * Time.deltatime (Que puede ser como un 0.02f)), esto me moverá a  (0.1, 0, 0) porque es el 1% de 10 que es la distancia a recorrer en X.

Han pasado varios frames después en el que ya voy a mitad del destino, es decir mi GameObject va en(5, 0, 0), sigo pidiendo el punto a 0.01, pero ahora no entre (0, 0, 0) y (10, 0, 0), si no de (5, 0, 0) y (0,0,0), es decir el 1% de 5 que es la distancia en X, sera 0.05, ¡ya la mitad de lo que empece en el primer frame a moverme!, esto genera que el movimiento tenga una velocidad uniforme y se vaya desacerando y tarde algo en llegar al destino. Muchos no lo notan y solo piensan que no es preciso y lo “solucionan” que si esta ya a cierta distancia, ya “llego”.

¿Como usar correctamente Lerp?

Ya entendiendo la teoría y el problema, tenemos siempre que conservar el punto inicio y avanzar a un ritmo. Esto podemos hacer así.


float rateTiempo = 1f/TiempoEnHacer;
float rateVelocity = 1f/ Vector3.Distance(startPos, endPos) * Velocidad;
float t = 0.0f;

if(t <= 1f)
{
 t += Time.deltaTime * rate;
 transform.position = Vector3.Lerp(startPos, endPos, t);
}

‘rate’ solo tenemos que sustituir por ‘rateTiempo’ o ‘rateVelocity’ según si necesitamos que recorra eso siempre en un tiempo exacto o se mueva a una velocidad. Y ‘startPos’ son las coordenadas del punto inicial y ‘endPos’ son las coordenadas donde deseamos terminar.

De esta manera, siempre la distancia es la misma y la velocidad constante. Ahora existen 2 rate en este caso, la  ‘rateTiempo’ cuando deseas que haga el recorrido en un cierto intervalo de tiempo o ‘rateVelocity’ para hacer el recorrido a una velocidad, cualquiera de las 2 se sustituye por ‘rate’ dentro del if.

La misma teoría se aplica para la rotación, Vectores 2, 3, 4 o incluso solo un lerp entre 2 números.

Aquí dejo un paquete de Unity que contiene una escena con un pequeño ejemplo Ejemplo Lerp.

Singletons (Instancia única)

El singleton (instancia única), es una clase que sólo contiene una instancia y tiene un punto de acceso de manera global a ella. Un Singleton se encarga de auto generar una instancia en caso que no exista una y su referencia es global.

Las utilidades de un singleton son bastantes, desde tener una clase que sirva de almacén de datos y cualquier otra clase pueda acceder a ella y sus funciones y variables de manera global. Por ejemplo si en tu juego solo habrá una cámara y tiene su clase o script que se encarga de controlarlo, se puede volver un singleton para que modificar la cámara bastaría con: CamaraClass.SetPos(NewPos) en caso de C# y CamaraClass::SetPos(NewPos) en caso de C++.

C++

En caso de C++, una manera de tener referencia global es declarar una variable hasta arriba de un archivo, pero esto se complica al manejar varias clases y si queremos tener una referencia de una variable, es mandarlo como parametro como referencia, pero en caso que una clase solo va existir uno, como el que controla la camara, la manera de declarar una clase singleton es tener los 2 archivos para una clase el header(.h) y el ‘Class Code’ (.cpp).

En el ‘Header’ al final del archivo y fuera de las llaves ‘{‘ y ‘}’ se declara un extern del tipo de la clase y como se llamara.


extern MICLASSE g_variable;

Y en el empiezo de ‘Class Code’ se declara:


MICLASSE g_varaible;

De esta manera en todos las clases que queremos hacer referencia a la clase, solo bastara agregar como include el header y al llamar g_variable este harán referencia exactamente a la misma clase con las mismas variables. Bastante útil como contenedor para variables compartidas en varias clases.

C# / Unity

En caso de Unity, una manera popular de tener referencia a un script es declarar una variable publica del tipo del script y en el editor asignar la referencia. Esto no es malo, es una buena manera , sencilla y segura. Pero cuando sabemos que solo puede existir un GameObject con ese script a la vez podemos volverlo un Singleton y no será necesario ni asignarlo por editor ni código, solo llamar el script. Una manera sencilla de volver un singleton un GameObject es:

Creamos un script que yo llame “MiCamara” y se la asignamos a la camara (En mi caso, simulare que mi juego, siempre solo existira una camara por escena).

public class MiCamara : MonoBehaviour
{
    public static MiCamara instancia;

    void Awake()
    {
        instancia = this;
    }

    public void Mover ()
    {
        transform.Translate (Vector3.forward, Space.World);
    }
}

Donde se tiene que declarar una varaible estatica del mismo tipo de la clase que quieres volver un singleton, en este caso ‘MiCamara’. Entonces al empezar la escena, el script se autoasignara en ‘instancia’. Por lo que si quisiera llamar la función ‘Mover’ desde otro script, solo bastara que se llame:


MiCamara.instancia.Mover ();

Bastará escribir el nombre de la clase, ‘instancia’ y sin tener referencia por variable publica en el script, el codigo sabra que con ‘MiCamara.instancia’ te refieres a la camara y en este caso, lograra mover la camara del juego.

Ahora una clase con puras variables publicas y estáticas y removiendo el “: MonoBehaviour” de la clase, todo su contenido sera accesible por todos los scripts y además de servir para compartir variables entre diversos scripts, al cambiar entre escenas sus valores no serán afectados, por lo que es una forma sencilla y optima para comunicar datos entre escenas. Incluso se le puede asignar GameObjects(Como Prefabs), Texture2D, etc.

public class Contenedor
{
    public static int vidas;
    public static bool EstaVivo;
    public static float VelocidadJuego;
}

MipMaps en Unity

Este script es parte de Arj2D.

Los MipMaps de una textura es cuando Unity pre genera varias versiones de una imagen para cuando un Objeto que utilice esa imagen se encuentra escalado o alejado de la cámara (Solo en cámara perspectiva), para evitar que en cada cuadro sea calculado ese cambio de escala en la imagen y ahorrar tiempo en el procesamiento.

En proyectos 3D, si una textura se utilizara en un modelo 3D es bueno dejárselo, pero en caso de un proyecto 2D y sabemos que esa imagen no la escalaremos será mostrado con escala normal como el UI, podemos desactivárselo, ya que al dejarlo activado, este archivo pesara un 30% más.

Desactivar MipMaps por defecto o automáticamente.

Ahora, aquí les comparto un script que debe estar dentro de una carpeta llamada “Editor”, el cual genera que automáticamente todas las nuevas imágenes que se agreguen al proyecto, tengan deshabilitado Mipmaps por defecto.

Manejar aspecto de pantalla para diferentes resoluciones

Este script es parte de Arj2D.

Cuando se trabaja para dispositivos móviles, es normal encontrarse con un pequeño problema y más si se trabaja en 2D es que al haber tantos aspectos de pantalla entre tanto dispositivo en el mercado, es fácil que si desarrollamos nuestro juego donde en una esquina esta un objeto por ejemplo el mostrador de puntaje, al pasarlo a otro dispositivo con una dimensión diferente (Más frecuente cuando es uno de menor dimensión) el puntaje ya no aparece en pantalla o caso contrario donde la resolución es mayor el puntaje, este aparece, pero ya no en la esquina.

Para solucionar este problema sin tener que ajustar todo el contenido de nuestra(s) escena(s), podemos agregar este script a cada camera del juego y poner la resolución original con la que fue desarrollado el juego y listo.

Este funciona de 2 maneras, una es forzar la cámara para que se ajuste a la pantalla simplemente llamando “this.GetComponent<Camera>().aspect = AspectoDeseado” la desventaja de este método es que puede distorsionar un poco el render si el aspecto difiere mucho, sin embargo es el más utilizado.

La otra manera es calcular la mayor cantidad espacio de la pantalla que se puede utilizar sin forzar la distorsión y solo dibujar en esa área, sin embargo la desventaja es que en algunos dispositivos puede quedar espacio en las orillas sin usarse. Nota mi script añade una segunda cámara al usar este modo para llenar de color negro esta parte, ya que si no se añade esta segunda cámara en algunos dispositivos llena faltante como se le de la gana al diapositivo y puede generar efectos curiosos.


private void Resize()
{
 //Aspect ratio
 float targetaspect = DesignAspectWidth / DesignAspectHeight;

 //check actual aspectratio
 float windowaspect = (float)Screen.width / (float)Screen.height;

 //check actual vs wish aspect
 float scaleheight = windowaspect / targetaspect;

 if (scaleheight &lt; 1.0f) //portrait
 {
  Rect rect = GetComponent().rect;

  rect.width = 1.0f;
  rect.height = scaleheight;
  rect.x = 0;
  rect.y = (1.0f - scaleheight) / 2.0f;

  GetComponent().rect = rect;
 }
 else //lanscape
 {
  float scalewidth = 1.0f / scaleheight;

  Rect rect = GetComponent().rect;

  rect.width = scalewidth;
  rect.height = 1.0f;
  rect.x = (1.0f - scalewidth) / 2.0f;
  rect.y = 0;

  GetComponent().rect = rect;
 }

 //Create background in black
 CreateBackGround();
}

private void CreateBackGround()
{
 Camera cam = new GameObject().AddComponent();
 cam.gameObject.isStatic = true;
 cam.depth = -10;
 cam.cullingMask = 0;
 cam.farClipPlane = 1f;
 cam.orthographic = true;
 cam.backgroundColor = Color.black;
 cam.gameObject.name = "BackGround_Camera";
}

DESCARGAR SCRIPT

Arj2D

Arj2D es un framework que estoy desarrollando que trae scripts para el Editor, GameObjects, librerías y singletons que ayudan a la elaboración de proyectos en Unity orientado a 2D. Algunos scripts son compatibles con proyectos 3D, pero en si el framework esta orientado al 2D. Ya que el framework esta en desarrollo y contiene varios scripts, iré publicando aquí en el blog partes de él y así como un poco más detallada de que hacen.

El Framework es de código abierto y gratuito, y se encuentra hospedado en GitHub para que siempre puedan tener acceso a la ultima versión. Arj2D.

Si tienes un proyecto que utilice una parte de el framework, pueden decirme y lo publicare aquí.

Juegos/Proyectos que usan Arj2D:

ShoeBox y Unity – (Generador de Atlas para Unity)

ShoeBox es un programa gratuito que permite unir varias imágenes para elaborar un Atlas (Una imagen grande con varias imágenes más pequeñas), el cual los Atlas son muy útiles en el momento de trabajar en videojuegos ya que sirve mucho en la optimizan (En otro post hablare de esto). Lo mejor de todo es que es completamente gratuito.

Interfaz del programa

Aquí les agrego la imagen del antes y después de utilizar este programa. Solo debemos arrastrar todas las imagenes que queremos que se unan en una mayor a “Sprite Sheet” de ShoeBox.

Mario_shoebox

De 44 imágenes, obtenemos solo una imagen, pero conservando sus tamaños.

ShoeBoxReading (Importador de ShoeBox a Unity)

Obtenemos una imagen más grande que tiene adentro de el todas las imágenes que forman las animaciones del personaje (Mario bros) en este caso y un archivo llamado “sprites.xml” el cual usaremos para poder importarlo en Unity.

Para esto necesitaremos de un script para Unity que yo eh elaborado, el cual podemos obtener de aquí Link. Y este script tenemos que pasarlo a Unity dentro de una carpeta llamada “Editor” (Si no tenemos, la creamos). Una vez agregado pasamos agregar los 2 archivos que nos genero ShoeBox que es la imagen Atlas de Mario Bros que tenemos que asignar como Sprite y el archivo “sprites.xml”, ambos archivos podemos cambiarles el nombre. Dentro de Unity iremos a “Windows -> ShoeBoxReading -> Import” y nos mostrara una ventana que nos pedirá un Texture2D y un archivo, aquí asignaremos los 2 archivos que habremos pasado a Unity y indicamos donde queremos el pivote de los sprites y le damos en “Read”  y listo.

shoeboxreading

Listo ya tenemos nuestros sprites para poder trabajar en Unity y de manera optimizada. Ahora el archivo “sprites.xml” pueden eliminarlo (y en caso recuperarlo usar el siguiente script) o dejarlo ahí en el proyecto, al final al cabo al momento de compilar Unity ignorara este archivo y no afectara en el tamaño final de la compilación.

ShoeBoxMaked (Exportador de Unity a ShoeBox):

También eh elaborado un script que permite a partir de un Atlas, generar el archivo “sprite.xml” para poder recuperar las imágenes y separarlas con ayuda de ShoeBox. Esto en caso que hayamos eliminado el archivo “sprite.xml” y la opción de “Extract sprites”  de ShoeBox no haya dado resultado.

Para eso bajaremos el archivo ShoeBoxMaked y lo agregaremos a Unity en una carpeta llamada “Editor” y pasaremos a “Windows -> ShoeBoxReading -> ShoeBox Export” donde nos mostrara una ventana donde nos pedirá un Texture2D y aquí asignaremos el Atlas con sus sprites ya asignados de Unity y le damos en “Create” y nos genera un archivo “(Nombre del atlas).xml” en la misma carpeta donde se encuentra el Atlas que utilizamos, y ahora abrimos esta carpeta en el explorador y arrastramos estos dos archivos a la opción “Read Sprites” y obtendremos sprite como imagen separada, el proceso inverso de “SpriteSheet”.

marios

Al dar en Save almacena cada sprite como imagen independiente en la misma carpeta donde se encuentran los 2 archivos que usamos.

Preguntas (FAQ):

  • ¿Porque no generas un archivo para descargar inmediatamente?
    • Uso GitHub para compartir proyectos de codigo abierto y de esta manera si hago un cambio es fácil siempre descarguen la versión más reciente. Si prefieres puedes ir a la raiz del proyecto LINK y de lado derecho le das en “Download ZIP” y solo importa la carpeta “Editor” a Unity.
  • Unity ya tiene su generador de Atlas, ¿porque usar ShoeBox?.
    • Bueno, estos scripts los genere cuando el generador de Atlas era exclusivo de la versión PRO, pero sigo usándolo para tener un mayor control del Atlas.

Gestor de proyectos recientes en Unity

Al abrir Unity, este nos muestra una lista de todos los proyectos con los que hemos trabajado dentro de Unity. Pero con el paso del tiempo se irán acumulando y no es necesario que siempre tengamos el acceso directo a todos los proyectos. Es por eso que eh desarrollado este software que permite visualizar todos los proyectos que están en la lista de Unity de proyectos recientemente abierto y podremos seleccionar y eliminar con un clic aquellos proyectos que ya no deseemos que aparezcan en la lista.

projectlistunitymaanger

Nota: Solo lo remueve de la lista de proyectos recientes en Unity, NO elimina el proyecto del disco duro. Así si deseamos reabrir un proyecto que no se encuentre en la lista, bastara con usar el abrir proyecto.

Descargar versión para Unity 5 

Descargar versión para Unity 4

Hola Mundo!

Hola a todos, bienvenidos a mi blog. Anteriormente tenia daba mantenimiento a mi ex blog Arjïerda, pero después de un tiempo decidí reabrir otro blog, que es este Arjierda Games. Aquí estará más enfocado a la programación y más que nada al desarrollo de videojuegos. Generalmente sera sobre C++, C# enfocado a Unity y por ahí que otro lenguaje de programación. Así como explicación de algunas teorías y consejos. Espero sea de su agrado y no olviden en comentar y compartir.

También publicare sobre herramientas que vaya desarrollando y el como usarlas.