Crear un conector de objetos

Started by DCelso, July 13, 2009, 10:14:10 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

DCelso

Hola a todos,
he estado dándole vueltas a un ejecicio prático: Cómo crear un hilo elástico de conexión entre dos objetos y que al mover cualquiera de estos objetos este hilo se estire y siempre una a los objetos estén donde estén.

La primera idea que se me ocure es hacer un proceso para cada objeto y un proceso para el hilo en el que la componente x e y sea justo el centro que une a los dos puntos de los objetos unidos y el graph sea una imagen de ancho y alto las proyecciones de la recta que une a los dos puntos en la que se dibuja la recta de una esquina a la otra. Pero esto no lo veo muy eficiente. Lo implementaré a ver que tal pero:
¿Que se os ocurriria a vosotros para realizar este ejercicio?
Monstruos Diabólicos

"A PAck of classic GAMEs For BennuGD" en desarrollo
http://code.google.com/p/apagame4be/

SplinterGU

si bien el crap de los zombies no es exactamente un hilo elastico, si hay un link entre los objectos, solo deberia añadirle la componente elasticidad... o como sea, creo que esto podria ayudarte un poco.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Prg

en el div había un juego en modo 8 que tenía algo similar a lo que quieres se lograba mediante una multitud de procesos que se posicionaban mediante get_distx y get_disty entre el punto de inicio y fin, y acomodando su angle... eso creo (lo imagino, creo que nunca lo revisé muy a fondo)

también puedes crear un gráfico de la distancia de la conexión cada frame, borrarlo una vez presentado y girarlo en el ángulo de los procesos.
en humos puedes mover la camara con los cursores. es necesario para los niveles a partir del dos :)

laghengar

Empezaría intentandolo hacer con una primitiva de línea, creo que bennu tiene algo de eso. También estoy pensando en un sprite que tuviese una altura fijada, 5 píxeles por ejemplo,  y la anchura sea de un píxel. Bueno tendría que pensar también como quiero la forma de ese hilo pero empezaría así.

La cuestión con el sprite es en estos puntos:

1-coordenadas del sprite fijada en el primer objeto a unir.
2-angulo del sprite get_angle(objeto_1, objeto_2);
3-sizex=get_dist(objeto_1, objeto_2);

Creo que las funciones funcionan así, míralo en la wiki para hacerlo de una forma segura.

De todas formas si quieres hacer que el sprite tenga 4 píxeles, por ejemplo, de ancho. El sizex sería get_dist(objeto_1,objeto_2)/4;

Un saludo.
!!!Blender Blender Blender yuhuuuuuuu¡¡¡ novato o_O

DCelso

He realizado la implementación del algoritmo que tenía en mente.
El resultado es el siguiente.
El conector no funciona del todo bien y no entiendo el porqué, tendré que poner trazas a ver qué es lo que falla, podeis probarlo dando vueltas  por la silueta roja con el botón del raton pulsado.
A ver si alguien averigua el por qué a veces no llega el conector al punto central de los objetos, tiene que ser alguna variable tonta a 0 o por precisión, digo yo.
Monstruos Diabólicos

"A PAck of classic GAMEs For BennuGD" en desarrollo
http://code.google.com/p/apagame4be/

DCelso

Nada, no encuentro el bug que hace que a veces la línea que une los objetos no vaya de centro a centro.
Monstruos Diabólicos

"A PAck of classic GAMEs For BennuGD" en desarrollo
http://code.google.com/p/apagame4be/

SplinterGU

no es un bug... es un error conceptual...

asi te sirve?
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

DCelso

#7
Splinter, gracias por confiar tanto en mis conceptos :(, pero esta vez lo siento, estaban bien, era fallo de precisión en la división del cálculo de la pendiente de la recta.

Resulta que f_m era un float pero si asignas del tirón la división de dos enteros, primero que calcula la división de los enteros en precisión de enteros y luego se guarda en el float.
Así que lo he arreglado guardando primero en el float el dividendo entero y luego dividiendo este float por el otro entero y va bien.

Pensando un poco más en el tema ví que podía simplificarse dibujando siempre una recta en el map desde el punto 0,0 hasta el otro extremo (width, height) y jugando con los flags del map orientar la recta.

En cuanto a tu forma, eres un monstruo, el resultado es genial y perfecto, ahora, el código es bastante dificil de entender :), aún no entiendo cual es el significado conceptual (o matemático) de f_x y f_y y cómo que al sumarlos a x e y vas creando una recta :D
Tu forma de calcular el máximo y mínimo creo que consume mas tiempo  que la mia (el doble) ya que necesita duplicar los condicionales tanto para máximo como para mínimo.

Adjunto los tres ejemplos para que puedas(y podais) compararlos.

En los míos no sé el motivo de porqué no se dibujan todos los puntos de la recta en determinadas circunstancias, al principio creo que es otra vez culpa de precisión tendré que indagar un poco más.

¿Que opinais?
Monstruos Diabólicos

"A PAck of classic GAMEs For BennuGD" en desarrollo
http://code.google.com/p/apagame4be/

SplinterGU

#8
jajaja... me hiciste reir...

pero no fue solo eso, puse todo a float y tampoco iba... cambiaste un par de cosas mas...

veo que tomaste algunas ideas... bien... lo del flag esta muy bien...

el problema que tenes con el algoritmo es que lo basas en una de las dimensiones del area (por asi decirlo), en este caso width, con lo que si el ancho es 0, no dibujas nada... y se saltean puntos si el ancho es menor al alto...

lo que hice pretende ser claro en vez de optimo, sin embargo es bastante optimo, no es tanto sacrificio hacer una resta extra, si lo seria quizas dentro del loop... el ejemplo en cuestion que hice es muy simple, tenes una "distancia maxima a recorrer" y entonces considerando que "distancia maxima a recorrer" son los pasos a realizar calculas los incrementos de cada uno de los pasos, para cada una de las coordenadas... obviamente uno de los incrementos sera -1, 0 o 1 y el otro sera < 1, depende de cual sea el que coincide con la cantidad de pasos... es demasiado simple (ahora que lo explique seguro que coincidis en esto)... esto es mas matematico que procedural... yo prefiero usar formurlas que serie de if, switchs, etc... y este dibuja todos y cada uno de los puntos de la recta...

tambien podrias utilizar draw_line directamente... pero bueno, eso es otro tema.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

DCelso

Ya entiendo en qué falla mi algoritmo, también problema de la precisión :D.
En teoría y papel no falla debido a que cojo infinitas muestras entre los puntos de inicio y final.
Recorriendo "x" desde el primer valor hasta el último y obteniendo "y" con la fórmula de la recta, se obtiene la recta, el problema es que es impresiso ya que como voy incrementando de uno en uno en "x", cuando haya menos puntos de ancho que de alto, solo dibujo de alto los mismos puntos que de ancho.
Tendría que comprobar en qué coordenada hay más puntos y dependiendo de cual sea calcular "x" en función de "y" o calcular "y" en función de "x". Y así no perder precisión.

Ahora entiendo tambien tu algoritmo, muy buena deducción práctica, un buen algoritmo sin base matemática teórica y con gran eficacia práctica, lo dicho eres un lince, sabes más que el diablo :D.

En cuanto a lo de usar draw_line, juas, aqui perdiendo el tiempo yo en dibujar una línea todo metido en el papel de un programador y ni se me ocurrió pensar en usar una función para dibujar la recta. Lo que me va a facilitar y simplificar esa función el ejemplo.
Un gran punto negativo a mi contra, mira que intentar reinventar la rueda :D. Merezco que me quites un karma por lo menos.
Monstruos Diabólicos

"A PAck of classic GAMEs For BennuGD" en desarrollo
http://code.google.com/p/apagame4be/

SplinterGU

ja, no, todo bien... yo segui en la base de tu ejemplo, porque supuse que en algun momento en vez de puntos quizas querrias usar graficos o procesos... y esto era solo un draft... ahora si vas a usar finalmente pixels, te sugiero uses draw_line...

;)
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

DCelso

Monstruos Diabólicos

"A PAck of classic GAMEs For BennuGD" en desarrollo
http://code.google.com/p/apagame4be/

DCelso

Nuevo ejemplo de conexión de nodos.
Usa la técnica de dibujar la recta del map entre los puntos (0,0)  y (width,height) y jugar con el valor de la variable flags.
Es el que mejor rendimento me ha dado de los tres. La verdad es que tampoco se me ocurren formas para ponerlos a prueba, simplemente fué moviéndolos y creando muchos.
Monstruos Diabólicos

"A PAck of classic GAMEs For BennuGD" en desarrollo
http://code.google.com/p/apagame4be/

SplinterGU

la verdad que no se que pruebas hiciste, pero la funcion que puse tiene mejor rendimiento... poco, pero mejor... y con estos cambios que vas a ver a continuacion, si que tiene mucho mejor rendimiento (incluido el cambio para que se muevan las 2 bolas)... tene en cuenta que cuanto mayor es la distancia del conector, mayor sera el tiempo consumido, tene en cuenta eso para las pruebas.


import "mod_math";

#define MAX(a,b)    (((b)>(a))?(b):(a))
#define MIN(a,b)    (((b)<(a))?(b):(a))
#define SGN(a)      ((a)<0?-1:(a)==0?0:1)

Global
depth = 32;
teoricFPS=30;
int procesos[2];
int object_picked;
end



Begin
   set_title("conector");
set_mode(800,600,depth);
set_fps(teoricFPS,0);
   set_fps(0,0);
   write_int(0,10,10,0,&fps);
   procesos[0] = object(300,200);
   procesos[1] = object(400,300);
   conector ();
   mouse.graph = load_png("mouse.png");
   while (!key(_esc))
if (key(_f))
           if (full_screen==true)
               full_screen=false;
           else
               full_screen=true;
           end
           set_mode(800,600,depth);
           while (key(_f))
     frame;
           end;
       end
       frame;
end
let_me_alone();
end

process object (x,y)
begin
   priority = 100;
   size = 50;
graph = load_png("node.png");
   while (!key(_esc))
       if mouse.left && ( object_picked == id || collision (type mouse) ) ;
           x = mouse.x;
           y = mouse.y;
           object_picked = id;
       elif ( object_picked == id )
           object_picked = 0;
       end
       Frame;
end;
end;

process conector ()
private
   float width,height;
   float f_x;
   float f_y;
   float i, j;
   float x0, y0;
   int last_x0[1], last_y0[1];
   float min_x, min_y;
   float max_x, max_y;
   float divider;
   color;
begin
last_x0 = 0;
last_y0 = 0;
color = RGB(255,0,255);
   while (!key(_esc))
       if ( last_x0[0] != procesos[0].x OR last_y0[0] != procesos[0].y OR
            last_x0[1] != procesos[1].x OR last_y0[1] != procesos[1].y )
       last_x0[0] = procesos[0].x;
       last_y0[0] = procesos[0].y;
       last_x0[1] = procesos[1].x;
       last_y0[1] = procesos[1].y;
        unload_map(0, graph);

           min_x = MIN(procesos[0].x, procesos[1].x);
           min_y = MIN(procesos[0].y, procesos[1].y);

           max_x = MAX(procesos[0].x, procesos[1].x);
           max_y = MAX(procesos[0].y, procesos[1].y);

           width = max_x - min_x;
           height = max_y - min_y;

           divider = MAX(width, height);

           f_x = width / divider * SGN( procesos[1].x - procesos[0].x);
           f_y = height / divider * SGN( procesos[1].y - procesos[0].y);

           x = min_x + width / 2;
           y = min_y + height / 2;

           graph = new_map (width + 1, height + 1, depth);
           x0 = f_x < 0 ? width : 0 ;
           y0 = f_y < 0 ? height : 0 ;

           from i = 0 to divider;
               x0 += f_x;
               y0 += f_y;
               map_put_pixel(0,graph,x0,y0,color);
           end

       end
       Frame;
end;
unload_map(0, graph);
end;
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

SplinterGU

funciones RGB, collision, consumen mucho, asi que si se pueden calcular fuera de los bucles (RGB) y como ultimo segmento de una condicion donde haya otras condiciones mas simples que den por verificada la condicion con mayor frecuencia, mejor.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2