Archive for the ‘General’ Category

Desarrollo: Dividiendo el espacio

Una de los problemas que aún sigo teniendo, es el problema de rendimiento ya que no puedo conseguir bien los 60 FPS especialmente cuando tengo muchas entidades (itemes, objetos, enemigos, triggers,etc..) creadas en el juego debido a que tengo actualizarlas una por una, aunque estás no se vean en pantalla lo cual implica un costo de tiempo.

Buscando en Internet la mejor alternativa que se podía implementar fácilmente  (o en apariencia)  era implementar un QuadTree. Bueno aunque no seguí al pie de la letra los algoritmos que salen en Wiki pero, el concepto no era tan difícil de comprender.

Así que implementé 3 tipos de clases: la clase QuadTreeNode y sus dos clases hijas QuadTreeNodeLeaf(hoja) y QuadTreeNodeBranch(rama). Puede que no haya seguido la nomenclatura usada comúnmente en la literatura pero me sirve para distinguir bien a las clases 🙂

El QuadTreeNode es una clase abstracta en las cuales defino algunas cosas necesarias como los métodos en común Insertar(Insert),  Preguntar(Query) y Relocalizar(Reallocate) y datos necesarios como la dimensión o el área que representa el nodo y un  puntero de la variable puntero que tiene el padre(El cual lo explicaré más adelante).

