Unidad: cómo mover una nave de manera realista a un punto en un juego 2D de arriba hacia abajo


14

Estoy tratando de mover un velero al punto donde hice clic con el mouse. este movimiento debe ser realista (remo en la parte posterior donde se mueve el barco), de modo que si se hace clic con el mouse y en frente del barco, el barco debe moverse luego allí con una trayectoria con curvas para tener la rotación correcta

Me alegraría si alguien pudiera ayudarme con este problema, gracias movimiento de barcos


1
Como su imagen parece representar velas: ¿se debe tener en cuenta el viento? Algunas maniobras son imposibles de hacer con el viento incorrecto o la falta del mismo.
Nadie

Más concretamente, el movimiento realista de un velero realmente requiere tener en cuenta el viento; ignorarlo sería casi como ignorar la gravedad al implementar el salto. No necesariamente necesita un modelo de viento particularmente detallado, pero debe tener en cuenta que sus barcos están siendo empujados por el viento en sus velas (y el agua contra su quilla y timón). En particular, los barcos no pueden navegar directamente a favor del viento; que tendrán que vencer a su manera en su lugar.
Ilmari Karonen

Usualmente, un "punto de goto" se puede dividir en fase de rotación y fase de movimiento hacia adelante. Tome el mismo enfoque pero imponga a la rotación un movimiento hacia adelante. Por ejemplo, cada radio de rotación x mueve el bote hacia adelante de y metros
dnk drone.vs.drones

Respuestas:


7

Ver esta página

Agregar vueltas realistas

El siguiente paso es agregar giros curvos realistas para nuestras unidades, de modo que no parezcan cambiar de dirección abruptamente cada vez que necesiten girar. Una solución simple implica el uso de una spline para suavizar las esquinas abruptas en giros. Si bien esto resuelve algunas de las preocupaciones estéticas, aún resulta en un movimiento físicamente muy poco realista para la mayoría de las unidades. Por ejemplo, podría cambiar una curva abrupta de un tanque en una curva cerrada, pero el giro curvo aún sería mucho más apretado de lo que realmente podría realizar el tanque.

Para una mejor solución, lo primero que debemos saber es el radio de giro de nuestra unidad. El radio de giro es un concepto bastante simple: si está en un estacionamiento grande en su automóvil, y gira la rueda hacia la izquierda todo lo que pueda y procede a conducir en un círculo, el radio de ese círculo es su giro radio. El radio de giro de un Volkswagen Beetle será sustancialmente menor que el de un SUV grande, y el radio de giro de una persona será sustancialmente menor que el de un oso grande y pesado.

Digamos que está en algún punto (origen) y apuntado en una determinada dirección, y necesita llegar a otro punto (destino), como se ilustra en la Figura 5. El camino más corto se encuentra girando a la izquierda todo lo que pueda puede hacerlo, yendo en círculo hasta que apunte directamente al destino, y luego avanzando, o girando a la derecha y haciendo lo mismo. Figura 5: Determinar la ruta más corta desde el origen hasta el destino.

En la Figura 5, la ruta más corta es claramente la línea verde en la parte inferior. Este camino resulta bastante sencillo de calcular debido a algunas relaciones geométricas, ilustradas en la Figura 6.

Figura 6: Cálculo de la longitud de la ruta.

Primero calculamos la ubicación del punto P, que es el centro de nuestro círculo de giro, y siempre está a un radio de distancia del punto de partida. Si estamos girando a la derecha desde nuestra dirección inicial, eso significa que P está en un ángulo de (initial_direction - 90) desde el origen, entonces:

angleToP = initial_direction - 90
P.x = Origin.x + r * cos(angleToP)
P.y = Origin.y + r * sin(angleToP)

Ahora que conocemos la ubicación del punto central P, podemos calcular la distancia desde P hasta el destino, que se muestra como h en el diagrama:

dx = Destination.x - P.x
dy = Destination.y - P.y
h = sqrt(dx*dx + dy*dy)

