Necesito una mano para calcular distancias XY

Iniciado por WHK, 23 Octubre 2016, 00:57 AM

0 Miembros y 1 Visitante están viendo este tema.

WHK

Hola, tengo una duda, me he dado muchas vueltas y no llego a puerto aun.

Tengo un plano de 100x100, tengo un objeto en la posición 30x30, ¿cómo lo puedo mover de posición x cantidad de espacios usando un grado de inclinación?.

Por ejemplo, quiero moverlo en dirección hacia arriba y a la derecha en 45 grados.

El problema central es el siguiente: Tengo un circulo y un objeto que se mueve al rededor de el en su superficie, ambos objetos se mueven de manera independiente pero necesito que el objeto se mueva de manera que simule estar unido al borde del circulo, despues de esto tengo una función que debiera aumentar la separación entre el circulo y el objeto sin perder la sincronización de rotación ya que este circulo va rotando en una dirección al azar (ccw o cw).

Actualmente hice sin problemas que el objeto esté centrado con respecto al circulo y que este rote en la misma velocidad del circulo usando su base y no su centro, ahora solo necesito establecer su distancia, pero esta distancia esta relacionada con la cantidad de grados de rotación del objeto y ahi es donde quedé.

Hice este post en programación general porque no necesito que me hagan el código, quiero entenderlo para aplicarlo en muchas situaciones. De todas maneras este es el código que uso para hacer rotar el objeto sobre el circulo:

Código (java) [Seleccionar]
// Cambia el tamaño
       this.matrix.setScale(1, 1);

       // Rota la imagen a partir de su centro
       this.matrix.postRotate(this.angle, this.image.getWidth() / 2, this.image.getHeight());

       // Posiciona la nave al centro del circulo
       this.matrix.postTranslate(
               this.start_circle.getLeft() + (this.start_circle.getWidth() / 2) - (this.image.getWidth() / 2),
               this.start_circle.getTop() + (this.start_circle.getHeight() / 2) - this.image.getHeight()
       );


Es código Java para Android + canvas.

Una solución que encontré fue tomar el punto de rotación vertical muy abajo, para que simulara la rotación sobre un circulo, pero esto significaba que a la posición final tenía que restarle pixeles y cuando tenia que mover el objeto se me hacia todo un desmadre incontrolable y para solucionarlo tenía que crear condicionales para saber si el opbjeto estaba rotando o habia que aumentar el espacio y tenia un código muy mal optimizado, asi que lo eliminé y ando en busca de algo mas óptimo.

El tema debiera quedar algo así:


  • Si el grado es 0 entonces se suma la distancia el 100% sobre vertical
  • Si el grado es 45 entonces se suma la distancia el 50% sobre vertical y 50% horizontal
  • Si el grado es 90 entonces se suma la distancia el 100% sobre horizontal
  • si el grado es 135 entonces se suma la distancia el 50% horizontal y se resta el 50% vertical
  • si el grado es 180 entonces se resta la distancia el 100% vertical
  • si el grado es 225 entonces se resta la distancia el 50% sobre vertical y 50% horizontal
  • si el grado es 270 entonces se resta la distancia 100% sobre horizontal
  • Si el grado es 315 entonces se resta la distancia 50% sobre horizontal y se suma 50% sobre vertical
  • Si el grado es 360 entonces se suma la distancia el 100% sobre vertical

Saludos.

engel lex

no estoy muy seguro que quieres hacer, podrías dibujar algo para hacerlo más visual

primero para mover un objeto con respecto a un angulo usas seno y coseno
x += sin(alfa)*escalar
y += cos(alfa)*escalar



para simular un movimiento circular esas esto en base al angulo del circulo, aunque como es un movimiento uniforme puedes simplemente calcular la inclinación como movimiento


fijate este ejemplo, está en "java" (para processing) lo puedes pegar y ejecutar aquí

Código (java) [Seleccionar]

