Unidade - Como mover um navio de forma realista para um ponto em um jogo 2D de cima para baixo

14

Estou tentando mover um veleiro para o ponto em que cliquei com o mouse. esse movimento deve ser realista (remo na parte traseira, onde o navio se move); portanto, se o clique do mouse for deixado e na frente do navio, o navio deve depois se mover para lá com um caminho curvo para ter a rotação correta

ficaria feliz se alguém pudesse me ajudar com esta questão obrigado movimento de navios

DavidT
fonte
1
Como sua imagem parece representar velas: o vento deve ser levado em consideração? Algumas manobras são impossíveis de fazer com o vento errado ou com a falta dele.
Ninguém
Mais precisamente, o movimento de um navio à vela de aparência realista realmente exige levar o vento em consideração; ignorá-lo seria quase como ignorar a gravidade ao implementar o salto. Você não precisa necessariamente de um modelo de vento particularmente detalhado, mas precisa ter em mente que seus navios estão sendo empurrados pelo vento em suas velas (e a água contra a quilha e o leme). Em particular, os navios não podem navegar diretamente contra o vento; eles precisam bater o seu caminho lá em vez disso.
Ilmari Karonen
Geralmente, um "ponto de goto" pode ser dividido em fase de rotação e fase de movimento para frente. Tome a mesma abordagem, mas imponha à rotação um movimento para frente. Exemplo cada x rad de rotação mover-se para a frente do barco de metros y
dnk drone.vs.drones

Respostas:

7

Vejo esta página

Adicionando voltas realistas

O próximo passo é adicionar curvas realistas às nossas unidades, para que elas não pareçam mudar de direção abruptamente toda vez que precisam girar. Uma solução simples envolve o uso de um spline para suavizar os cantos abruptos em turnos. Enquanto isso resolve algumas das preocupações estéticas, ainda resulta em um movimento fisicamente muito irreal para a maioria das unidades. Por exemplo, isso pode transformar uma curva abrupta de um tanque em uma curva apertada, mas a curva curva ainda seria muito mais apertada do que o tanque poderia realmente executar.

Para uma solução melhor, a primeira coisa que precisamos saber é o raio de viragem da nossa unidade. Raio de viragem é um conceito bastante simples: se você estiver em um grande estacionamento no seu carro e gire a roda para a esquerda o máximo possível e continue dirigindo em círculo, o raio desse círculo será a sua virada. raio. O raio de viragem de um Volkswagen Beetle será substancialmente menor que o de um grande SUV, e o raio de viragem de uma pessoa será substancialmente menor que o de um urso grande e pesado.

Digamos que você esteja em algum ponto (origem) e apontado em uma determinada direção, e precise chegar a outro ponto (destino), conforme ilustrado na Figura 5. O caminho mais curto é encontrado girando à esquerda o máximo possível. pode, andando em círculo até que você esteja diretamente apontado para o destino e, em seguida, prosseguindo, ou girando à direita e fazendo a mesma coisa. Figura 5: Determinando o caminho mais curto desde a origem até o destino.

Na Figura 5, a rota mais curta é claramente a linha verde na parte inferior. Esse caminho acaba sendo bastante simples de calcular devido a algumas relações geométricas, ilustradas na Figura 6.

Figura 6: Calculando o comprimento do caminho.

Primeiro calculamos a localização do ponto P, que é o centro do nosso círculo de viragem, e está sempre o raio r longe do ponto inicial. Se estivermos virando à direita em nossa direção inicial, isso significa que P está em um ângulo de (initial_direction - 90) a partir da origem, então:

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

Agora que sabemos a localização do ponto central P, podemos calcular a distância de P ao destino, mostrada como h no diagrama:

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

Neste ponto, também queremos verificar se o destino não está dentro do círculo, porque, se estivesse, nunca poderíamos alcançá-lo:

if (h < r)
    return false

Agora podemos calcular o comprimento do segmento d, uma vez que já sabemos os comprimentos dos outros dois lados do triângulo retângulo, ou seja, he er. Também podemos determinar o ângulo da relação do triângulo retângulo:

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

Finalmente, para descobrir o ponto Q no qual deixar o círculo e começar na linha reta, precisamos conhecer o ângulo total +, e é facilmente determinado como o ângulo de P ao 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)

Os cálculos acima representam o caminho de rotação à direita. O caminho da esquerda pode ser calculado exatamente da mesma maneira, exceto que adicionamos 90 à diretiva_inicial para calcular o angleToP e, mais tarde, usamos - em vez de +. Depois de calcular os dois, simplesmente vemos qual caminho é mais curto e o usamos.

