[DB-AL]Rotation avec souris

Pour les scripts écrits en C#
Règles du forum
Merci de respecter la NOMENCLATURE suivante pour vos TITRES de messages :

Commencez par le niveau de vos scripts
DB = Débutant
MY = Moyen
CF = Confirmé

Puis le domaine d'application
-RS = Réseau
-AL = Algorithmie

Exemple :

[DB-RS] Mouvement perso multijoueur
EmileF
Messages : 673
Inscription : 18 Mars 2017 19:39

[DB-AL]Rotation avec souris

Message par EmileF » 23 Juin 2019 17:12

Bonjour,

Voilà pas mal de temps que je cherche une solution pour un détail qui tarabuste.
Je me suis créé un petit outil pour gérer les rotations avec la souris comme avec une manivelle.
Cet outil me permet d'orienter ma manivelle dans les 3 directions, et les objets reliés pivotent selon l'orientation de ma manivelle.
Je clique sur ma manivelle, et je fais tourner mon curseur dans un sens ou dans l'autre selon mon désir et jusque là tout va bien.

Mon soucis est que quand je lâche ma manivelle, et que j'y reviens dessus, mes objets ont un sursaut pour s'aligner par rapport à la nouvelle position de ma souris, ce comportement et normal, en fait, compte tenu de la programmation, mais je voudrais éviter ce sursaut, et c'est là que je fais appel à votre perspicacité, car je n'arrive pas à trouver une solution.

Voici mon code:

Code : Tout sélectionner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
public class Test : MonoBehaviour
{
    public enum ModeRotation
    {
        Forward,
        Right,
        Up
    }
    public Camera Camera;
    public List<Transform> APivoter;
    public ModeRotation modeRotation = ModeRotation.Up;
    Transform Objet;
    List<Vector3> ExRot;

    private void Start()
    {
        Objet = transform.GetChild(0);
    }

    bool run;
    private void Update()
    {
        if(!run)
        {
            run = Application.isPlaying;
            if (modeRotation == ModeRotation.Forward)
                transform.eulerAngles = new Vector3(90, 0, 0);
            else if (modeRotation == ModeRotation.Up)
                transform.eulerAngles = new Vector3(0, 0, 0);
            else if (modeRotation == ModeRotation.Right)
                transform.eulerAngles = new Vector3(0, 0, 90);
        }
        if (modeRotation == ModeRotation.Forward)
        {
            if (Input.GetMouseButton(0))
            {
                Vector3 pos = RaycastPos(Camera, transform);
                if (pos != Vector3.zero)
                {
                    pos.z = Objet.position.z;
                    Vector3 targetDir = pos - transform.position;
                    float angleBetween = Vector3.SignedAngle(Objet.up, targetDir, Vector3.forward);
                    Objet.Rotate(Objet.forward, angleBetween);

                    for (int i = 0; i < APivoter.Count; i++)
                    {
                        APivoter[i].Rotate(APivoter[i].forward, angleBetween);
                    }
                }
            }
        }
        else if (modeRotation == ModeRotation.Up)
        {
            if (Input.GetMouseButton(0))
            {
                Vector3 pos = RaycastPos(Camera, transform);
                if (pos != Vector3.zero)
                {
                    pos.y = Objet.position.y;
                    Vector3 targetDir = pos - transform.position;
                    float angleBetween = Vector3.SignedAngle(Objet.forward, targetDir, Vector3.up);
                    Objet.Rotate(Objet.up, angleBetween);

                    for (int i = 0; i < APivoter.Count; i++)
                    {
                        APivoter[i].Rotate(APivoter[i].up, angleBetween);
                    }
                }
            }
        }
        else if (modeRotation == ModeRotation.Right)
        {
            if (Input.GetMouseButton(0))
            {
                Vector3 pos = RaycastPos(Camera, transform);
                if (pos != Vector3.zero)
                {
                    pos.x = Objet.position.x;
                    Vector3 targetDir = pos - transform.position;
                    float angleBetween = Vector3.SignedAngle(Objet.up, targetDir, Vector3.right);
                    Objet.Rotate(Objet.right, angleBetween);

                    for (int i = 0; i < APivoter.Count; i++)
                    {
                        APivoter[i].Rotate(APivoter[i].right, angleBetween);
                    }
                }
            }
        }
    }

    public Vector3 RaycastPos(Camera camera, Transform objet)
    {
        //on envoie le rayon vers la position de la souris
        Ray ray = camera.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray, out RaycastHit hit))
        {
            //s'il rencontre l'objet
            if (hit.transform == objet)
            {
                //retourne la position du clic;
                return hit.point;
            }
        }
        return Vector3.zero;
    }
}

