Bonjour, et problème de récup d'angles de rotation

Questions à propos du scripting. Hors Shader, GUI, Audio et Mobile.
Vinchont
Messages : 62
Inscription : 18 Sep 2014 14:48

Bonjour, et problème de récup d'angles de rotation

Message par Vinchont » 22 Sep 2014 13:28

Tout d'abord bonjour,

Je suis Vinchont et je viens de m'inscrire.

Donc je suis développeur java et web à la base, et je me suis mis à Unity il y a quelques mois maintenant. J'ai deux projets en cours actuellement: un rail shooter dont le moteur est bien avancé mais les besoins en production sont trop grands pour moi seul, et un petit jeu de reflexion à mi chemin entre un "point&click" et un "escape the room" commencé au début de la semaine et qui m'occupe là maintenant tout de suite.

Donc le joueur assis à son bureau détaille et interagit avec des objets variés en les manipulant. cf le sreen suivant:
Image


les interactions sont contextuelles, si le joueur clique sur l'objet, il manipulera l'objet, s'il clique ailleurs, il bougera la tête.

Le problème vient du script de manipulation de la caméra et de l'objet. J'ai repiqué un script que j'ai modifié comme suit:

Code : Tout sélectionner

public class MyMouseOrbit : MonoBehaviour {

	// Différence du déplacement de la souris entre deux update
	static float deltaX = 0F;
	static float deltaY = 0F;

	// Multiplicateur
	static float sensitivityX = 8F;
	static float sensitivityY = 8F;

	// Flottants pour stocker les coordonnées de rotation en X et Y à réinjecter après traitement
	//valeur de rotation de l'axe Y
	static float mHdg = 0F;
	//valeur de rotation de l'axe X
	static float mPitch = 0F;

	// flag pour définir le type de mouvement à effectuer
	static bool moveObject = false;

	// Variable qui récupèrera l'instance l'objet en cours d'utilisation
	GameObject currentObject = null;

	void Start()
	{
		// owt?
	}
	
	void Update()
	{
		// Vérification faite au clic sur l'écran
		// sert à définir quel objet a été cliqué
		// pour savoir quel comportement adopter
		if(Input.GetMouseButtonDown(0)){
			currentObject = WhatIsClicked();
			Debug.Log (currentObject.tag);

                        // Partie qui pose problème
			if( currentObject != null && currentObject.tag == "object"){
				moveObject = true;
				mPitch = currentObject.transform.eulerAngles.x;
				mHdg = currentObject.transform.eulerAngles.y;
			} else {
				moveObject = false;
				mPitch = gameObject.transform.eulerAngles.x;
				mHdg = gameObject.transform.eulerAngles.y;
			}
                        // Fin de la partie qui pose problème
		}

		// Garder le comportement tant que le bouton
		// reste enfoncé
		if (Input.GetMouseButton(0))
		{
			deltaX = Input.GetAxis("Mouse X") * sensitivityX;
			deltaY = Input.GetAxis("Mouse Y") * sensitivityY;

			// Le code n'est pas factorisé parce que je ne sais pas 
			// encore quels autres comportements viendront se greffer
			if(moveObject){
				// ATTENTION: les signes moins sont inversés ici parce que
				// l'objet et la caméra ne tournent pas de la meme manière 
				ChangeHeading(-deltaX, currentObject);
				ChangePitch(deltaY, currentObject);
			} else {
				// ATTENTION: les signes moins sont inversés ici parce que
				// l'objet et la caméra ne tournent pas de la meme manière 
				ChangeHeading(deltaX, gameObject);
				ChangePitch(-deltaY, gameObject);
			}
		}

		// Action à lancer au relachement du bouton de la souris
		if(Input.GetMouseButtonUp(0)){
			// Rien à faire pour l'instant
		}

	}

	GameObject WhatIsClicked(){
		Ray ray = Camera.main.ScreenPointToRay( Input.mousePosition );
		RaycastHit hit;

		// On test sur quel objet 3D on clic
		if( Physics.Raycast( ray, out hit, 100 ) ){
			GameObject localObject = hit.transform.gameObject;
			return localObject;
		}
		return null;
	}

	// Modification de l'axe X
	void ChangePitch(float aVal, GameObject localObject)
	{
		mPitch += aVal;
		WrapAngle(ref mPitch);
		localObject.transform.eulerAngles = new Vector3(mPitch, mHdg, 0);

	}
	
