Unity - Comment déplacer un vaisseau de manière réaliste vers un point dans un jeu top-down 2D

14

j'essaye de déplacer un voilier au point où j'ai cliqué avec la souris. ce mouvement doit être réaliste (rame à l'arrière où le navire se déplace) donc si le clic de la souris est laissé et devant le navire le navire doit ensuite s'y déplacer avec un chemin sinueux afin d'avoir la bonne rotation

je serais heureux si quelqu'un pouvait m'aider avec ce problème merci mouvement de navire

DavidT
la source
1
Comme votre image semble représenter les voiles: faut-il tenir compte du vent? Certaines manœuvres sont impossibles à faire avec le mauvais vent ou son absence.
Personne
Plus précisément, un mouvement de voilier d' aspect réaliste nécessite vraiment de prendre en compte le vent; l'ignorer serait presque comme ignorer la gravité lors de la mise en œuvre du saut. Vous n'avez pas nécessairement besoin d'un modèle de vent particulièrement détaillé, mais vous devez garder à l'esprit que vos navires sont poussés par le vent dans leurs voiles (et l'eau contre leur quille et leur gouvernail). En particulier, les navires ne peuvent pas naviguer directement au vent; ils doivent battre leur chemin à la place.
Ilmari Karonen
Habituellement, un "goto point" peut être divisé en phase de rotation et phase de mouvement vers l'avant. Prenez la même approche mais imposez à la rotation un mouvement vers l'avant. Exemple chaque x rad de rotation fait avancer le bateau de y mètres
dnk drone.vs.drones

Réponses:

7

Voir cette page

Ajout de virages réalistes

L'étape suivante consiste à ajouter des virages incurvés réalistes à nos unités, afin qu'elles ne semblent pas changer brusquement de direction à chaque fois qu'elles doivent tourner. Une solution simple consiste à utiliser une spline pour lisser les virages abrupts en virages. Bien que cela résout certaines des préoccupations esthétiques, il en résulte toujours un mouvement physiquement très irréaliste pour la plupart des unités. Par exemple, cela pourrait transformer une courbe brusque d'un réservoir en une courbe serrée, mais le virage incurvé serait toujours beaucoup plus serré que le réservoir ne pourrait réellement le faire.

Pour une meilleure solution, la première chose que nous devons savoir est le rayon de braquage de notre unité. Le rayon de braquage est un concept assez simple: si vous êtes dans un grand parking dans votre voiture, et tournez la roue vers la gauche aussi loin que possible et continuez à rouler en cercle, le rayon de ce cercle est votre virage rayon. Le rayon de braquage d'une Volkswagen Beetle sera sensiblement plus petit que celui d'un gros SUV, et le rayon de braquage d'une personne sera sensiblement inférieur à celui d'un gros ours lourd.

Disons que vous êtes à un certain point (origine) et pointé dans une certaine direction, et vous devez vous rendre à un autre point (destination), comme illustré dans la figure 5. Le chemin le plus court se trouve soit en tournant à gauche aussi loin que vous peut, en faisant un cercle jusqu'à ce que vous soyez directement pointé vers la destination, puis en avançant, ou en tournant à droite et en faisant la même chose. Figure 5: Déterminer le chemin le plus court de l'origine à la destination.

Sur la figure 5, l'itinéraire le plus court est clairement la ligne verte en bas. Ce chemin se révèle assez simple à calculer en raison de certaines relations géométriques, illustrées à la figure 6.

Figure 6: Calcul de la longueur du chemin.

Nous calculons d'abord l'emplacement du point P, qui est le centre de notre cercle de braquage, et est toujours à un rayon r du point de départ. Si nous tournons à droite de notre direction initiale, cela signifie que P est à un angle de (direction_initiale - 90) par rapport à l'origine, donc:

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

Maintenant que nous connaissons l'emplacement du point central P, nous pouvons calculer la distance de P à la destination, indiquée par h sur le diagramme:

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

À ce stade, nous voulons également vérifier que la destination ne se trouve pas dans le cercle, car si elle l'était, nous ne pourrions jamais l'atteindre:

if (h < r)
    return false

Nous pouvons maintenant calculer la longueur du segment d, car nous connaissons déjà les longueurs des deux autres côtés du triangle rectangle, à savoir h et r. Nous pouvons également déterminer l'angle à partir de la relation triangle-droite:

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

Enfin, pour déterminer le point Q auquel quitter le cercle et commencer sur la ligne droite, nous devons connaître l'angle total +, et est facilement déterminé comme l'angle de P à la destination:

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)

Les calculs ci-dessus représentent la trajectoire de virage à droite. Le chemin de gauche peut être calculé exactement de la même manière, sauf que nous ajoutons 90 à initial_direction pour calculer angleToP, et plus tard nous utilisons - au lieu de +. Après avoir calculé les deux, nous voyons simplement quel chemin est le plus court et utilisons celui-ci.

