jueves, 20 de octubre de 2011

Una entrada interesante sobre Boost.Serialization

Me ha interesado mucho este articulo en IBM.com sobre Boost.Serialization. Basicamente esta libreria te permite convertir un objeto en un chorro de bytes (y viceversa), permitiendote enviar objetos por la red o guardarlos en un archivo. Es ideal para ayudar a un desarrollador a crear partidas salvadas y cargarlas luego, o para crear partidas en red.

El articulo es en ingles, o sea, el idioma de la informatica y de internet (yo solo lo dejo ahi... para que lo pienses.... :) )

Espero que te guste.

jueves, 13 de octubre de 2011

Apuntes de Multithreading (II)


En este segundo capitulo pretendo mostrar como se crean threads. Un thread, como expliqué en el anterior artículo, es un objeto de la clase boost::thread, asi que al crearlo se llama al constructor.

Al crearlo, como parámetro de entrada le damos una función que es la que ejecutaremos en un thread separado.

void func1()
{
    //hacer algo aqui
}
int main()
{
    boost::thread t(func1);
    t.join();
}


Aunque tambien podemos usar functors para indicar al thread que tarea ejecutar.

class complexFunc2
{
    void operator()() const
    {
        //hacer algo complejo aqui.
    }  
};

int main()
{
    boost::thread t(complexFunc2);
    t.join();
}


Hay algo que es importante. El parametro que le pasamos a un thread entra por copia y no por referencia. Una vez finaliza el thread, el objeto que le hemos pasado por copia es destruido. Esta operacion no tiene ningún peligro excepto si entre tus datos miembro tienes punteros, y el destructor los intenta borrar, asi que cuidado.

Por ejemplo:

class complexFunc3
{
    int& number;
    complexFunc3(int& _number):number(_number){}
    void operator()() const
   {
     for(int i = 0; i < 10000; i++)
       printf("%d\n",number);
   }
};
int main()
{
    int myVar = 2;
    boost::thread t(complexFunc2(myVar));
}


Una vez acaba el main, el thread principal (nuestro programa principal siempre es un thread) acaba y libera recursos. En este caso myVar es destruida. Probablemente en una de las iteraciones del bucle, printf fallará porque myVar ha dejado de existir, y por tanto number es una referencia a un número que ya no existe, y fallará.

Para evitarlo deberiamos llamar al método join(), para que el main espere la finalización de thread antes de salir. El join deberia ser llamado si al final de una funcion o dentro de la excepcion. Esto es:

int main()
{  
    int myVar = 2;
    boost::thread t(complexFunc2(myVar));

    try{
        // Algunas operaciones que pueden gnerar excepcion.
    }
    catch()
    {
        t.join();
        throw;
    }
    t.join();
}


Nos puede ser útil tambien hacer lo contrario y es separar definitivamente el thread del principal. Para ello primero debemos comprobar que hay un thread para separar, o para juntar en caso de que vayamos a usar join. Para comprobarlo usamos t.joinable(), y si sale true es que podemos hacer un detach().

int main()
{  
    boost::thread t(func);
    if(t.joinable())
        t.detach();
}
Por ultimo, explico que pasar parámetros a un thread es trivial.
void func(int i, float f){}
int main()
{  
    boost::thread t(func,2,2.5f);
    t.join();
}


Pero no hay que olvidar que los parametros se copian y que al final de la ejecución son destruidos asi que hay que tener en cuenta que enviamos y que pasará cuando sean destruidos, o que pasará cuando la función que crea el thread finalice y destruya las funciones creadas alli y el thread siga en marcha.

Pues aqui llega el final de este post, aunque todavia me queda un largo camino con los threads.

lunes, 10 de octubre de 2011

Apuntes de Multithreading

Probablemente te vas a aburrir con esta entrada, pero no pretendia ser eso sino más bien una especie de apuntes por que estoy aprendiendo desde 0 un poco de multithreading en C++.  En realidad queria escribir algo de boost::thread, pero al final se ha juntado todo un poco...