	// Modification de l'axe Y
	void ChangeHeading(float aVal, GameObject localObject)
	{
		mHdg += aVal;
		WrapAngle(ref mHdg);
		localObject.transform.eulerAngles = new Vector3(mPitch, mHdg, 0);
	}
	
	public static void WrapAngle(ref float angle)
	{
		if(moveObject){
			// Reinitialise la valuer a chaque tour complet
			if(angle < -0F)
				angle += 360F;
			if(angle > 360F)
				angle -= 360F;
		} else {
			// Butee dans le mouvement du GameObject
			if(angle < -90F)
				angle = -90F;
			if(angle > 90F)
				angle = 90F;
		}
	}
}
Si on retire la "partie qui pose problème", les déplacements se passent bien, c'est juste que la caméra et l'objet au centre se partagent les mêmes variables de rotation et je ne veux pas ça, l'écran saute, c'est moche et c'est surtout idiot.

J'ai recherché sur ce forum et ailleurs avant de poster ici et tout ce que j'ai trouvé, c'est "n'utilisez pas eulerAngles pour lire les coordonnées de rotation, c'est réservé à l'écriture, vous obtiendrez des trucs aberrants si vous le faites", ce que je confirme. Mais j'ai du mal à voir une alternative, même pas une petite conversion de Quaternion vers Euler.

J'ai bien cherché à utiliser les données transform.rotation, ce sont des flottants, et il faut les cos/sin, et les mouvements de rotation sont moins beaux/réguliers (parce que sinusoidaux).

Quelqu'un a-t-il un conseil?

Grazie mille d'avance.

signé Vinchont. Je vous kiss.

Avatar de l’utilisateur
cayou66
Codeur
Codeur
Messages : 6450
Inscription : 30 Juin 2011 14:45
Localisation : Montréal

Re: Bonjour, et problème de récup d'angles de rotation

Message par cayou66 » 22 Sep 2014 15:06

Salut
t'as essayé avec la fonction Rotate?
http://docs.unity3d.com/ScriptReference ... otate.html

Avec ça tu ne devrais plus avoir de problème d'angle.

Vinchont
Messages : 62
Inscription : 18 Sep 2014 14:48

Re: Bonjour, et problème de récup d'angles de rotation

Message par Vinchont » 22 Sep 2014 17:45

En fait, c'est pas l'application de la nouvelle valeur de rotation qui pose problème, c'est la récupération de l'ancienne.

Vu que j'alterne entre la rotation de la caméra et de l'objet, j'ai besoin de récupérer leurs angles au moins en x et en y avant d'incrementer leurs valeurs, et j'aimerais beaucoup que ça soit en degrées, pour des problèmes de précision que j'aurais pas avec des valeurs issus du transform.Rotate.x/y.

C'est vraiment la partie de code contenue dans le OnMouseButtonDown qui pose problème, si je la retire, le reste du code fonctionne très bien.

Sinon, oui, j'ai tenté le rotate...

Je devrais peut-être refondre cette partie de code en fait, mais elle correspond vraiment à ce que j'attends, donc ça serait dommage de tout abandonner...

Avatar de l’utilisateur
cayou66
Codeur
Codeur
Messages : 6450
Inscription : 30 Juin 2011 14:45
Localisation : Montréal

Re: Bonjour, et problème de récup d'angles de rotation

Message par cayou66 » 22 Sep 2014 19:21

J'ai du mal à saisir, tu utilise du code similaire pour les deux objets (caméra et ton objet) avec tout un tas de variables statiques. Pourquoi static?
La meilleure façon est d'avoir des variables publiques qui vont apparaitrent dans l'inspecteur. Ces variables auront des valeurs différentes pour chaque objet qui va détenir ton script. Tu peux donc faire un script "similaire" avec des petits changements de comportement en utilisant des public bool dans ton script.

Ce que j'aurais fait c'est un simple Rotate avec la direction de la souris lorsque celle ci est enfoncée.

Code : Tout sélectionner

public float mouseAcceleration = 1;

private Vector3 oldPosition;

void Update()
{
  if(Input.GetMouseButtonDown(0))
  {
    oldPosition = Input.mousePosition;
  }
  if(Input.GetMouseButton(0))
  {
    transform.Rotate((Input.mousePosition - oldPosition) * mouseAcceleration);
  }
}
Code pas testé, c'est une simple idée.