pour le mettre en place, il suffit de créer un empty, avec un scale de (4, 0.2, 4), avec un boxcollider va bien.
mettre le script sur cet empty.
Enfant de cet empty mettre un Cube (par exemple, mais sans collider pour ne pas qu'il gêne) pour prendre les commandes. Ça peut être un empty aussi. mais avec un cube on peut contrôler l'effet des commandes.

D'autres objets peuvent être reliés à la propriété "APivoter", ce sont eux en fait les cibles de la rotation.

Voilà, près pour les tests.

On peut changer la direction de la manivelle en changeant le "ModeRotation"
En mode run, cliquer et draguer en tournant sur le cube, il doit pivoter.
si vous relachez le clic et que vous recommencez à partir d'une autre position, le cube et les objets se mettent en place par rapport au nouveau clic, c'est ce qui me dérange.

Si vous quelqu'un avait une idée pour régler ce détail, ce serait sympa.
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6185
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: [DB-AL]Rotation avec souris

Message par boubouk50 » 24 Juin 2019 10:29

Tu n'as pas une fonction d'initialisation?
Elle serait appelée au moment du clic, avant d'activer la rotation de la manivelle, et permettrait de définir la rotation actuelle comme étant celle de départ.
Cela enlèverait la première rotation (angleBetween) qui est calculée sur selon l'axe up fixe plutôt que celui en cours.
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

EmileF
Messages : 673
Inscription : 18 Mars 2017 19:39

Re: [DB-AL]Rotation avec souris

Message par EmileF » 24 Juin 2019 12:02

Merci boubouk pour tes conseils,

J'ai essayé au moment du clic de récupérer la rotation initiale de la manivelle, mais je n'ai pas su comment l'utiliser par la suite.

je ne comprends pas
boobook a écrit :Cela enlèverait la première rotation (angleBetween) qui est calculée sur selon l'axe up fixe plutôt que celui en cours.
angleBetween j'en ai besoin à chaque frame.
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6185
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: [DB-AL]Rotation avec souris

Message par boubouk50 » 24 Juin 2019 13:46

Je pense que le saut de rotation que tu vois est du à la première mise à jour de la rotation lorsque tu calcules angleBetween. Il vaut l'angle entre le up de ton objet et le forward de ta manivelle, donc peut valoir jusqu'à 180° au premier calcul si les deux axes sont opposés. Ensuite, comme les axes sont proches, alors la rotation se poursuit normalement.
Je pense donc que ton souci est l'initialisation de cet angle. A la première mise à jour, il devrait valoir 0.

Sinon, tu peux le voir autrement, au lieu de trouver l'angle entre les deux, pourquoi ne pas définir le degré de rotation de la manivelle plutôt? L'angle effectué entre 2 mise à jour, je veux dire. Ainsi, pas de problème de saut.
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

EmileF
Messages : 673
Inscription : 18 Mars 2017 19:39

Re: [DB-AL]Rotation avec souris

Message par EmileF » 24 Juin 2019 14:32

Oui, c'est tout à fait ça, au premier clic l'angle peut aller jusqu'à 180°

J'ai cherché à calculer un offset par exemple lors de ce premier clic pour initialiser cette différence d'angle à zéro comme tu me le conseille, mais je n'y suis pas arrivé, il y a quelque chose qui m'échappe. J'ai un peu de mal avec les rotations.
boubouk a écrit :Sinon, tu peux le voir autrement, au lieu de trouver l'angle entre les deux, pourquoi ne pas définir le degré de rotation de la manivelle plutôt? L'angle effectué entre 2 mise à jour, je veux dire. Ainsi, pas de problème de saut.
C'est ce que je fait je crois non? le anglebetween ce n'est pas ça? Sinon, je ne voix pas comment faire pour que ça suive fidèlement la souris
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6185
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: [DB-AL]Rotation avec souris

Message par boubouk50 » 24 Juin 2019 15:09

Oui, alors l'offset calculé sera le premier angleBetween. Il sera additionné au vecteur object.up lors du calcul de l'angle final.
Sinon, ce que je te propose c'est de calculer l'angle entre le vecteur target présent et celui de la frame précédente. Il représente donc l'angle de la souris par rapport à la rotation qui a pour centre ton objet.

Les coroutines sont intéressantes pour ce cas. Car un appui (OnMouseDown) te permet de la lancer et ensuite de gérer l'initialisation de cet angle avant la boucle.
Pour ce faire avec un Update, dans ce cas, je te conseille que le clic appel une fonction d'initialisation externe à l'Update qui elle change le booléen qui te sert de déclencheur dans l'Update.
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

EmileF
Messages : 673
Inscription : 18 Mars 2017 19:39

Re: [DB-AL]Rotation avec souris

Message par EmileF » 24 Juin 2019 16:41

Bon, ok,
en calculant l'anglebetween au premier clic, et en le mettant en offset

et en enlevant l'offset pour les anglebetween suivant ça marche pour les objets joints, mais ça le marche pas pour mon cube témoin à cause des scales,

l'important c'est que ça marche pour les autres objets.

Merci boubouk

pour ce qui est des coroutines, je n'arrive pas à comprendre leur fonctionnement, mais je ne me suis pas encore vraiment penché dessus.
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6185
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: [DB-AL]Rotation avec souris

Message par boubouk50 » 24 Juin 2019 16:47

EmileF a écrit :
24 Juin 2019 16:41
pour ce qui est des coroutines, je n'arrive pas à comprendre leur fonctionnement, mais je ne me suis pas encore vraiment penché dessus.
J'en rajoute une couche volontairement ;)
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

EmileF
Messages : 673
Inscription : 18 Mars 2017 19:39

Re: [DB-AL]Rotation avec souris

Message par EmileF » 24 Juin 2019 17:28

J'avoue que je n'en vois pas vraiment l’intérêt
La différence entre l'intelligence et la stupidité est que l'intelligence est limitée.

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6185
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: [DB-AL]Rotation avec souris

Message par boubouk50 » 24 Juin 2019 18:12

Essentiellement par optimisation et contrôle.
Un Update () est généralement plus lourd en performance/ressources. (évidemment, tout dépend ce que tu y fais)
Tu as le contrôle sur une coroutine (fréquence des mise à jour, arrêt/départ, etc)

Perso, je trouve aussi plus lisible d'avoir des coroutines que des updates où tout y est entassé avec des conditions qui peuvent être supprimées avec les paramètres de la coroutine.
Mais si tu es plus à l'aise avec l'update, il fait le taff, ce sont juste deux façons différentes de faire la même chose.
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

Répondre

Revenir vers « (C#) CSharp »