Em nossa implementação desse algoritmo e dos seguintes, utilizamos uma estrutura de dados que armazena até quatro "segmentos de linha" distintos, sendo cada um deles reto ou curvado. Para os caminhos curvos descritos aqui, existem apenas dois segmentos usados: um arco seguido por uma linha reta. A estrutura de dados contém membros que especificam se o segmento é um arco ou uma linha reta, o comprimento do segmento e sua posição inicial. Se o segmento for uma linha reta, a estrutura de dados também especificará o ângulo; para arcos, especifica o centro do círculo, o ângulo inicial no círculo e o total de radianos cobertos pelo arco.

Depois de calcular o caminho curvo necessário para obter entre dois pontos, podemos calcular facilmente nossa posição e direção a qualquer instante no tempo, como mostra a Listagem 2.

Listagem 2. Calculando a posição e a orientação em um determinado momento.

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
Draco18s não confia mais no SE
fonte
4
Essa resposta realmente não analisa a física dos navios. Também acho problemático que seja basicamente um link e um longo trecho de outro site (não tenho certeza da legalidade).
Ninguém
A última vez que forneci um recurso existente que era uma solução para a pergunta que estava sendo feita, fui solicitado a incluir o conteúdo do link no caso de o site de destino deixar de existir. Agora me pedem para não incluir o conteúdo. Decida-se.
Draco18s não confia mais no SE
3
@ Draco18s: O que você deve fazer é resumir os pontos essenciais do material vinculado em suas próprias palavras. (Ou, melhor ainda, responda à pergunta com base em sua própria experiência e use apenas links como material de apoio ou para outras leituras.) Citações curtas geralmente são boas, especialmente em situações em que não podem ser realmente evitadas (por exemplo, citando a informação exata de alguém). palavras para demonstrar que realmente disseram algo), mas citar uma parte substancial de um artigo está realmente indo além do uso justo .
Ilmari Karonen
Se o ponto estiver dentro do círculo, você pode sair um pouco e voltar.
precisa saber é o seguinte
(Sal. Veja também essas duas perguntas sobre meta.SE.)
Ilmari Karonen 08/12/15
7

Como solução simples, como já disse em um comentário, você pode tentar esta abordagem:

considere uma fase em que você aponta o navio na direção do alvo; nessa fase, você aplica uma rotação ao gole, mas também um movimento para frente. Quando o navio já está enfrentando o alvo, você pode aplicar uma velocidade de avanço total. Eu organizei um teste no love2d, aqui segue o método de atualização do navio.

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

insira a descrição da imagem aqui

A animação de exemplo mostra (o loop final) um caso em que o navio não pode alcançar o alvo, pois a combinação de velocidade de rotação e avanço define um raio de rotação muito grande; nesses casos, pode ser útil reduzir o " turnForwordSpeed" ou melhor depende da distância do ângulo ( a) e da distância do alvo.

dnk drone.vs.drones
fonte
Essa é uma boa resposta, mas pode ou não ser realista o suficiente para o OP. Ao contrário, digamos, dos carros, os navios realmente não têm um "raio de viragem": a maioria dos navios com motor próprio (motor / humano) pode girar uma moeda de dez centavos, enquanto os veleiros dependem do vento e podem realmente ter um giro efetivo negativo raio ao prender, no sentido de que virar à esquerda contra o vento pode fazer com que o navio desvie para a direita. O que navios fazem têm é a inércia (e arraste): eles não podem virar ou mover instantaneamente, e uma vez em movimento ou virar, levar algum tempo e força para parar. Ainda assim, tenha um +1.
Ilmari Karonen
Muito obrigado pela sua resposta!!! :) Você senhor, é meu heroi!
DavidT
@DavidT Em seguida, considere marcar sua resposta como a aceita, se foi capaz de resolver seu problema satisfatoriamente. :)
Mand
-2

Sistema de malha do Unity Nav, provavelmente faria o que você quer com um pouco de brincadeira com os valores do agente de navegação.

Nav Malhas são bastante simples de usar. E apenas utilizável na configuração de cima para baixo (ou pelo menos disponível apenas para movimentos x / z)

Página manual do Unity sobre como configurar uma malha de navegação

Basicamente, você pode usar qualquer malha de forma para criar uma área de navegação e adicionar agentes de navegação aos seus objetos e fazer com que eles encontrem seus caminhos ao redor de uma malha de navegação

ProtoJazz
fonte
Acho que a resposta de Draco18 também não existe nesse sentido. No entanto, a sua não é uma resposta real e mais um comentário.
Ninguém
2
Essa é uma boa sugestão, mas, para ser uma boa resposta, precisa de suporte e informações sobre a implementação. Adicione algumas informações sobre a configuração de malhas de navegação para tornar esta uma boa resposta. Eu acho que é o que os comentadores anteriores estão tentando dizer :)
sirdank