Vinchont
Messages : 62
Inscription : 18 Sep 2014 14:48

Re: Bonjour, et problème de récup d'angles de rotation

Message par Vinchont » 23 Sep 2014 16:22

Bonjour,

Merci pour la proposition. J'avais déjà essayé avec le Rotate mais j'ai retenté dans le doute.

J'ai adapté (par ex en mettant à jour le oldPosition) mais le résultat n'est pas encore concluant:

-bouger en diagonale me fait tourner sur l'axe Z et je me retrouve à l'envers après 3 tours de souris
Image

-Un effet étrange inverse mes coordonnées: mes X deviennent des Y et les Y des X

-La méthode WrapAngle qui borne mes rotations n'est plus utilisable puisque je n'ai plus un accès direct aux valeurs des angles, je ne peux donc plus limiter mes rotations de caméra

... Même en y mettant de la bonne fois, je crois que ça n'est pas une bonne solution, mais merci.

Le script est intégré uniquement à la caméra, le static est un peu de parano pour n'avoir qu'une seule fois les variables au cas où je me retrouve avec plusieurs fois ce script (genre en ajoutant d'autres caméras à la scène... ou oui, je pourrais aussi simplement déplacer la caméra, c'est vrai) limiter les risques d'erreur de manipulation en n'ayant qu'une occurrence de la variable, ce qui m'impose un peu de rigueur dans le traitement, ce qui n'est pas un moins, et peut être économiser un peu de mémoire.

Il n'existe vraiment pas de moyen propre de récupérer les valeurs d'Euler d'un objet? ou même de le calculer à partir du rotate ou du quaternion? Je pense que je peux me le permettre, puisque cette opération ne se fera qu'une fois par clic souris, ça n'entachera pas trop mon framerate.

En tout cas, merci quand même cayou.

Avatar de l’utilisateur
cayou66
Codeur
Codeur
Messages : 6450
Inscription : 30 Juin 2011 14:45
Localisation : Montréal

Re: Bonjour, et problème de récup d'angles de rotation

Message par cayou66 » 23 Sep 2014 16:32

En fait c'est un simple MouseLook que tu cherches à faire, c'est ça?

En voici un bon:
http://forum.unity3d.com/threads/a-free ... ook.73117/

Vinchont
Messages : 62
Inscription : 18 Sep 2014 14:48

Re: Bonjour, et problème de récup d'angles de rotation

Message par Vinchont » 24 Sep 2014 15:48

Merci,

Ton script ressemble assez à mon script de départ mais il m'a bien aiguillé et j'essaie d'améliorer le mien en ce moment même.

J'essaie de faire un script propre et je reviens mettre la correction ici.

Merci.

Avatar de l’utilisateur
AlexisVaillant
Messages : 17
Inscription : 16 Jan 2012 15:35
Localisation : Montréal
Contact :

Re: Bonjour, et problème de récup d'angles de rotation

Message par AlexisVaillant » 24 Sep 2014 17:08

Si j'ai bien compris tu veux pouvoir manipuler ton objet avec la souris. Par contre j'ai l'impression que tu veux aussi manipuler la caméra. Si tel est le cas, ça me semble un peu tricky puisque les mouvements de l'objet via la souris se feront nécessairement par rapport à la caméra. Et ça c'est sans compter les possibles envie de vomir du joueur.

Pour ce qui est de la manipulation de l'objet avec la souris, j'ai trouvé ce script ici qui fonctionne super bien. Et il est d'une simplicité déconcertante :

Code : Tout sélectionner

using UnityEngine;
using System.Collections;

public class manipulateObject : MonoBehaviour {
	
	public float sensitivityX = 250.0f;
	public float sensitivityY = 250.0f;
	private bool down = false;

	void Update()
	{
		if( Input.GetMouseButtonDown( 0 ) )
			down = true;
		else if( Input.GetMouseButtonUp( 0 ) )
			down = false;
		
		if( down )
		{
			float rotationX = Input.GetAxis("Mouse X") * sensitivityX;
			float rotationY = Input.GetAxis("Mouse Y") * sensitivityY;
			transform.Rotate( Camera.main.transform.up, -Mathf.Deg2Rad * rotationX, Space.World );
			transform.Rotate( Camera.main.transform.right, Mathf.Deg2Rad * rotationY, Space.World );
		}
	}


}