En principio habria que saber que un thread es un proceso que se ejecuta paralelamente a la aplicacion. Desde el punto de vista de Boost (aunque dentro de poco será std::thread), un thread es una clase, que podemos crear cuando queramos. Si tenemos instalado boost como libreria global a todo el sistema, no necesitamos nada para compilarlo. El código seria este:

#include "iostream"
#include  "boost/thread.hpp"

void hola()
{
    std::cout<<"Hola mundos paralelos!!!\n";
}

int main()
{
    boost::thread t(hola);
    t.join();
}

Si esto te compila y ejecuta sin quejarse es que tienes bien instalado Boost. ¿Pero funciona realmente?
Vamos a probar esto:


#include "iostream"
#include  "boost/thread.hpp"

const unsigned int MAX = 1000;
void hola()
{
    for(unsigned int i = 0; i < MAX; ++i)
    {
    	std::cout << "Mensaje dentro de la funcion HOLA numero " << i << "\n";
    }
}
int main()
{
    boost::thread t(hola);
    for(unsigned int j = 0; j < MAX; ++j)
    {
    	std::cout << "Mensaje desde el main con numero " << j << "\n";
    }
    t.join();
}
Si redireccionas la salida a un archivo, por que son 2000 lineas, tendrás que las lineas no salen separadas. Puedes encontrar lineas como esta:
Mensaje desde el main con numero Mensaje dentro de la funcion HOLA numero 13
Mensaje desde el main con numero 1014
Los carácteres entran cuando pueden, aunque pise media frase en el camino del otro thread.

Y que hace este código? Pues primero creamos un objeto thread. Como parámetro del constructor, le pasamos la función que queremos ejecutar. Luego viene el bucle que escribe mensajes en el thread principal, aunque dentro del thread tambien se estan enviando mensajes. Una vez acaba el bucle principal, si no hubiera nada más, el programa principal acabaria y el thread se quedaria alli haciendo lo que sea que tiene que hacer.

Para decir al programa que cierre el thread antes de irse, llamamos a join() que es como pedirle al programa que espere en ese punto al thread antes de continuar, y despues continue.

Y asi acaba la primera entrada sobre threads.

sábado, 1 de octubre de 2011

Creando una fuente de objetos en Unity3D

Sigo con mis experimentos en Unity. Lo que estoy intentando hacer es una fuente de objetos, es decir, que sobre un punto se vayan instanciando objetos, que irán cayendo en el suelo y desapareciendo.

Creando el terreno:
En esta parte voy a crear una especide de caja donde irán cayendo los objetos. La caja tiene cuatro paredes bajas y un suelo. Para crear el suelo voy al menú, y busco GameObject | Create Other |  Cube. Para ir rápido lo voy a situar en el (0,0,0), y lo voy a poner de unos 20x20 con una altura (en unity, por defecto la altura siempre es la 'y') de 0,2.

Luego ajustamos las paredes una a una:
Las paredes son a ojo pero con uno de grosor y 21 de ancho (en unos casos será Z y en otros X) y con una altura de 3 debería valer.


En el momento de ejecutarlo lo vas a ver muy negro asi que pongo 3 - 4 luces. Una direccional, y el resto de tipo spot, que hacer un radio de luz. Puedes experimentar, si quieres y cambiar el color, intensidad, numero de luces, etc.


Creando el Prefab.
Ahora tenemos que ver el objeto que irá creandose en la fuente. Vamos a diseñar uno. Cuando tengamos lo que queremos, haremos un prefab, que es algo asi como un modelo o molde para poder crear copias idénticas.

En mi caso voy a crear un cubo de 0.5 de lado, al que llamaré falling_box (originalidad ante todo :) ). En principio lo pondo a 5 de altura. Para que se vea claro, le pongo un material cualquiera. Voy a Materials, y elijo uno. En mi caso Fire Add. El cubo, por sí solo no va a moverse. Necesito decirle al cubo que pesa y para eso le voy a añadir un componente de Rigid body. Con el objeto seleccionado voy a component, voy a Component | Physics | RigidBody y veremos que aparece un componente RigidBody en el inspector del objeto falling_box. Si le damos al play veremos que cae, aunque cae a plomo. Le vamos a cambiar el material del que esta hecho. Para eso, vamos a los assets y seleccionamos Physics Materials. Le ponemos Bouncy en el recudro del Box Collider, en el inspector. Ahora podemos darle al play otra vez y nuestro objeto rebotará alegremente por el suelo. 

Nota: Si rotamos un poco el cubo, unos 5-45 grados cada componente, el cubo no caerá plano y botará de manera realista.

Guardamos el proyecto (File | Save Project) y preparamos nuestros deditos de programador. Vamos a hacer algunos scripts. La idea es que al cabo de un tiempo los cubos vayan desapareciendo para que no se acumulen muchos. Para ello vamos a usar un Destroyer. Le diremos que se destruya a sí mismo al cabo de 5 segundos. 
Debemos ir al panel project, crear primero un folder llamado scripts y despues un script, que en mi caso se llamará AutoDestroyer y será en C#. Cuando se crea viene con 2 funciones sin codigo, update y start. Yo le añado el código a start para que quede asi:
public class AutoDestroy : MonoBehaviour {
    
    // Use this for initialization
    void Start() {
        Destroy(gameObject, 5);
    }
}
Si lo probamos, vemos que el objeto efectivamente cae y siempre se destruye al cabo de 5 segundos. Como ya tenemos el modelo que teniamos, vamos a enlatarlo. Para ello, vamos al panel project y creamos otro folder llamado prefabs. Despues en el mismo panel project hacemos click derecho y seleccionamos un prefab, al que llamaremos FalligBouncyCube. Al principio vemos que esta blanco, que quiere decir que no tiene nada. Ahora arrastramos nuestro FallingBox al prefab, y veremos que cambia de color. 

Para probar el prefab podemos arrastrar unas cuantas veces el prefab al hierarchy o a la escena, para ver como van apareciendo cubos. Si se superponen, podemos moverlos y situarlos donde queramos.

Creando la fuente de los cubos.
La fuente de los cubos es simplemente un punto en el espacio. Se pueden crear GameObjects vacios. Lo único que tienen es una posición + rotación + escala, o sea una transformación. Lo situamos en 0,5,0. Le añadimos un script que cada segundo lance un cubo. El script seria este:
public GameObject thePrefab;
private float m_timeCounter;
private int m_objectCounter;

// Use this for initialization
void Start () {
	m_timeCounter = 0.0f;
	m_objectCounter = 0;
}

// Update is called once per frame
void Update () {
	
	m_timeCounter += Time.deltaTime;
	if(m_timeCounter > 1 && m_objectCounter < 300)
	{
		m_timeCounter = 0;
		Instantiate(thePrefab,transform.position, transform.rotation);	
		m_objectCounter++;
	}
}
Por partes. El start es un constructor. Alli inicializamos objetos. Si te fijas tenemos 3 miembros, dos privados y uno publico. El public es visible desde fuera, pero que quiere decir esto? Al arrastrar el script al objeto vacio vemos que aparece esto:
Asi que si le arrastramos el objeto FallingBouncyCube sera exactamente eso lo que cree. Cada cuanto lo creará? Cada segundo. Time.deltaTime guarda el tiempo que pasa entre cada frame, con lo que sumando tiempos conseguimos un reloj rudimentario. Para limitar el número de objetos, contamos en m_objectCounter y como maximo serán 300. Lo probamos y vemos que cada segundo cae un cubo, que tarda 5 segundos en desaparecer. Asi que solo veremos 5 cubos en pantalla.

Pero funciona!!! En un post futuro, flexibilizare todo esto que he creado para que sea mas cómodo configurarlo. Si tienes alguna duda, escribe un post!!!