Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: MasterPunk en 4 Enero 2012, 16:11 pm



Título: problema vectores, allegro.
Publicado por: MasterPunk en 4 Enero 2012, 16:11 pm
Hola, estoy haciendo un juego en c++ con allegro4 (no se lo suficiente de programación, pero así aprendo).

Estoy teniendo un problema al intentar mejorar una parte del codigo que pretendo que haga que el personaje del juego se mueve hacia donde hago clic con el raton en linea recta a velocidad constante.
Las variables posx y posy son la posicion actual del personaje en la pantalla, derx y dery almacenan las coordenadas del ultimo clic y la variable velocidad es la velocidad del personaje(cuanto menor sea la velocidad mas rapido irá).
Codigo antiguo:
Código
  1. while(...){
  2.    contador++;
  3.  
  4.    if( derx!=0 && contador % velocidad == 0)  //en x
  5.        if(posx!=derx)  
  6.            if(posx<derx)
  7.                posx+= 1;
  8.            else
  9.                posx-= 1;
  10.    if( dery!=0 && contador % velocidad == 0)  //en y
  11.        if(posy!=dery)  
  12.            if(posy<dery)
  13.                posy+= 1;
  14.            else
  15.            posy-= 1;
  16. }
  17.  


Con este codigo como podeis ver el recorrido del personaje no es el adecuado. Primero se mueve trazando un angulo de 45º y una vez que una de las coordenadas ha llegado se desplaza en la otra. =S no se como explicarlo pero creo que se entiende con el codigo.
Otro de los problemas de este codigo es que la velocidad con la que se mueve no es continua.

Por ello escribi este otro codigo:
Código
  1. distanciax = derx - posx;
  2. distanciay = dery - posy;
  3. float distancia = distanciax/distanciay;
  4.  
  5. if( derx!=0 && contador % (velocidad*(int)distancia) == 0) //en x
  6.         if(posx!=derx)            
  7.              posx += (int)distancia;
  8.  
  9. if(dery!=0 && contador % velocidad == 0)  //en y
  10.         if(posy!=dery)  
  11.           if(posy<dery)
  12.              posy+= 1;
  13.           else
  14.              posy-= 1;
  15.  

Hasta ahi bien, el problema es que al ejecutarlo el programa deja de responder.

Me podeis echar una mano??
Gracias, MasterPunk


Título: Re: problema vectores, allegro.
Publicado por: Kherom en 6 Enero 2012, 17:18 pm
¿El segundo código va dentro de un while? ¿Cuál es la condición de parada?

Así sin mirar mucho el programa no parece que hayas accedido a memoria que no debes por lo que lo normal es que se te cuelgue si entra en bucle infinito.

De todas formas no he hecho mucho caso al código por que me parece raro de cojones, ¿Por qué no te limitas a sumar a la posición un vector velocidad multiplicado por el tiempo entre frames?


Título: Re: problema vectores, allegro.
Publicado por: MasterPunk en 7 Enero 2012, 02:07 am
¿El segundo código va dentro de un while? ¿Cuál es la condición de parada?

Así sin mirar mucho el programa no parece que hayas accedido a memoria que no debes por lo que lo normal es que se te cuelgue si entra en bucle infinito.

De todas formas no he hecho mucho caso al código por que me parece raro de cojones, ¿Por qué no te limitas a sumar a la posición un vector velocidad multiplicado por el tiempo entre frames?

El segundo codigo va igual que el primero dentro de un while (!key[KEY_ESC]){...} para que el juego pare cuando se pulse Esc.
El personaje(posx, posy) para cuando llega a la posicion en la que pulsamos(derx, dery)

En este segundo codigo lo que intento es calcular la diferencia de distancia entre el personaje y el destino en el eje x y en el eje y, para calcular la proporcion en la que tienen que aumentar o disminuir las coordenadas del personaje para ir en la direccion correcta.

Aun llevo poco en el mundo de la programacion y esta es la primera vez que intento hacer algo parecido, asi que si sabes hacerlo mas sencillo dime como :P


Título: Re: problema vectores, allegro.
Publicado por: SirLanceCC en 8 Enero 2012, 11:12 am
Código
  1. distanciax = derx - posx;
  2. distanciay = dery - posy;
  3. float distancia = distanciax/distanciay;

Si dery y posy son iguales, al calcular distancia se produce una división entre cero y el programa termina.


Título: Re: problema vectores, allegro.
Publicado por: Kherom en 8 Enero 2012, 16:37 pm
Lo que yo no entiendo es el por qué de esa división xD Lo lógico sería hacerlo al revés para obtener la tangente...

De todas formas a mí los floats nunca se me han quedado a cero exacto, aunque podría ser.


Título: Re: problema vectores, allegro.
Publicado por: MasterPunk en 8 Enero 2012, 17:10 pm
Código
  1. distanciax = derx - posx;
  2. distanciay = dery - posy;
  3. float distancia = distanciax/distanciay;

Si dery y posy son iguales, al calcular distancia se produce una división entre cero y el programa termina.

Eso es! por eso terminaba el programa =D

Lo he arreglado pero la trayectoria del personaje no es la que esperaba TT.TT

Lo intentare plantear de otra manera, gracias Sir

Lo que yo no entiendo es el por qué de esa división xD Lo lógico sería hacerlo al revés para obtener la tangente...

De todas formas a mí los floats nunca se me han quedado a cero exacto, aunque podría ser.

Quizas es porque me pasaba las clases de trigonometria haciendo dibujitos en la mesa jajaja

Es broma, lo intentare plantear mejor. Gracias por la ayuda khenom.


Título: Re: problema vectores, allegro.
Publicado por: Kherom en 8 Enero 2012, 17:13 pm
A ver, sacas la tangente, de ahí el ángulo, con el ángulo y el módulo (módulo*cos ang y módulo*sen ang) sacas el vector velocidad y a partir de ahí haces la suma.

Con tu código lo si se mueve es pura casualidad xD


Título: Re: problema vectores, allegro.
Publicado por: SirLanceCC en 8 Enero 2012, 17:53 pm
Nada de módulos ni cosenos, necesitas trabajar un poco más con vectores.