[cpp collapse=”true”]
template<typename T>
class QuadTree{
protected:
private:
class QuadTreeNodeLeaf; //class foward
class QuadTreeNode{
protected:
private:
public:
QuadTreeNode **me;
AABB dimension;
QuadTreeNode(QuadTreeNode **m,const AABB &aabb):me(m),dimension(aabb){}
virtual void Insert(Vector2i point, T t) = 0;
virtual bool Query(const AABB &aabb,List<T> &out) = 0;
virtual void Reallocate(QuadTreeNodeLeaf *nodo) = 0;
};
[/cpp]

La clase QuadTreeNodeLeaf es la encargada de guardar un punto(más el dato claramente) que estará distribuido sobre el área del juego.  Esta clase es importante también porque es la encargada de expandir el árbol ya que puede decirse que se transforma en un Nodo interno (QuadLeafNodeBranch) aumentando la altura del árbol.

[cpp collapse=”true”]
class QuadTreeNodeLeaf : public QuadTreeNode{
protected:
private:
public:
T data;
Vector2i point;
QuadTreeNodeLeaf(QuadTreeNode **me,const AABB &aabb,T _data,Vector2i _point):QuadTreeNode(me,aabb) {
data = _data;
point = _point;
}
void Reallocate(QuadTreeNodeLeaf *nodo)
{
//pues que mala suerte, tengo que relocalizar esto ….
QuadTreeNodeBranch *branch = new QuadTreeNodeBranch(me,dimension);
*me = branch; //hacer que me apunte a la nueva rama
branch->Reallocate(this);
branch->Reallocate(nodo);
}
void Insert(Vector2i point, T t)
{
//entonces debemos agregar un nuevo nodo….
//debemos convertir este nodo en un nodo rama
QuadTreeNodeBranch *branch = new QuadTreeNodeBranch(me,dimension); //hacemos que el puntero que me apunta a mí, ahora apunte a este nuevo nodo interno
*me = branch;
branch->Insert(point,t);
branch->Reallocate(this);
}
bool Query(const AABB &aabb,List<T> &out){
if(aabb.containsPoint(point)){
//pues… ya estamos acá, entonces me agrego 😀
out.add(data);
return true;
}else{
return false;
}
}
};
[/cpp]

Y finalmente queda la clase QuadTreeNodeBranch (que es un nodo interno) que es la culpable de dividir el area en 4 partes iguales.

[cpp collapse=”true”]
class QuadTreeNodeBranch: public QuadTreeNode{
protected:
private:
public:
QuadTreeNode *quadrants[4];
QuadTreeNodeBranch(QuadTreeNode **me,const AABB &aabb):QuadTreeNode(me,aabb){
quadrants[0] = NULL;
quadrants[1] = NULL;
quadrants[2] = NULL;
quadrants[3] = NULL;
}
void Insert(Vector2i point, T t){
//dividir el dimension
Vector2i p = dimension.p;
Vector2i e = dimension.e;
Vector2i x(e.x * 0.5, e.y * 0.5);
AABB quad[4] = {
AABB(p+Vector2i( x.x,-x.y), x),
AABB(p+Vector2i( x.x, x.y), x),
AABB(p+Vector2i(-x.x, x.y), x),
AABB(p+Vector2i(-x.x,-x.y), x)
};

for(int i=0; i<4; i++){
if(quad[i].containsPoint(point)){
if(quadrants[i] == NULL){
quadrants[i] = new QuadTreeNodeLeaf(&quadrants[i],quad[i],t,point);
}else{
quadrants[i]->Insert(point,t);
}
break;
}
}
}
void Reallocate(QuadTreeNodeLeaf *nodo){
//dividir el dimension
Vector2i point = nodo->point;
Vector2i p = dimension.p;
Vector2i e = dimension.e;
Vector2i x(e.x * 0.5, e.y * 0.5);
AABB quad[4] = {
AABB(p+Vector2i( x.x,-x.y), x),
AABB(p+Vector2i( x.x, x.y), x),
AABB(p+Vector2i(-x.x, x.y), x),
AABB(p+Vector2i(-x.x,-x.y), x)
};
for(int i=0; i<4; i++){
if(quad[i].containsPoint(point)){
if(quadrants[i] == NULL){
quadrants[i] = nodo;
nodo->me = &quadrants[i];
nodo->dimension = quad[i];
}else{
quadrants[i]->Reallocate(nodo);
}
break;
}
}

}
bool Query(const AABB &aabb,List<T> &out){
if(dimension.overlaps(aabb))
{
bool r = false;
for(int i=0; i<4; i++)
{
if(quadrants[i])
{
r |= quadrants[i]->Query(aabb,out);
}
}
return r;
}
else
{
return false;
}
}
};
[/cpp]

En mi afán de ahorrar memoria, yo agregué un método adicional que lo que hace es relocalizar un nodo y para eso necesité un puntero a la variable que tiene el nodo padré que es a su vez un puntero al nodo hijo (lo llamé me y es un QuadTreeNode**). El asunto es que cada vez que un nodo hoja(QuadTreeNodeLeaf) se convertía en un nodo interno(QuadTreeNodeBranch), tenia que volver a reinsertar el punto que contenía el actual nodo pero, si usaba el método Insert iba a utilizar innecesariamente más memoria(aunque sea poquita). Así que cree una variante de Insert y la llamé Reallocate que lo único que hace es buscar una nueva posición(dentro del árbol) y actualizar los datos del nodo hoja que tuve que reemplazar y asi evitándose una nueva llamada a new.

En este articulo no mostré como hacer un QuadTree solo mostré mi propia implementación de este y los detalles que tuve que considerar, ya que está lo suficienmente explicado en Wikipedia

Sin embargo a pesar que logré exitosamente agregar QuadTree a mi engine, de 8 a 20 FPS que apenas lograba con cierto nivel del juego ahora alcanzo los 40 a 50 FPS. Aún me quedan cosas por mejorar, investigar y que responder para poder llegar decentemente a los 60 FPS.

Casi casi, mi primer parte

Mientras iba a buscar la torta de la celebración de cumpleaños de mi hermana, me disponia a cruzar el semaforo al cual estaba atento si cambiaba o no y derrepente me doy cuenta que un carabinero me habia llamado a orillarme. Rapidamente me orillo como puedo y bajo la ventana de la camioneta mientras mi hermano apagó la radio. Carabinero : “Documentos del vehiculo y extintor”, maldición!!! desconocia si habia o no habia extintor en el vehiculo pero calmado saque los documentos del vehiculo y mi licencia los cuales el carabinero reviso detalladamente. Carabinero : “El extintor”, a lo cual repondo “vamos por parte” ya afuera del vehiculo para poder sacar el extintor, el cual mi hermano ya habia sacado del asiento trasero,  senti un alivio, saber que el Extintor  estaba asi que se lo pase, pero algo preocupado si estuviera caduco. Y al final el carabinero respondio “Todobien”, luego de eso me voy respirando tranquilamente.

Se notaba a leguas que el carabinero queria sacarme un parte, pero gracias a mi padre que tenia todo en su vehiculo en comparación al jeep(el cual no esta operativo de hace tiempo) que no tiene nada de eso.

La razón de este post en mi blog es desconocida.

Transfiriendo archivos usando Java de la forma incorrecta

Hoy en día les mostrare como transferir archivos en java de la forma incorrecta.
La razón de este artículo es que un amigo me pidió ayuda de cómo transferir archivos a pesar que le dije como hacerlo, no logró hacerlo de la manera correcta(hasta donde yo se). Y por asuntos didácticos dividiré este artículos en dos partes (transfiriendo archivos de manera incorrecta y correcta).

El siguiente código que les mostraré como transferir el archivo de la forma incorrecta, espero que al leerlo se de cuenta de cual es el error.

Primero debemos crear el servidor, primero el código para aceptar una simple conexión

ServerSocket server = new ServerSocket(1234);
Socket conexion = server.accept();        

Básicamente lo que hacemos es crear un ServerSocket el cual se pone a la escucha en el puerto 1234 (un numero cualquiera pero debe ser superior a 1024). La siguiente linea lo que hace es esperar una conexión (esta función se bloquea hasta que alguien se conecte al puerto abierto) y devolverá un objeto Socket el cual manejará la conexión.

Luego debemos enviar el archivo (de la manera mala)

File transfer = new File("~/archivo pequeño.doc");
FileInputStream fin = new FileInputStream(transfer);
byte datos[] = new byte[fin.available()]; ///noten esto
fin.read(datos);
OutputStream out = conexion.getOutputStream();
out.write(datos);
out.flush();
out.close();
conexion.close();

Básicamente hemos transferido nuestro archivo de mala manera, pero también nos falta recibir nuestro archivo también de mala manera

Socket descargar = new Socket("localhost",1234);
InputStream in = descargar.getInputStream();
byte descarga[] = new bytes[in.avalaible()]; //noten esto
in.read(descarga);
FileOutputStream fout = new FileOutputStream(new File("~/archivo transferido.doc"));
fout.write(descarga);
descargar.close();

En las partes que les mencione en el código (noten esto) se darán cuenta que nuestro programa puede quedarse sin memoria al tratar de transferir un archivo muy grande.

Bueno espero que tengán deduzcan la forma correcta de transferir archivos antes que yo la postee, Saludos!!

Nota:Avisar si hay algún error, hice a la rapida este articulo :S

Obtener los angulos de rotacion de un quaternion (cuaternión)

Hubo un tiempo (no largo), el cual no sabia como extraer el ángulo de rotación de un cuaternión.
Para empezar no sabia que era un cuaternión aunque los había escuchado, averiguando por internet encontré la definición de ellos (pero como yo no soy matemático no pienso arriesgarme ni a copiar la definición), pero no sabia como extraer el ángulo de rotación ya que lo necesitaba para rotar un objeto en irrlicht. Mi búsqueda termino cuando me tope con esta función q={cos(Ɵ/2),sen(Ɵ/2)r}, donde Ɵ es el ángulo de rotación y r el vector del eje donde se rota un objeto, tal como se muestra en la siguiente imagen

Bueno con esa formula me quedaba más claro, aunque todavía no sabia sacar el ángulo. Para eso me di un caso particular, que la rotación se realiza en un solo eje, entonces tendría valores de r = (1,0,0) , (0,1,0) y (0,0,1). Entonces aplique la función inversa y saque en ángulo.

Por cierto lo hice en C

[c]
#include <math.h>
//….
float q[4]; //un arreglo para almacenar el quaternion
getBodyRotation(body,q); //función que almacena la rotación en un cuaternión
//asumo que r = (0,1,0)
float angulo = atan2(q[0],q[2]) * 2; //El ángulo obtenido
[/c]
Bueno solo lo pude hacer para el caso particular donde r es un eje coordenado.
Saludos

Ya no soy el unico

Creo que a nadie le importara esto, pero se me ocurrio un buen tema para escribir un rato.

Bueno como saben mi nick es “egyware“, para todos los lugares de internet ese es mi nick, hace un tiempo ociando queria registrar el dominio egyware.com sabiendo que no tenia dinero pero lo quise hacer y me di cuenta que estaba registrado a alguien de Egipto. Bueno me anduve enojando pero se me olvido con el tiempo…

Ahora la organizacion egyware de Egipto crearon un grupo en facebook ver grupo (gracias al alguien que me aviso) y ahora para el colmo de los colmo los amigos o colegas de esta organizacion me enviaron un correo donde yo era uno de los destinatarios aqui se los transcribo

Asunto: Cairo ICT

de Reham:

Dear Sir,

We Would Like TO Thank You For Stopping by our booth “EMS” at Cairo ICT 2010

Creo que no podre ir a su evento, y esa persona si no le avisan tampoco.

Me despido

Saludos a todos