En este punto, también queremos verificar que el destino no esté dentro del círculo, porque si lo fuera, nunca podríamos alcanzarlo:

if (h < r)
    return false

Ahora podemos calcular la longitud del segmento d, ya que ya conocemos las longitudes de los otros dos lados del triángulo rectángulo, a saber, h y r. También podemos determinar el ángulo a partir de la relación triángulo rectángulo:

d = sqrt(h*h - r*r)
theta = arccos(r / h)

Finalmente, para descubrir el punto Q en el que salir del círculo y comenzar en la línea recta, necesitamos conocer el ángulo total +, y se determina fácilmente como el ángulo desde P hasta el destino:

phi = arctan(dy / dx) [offset to the correct quadrant]
Q.x = P.x + r * cos(phi + theta)
Q.y = P.y + r * sin(phi + theta)

Los cálculos anteriores representan la ruta de giro a la derecha. La ruta de la izquierda se puede calcular exactamente de la misma manera, excepto que agregamos 90 a initial_direction para calcular angleToP, y luego usamos - en lugar de +. Después de calcular ambos, simplemente vemos qué camino es más corto y usamos ese.

En nuestra implementación de este algoritmo y los siguientes, utilizamos una estructura de datos que almacena hasta cuatro "segmentos de línea" distintos, cada uno de los cuales es recto o curvo. Para las rutas curvas descritas aquí, solo se utilizan dos segmentos: un arco seguido de una línea recta. La estructura de datos contiene miembros que especifican si el segmento es un arco o una línea recta, la longitud del segmento y su posición inicial. Si el segmento es una línea recta, la estructura de datos también especifica el ángulo; para los arcos, especifica el centro del círculo, el ángulo inicial del círculo y el total de radianes cubiertos por el arco.

Una vez que hemos calculado la ruta curva necesaria para llegar entre dos puntos, podemos calcular fácilmente nuestra posición y dirección en cualquier instante dado, como se muestra en el Listado 2.

LISTADO 2. Cálculo de la posición y orientación en un momento particular.

distance = unit_speed * elapsed_time
loop i = 0 to 3:
    if (distance < LineSegment[i].length)
        // Unit is somewhere on this line segment
        if LineSegment[i] is an arc
            //determine current angle on arc (theta) by adding or
            //subtracting (distance / r) to the starting angle
            //depending on whether turning to the left or right
            position.x = LineSegment[i].center.x + r*cos(theta)
            position.y = LineSegment[i].center.y + r*sin(theta)
        //determine current direction (direction) by adding or
        //subtracting 90 to theta, depending on left/right
        else
            position.x = LineSegment[i].start.x 
              + distance * cos(LineSegment[i].line_angle)
            position.y = LineSegment[i].start.y
              + distance * sin(LineSegment[i].line_angle)
        direction = theta
        break out of loop
    else
        distance = distance - LineSegment[i].length

44
Esta respuesta realmente no analiza la física de los barcos. También me parece problemático que sea básicamente un enlace y un extenso extracto de otro sitio web (no estoy seguro de la legalidad).
Nadie

La última vez que proporcioné un recurso existente que era una solución a la pregunta que se me hizo, se me pidió que incluyera el contenido del enlace en caso de que el sitio objetivo dejara de existir. Ahora se me pide que no incluya el contenido. Decídete.
Draco18s ya no confía en SE

3
@ Draco18s: lo que debe hacer es resumir los puntos esenciales del material vinculado en sus propias palabras. (O, mejor aún, responda la pregunta en función de su propia experiencia, y solo use enlaces como material de apoyo o para lecturas adicionales.) Las citas cortas generalmente son correctas, especialmente en situaciones en las que no se pueden evitar realmente (por ejemplo, citar exactamente el nombre de alguien palabras para demostrar que realmente dijeron algo), pero citar una parte sustancial de un artículo realmente va más allá del uso justo .
Ilmari Karonen

Si el punto está dentro del círculo, puedes salir un poco y volver.
user253751

(Sal. Ver también estas dos preguntas sobre meta.SE.)
Ilmari Karonen

