J'ai encore une fois besoin de vos lumières
Je suis en train de créer un espèce de casse tête qui consiste à retrouver l'emplacement des roues dentées dans un rouage pour le faire fonctionner.
Les roues sont placées au hasard au départ par script.
Le rouage se présente verticalement comme plaqué sur un mur.
Quand l'ensemble du rouage est orienté à 0 degrés sur l'axe des y, tout marche bien. Quand il est orienté à 180°, en fait sur le mur d'en face, il n'y a plus qu'une roue sur deux qui est bien placée. Mon problème vient du fait qu'il y a vraiment une roue sur 2 bien placée, en fait si j'ai bien repéré, les roues paires sont bien les impaires non. Voilà des heures que j'essaye de comprendre le phénomène mais ça me dépasse.
Si quelqu'un avait un soupçon de solution, ce serai nickel.
Voici le script, désolé, il fait près de 400 lignes, mais il est commenté
Code : Tout sélectionner
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rouage : MonoBehaviour
{
public Camera Camera; //pour gérer les raycasts
public Enigme Enigme; //pour une relation avec le reste du jeu
public Player Player; //pour orienter vers le coffre s'il y a lieu
public Transform Coffre;//le coffre contenant le vase pour la suite quand l'énigme est trouvée
//public bool execute;
public Transform Cremaillere; // la crémaillère finale
public Roue[] Roues; //les préfabs des roues
public int nombre; //le nombre de roues du rouage
public float speed; //la vitesse de base
public float delai; //le temps de rotation des roues quand l'énigme est trouvée
List<Roue> rouage; //la liste des roues du rouage à partir de la crémaillère
List<Transform> tsStart;//la liste des transforms contenant l'axe du départ
List<Transform> tsEnd; //la liste des transforms contenant l'axe de l'arrivée
//
public List<int> IntEnd; //liste des index indiquant la référence de la roue à l'arrivée pour controler que la roue est de la bonne taille
public List<int> IndexArrives; //liste des index des roues dans le rouage à l'arrivée pour les faire pivoter dans le bon sens et à la bonne vitesse par rapport à l'ensemble
float speedCremaillere; //vitesse du déplacement de la crémaillere
bool move; //pour appliquer les animations quand l'énigme est résolue
public float orientation; //la rotation de l'ensemble (je pensais que ça pouvait être utile pour régler le problème)
int current; //index de la roue en cours de déplacement (drag)
float distance; //distance entre la roue et la caméra pour le drag
Vector3 offset; //distance entre la roue et le curseur pour le drag
private void Start()
{
//orientation générale de l'ensemble
orientation = transform.eulerAngles.y;
//Pour créer le rouage
//Le nombre d'essais et là pour éviter les boucles infinies
retour0:
int essais = 0;
retour:
if (!CreerRouage())
{
essais++;
if (essais < 1000)
goto retour;
else
print("Initialisation impossible");
}
//Place les axes pignons pour le départ du jeu
//Le nombre d'essais et là pour éviter les boucles infinies
essais = 0;
retour1:
if (!PositionneStarts())
{
essais++;
if (essais < 1000)
goto retour1;
else
{
print("Positionnement impossible");
goto retour0;
}
}
}
private bool CreerRouage()
{
//initialisation des lists
IntEnd = new List<int>();
IndexArrives = new List<int>();
rouage = new List<Roue>();
//récupère et vide le transform dans lequel serant affichée les roues
Transform roues = transform.Find("Roues");
roues.Vide(); //Extension pour supprimer tous les gameobjects enfants du transform
//crée la première roue, et positionne là par rapport à la crémaillère
int v = UnityEngine.Random.Range(0, Roues.Length);
Roue r = Instantiate(Roues[v], roues);
r.transform.localPosition = Cremaillere.localPosition + new Vector3(0, r.rayon, 0);
r.transform.localEulerAngles = new Vector3(0, 0, 0);
r.index = v;
IntEnd.Add(v);
IndexArrives.Add(-1);//c'est juste pour créer autant de int que de roue la valeur ne compte pas
rouage.Add(r);
//Cree les roues
for (int i = 0; i < nombre-1; i++)
{
//100 essais avant d'abandonner pour eviter les boucles infinies
int coups = 0;
retour:
coups++;
if (coups > 100)
{
print("Infini");
return false;
}
//POUR CREER UNE ROUE
//récupère l'index de la roue suivante
v = UnityEngine.Random.Range(0, Roues.Length);
//pour calculer la position de la roue autour de la roue précédente
int nDents = rouage[i].nDents / 2;
//l'angle doit correspondre à la pointe d'une dent de la roue précédente pour éviter les corrections de rotation
//ce sera une des dents dirigée vers le haut (mode self) de la roue précédente
float angle = (UnityEngine.Random.Range(0, nDents) - nDents / 2) * rouage[i].pas + rouage[i].transform.eulerAngles.z;
//le rayon est la somme des rayons des 2 roues
float rayon = rouage[i].rayon + Roues[v].rayon;
//calcule la position de la roue par rapport à la roue précédente
//JE PENSE QUE C EST ICI QUE CA COINCE
Vector3 pos = RotatePointAroundPivot(rayon, rouage[i].transform, angle);
//si la position horizontale est trop à droite
if (pos.x + Roues[v].rayon > transform.position.x + 1.2f)
{
print("Trop à droite");
goto retour;
}
//ou trop à gauche
if (pos.x - Roues[v].rayon < transform.position.x - 1.2f)
{
print("Trop à gauche");
goto retour;
}
//ou trop haute
if (pos.y + Roues[v].rayon > transform.position.y + 2.5f)
{
print("Trop haut");
goto retour;
}
//si trop bas
if (pos.y - Roues[v].rayon * 1.5f < Cremaillere.position.y)
{
print("Cremaillére touchée");
goto retour;
}
//ou si ça chevauche une autre roue (ça arrive des fois que c'est limite malgré l'augmentation du rayon à 1.5
bool ok = true;
for (int j = 0; j < i-1; j++)
{
if (Vector3.Distance(rouage[j].transform.position, pos)< rouage[j].rayon * 1.5f + Roues[v].rayon * 1.5f)
{
print(rouage[j] + " touchée");
ok = false;
break;
}
}
if (!ok)
goto retour;
//toutes les conditions sont remplies on crée la roue
Roue roue = Instantiate(Roues[v], roues);
roue.index = v;
IntEnd.Add(v);
IndexArrives.Add(-1);
roue.transform.localEulerAngles = new Vector3(0, 0, angle);
roue.transform.localPosition = pos;
rouage.Add(roue);
}
//maintenant que toutes les roues sont crées
//on déparente les axes end pour qu'il ne bougent plus si on déplace la roue
tsEnd = new List<Transform>();
for (int i = 0; i < nombre; i++)
{
Transform ts = rouage[i].transform.Find("AxeEnd");
//ça parce que j'ai une erreur de nullité parfois sans que j'en ai trouvé la raison et qui ne gène pas dans le construction de mon rouage
if (ts == null || roues == null)
return false;
ts.parent = roues;
tsEnd.Add(ts);
}
return true;
}
//Positionne les roues pour le départ du jeu sur la façade du coffre bas
private bool PositionneStarts()
{
for (int i = 0; i < nombre-1; i++)
{
//1000 essais pour éviter les boucles infinies
int coups = 0;
retour:
coups++;
if (coups > 1000)
return false;
//calcule les positions au hasard
float x = UnityEngine.Random.Range(-2.5f, 2.5f);
float y = UnityEngine.Random.Range(-3f, -2f);
Vector3 pos = new Vector3(x, y, -0.35f); //-0.35f parce que le coffre bas est plus épais
//on évite les chevauchements
bool ok = true;
for (int j = 0; j < nombre; j++)
{
if (i != j)
{
if (Vector3.Distance(pos, rouage[j].transform.localPosition) < rouage[i].rayon + rouage[j].rayon)
{
ok = false;
break;
}
}
}
if (!ok)
goto retour;
rouage[i].transform.localPosition = pos;
}
//on liste les axes start et on les déparente pour éviter de les déplacer avec les roues
Transform roues = transform.Find("Roues");
tsStart = new List<Transform>();
for (int i = 0; i < nombre; i++)
{
Transform ts = rouage[i].transform.Find("AxeStart");
ts.parent = roues;
tsStart.Add(ts);
}
//pour signaler que tout va bien
return true;
}
private void Update()
{
//pour éviter l'exécution si résolu
if (!Enigme.Resolue)
{
//pour appliquer les animations
if (move)
{
//fait pivoter les roues
for (int i = 0; i < nombre; i++)
{
rouage[i].transform.Rotate(0, 0, rouage[i].speed);
}
//fait glisser la crémaillère
Cremaillere.Translate(speedCremaillere, 0, 0);
delai -= Time.deltaTime;
//si délai terminé
if (delai <=0)
{
//on fait pivoter le player vers le coffre(si player y a)
if (Player)
Player.RotateVers(Coffre.position);
//on signale que l'énigme est résolue
Enigme.Resolue = true;
}
}
else
{
//à la pression de la touche gauche de la souris
if (Input.GetMouseButtonDown(0))
{
//petite extension raycast pour récupérer le transform sous le clic si tag = "Gear"
Transform gear = Camera.RaycastObjet("Gear");
if (gear != null)
{
//on récupère l'index dans le rouage de la roue cliquée
int g = rouage.IndexOf(gear.GetComponent<Roue>());
if (g > -1)
{
//si c'est ok on calcule distance et offset de départ pour le drag
current = g;
distance = Camera.WorldToScreenPoint(rouage[current].transform.position).z;
offset = rouage[current].transform.position - MouseWorldPos();
}
}
}
if (current > -1)
{
//si le bouton gauche de la souris reste pressé
if (Input.GetMouseButton(0))
{
//on déplace la souris ebn suivant le curseur
rouage[current].transform.position = MouseWorldPos() + offset;
}
//quand on relache le bouton de la souris
if (Input.GetMouseButtonUp(0))
{
bool ok = false;
float d = 10;
int p = -1;
//on recherche l'axe end le plus proche
for (int i = 0; i < nombre; i++)
{
float dist = Vector3.Distance(rouage[current].transform.position, tsEnd[i].position);
if (dist < d)
{
d = dist;
p = i;
}
}
//si la plus petite distance est inférieure à 1
if (d < 1)
{
//on positionne et rotationne la roue par rapport à l'axe End
rouage[current].transform.position = tsEnd[p].position;
rouage[current].transform.rotation = tsEnd[p].rotation;
IndexArrives[current] = p; //on récupère l'index pour les rotations
Controle(); //on controle si terminé
}
else
{
//si trop loin on ramène la roue sur son axe start
rouage[current].transform.position = tsStart[current].position;
rouage[current].transform.rotation = tsStart[current].rotation;
IndexArrives[current] = -1;
}
current = -1;
}
}
}
}
}
//pour controler si toutes les roues sont placées
private void Controle()
{
for (int i = 0; i < nombre-1; i++)
{
//vérifie que l'index de la roue corresponde à l'index de la position End
if (IndexArrives[i]<0 || rouage[IndexArrives[i]].index != IntEnd[i])
return;
}
//si on arrive ici c'est qua toutes les roues sont en place
FaitTourner();
}
private void FaitTourner()
{
//la roue 11 est restée en place pour indiquer la fin du rouage
IndexArrives[11] = 11;
//la roue 11, roue moteur prend la vitesse de base
rouage[IndexArrives[nombre - 1]].speed = speed;
//on remonte le rouage de l'avant dernière roue à la première pour calculer les vitesses et sens de rotation
for (int i = nombre - 2; i >= 0; i--)
{
rouage[IndexArrives[i]].speed = -rouage[IndexArrives[i + 1]].speed / rouage[IndexArrives[i]].nDents * rouage[IndexArrives[i + 1]].nDents;
//si c'est la première roue
if (IndexArrives[i] == 0)
{
//on calcule la vitesse de la crémaillère
float R = rouage[IndexArrives[i]].rayon; // 0.56f;
float W = rouage[IndexArrives[i]].speed * Mathf.Deg2Rad;
speedCremaillere = R * W;
}
}
//on déclenche les animations
move = true;
}
//pour calculer la position de la souris pour le drag
Vector3 MouseWorldPos()
{
Vector3 mousepoint = Input.mousePosition;
mousepoint.z = distance;
return Camera.ScreenToWorldPoint(mousepoint);
}
//pour calculer la position d'un point autour d'un transform selon son rayon et l'angle
public Vector3 RotatePointAroundPivot(float rayon, Transform pivot, float angleZ)
{
//JE PENSE QUE LE PROBLEME PEUT ETRE ICI, J AI MIS L ORIENTATION POUR LE CAS MAIS CA NE CHANGE RIEN
Quaternion angle = Quaternion.Euler(0, orientation, angleZ);
Vector3 point = pivot.position + new Vector3(0, rayon, 0);
return RotatePointAroundPivot(point, pivot.position, angle);
}
public Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Vector3 angles)
{
return RotatePointAroundPivot(point, pivot, Quaternion.Euler(angles));
}
public Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Quaternion rotation)
{
return rotation * (point - pivot) + pivot;
}
}