class Circulo { //clase circulo... no importa para esto, simplemente dibuja en pantalla
  float y, x, size;
  color c;

  Circulo(float nx, float ny, float ns, int r, int g, int b) { 
    y = ny;
    x = nx;
    size = ns;
    c = color(r,g,b);
  }
  void update() {
    fill(c)
    ellipse(x, y, size, size);
  }
}

Circulo base, satelite;
float alfa= 0;

void setup() {//tampoco importa, solo da las condiciones iniciales
  size(500, 500);
  smooth();
  noStroke();
  base = new Circulo(0,0,100, 255,255,0); //aqui se crea el circulo en (0,0) y diametro 100
  satelite = new Circulo(150,200,20,0,0,255);//aqui el otro objeto diametro 20
}

void draw()
{

  background(0,0,0);
  satelite.x = base.x + sin(alfa)*base.size/2 ;
  //el objeto se coloca en el x de la base, y se le suma el angulo  por el radio
  satelite.y = base.y + cos(alfa)*base.size/2;
  //lo mismo en y

  base.x += 0.1;//muevo el circulo para observar como el satelite acompaña
  base.y += 0.1;

  base.update();
  satelite.update();
  alfa += 0.03;//cambio 0.03 grados por frame
  alfa %= 360; // limito a 360 grados
}
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

WHK


engel lex

creo que es lo más optimo y no consume casi procesador actualmente (a menos que lo hagas miles de veces por frame)
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

WHK

#4
Muy bien!, ahora me toca ajustar la relación entre grados y el alpha que se le asignó, porque si le paso como alpha directamente el angulo, rota muy rápido, por ejemplo mi circulo rota 360 grados cada 5 segundos aprox y el valor del alpha que se ajusta perfectamente es 0.022, asi que tocará ajustar eso que no creo que sea tan dificil.

Por lo menos lo que me tenía mas preocupado funciona de lujo.

Código (java) [Seleccionar]
float alfa= 360;

   @Override
   public synchronized void update() {
       super.update();

       // Control de frames
       if (last_millisecond == null) {
           this.last_millisecond = Calendar.getInstance().getTimeInMillis();
       }

       Long current_millisecond = Calendar.getInstance().getTimeInMillis();
       Long diff_millisecond = current_millisecond - this.last_millisecond;
       this.last_millisecond = current_millisecond;

       // Contexto
       if(!this.launched) {
           this.angle = this.angle + (diff_millisecond / 10);
           this.angle = (this.angle % 360); // Previene el desbordamiento
       }else{
           this.diameter_rotation_ship = this.diameter_rotation_ship + (diff_millisecond / 12);
       }

       // Controlador

       // Cambia el tamaño
       this.matrix.setScale(1, 1);

       // Rota la imagen a partir de su centro
       this.matrix.postRotate(this.angle, this.image.getWidth() / 2, this.image.getHeight());
       
       // Posiciona el objeto al centro del circulo
       this.matrix.postTranslate(
               this.start_circle.getLeft() + (this.start_circle.getWidth() / 2) - (this.image.getWidth() / 2) +
                       (((Double)Math.sin(alfa)).floatValue() * (this.start_circle.getWidth() / 2)),
               this.start_circle.getTop() + (this.start_circle.getHeight() / 2) - this.image.getHeight() +
                       (((Double)Math.cos(alfa)).floatValue() * (this.start_circle.getHeight() / 2))
       );

       /*
       this.matrix.postTranslate(
               this.start_circle.getLeft() + (((Double)Math.sin(alfa)).floatValue() * (this.start_circle.getWidth() / 2)),
               this.start_circle.getTop() + (((Double)Math.cos(alfa)).floatValue() * (this.start_circle.getHeight() / 2))
       );
       */

       alfa -= 0.022;//cambio 0.03 grados por frame
       alfa %= 360; // limito a 360 grados
       if(alfa == 0)
           alfa = 360;
   }

engel lex