7

Como solución simple, como ya dije en un comentario, puedes probar este enfoque:

considere una fase en la que apunta la nave en la dirección del objetivo, en esa fase aplica una rotación al sorbo pero también un movimiento hacia adelante. Cuando la nave ya está orientada hacia el objetivo, puedes aplicar una velocidad de avance total. Arreglé una prueba en love2d, aquí sigue el método de actualización de la nave.

turnAngSpeed = 0.4 --direction changing speed
ForwordSpeed = 40 -- full forward speed
turnForwordSpeed = ForwordSpeed *0.6 -- forward speed while turning
function ent:update(dt)
            dir = getVec2(self.tx-self.x,self.ty-self.y) -- ship --> target direction (vec2)
            dir = dir.normalize(dir) --normalized                               
            a= dir:angle() - self.forward:angle() --angle between target direction e current forward ship vector
            if (a<0) then
             a=a+math.pi *2 -- some workaround to have all positive values
            end

            if a > 0.05 then -- if angle difference 
                if a < math.pi then
                    --turn right
                    self.forward = vec2.rotate(self.forward,getVec2(0,0),turnAngSpeed * dt)
                else
                    --turn left
                    self.forward = vec2.rotate(self.forward,getVec2(0,0),-turnAngSpeed * dt)
                end             
                --apply turnForwordSpeed
                self.x = self.x+ self.forward.x * turnForwordSpeed * dt
                self.y = self.y+ self.forward.y * turnForwordSpeed * dt
            else 
                --applly ForwordSpeed
                self.x = self.x+ self.forward.x * ForwordSpeed * dt
                self.y = self.y+ self.forward.y * ForwordSpeed * dt
            end
end

ingrese la descripción de la imagen aquí

La animación de ejemplo muestra (el bucle final) un caso en el que el barco no puede alcanzar el objetivo, ya que la combinación de velocidad de giro y avance define un radio de giro demasiado grande, en estos casos puede ser útil para reducir el " turnForwordSpeed" o mejor hacerlo depende de la distancia angular ( a) y la distancia objetivo.


Esta es una buena respuesta, pero puede o no ser lo suficientemente realista para el OP. A diferencia de, digamos, los automóviles, los barcos no tienen realmente un "radio de giro": la mayoría de los barcos con motor propio (motor / humano) pueden girar esencialmente un centavo, mientras que los barcos de vela dependen del viento y pueden tener un giro efectivo negativo radio al virar, en el sentido de que girar a la izquierda hacia el viento puede hacer que la nave se desplace hacia la derecha. Lo que los barcos tienen es inercia (y arrastre): no pueden girar o moverse instantáneamente, y una vez que se mueven o giran, toman un poco de tiempo y fuerza para detenerse. Aún así, tiene un +1.
Ilmari Karonen

¡¡¡Muchas gracias por su respuesta!!! :) ¡Usted señor, es mi héroe!
DavidT

@DavidT Luego considere marcar su respuesta como la aceptada, si fue capaz de resolver su problema satisfactoriamente. :)
Y el

-2

Sistema de malla Unity Nav, probablemente haga lo que quiera con un poco jugando con los valores del agente de navegación.

Las mallas de navegación son bastante simples de usar. Y solo se puede usar en la configuración de arriba hacia abajo (o al menos solo disponible para el movimiento x / z)

Página del manual de Unity sobre cómo configurar una malla de navegación

Básicamente, puede usar cualquier malla de forma para hornear un área de navegación y agregar agentes de navegación a sus objetos y hacer que encuentren sus rutas alrededor de una malla de navegación


Me parece que la respuesta de Draco18s también falta en ese sentido. Sin embargo, la suya no es una respuesta real y más un comentario.
Nadie

2
Esta es una buena sugerencia pero, para ser una buena respuesta, necesita apoyo e información sobre la implementación. Agregue información sobre la configuración de mallas de navegación para que sea una buena respuesta. Creo que eso es lo que los comentaristas anteriores intentan decir :)
sirdank
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.