Vinchont
Messages : 62
Inscription : 18 Sep 2014 14:48

Re: Bonjour, et problème de récup d'angles de rotation

Message par Vinchont » 25 Sep 2014 10:34

Bon, après étude du code, il s'avère que le Mathf.Clamp n'est pas vraiment d'une grande aide dans mon problème de récupération et de correction de mes angles. J'ai donc opté pour une solution un peu batarde entre l'écriture directe en angles d'euler pour bouger la caméra (ma solution de départ) et un bête Rotate pour bouger mon objet.

Rien de transcendant mais je mets quand même:

Code : Tout sélectionner

using UnityEngine;
using System.Collections;


public class MyMouseOrbit : MonoBehaviour {

	// Différence du déplacement de la souris entre deux update
	static float deltaX = 0F;
	static float deltaY = 0F;

	// Multiplicateur
	public static float sensitivityX = 8F;
	public static float sensitivityY = 8F;

	// Flottants pour stocker les coordonnées de rotation en X et Y à réinjecter après traitement
	//valeur de rotation de l'axe Y
	static float mHdg = 0F;
	//valeur de rotation de l'axe X
	static float mPitch = 30F;

	// flag pour définir le type de mouvement à effectuer
	static bool moveObject = false;


	// Variable qui récupèrera l'instance l'objet en cours d'utilisation
	static GameObject currentObject = null;

	void Start()
	{
		// owt?

	}
	
	void Update()
	{
		// Vérification faite au clic sur l'écran
		// sert à définir quel objet a été cliqué
		// pour savoir quel comportement adopter
		if(Input.GetMouseButtonDown(0)){

			currentObject = WhatIsClicked();
			Debug.Log (currentObject.tag);

			if( currentObject != null && currentObject.tag == "object"){
				moveObject = true;
			} else {
				moveObject = false;
			}
		}

		// Garder le comportement tant que le bouton
		// reste enfoncé
		if (Input.GetMouseButton(0))
		{

			deltaX = Input.GetAxis("Mouse X") * sensitivityX;
			deltaY = Input.GetAxis("Mouse Y") * sensitivityY;

			// Le code n'est pas factorisé parce que je ne sais pas 
			// encore quels autres comportements viendront se greffer
			if(moveObject){

				currentObject.transform.Rotate(new Vector3(deltaY,-deltaX,0));

			} else {

				ChangeHeading(deltaX, gameObject);
				ChangePitch(-deltaY, gameObject);

			}

		}

		// Action à lancer au relachement du bouton de la souris
		if(Input.GetMouseButtonUp(0)){
			// Rien à faire pour l'instant
			if(moveObject){
			} else {
			}
		}
	}

// Renvoie le gameobject qui a été cliqué ou null s'il n'y a rien
	GameObject WhatIsClicked(){
		Ray ray = Camera.main.ScreenPointToRay( Input.mousePosition );
		RaycastHit hit;

		// On test sur quel gameobject on clique
		if( Physics.Raycast( ray, out hit, 100 ) ){

			GameObject localObject = hit.transform.gameObject;
			Debug.DrawLine(ray.GetPoint(0), hit.point);

			return localObject;

		}
		return null;
	}

	// Modification de l'axe Y
	void ChangePitch(float aVal, GameObject localObject)
	{
		mPitch += aVal;
		WrapAngle(ref mPitch);
		localObject.transform.eulerAngles = new Vector3(mPitch, mHdg, 0);
	}
	
	// Modification de l'axe X
	void ChangeHeading(float aVal, GameObject localObject)
	{
		mHdg += aVal;
		WrapAngle(ref mHdg);
		localObject.transform.eulerAngles = new Vector3(mPitch, mHdg, 0);
	}
	
//corrige les angles pour limiter la rotation de la caméra
	public static void WrapAngle(ref float angle)
	{
		// Butee dans le mouvement du GameObject
		if(angle < -90F)angle = -90F;
		if(angle > 90F)	angle = 90F;
	}	
}
Merci Alexis, même si j'avais déjà tenté le rotate, il s'avère que la solution est utile.

D'ailleurs, cette rotation ne me plait pas beaucoup, je vais essayer de modifier son comportement, mais ça c'est un autre problème.

Merci à tous les deux pour votre aide.

Répondre

Revenir vers « Scripting »