si quieres una vuelta cada 5 segundos sin importar el framerate, puedes hacerlo con el diff_millisecond (esto sería el diferencial de tiempo sobre update)

alfa = diff_millisecond * 360/5000 

360/5000 es la cantidad de grados que debe avanzar por milisegundo para mantenerse al ritmo.... al multiplicarlo por diff_millisecond, lo multiplicas por la cantidad de milisegundos avanzados desde la ultima vez... esta tecnica se usa para mantener sincronia en perdida de fps :P


por curiosidad, que haces?
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

WHK

jajajaja pues si, tenía varias opciones para controlar los fps, al comienzo solo sabia manejar animaciones en base al while del update del canvas, pero con el tiempo me di cuenta que la velocidad del while era diferente en diferentes dispositivos, en el pc era rápido, en el movil era mas lento y no siempre era una velocidad constante, a veces la velocidad variaba de muy rápido a muy lento o a veces producía pequeños cortes, entonces como el audio se desincronizaba con la animación se me vino la pregunta de como corregir esto:

Una opción era enviar el numero del frame al controlador para que la animación y la pista de audio se sincronizara en base a la velocidad del frame, pero despues de esto tuve otro problema, este problema consistia en que cuando se bloqueaba la app por un tiempo muy corto (menos de un segundo) tanto la animación como el juego se cortaban, entonces cuando el lagg era muy grande la animación se veia muy cortado y los controles ya no funcionaban bien porque para terminar una acción con un botón tenias que mantenerlos sostenido o perdias la acción. Despues me di cuenta que este tipo de desface tambien lo sufrian la mayoría de los juegos de videos antiguos como los de ps1, snes, emuladores, etc, y ahi me di cuenta que todos esos juegos viejos se basan en la sincronización por frames.

Cuando me pasó eso me di cuenta que los juegos de hoy no sucede eso, por ejemplo si la animación se está ejecutando y hay lagg entonces el desface hace que por ejemplo si lanzas una pelota y a mitad de camino se bloquea la app lo verás al final del camino cuando se desbloquee, eso quiere decir que la sincronización ya no depende del frame sino del tiempo, a diferencia de la sincronización por frame que cuando se desbloquea la app ahi recien se ve la siguiente posicion de la pelota.

Me di cuenta que esto solucionaría el problema del desface del audio ya que a pesar de que la animación se bloquee este no impide que la animación se siga sincronizando con el audio, a demás permite que pequeños lags no afecte a la experiencia final del juego ya que podrás seguir jugando a la velocidad que acostumbras a pesar de que dejes de ver un par de frames.

Por eso se me ocurrió calcular la diferencia del tiempo en milisegundos y en base a eso calcular la siguiente posición del dibujado del canvas, de esa manera no limito la animación a x cantidad de frames por segundo sino que en ves de eso en cada frame la app calculará la posición y la posicionará donde debe ir, de otra manera si el juego se sincroniza por frames y tiempos (frameskip) hará que un juego diseñado a 60fps no se vea a mayor velocidad en dispositivos con una taza de refresco mas alta, pero de esta manera la animación se adapta a la taza de animación soportada por el hardware y le da una mejor experiencia al usuario final.

Realmente no lo leí de otros lados, lo saqué en base a conclusiones solamente.