Dans notre implémentation de cet algorithme et de ceux qui suivent, nous utilisons une structure de données qui stocke jusqu'à quatre «segments de ligne» distincts, chacun étant soit droit soit courbe. Pour les trajectoires courbes décrites ici, il n'y a que deux segments utilisés: un arc suivi d'une ligne droite. La structure de données contient des membres qui spécifient si le segment est un arc ou une ligne droite, la longueur du segment et sa position de départ. Si le segment est une ligne droite, la structure de données spécifie également l'angle; pour les arcs, il spécifie le centre du cercle, l'angle de départ sur le cercle et le total des radians couverts par l'arc.

Une fois que nous avons calculé le chemin incurvé nécessaire pour se rendre entre deux points, nous pouvons facilement calculer notre position et notre direction à tout instant donné, comme le montre le listing 2.

LISTE 2. Calcul de la position et de l'orientation à un moment donné.

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 ne fait plus confiance à SE
la source
4
Cette réponse ne s'intéresse pas vraiment à la physique des navires. Je trouve également problématique qu'il s'agisse essentiellement d'un lien et d'un long extrait d'un autre site Web (je ne suis pas sûr de la légalité).
Personne
La dernière fois que j'ai fourni une ressource existante qui était une solution à la question posée, on m'a demandé d'inclure le contenu du lien dans le cas où le site cible cesserait d'être. Maintenant, on me demande de ne pas inclure le contenu. Décidez-vous.
Draco18s ne fait plus confiance au SE
3
@ Draco18s: Ce que vous devez faire est de résumer les points essentiels du matériel lié à vos propres mots. (Ou, mieux encore, répondez à la question en fonction de votre propre expérience et n'utilisez que des liens comme support ou pour une lecture plus approfondie.) Les citations courtes sont généralement OK, en particulier dans les situations où elles ne peuvent pas être vraiment évitées (par exemple, en citant l'exact de quelqu'un mots pour démontrer qu'ils ont vraiment dit quelque chose), mais citer une partie substantielle d'un article va vraiment au-delà de l' usage loyal .
Ilmari Karonen
Si le point est dans le cercle, vous pouvez sortir un peu et revenir.
user253751
(Ps. Voir aussi ces deux questions sur meta.SE.)
Ilmari Karonen
7

Comme solution simple, comme je l'ai déjà dit dans un commentaire, vous pouvez essayer cette approche:

considérez une phase où vous pointez le vaisseau dans la direction cible, dans cette phase vous appliquez une rotation à la gorgée mais aussi un mouvement vers l'avant. Lorsque le navire fait déjà face à la cible, vous pouvez appliquer une vitesse d'avance maximale. J'ai organisé un test dans love2d, voici la méthode de mise à jour du vaisseau.

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

entrez la description de l'image ici

L'exemple d'animation montre (la boucle finale) un cas où le navire ne peut pas atteindre la cible, car la combinaison de la vitesse de virage et de la marche avant définit un rayon de braquage trop grand, dans ce cas, il peut être utile de réduire le " turnForwordSpeed" ou mieux de le faire en fonction de la distance angulaire ( a) et de la distance cible.

dnk drone.vs.drones
la source
C'est une bonne réponse, mais elle peut ou non être assez réaliste pour l'OP. Contrairement, disons, aux voitures, les navires n'ont pas vraiment de "rayon de braquage": la plupart des navires autonomes (à moteur / humain) peuvent essentiellement allumer un sou, tandis que les voiliers dépendent du vent et peuvent en fait avoir un virage efficace négatif rayon lors du virement de bord, dans le sens où tourner à gauche dans le vent peut faire dériver le navire vers la droite. Qu'est - ce que les navires n'ont une inertie (et glisser): ils ne peuvent pas tourner ou déplacer instantanément, et une fois en mouvement ou tourner, prendre un certain temps et la force pour arrêter. Toujours avoir un +1.
Ilmari Karonen
Merci beaucoup pour votre réponse!!! :) vous monsieur êtes mon héros!
DavidT
@DavidT Ensuite, envisagez de marquer sa réponse comme acceptée, si elle a pu résoudre votre problème de manière satisfaisante. :)
Le
-2

Système de maillage Unity Nav, il ferait probablement ce que vous voulez en jouant un peu avec les valeurs de l'agent de navigation.

Les maillages de navigation sont assez simples à utiliser. Et uniquement utilisable dans la configuration descendante (ou du moins uniquement disponible pour le mouvement x / z)

Page de manuel Unity sur la configuration d'un maillage de navigation

Fondamentalement, vous pouvez utiliser n'importe quel maillage de forme pour créer une zone de navigation, ajouter des agents de navigation à vos objets et leur faire trouver leur chemin autour d'un maillage de navigation

ProtoJazz
la source
Je trouve que la réponse de Draco18s manque également à cet égard. Cependant, la vôtre n'est pas une vraie réponse et plutôt un commentaire.
Personne
2
C'est une bonne suggestion mais, pour être une bonne réponse, elle a besoin de soutien et d'informations sur la mise en œuvre. Veuillez ajouter quelques informations concernant la configuration des maillages de navigation pour en faire une bonne réponse. Je pense que c'est ce que les commentateurs ci-dessus essaient de dire :)
sirdank