Tienes la posición de tu personaje en un vector P, y donde haces clic en otro vector D.
Para obtener un vector que vaya de P a D, resta (http://en.wikipedia.org/wiki/Euclidean_vector#Addition_and_subtraction) D - P.
Ahora tienes un vector de un tamaño que puede ser cualquiera, para adaptarlo a tus necesidades lo conviertes en vector unitario (http://en.wikipedia.org/wiki/Euclidean_vector#Length), lo multiplicas por la velocidad deseada y le llamas V.
Para avanzar sumamos P += V.

Ahora bien, para calcular el vector unitario se divide X y Y entre la longitud del vector y si el vector mide cero estamos en las mismas (fuuuuuu!!!). Para arreglar eso definimos so un vector mide cero su vector unitario es (0,0). Cuando multipliques por la velocidad seguirá siendo (0,0) y cuando actualices P no cambiará su valor, pero de todos modos habrás llegado a tu destino.

Espero que sea de ayuda.


Título: Re: problema vectores, allegro.
Publicado por: MasterPunk en 8 Enero 2012, 17:54 pm
Código
  1.      double tangente;
  2.      if(posx != derx)
  3.              tangente = dery - posy/derx - posx;
  4.      else
  5.              tangente = 10; //un valor maximo
  6.      double angulo = atan(tangente);
  7.  
  8.  
  9.      if(contador % velocidad_bacteria == 0){ //para que no se mueva demasiado rapido
  10.  
  11.                 posx += (int)(sin(angulo)*5);
  12.                 posy += (int)(cos(angulo)*5);}

Pero con este codigo...
(http://img828.imageshack.us/img828/6655/capturabz.png) (http://imageshack.us/photo/my-images/828/capturabz.png/)
no se como trabajar con los doubles si los pixeles el numero de pixeles es entero... =S


Título: Re: problema vectores, allegro.
Publicado por: MasterPunk en 9 Enero 2012, 01:19 am
Nada de módulos ni cosenos, necesitas trabajar un poco más con vectores.

Tienes la posición de tu personaje en un vector P, y donde haces clic en otro vector D.
Para obtener un vector que vaya de P a D, resta (http://en.wikipedia.org/wiki/Euclidean_vector#Addition_and_subtraction) D - P.
Ahora tienes un vector de un tamaño que puede ser cualquiera, para adaptarlo a tus necesidades lo conviertes en vector unitario (http://en.wikipedia.org/wiki/Euclidean_vector#Length), lo multiplicas por la velocidad deseada y le llamas V.
Para avanzar sumamos P += V.

Ahora bien, para calcular el vector unitario se divide X y Y entre la longitud del vector y si el vector mide cero estamos en las mismas (fuuuuuu!!!). Para arreglar eso definimos so un vector mide cero su vector unitario es (0,0). Cuando multipliques por la velocidad seguirá siendo (0,0) y cuando actualices P no cambiará su valor, pero de todos modos habrás llegado a tu destino.

Espero que sea de ayuda.

Tienes razon, mejor trabajar con vectores que con 2 variables.
Sobre tu planteamiento...
El vector unitario tiene de modulo 1, por tanto el desplazamiento en x y en y va a ser menor de uno por cada frame, y no puedo desplazarme medios pixeles. Al pasarlo a int va a ser siempre 0. (si no me equivoco).


Título: Re: problema vectores, allegro.
Publicado por: Kherom en 9 Enero 2012, 02:16 am
Tienes razon, mejor trabajar con vectores que con 2 variables.
Sobre tu planteamiento...
El vector unitario tiene de modulo 1, por tanto el desplazamiento en x y en y va a ser menor de uno por cada frame, y no puedo desplazarme medios pixeles. Al pasarlo a int va a ser siempre 0. (si no me equivoco).

Él te dice que saques el vector unitario y luego lo multipliques por la velocidad que desees. Por otro lado un entero se redondea siempre a 0, pero si mantienes las variables de la posición como float los pequeños incrementos se irán acumulando y avanzará el píxel en cuanto llegue. Así que deberías trabajar siempre con floats y hacer el cast en el momento de dibujar.

En cualquier caso yo haría algo así (Puede que haya errores, ahora no puedo probar, sólo tengo el bloc de notas xD):

Código
  1. float tan, ang, vx, vy, velocidad; //Deberias pasar todo a floats
  2.  
  3.  
  4. if (posx==derx && posy==dery) // Ponemos la velocidad a 0 cuando alcanzamos la posicion (Creo que seria conveniente hacer algo como if( posx>(derx-0.001)&&posx<(derx+0.001) && posy>(dery-0.001)&&posy<(dery+0.001) )por la posible imprecision que tienen los float
  5. {
  6. vx=0;
  7. vy=0;
  8. }
  9. else
  10. {
  11. if (derx-posx==0) //Si no hay x la velocidad esta en y
  12. {
  13. vx=0;
  14. if(dery-posy>0) //Si esta por encima
  15. vy=velocidad;
  16. else
  17. VY=-velocidad;
  18. }
  19. else
  20. {
  21. tan= (dery-posy)/(derx-posx) //No te olvides de los parentesis
  22. ang=(float)atan((double)tan);//Según cómo lo hagas deberías tener en cuenta si la velocidad es positiva o negativa, no me apetece poner los if ahora xD
  23. vy = (sin(angulo)*velocidad);
  24. vx = (cos(angulo)*velocidad); //creo que los cast son automaticos, si no los pones, también se podrian quitar en la atan ya que creo que sale sólo un warning, pero no estoy seguro (no lo puedo comprobar ahora)
  25. }
  26. }
  27.  
  28. //Todo lo anterior debería ejecutarse sólo una vez al hacer clik, luego sólo tendrías que comprobar si ya ha llegado al final para poner la velocidad a 0.
  29.  
  30. posy+=vy;
  31. posx+=vx;
  32.  

La opción del vector unitario también está bien pero pierdes la opción de mover el personaje con las teclas al no tener la dirección, con éste método le das un ángulo en radianes y se va moviendo.

En cuanto a lo de que no se mueva demasiado rápido lo que tienes que hacer es 1º jugar con el valor que le das a la velocidad y sobre todo tener en cuenta que el framerrate puede variar sobre según el equipo, así que deberías calcular los ms entre frame y frame para adaptarla.

Algo tipo

Código
  1. posy+=vy*msTranscurridos;
  2. posx+=vx*msTranscurridos;
  3.  

Siendo msTrancurridos el tiempo que ha pasado desde el último frame. Otra opción es dejar el framerrate fijo (haciendo que el código sólo se ejecute cada x milisegundos) y olvidar ésto, pero en equipos lentos además de reducir el framerate se reducirá la velocidad.


Título: Re: problema vectores, allegro.
Publicado por: MasterPunk en 10 Enero 2012, 22:45 pm
Algo parecido habia intentado yo, pero hay un problemilla:

posx y posy deben ser enteros para poder mostrar el grafico del personaje:

Código
  1. void putpixel(BITMAP *bmp, int x, int y, int color); //si, dibujo al personaje en pantalla pixel a pixel...  :rolleyes:

El codigo que has puesto seria perfecto si la pantalla fuera mas grande, pero siendo como es la velocidad perfecta es de 0,1 o 0,2 pixeles por frame.

Código
  1. float velocidad = 0.2;
  2. posx += (int)velocidad;

El personaje no se mueve. Por ello he utilizado el contador, para movel el personaje cada v frames, siendo v la velocidad.

Por lo demas todo perfecto, voy a arreglar y a probar el codigo. Gracias.


Título: Re: problema vectores, allegro.
Publicado por: Kherom en 10 Enero 2012, 23:23 pm
A ver:

float posxf=0;

posxf+=0.2;
putpixel(BITMAP *bmp, posf, int y, int color);

No hace nada.

posxf+=0.2;
putpixel(BITMAP *bmp, posf, int y, int color);

No hace nada.

posxf+=0.2;
putpixel(BITMAP *bmp, posf, int y, int color);

No hace nada.

posxf+=0.2;
putpixel(BITMAP *bmp, posf, int y, int color);
No hace nada.

posxf+=0.2;
putpixel(BITMAP *bmp, posf, int y, int color);

Avanza un píxel (posf ahora con el cast vale 1, antes 0).

Así es como lo tienes que hacer, vas sumando la posición al float y luego se lo pasas a la función que lo dibuje como entero, los decimales se desprecian pero cada x frames avanza un píxel. De ese modo no te tienes que preocupar por qué valores das a la velocidad, ya se moverá cuando se tenga que mover.

Al pasarle el float a la función, que acepta enteros, hará automáticamente un cast, asi que no te tienes que preocupar. Si quieres evitar el warning haz el cast a mano al pasar el argumento ( (int)posxf );


Título: Re: problema vectores, allegro.
Publicado por: MasterPunk en 11 Enero 2012, 00:30 am
(http://img705.imageshack.us/img705/795/capturaau.png) (http://imageshack.us/photo/my-images/705/capturaau.png/)

Muahahaha, 200 warnings pero funciona =D
Que alegria, asi debia sentirse dios cuando le dijeron como compilar el mundo xD

Que funcione es lo de menos, lo importante es que en este post me habeis enseñado varias cosas que tenia que saber.
Muchas gracias por la ayuda ;)


Título: Re: problema vectores, allegro.
Publicado por: Kherom en 11 Enero 2012, 01:07 am
Si haces el cast a int a mano
Código:
función( (int)numeroflotante )
evitarás los warnings, ya que para lo único que sirven en éste caso es para indicar una posible pérdida de precisión, que es justamente lo que andas buscando.

De todas formas ahora que me fijo, para que tengas tantos warnings, ¿Llamas a la función una vez por píxel A MANO? xD


Título: Re: problema vectores, allegro.
Publicado por: MasterPunk en 11 Enero 2012, 02:25 am
Si haces el cast a int a mano
Código:
función( (int)numeroflotante )
evitarás los warnings, ya que para lo único que sirven en éste caso es para indicar una posible pérdida de precisión, que es justamente lo que andas buscando.

De todas formas ahora que me fijo, para que tengas tantos warnings, ¿Llamas a la función una vez por píxel A MANO? xD

Si, lo e los warnings ya lo he arreglado, que para eso esta la herramienta remplazar :P

Es una p***da que en allegro 4 no se puedan meter png, y como con las bmp se ve el cuadradito negro alrededor de la imagen lo he arreglado dibujandolo pixel a pixel. Costoso, pero ya esta hecho xD
40x40 pixeles en color.

Si no conoces el camino rapido te toca andar el largo =S


Título: Re: problema vectores, allegro.
Publicado por: Kherom en 11 Enero 2012, 13:44 pm
Eliges un color para las transparencias (por ejemplo un rosa que no te guste, o el negro si las imágenes no tienen negro), luego cargas en memoria la imagen y mediante un bucle for pintas sólo los píxeles que no sean de ese color.


Título: Re: problema vectores, allegro.
Publicado por: MasterPunk en 12 Enero 2012, 00:49 am
no se ni como comprobar el color de los pixeles ni como pintar solo algunos pixeles, asi que si me dices como me harias un segundo gran favor


Título: Re: problema vectores, allegro.
Publicado por: Kherom en 12 Enero 2012, 01:15 am
no se ni como comprobar el color de los pixeles ni como pintar solo algunos pixeles, asi que si me dices como me harias un segundo gran favor

Primero necesitas los datos de la imagen cargados en memoria, luego compruebas con un editor de imágenes cuál es el valor del color que vayas a usar para la transparencia, y luego mediante un par de bucles for vas pintando sólo los que no coincidan con ése color.


Título: Re: problema vectores, allegro.
Publicado por: MasterPunk en 12 Enero 2012, 02:25 am
voy a volver a leer en el manual de allegro los objetos bitmap


Título: Re: problema vectores, allegro.
Publicado por: SirLanceCC en 14 Enero 2012, 02:32 am
Puedes cargar un archivo .bmp con load_bitmap() (http://alleg.sourceforge.net/stabledocs/en/alleg010.html#load_bitmap) y dibujarlo en pantalla con la función draw_sprite() (http://alleg.sourceforge.net/stabledocs/en/alleg014.html#draw_sprite). Los píxels que sean de color (255,0,255) se pintarán como transparentes.