Estoy creando un motor de animación en android con físicas, un framework para crear cosas como juegos, animaciones tipo power point, presentación de documentos, animaciones en general de todo tipo, quiero hacer algo como unity 3d pero en lenguaje nativo usando librerías en ves de embeber una app dentro de otra, esto hará que el motor sea mucho mas optimizado que unity y las animaciones sean mucho mas fluidas ya que no necesitarás embeber un sistema en mono (c#) utilizando la interpretación de la interpretación de un código, sino de manera nativa directamente sin una interfaz gráfica, solamente utilizando código. Mas que nada para facilitar el uso de animaciones en apps incluyendo físicas. Como ejemplo estoy probando crear la animación de un cohete despegando de planeta en planeta.

engel lex

@.@ y lo estás haciendo a mano, no usas ningún framework... por lo menos para C++ hay un framework genial que puedes compilar para android (y pc), se llama openframeworks
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

WHK

#8
Finalmente quedó así:

Código (java) [Seleccionar]
/**
    * Actualiza la posición de los objetos
    */
   @Override
   public synchronized void update() {
       super.update();

       /**
        * Control de frames.
        * Controla los frames dependiendo del tiempo transcurrido,
        * esto prefieve en desface por lagg.
        */
       if (last_millisecond == null) {
           this.last_millisecond = Calendar.getInstance().getTimeInMillis();
       }

       Long current_millisecond = Calendar.getInstance().getTimeInMillis();
       Long diff_millisecond = current_millisecond - this.last_millisecond;
       this.last_millisecond = current_millisecond;


       /**
        * Contexto.
        * Calcula el grado de inclinación de los objetos y todo aquello
        * que sea necesario para calcular distancias y posicionamiento.
        */
       if(!this.launched) {
           // CW o CCW
           if(clock_wise) {
               this.angle += (diff_millisecond / 10);
           }else{
               this.angle -= (diff_millisecond / 10);
           }
           // Previene el desbordamiento
           this.angle = (this.angle % 360);
       }else{
           this.diameter_rotation_ship = this.diameter_rotation_ship + (diff_millisecond / 12);
       }


       /**
        * Controlador.
        * Controla el posicionamiento de los objetos para ser dibujado.
        */

       // Cambia el tamaño
       this.matrix.setScale(1, 1);

       // Rota la imagen a partir de su centro
       this.matrix.postRotate(this.angle, this.image.getWidth() / 2, this.image.getHeight());

       // % del angulo de 0 a 360
       Float angle_percent = ((this.angle * 100.0F) / 360);

       // -3.1 a 3.1
       Float alpha = -(((6.2F * angle_percent) / 100.0F) - 3.1F);

       // Posiciona el objeto al centro del circulo
       this.matrix.postTranslate(
               this.start_circle.getLeft() + (this.start_circle.getWidth() / 2) - (this.image.getWidth() / 2) +
                       (((Double)Math.sin(alpha)).floatValue() * (this.start_circle.getWidth() / 2)),
               this.start_circle.getTop() + (this.start_circle.getHeight() / 2) - this.image.getHeight() +
                       (((Double)Math.cos(alpha)).floatValue() * (this.start_circle.getHeight() / 2))
       );
   }


Le agregué la opción para rotar en sentido contrario cuando sea necesario.

Me di cuenta que la función cos y sin no inician directamente desde el grado 0 al 360 sino que utiliza valores mas extraños, por ejemplo el valor de alpha del 0 al 6.2 da una vuelta en 360 grados pero este inicia a partir de un costado y no desde el grado cero que es la parte superior central del circulo, por lo cual calculé que la posición de grado cero es 3.1 y para 360 es -3.1, por lo cual 180 grados son 0 en alpha, asi que lo que hice sin tener que utilizar el valor del tiempo dle frame como en el ejemplo que me diste, me basé mejor en el grado de inclinación haciendo que sea mas fluido para cualquier cantidad de fps, entonces tomé el porcentaje de 0 a 360 y me dió un valor, luego de 0 a 6.2 le saqué el valor de ese porcentaje y luego le resté 3.1 para que volviera otraves de 3.1 a -3.1 y listo! :D me anda de lujo en el pc y en el movil.



Muchas gracias por la ayuda.

Saludos.

engel lex

no está en sexagesimale, sino en radian XD casualmente media vuelta era 3.1416 grados cuando un circulo tiene incluso 2 pi de perimetro jejeje

hombre te has dado cuenta de detalles base de la ciencia rapido jejeje, en poco seguro das con turing u otro teorema de otra ciencia XD

exito con el programa ;)
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.