Calcule d'un angle à partir d'un triangle

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour à tous,

J'essaye de comprendre comment calculer un angle à partir de deux positions dans un jeu. J'ai pris pour exemple Counter Strike Source (car il est simple à comprendre et beaucoup de ressource grace a AlliedModders). Le but est simplement de calculer l'angle ideal d'un joueur pour tuer un adversaire.

Pour arriver à ça j'ai trois valeur, Counter Strike fonctionne bizarrement, la position des joueurs (leur origine) est toujours entre leurs jambes (0 sur Z (en local par rapport au joueur et pas au monde)), j'ai donc comme valeur la position de mon joueur, la position de l'ennemie (sa tête en l’occurrence) et ce qu'ils appellent le Eye Position ('est la position de la camera).

Représentation des joueurs sur une carte

Je par du principe que la première information dont j'ai besoin est l’hypoténuse de mon triangle mais je n'ai aucune idée de comment le calculer depuis mes deux points. Je sais même pas si je doit représenter mes valeurs comme ça ou simplement comme une droite, la représentation au dessus vient d'un autre jeu qui fonctionne pas forcément de la même façon.

Une fois que j'ai cette valeur il faut que je calcule l'angle approprié. Dans counter strike l'angle est stocké dans un vecteur2D comme ceci:

1
2
3
4
5
6
struct Vec2D
{
    float yaw;

    float pitch;
};

(Il y a en fait une troisième valeur (roll) mais elle vaut toujours 0.0f donc je ne m'en occupe pas du tout).

Exemple d'un angle (60.0f, 10.0f)

Le but est simplement de calculer le nouvel angle que je pourrai utiliser avec setang (fonction dispo dans le SDK).

Notez que ce code est utilisé sur le serveur est pas chez le client, je peux donc facilement le calculer avec les méthodes du SDK mais le but est de comprendre comment ça fonctionne.

J'ai trouvé un thread sur StackOverflow qui explique plus ou moins ce que je cherche à faire mais je comprend pas forcément ce qu'il essaye d'expliquer.

Le SDK (dispo sur GitHub) si vous en avez besoin.

EDIT: Voici comment l'angle est calculer dans le SDK

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void VectorAngles( const float *forward, float *angles )
{
    Assert( s_bMathlibInitialized );
    float   tmp, yaw, pitch;

    if (forward[1] == 0 && forward[0] == 0)
    {
        yaw = 0;
        if (forward[2] > 0)
            pitch = 270;
        else
            pitch = 90;
    }
    else
    {
        yaw = (atan2(forward[1], forward[0]) * 180 / M_PI);
        if (yaw < 0)
            yaw += 360;

        tmp = sqrt (forward[0]*forward[0] + forward[1]*forward[1]);
        pitch = (atan2(-forward[2], tmp) * 180 / M_PI);
        if (pitch < 0)
            pitch += 360;
    }

    angles[0] = pitch;
    angles[1] = yaw;
    angles[2] = 0;
}

Édité par #VK

Je ne comprends pas trop. Déjà, que représentent les segments en bleu ?

Il me semble que tu veux calculer la trajectoire du rayon pour aller d'un joueur à l'autre en ligne droite. Le cas échéant, ce n'est pas très compliqué : tu as deux points, par lesquels passe une unique droite. Mais je ne comprends pas ce que tu entends par "angle".

+0 -0

Je crois bien que tu veux trouver Yaw et Pitch tels que l'arme du joueur est pointée sur la tête de l'autre joueur, c'est ça ?

Dans ce cas, si tu as la position des deux tetes, tu as, comme dit au dessus, une droite qui passe par les deux têtes, portée disons par un vecteur unitaire (une flèche de longueur 1) $\vec{u}$.

Ton repère est constitué de trois vecteurs unitaires orthogonals (perpendiculaire), $\vec{e_x}$, $\vec{e_y}$ et $\vec{e_z}$.

Ton but est de trouver l'angle par rapport à ça. Quatre choses vont te servir :

  • La normalisation : tu divises les coordonnées du vecteur par sa norme.
  • La projection : $\Pi_{\vec{v}}(\vec{u}) = \dfrac{\vec{u}\cdot\vec{v}}{\|\vec{v}\|} \vec{v}$. Dans ton cas, ça revient à supprimer une des coordonnées et renormaliser.
  • Le produit scalaire : $\vec{u}\cdot\vec{v} = \|\vec{u}\| \cdot \|\vec{v}\| \cdot cos(\vec{u},\vec{v}) = x_u x_v + y_u y_v + z_u z_v$.
  • Le déterminant dans un plan : $\det(\vec{u}, \vec{v}) = x_u y_v - x_v y_u = \|\vec{u}\| \cdot \| \vec{v}\| \cdot \sin(\vec{u}, \vec{v})$ qui te donne l'information manquante pour être sûr de l'angle à donner.

Il te reste plus qu'à utiliser les outils du dessus en te placant par projection-normalisation dans les bons plans (ceux dans lesquels il y a les angles qui t'intéressent).

Vayel : oui, du vecteur qui part d'une tête et qui pointe vers l'autre tête.

Édité par unidan

+0 -0

Je crois bien que tu veux trouver Yaw et Pitch tels que l'arme du joueur est pointée sur la tête de l'autre joueur, c'est ça ?

Le cas échéant, il s'agit juste d'un passage des coordonnées cartésiennes en coordonnées sphériques, en prenant pour origine le point de départ du rayon, non ?

Édité par Vayel

+2 -0
Auteur du sujet

@vayel alors les lignes bleu représenter les cotés du triangle et la ligne verte représente l'hypoténuse, c'est comme ça que c'est expliquer dans les quelques articles que j'ai lu sur la toile. Mais comme dit en dessous

Je sais même pas si je doit représenter mes valeurs comme ça

Unidan, c'est ça en fait pas forcément sur un joueur, je voudrais créer une fonction qui me permette simplement en donnant un vector3d me retourne l'angle que j'ai besoin d'établir.

PS: comme dit sur irc mon niveau en math est pas fou, du coup j'ai rien compris à tes explications, je cours me documenter un peu

Édité par #VK

Je t'ai donné la solution dans le cas général, tu peux adapter à n'importe quel position (même lui tirer dans les pieds si ça te chante). Je suis parti de deux hypothèses néanmoins, qui me semblent assez raisonnable pour un jeu :

  • Les rotations sont effectuées distinctement des translations (donc on fait la rotation de la caméra/arme dans son propre repère, puis on déplace ce repère local dans le repère global, i.e la scène)
  • le yaw/pitch de la caméra sont le yaw/pitch de l'arme, c'est-à-dire que ça pointe vers l'endroit que tu veux atteindre, et l'arme fait feu au niveau de la caméra.

Si tu valides ces deux conditions, c'est tout bon, et ton hypoténuse et centre du repère ne servent pas ici, seul sert le vecteur qui porte le trait bleu, c'est-à-dire la position de départ et la position de fin.

Si l'une d'entre elle s'avère fausse, tu peux quand même partir de ce modèle en changeant les paramètres.

EDIT :

du coup, tu as besoin du point de départ et du point d'arrivée, on va les appeler $A(x_1, y_1)$ et $B(x_2, y_2)$. De ces deux points, tu peux créer le vecteur (informellement, c'est comme un point, deux coordonnées) $\vec{u} = B - A = (x_2-x_1, y_2 - y_1)$. En fait, en faisant ça, tu "redéfinies" $A$ comme étant une origine, et $\vec{u}$ comme le point $B$, mais en prenant $A$ comme référence. Ainsi $\vec{u}$ représente les coordonnées de ce point $B$ relativement à $A$, mais également la direction vers laquelle aller pour rejoindre $B$ à partir de $A$. Tu peux voir que la fonction $f : t \mapsto (1-t)A + tB$ vaut $A$ en $t=0$ et $B$ en $t=1$, et il s'agit d'une équation de droite (tu peux t'en rendre compte en rassemblant les $t$ et les termes constants). Ce truc, par rapport à A, tu l'écris $A + t(B-A) = A + t\cdot\vec{u}$, donc c'est par exemple comme ça que tu peux voir qu'il s'agit bien de la direction (puisqu'on a dit que c'était une équation de droite).

Maintenant, ce point, tu peux le voir sur 2 dimension, de deux manière différentes, en "projetant". Imagine que c'est comme si tu voyais un cylindre de haut (tu vois donc que le cercle) puis que de coté (tu vois donc qu'un rectangle). les deux points de vue te permettent de trouver des propriétés sur le cylindre. Ici c'est pareil, tu veux trouver des angles qui sont dans certains plan, donc tu vas ignorer la partie du vecteur qui t'intéresse pas. Si tu fais le dessin de l'angle avec et sans la projection, tu peux te rendre compte de pourquoi la projection est nécessaire.

Après, la normalisation, c'est pour avoir des vecteurs de norme 1, ça simplifie les formules du dessus ($\|\vec{u}\| = 1$ de cette façon, donc disparait).

Édité par unidan

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte