[vraiment résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Questions à propos du scripting. Hors Shader, GUI, Audio et Mobile.
Avatar de l’utilisateur
poupoule_h5n1
Messages : 48
Inscription : 28 Nov 2022 20:24

[vraiment résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par poupoule_h5n1 » 11 Déc 2022 19:15

Bien le bonjour
J'ai créer en tant que débutante un petit jeu en 2d pixel art.
Dans celui-ci, j'aimerais que, si le joueur active un boxCollider2D en bas d'un escalier, le scripte le déplace au dessus de l'escalier en passant par 3 waypoints (c'est un escalier anguleux) pendant que le niveau au dessus s'affiche. une fois arrivé au dessus, j'aimerais que le joueur retrouve ses contrôles.
la collision est détectée
l’animation d'affichage du niveau fonctionne
mais je n'arrive pas à déplacer le joueur de waypoint en waypoint.

Pour simplifier et faire des tests, j'ai mis dans le script de mon personnage une variable bool "testmove" pour activé ou désactivé le déplacement scripter.

voici le script :

Code : Tout sélectionner

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

public class PoupouleControle : MonoBehaviour
{
    public float speed = 3.0f;
    
    public int maxHealth = 6;

    public GameObject mottePrefab;

    public int health { get { return currentHealth; }}
    int currentHealth;

    public float timeInvincible = 2.0f;
    bool isInvincible;
    float invincibleTimer;
    
    Rigidbody2D rigidbody2d;
    float horizontal;
    float vertical;
        
    Animator animator;
    Vector2 lookDirection = new Vector2(1,0);

    public BoxCollider2D playerCollider;
    public bool morte = false;
    float timerGameOver = 3.0f;
    bool tempo = false;

    public AudioSource audiosource;
    public AudioClip hitSound;
    public AudioClip MotteSound;
   
    //c'est ici que je déclare les variable de mon test
    public Transform[] waypoints;
    private Transform target;
    private int destPoint = 0;
    public bool testmove = false;

    public static PoupouleControle Instance;

    private void Awake()
    {
        if (Instance != null)
        {
            Debug.LogWarning("Il y a déjà une instance de PoupouleControle dans la scène");
            return;
        }

        Instance = this;
    }

    void Start()
    {
        rigidbody2d = GetComponent<Rigidbody2D>();
        animator = GetComponent<Animator>();
        audiosource = GetComponent<AudioSource>();
        currentHealth = maxHealth;

        target = waypoints[0];
    }

    void Update()
    {
        if (morte)
        {
            return;
        }

	//c'est ici que commence le mouvement scripter
        if (testmove)
        {
            Vector3 test = target.position - transform.position;
            transform.Translate(test.normalized * speed * Time.deltaTime, Space.World);
		// si le joueur s'approche très près du 1er waypoint, le scripte passe au suivant.
            if (Vector3.Distance(transform.position, target.position) < 0.3f)
            {
                destPoint = (destPoint + 1) % waypoints.Length;
                target = waypoints[destPoint];
            }
		
	// ici je fait en sorte que le perso regarde dans la bonne direction pendant le mouvement scripter
            if (!Mathf.Approximately(test.x, 0.0f) || !Mathf.Approximately(test.y, 0.0f))
            {
                lookDirection.Set(test.x, test.y);
                lookDirection.Normalize();
            }
            animator.SetFloat("Look X", lookDirection.x);
            animator.SetFloat("Look Y", lookDirection.y);
            animator.SetFloat("Speed", test.magnitude);

            if (test.magnitude > 0.1f)
            {
                if (!audiosource.isPlaying)
                {
                    audiosource.Play();
                }
            }
            else
            {
                audiosource.Stop();
            }
        }
        //ici se sont les mouvements contrôlé par le joueur
        else
        {
            horizontal = Input.GetAxis("Horizontal");
            vertical = Input.GetAxis("Vertical");

            Vector2 move = new Vector2(horizontal, vertical);

            if (!Mathf.Approximately(move.x, 0.0f) || !Mathf.Approximately(move.y, 0.0f))
            {
                lookDirection.Set(move.x, move.y);
                lookDirection.Normalize();
            }
            animator.SetFloat("Look X", lookDirection.x);
            animator.SetFloat("Look Y", lookDirection.y);
            animator.SetFloat("Speed", move.magnitude);

            if (move.magnitude > 0.1f)
            {
                if (!audiosource.isPlaying)
                {
                    audiosource.Play();
                }
            }
            else
            {
                audiosource.Stop();
            }
        }
            
        if (isInvincible)
        {
            invincibleTimer -= Time.deltaTime;
            if (invincibleTimer < 0)
                isInvincible = false;
        }        

        if(Input.GetKeyDown(KeyCode.C))
        {
          Lancer();
        }

        if (tempo)
        {
            timerGameOver -= Time.deltaTime;
            if(timerGameOver < 0)
            {
                GameOverManager.Instance.JoueurMort();
                tempo= false;
            }    
        }
    }
    
    void FixedUpdate()
    {              
        if(!testmove)
        {        
            Vector2 position = rigidbody2d.position;       
            position.x = position.x + speed * horizontal * Time.deltaTime;           
            position.y = position.y + speed * vertical * Time.deltaTime;        
            rigidbody2d.MovePosition(position);
        }

    }

    public void ChangeHealth(int amount)
    {
        if (amount < 0)
        {
            if (isInvincible)
            {
                return;
            }

            currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth);
            barredesanté.instance.SetValue(currentHealth / (float)maxHealth);
            Debug.Log(currentHealth + "/" + maxHealth);

            if (currentHealth <= 0)
            {
                mort();
                return;
            }

            AudioManager.Instance.PlayClipAt(hitSound, transform.position);
            animator.SetTrigger("Hit");
            isInvincible = true;
            invincibleTimer = timeInvincible;
        }
        else
        {
            currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth);
            barredesanté.instance.SetValue(currentHealth / (float)maxHealth);
            Debug.Log(currentHealth + "/" + maxHealth);
        }
    }

    public void mort()
    {
        morte = true;
        animator.SetTrigger("mort");
        RigidbodyType2D bodyType = RigidbodyType2D.Kinematic;
        playerCollider.enabled = false;
        tempo = true;
    }

    public void respawn()
    {
        morte = false;
        animator.SetTrigger("respawn");
        RigidbodyType2D bodyType = RigidbodyType2D.Dynamic;
        playerCollider.enabled = true;
        currentHealth = maxHealth;
        barredesanté.instance.SetValue(currentHealth / (float)maxHealth);
    }

    void Lancer()
    {
        animator.SetTrigger("Lancer");
        AudioManager.Instance.PlayClipAt(MotteSound, transform.position);
        GameObject motteObject = Instantiate(mottePrefab, rigidbody2d.position + Vector2.up * 0.1f, Quaternion.identity);

        motte motte = motteObject.GetComponent<motte>();
        motte.Lancer(lookDirection, 300);

    }
    //Debug.Log("ok");
}
et voici une screen de projet :
Image
les losanges mauves sont les waypoints de test, ils sont nommés testchekpoint, testchekpoint(1) et testchekpoint(2)

(oui la perso s'appelle poupoule, oui il y a du fran-glais à foison, oui il y a aussi pas mal de fantaisie dans le nom des variables. Me juger pas svp ^^' )

Pour l'instant que je démarre le jeu tout va bien, le joueur peut contrôlé le perso.
quant je coche la variable "testmove" dans l'inspecteur, le mouvement scripter s’enclenche , le perso regarde dans la bonne direction et se dirige ver le 1er checkpoint , le dépasse et continue.
normalement le script est censé passer au waypoint suivant mais il ne le fait pas.
si je décoche "testmove" le joueur ne récupère pas le contrôle de ses mouvements.

Je suis consciente d'être une débutante, et que je devrais trouver la solution par moi même mais après avoir passer tout mon dimanche dessus ... j'espère que vous pourriez m'apporter un peu d'aide.
merci d'avoir lu mon appel
et merci d'avance pour l'aide que vous allez m'apporter
Dernière édition par poupoule_h5n1 le 17 Déc 2022 19:40, édité 3 fois.

Moi 1971
Messages : 727
Inscription : 29 Sep 2015 13:38

Re: Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par Moi 1971 » 12 Déc 2022 09:50

Bonjour, au vu de la description de ton problème je serais enclin a dire que le "bug" provient de la partie de ton code qui change de waipont. donc ici :

Code : Tout sélectionner

if (Vector3.Distance(transform.position, target.position) < 0.3f)
            {
                destPoint = (destPoint + 1) % waypoints.Length;
                target = waypoints[destPoint];
            }
Moi à chaque fois, j'utilise pour débuguer des debug.log() et donc je ferais comme ceci pour comprendre la mécanique du code et pour pouvoir le modifier comme il faut:

Code : Tout sélectionner

debug.log("Avant if");
if (Vector3.Distance(transform.position, target.position) < 0.3f)
            {
                debug.log(destPoint);
                destPoint = (destPoint + 1) % waypoints.Length;
                debug.log(destPoint);
                debug.log(target);
                target = waypoints[destPoint];
                debug.log(target);
            }
debug.log("Apres if");            
            
Ps : C'est écrit vite fait sans vérifier la syntaxe...

Avatar de l’utilisateur
poupoule_h5n1
Messages : 48
Inscription : 28 Nov 2022 20:24

Re: Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par poupoule_h5n1 » 12 Déc 2022 11:06

j'ai mis les debug.log comme et aucun n'est ressortis dans la console. Donc il n'entre pas dans la boucle pour changer de Waypoint.

j'ai un peu changer patauger avec les Debug.log et il s’avère que pour une raison que j'ignore, il pense que mon waypoint est ailleurs.

voici ce qui m'a permis de le voir

Code : Tout sélectionner

            Debug.Log(target.position);
            Vector3 test = target.position - transform.position;
            transform.Translate(test.normalized * speed * Time.deltaTime, Space.World);
            if (Vector3.Distance(transform.position, target.position) < 0.01f)
            {
                Debug.Log(destPoint);
                destPoint = (destPoint + 1) % waypoints.Length;
                Debug.Log(destPoint);
                Debug.Log(target);
                target = waypoints[destPoint];
                Debug.Log(target);
            }


Image

Les vrais coordonnée du checkpoint c'est x7.19 y2.54
et dans les logs il me dit x-44 y72

je comprends pas ...

Avatar de l’utilisateur
poupoule_h5n1
Messages : 48
Inscription : 28 Nov 2022 20:24

Re: Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par poupoule_h5n1 » 12 Déc 2022 11:16

Finalement j'ai trouver,
j'avais mis, dans la hirarchy, les waypoints comme enfant de mon personnage du coup ils se déplaçaient avec lui et le perso ne les atteignait jamais ...
une erreur un peu bête ^^'

merci d'avoir lu et désolée du dérangement

Avatar de l’utilisateur
jmhoubre
Messages : 856
Inscription : 05 Oct 2019 22:05

Re: [résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par jmhoubre » 12 Déc 2022 12:07

Bonjour,

je viens de finir de tester ton code, qui, comme je le pensais, était correct pour les waypoints. Comme je n'avais pas mis les waypoints enfants du joueur, je cherchais encore...

Je pense que si le joueur ne reprenait pas les commandes, c'est parce qu'en décochant testmove, la fenêtre game perdait le focus et les actions sur les touches de déplacement étaient inopérantes.

En revanche, j'aurais pas mal de conseils à te donner concernant ton code.

Avatar de l’utilisateur
poupoule_h5n1
Messages : 48
Inscription : 28 Nov 2022 20:24

Re: [résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par poupoule_h5n1 » 12 Déc 2022 20:04

jmhoubre a écrit :
12 Déc 2022 12:07
En revanche, j'aurais pas mal de conseils à te donner concernant ton code.
Je t'écoute avec plaisir je suis toujours prête a recevoir des conseils ^^

Surtout que ce code a été écris par petit bout au fur et a mesure de mon apprentissage en m'aidant de plusieurs tuto.
C'est un drôle de puzzle

Avatar de l’utilisateur
jmhoubre
Messages : 856
Inscription : 05 Oct 2019 22:05

Re: [résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par jmhoubre » 13 Déc 2022 13:01

Bonjour,

déjà, assembler des bouts de code provenant de plusieurs sources est assez naturel, je pense qu'on a tous débuté comme cela. Mais ce n'est pas une raison pour continuer.

Tu as sans doute remarqué que ta classe est plutôt longue. Cela rend la recherche d'erreur fastidieuse et augmente le risque d'erreur : nombreuses variables, défilement de l'écran permanent, ... Dans tous les langages de programmation, des principes existent et ont même été théorisés. Je ne vais pas les énumérer, mais un principe assez fondamental est qu'une classe ou une fonction font une chose et une seule.
Ta classe fait trop de choses : le mouvement, la santé, l'invincibilité, le jet de motte. Tu devrais la segmenter.

Segmenter son code
De même que tu ajoutes à Poupoule plusieurs composants (Collider, Rigidbody, ...), tu peux (et tu devrais) ajouter plusieurs scripts. Voici par exemple le script Health qui gère la santé de Poupoule.

Code : Tout sélectionner

using System;

using UnityEngine;

/// <summary>
/// Classe gérant la santé d'un personnage.
/// - propriété CurrentHealth.
/// - méthode TakeDamages.
/// </summary>
public class Health : MonoBehaviour
{
	public static event Action OnDeath;

	[SerializeField] private int _maxHealth = 6;

	private int _currentHealth;
	public int CurrentHealth => _currentHealth;

	private bool _died = false;
	public bool Died => _died;

	private Invincibility _invincibility;

	private void Awake ()
	{
		_currentHealth = _maxHealth;
		_invincibility = GetComponent<Invincibility> ();
	}

	private void Start ()
	{
		PoupouleControle.OnRespawn += PoupouleControle_OnRespawn;
	}

	private void PoupouleControle_OnRespawn ()
	{
		_died = false;
		_currentHealth = _maxHealth;
		//barredesanté.instance.SetValue (_currentHealth / (float) _maxHealth);
	}

	/// <summary>
	/// Inflige des dégâts au personnage.
	/// </summary>
	public void TakeDamages (int amount)
	{
		if (_invincibility.IsInvincible || amount < 0)
		{
			return;
		}

		_currentHealth = Mathf.Clamp (_currentHealth - amount, 0, _maxHealth);
		//barredesanté.instance.SetValue (_currentHealth / (float) _maxHealth);

		if (_currentHealth <= 0)
		{
			Die ();
			return;
		}

		//AudioManager.Instance.PlayClipAt (hitSound, transform.position);
		//animator.SetTrigger ("Hit");
		_invincibility.BecomeInvincible ();
	}

	private void Die ()
	{
		_died = true;
		//animator.SetTrigger ("mort");
		OnDeath?.Invoke ();
	}
}
  • J'ai commenté les partie liées à la barre de santé, à l'AudioManager et à l'animator, car je n'avais les éléments necessaires.
  • Pour communiquer entre les scripts j'utilise soit des events, soit des références.
    • Par exemple, le script Health met en place un event OnDeath, utilisé dans la méthode Die. Le script principal s'inscrit à cet event pour être notifié de la mort du joueur. Mais on peut faire autrement.
    • Health utilise une référence d'Invincibility pour communiquer avec ce dernier et accéder à ses méthodes et champs publics.
  • Le script principal a bien sûr été modifié.
Voiici le code d'Invincibility :

Code : Tout sélectionner

using UnityEngine;

/// <summary>
/// Ce composant gère l'invincibilité temporaire du joueur.
/// Elle est déclenchée par un appel de la méthode BecomeInvincible, et remise à zéro au bout de _durationInvincibility secondes.
/// </summary>
public class Invincibility : MonoBehaviour
{
	[SerializeField] private float _durationInvincibility = 2.0f;
	
	private bool _isInvincible;
	public bool IsInvincible { get { return _isInvincible; } }

	private float _invincibleTimer;

	private void Update ()
	{
		if (_isInvincible)
		{
			_invincibleTimer -= Time.deltaTime;
			if (_invincibleTimer < 0f)
			{
				_isInvincible = false;
			}
		}
	}

	/// <summary>
	/// Déclenche l'invincibilité du joueur.
	/// </summary>
	public void BecomeInvincible ()
	{
		_isInvincible = true;
		_invincibleTimer = _durationInvincibility;
	}
}
Invincibility peut être utilisé sans problème sur un ennemi par exemple, c'est ce qui est appelé réutilisation du code.

Une autre façon de facilité la maintenance et la lisibilité du code est l'écriture de méthodes simples réalisant une chose. Par exemple, dans ton script, toute la gestion du mouvement est faite dans Update. J'ai scindé ce code en 2 fonctions pour le mouvement du joueur et celui géré par le script : PlayerMove et ScriptMove, ce qui rend l'Update plus facile à appréhender. Peut-être te dis-tu que c'est inutile, que tu n'as pas de difficulté avec le script actuel ? Mais quand tu demandes à la communauté de t'aider, un script bien écrit rend les choses plus simples. Et qu'en sera-t-il quand tu liras ton code après un mois de pause ? Dernier argument, un développeur standard passe 80% de son temps à relire son code pour 20% à l'écrire. Une bonne raison de se faciliter la vie.

Le script principal :

Code : Tout sélectionner

using System;

using UnityEngine;

public class PoupouleControle : MonoBehaviour
{
	public static Action OnRespawn;
	public static PoupouleControle Instance;

	[SerializeField] private float speed = 3.0f;
	//[SerializeField] private GameObject mottePrefab;	

	private Rigidbody2D _rigidbody2D;
	private Collider _collider;
	private Health _health;

	private float _horizontal;
	private float _vertical;

	//Animator animator;
	private Vector2 lookDirection = new Vector2 (1, 0);

	private float timerGameOver = 3.0f;
	private bool tempo = false;

	//public AudioSource audiosource;
	//public AudioClip hitSound;
	//public AudioClip MotteSound;

	//c'est ici que je déclare les variable de mon test
	public Transform[] waypoints;
	private Transform target;
	private int destPoint = 0;
	public bool testmove = false;	

	private void Awake ()
	{
		if (Instance != null)
		{
			Debug.LogWarning ("Il y a déjà une instance de PoupouleControle dans la scène");
			return;
		}

		Instance = this;

		_rigidbody2D = GetComponent<Rigidbody2D> ();
		_collider = GetComponent<Collider> ();
		_health = GetComponent<Health> ();
		//animator = GetComponent<Animator> ();
		//audiosource = GetComponent<AudioSource> ();
	}

	private void Start ()
	{
		target = waypoints[0];
	}

	private void OnEnable ()
	{
		// Abonnement à l'event OnDeath.
		Health.OnDeath += Health_OnDeath;
	}
	
	private void OnDisable ()
	{
		// Désabonnement à l'event OnDeath, pour éviter les pb de fuite de mémoire.
		Health.OnDeath -= Health_OnDeath;
	}

	// Ce qui est fait lors de la notification de OnDeath.
	private void Health_OnDeath ()
	{
		_rigidbody2D.bodyType = RigidbodyType2D.Kinematic;
		_collider.enabled = false;
		tempo = true;
	}

	private void Update ()
	{
		if (_health.Died) { return;	}

		if (testmove)
		{
			ScriptMove ();
		}
		else
		{
			PlayerMove ();
		}

		//if (Input.GetKeyDown (KeyCode.C))
		//{
		//	Lancer ();
		//}

		if (tempo)
		{
			timerGameOver -= Time.deltaTime;
			if (timerGameOver < 0)
			{
				//GameOverManager.Instance.JoueurMort ();
				tempo = false;
			}
		}
	}

	private void ScriptMove ()
	{
		Vector3 test = target.position - transform.position;
		transform.Translate (speed * Time.deltaTime * test.normalized, Space.World);
		// si le joueur s'approche très près du 1er waypoint, le scripte passe au suivant.
		if (Vector3.Distance (transform.position, target.position) < 0.3f)
		{
			destPoint = (destPoint + 1) % waypoints.Length;
			target = waypoints[destPoint];
		}

		// ici je fait en sorte que le perso regarde dans la bonne direction pendant le mouvement scripter
		if (!Mathf.Approximately (test.x, 0.0f) || !Mathf.Approximately (test.y, 0.0f))
		{
			lookDirection.Set (test.x, test.y);
			lookDirection.Normalize ();
		}
		//animator.SetFloat ("Look X", lookDirection.x);
		//animator.SetFloat ("Look Y", lookDirection.y);
		//animator.SetFloat ("Speed", test.magnitude);

		if (test.magnitude > 0.1f)
		{
			//if (!audiosource.isPlaying)
			//{
			//	audiosource.Play ();
			//}
		}
		else
		{
			//audiosource.Stop ();
		}
	}

	private void PlayerMove ()
	{
		_horizontal = Input.GetAxis ("Horizontal");
		_vertical = Input.GetAxis ("Vertical");

		Vector2 move = new Vector2 (_horizontal, _vertical);
		print (move);

		if (!Mathf.Approximately (move.x, 0.0f) || !Mathf.Approximately (move.y, 0.0f))
		{
			lookDirection.Set (move.x, move.y);
			lookDirection.Normalize ();
		}
		//animator.SetFloat ("Look X", lookDirection.x);
		//animator.SetFloat ("Look Y", lookDirection.y);
		//animator.SetFloat ("Speed", move.magnitude);

		if (move.magnitude > 0.1f)
		{
			//if (!audiosource.isPlaying)
			//{
			//	audiosource.Play ();
			//}
		}
		else
		{
			//audiosource.Stop ();
		}
	}

	private void FixedUpdate ()
	{
		if (!testmove)
		{
			Vector2 position = _rigidbody2D.position;
			position.x += speed * _horizontal * Time.deltaTime;
			position.y += speed * _vertical * Time.deltaTime;
			_rigidbody2D.MovePosition (position);
		}

	}	

	public void Respawn ()
	{
		OnRespawn?.Invoke ();
		//animator.SetTrigger ("respawn");
		_rigidbody2D.bodyType = RigidbodyType2D.Dynamic;
		_collider.enabled = true;
		
	}

	//void Lancer ()
	//{
	//	//animator.SetTrigger ("Lancer");
	//	//AudioManager.Instance.PlayClipAt (MotteSound, transform.position);
	//	GameObject motteObject = Instantiate (mottePrefab, _rigidbody2D.position + Vector2.up * 0.1f, Quaternion.identity);

	//	motte motte = motteObject.GetComponent<motte> ();
	//	motte.Lancer (lookDirection, 300);

	//}
	//Debug.Log("ok");
}
Il y a sans doute plusieurs choses à examiner pour une éventuelle modification :
  • Le mouvement du joueur utilise la physique, et celui géré par le script non : c'est étrange, et mérite réflexion.
  • Les animations gagneraient à être gérées de façon centralisées, dans un seul script.
  • La modification du type de Rigidbody est incorrecte : tu modifies le type et non l'instance de ton joueur :

    Code : Tout sélectionner

    // Rigidbody2D.bodyType = RigidbodyType2D.Dynamic;  doit s'écrire :
    _rigidbody2D.bodyType = RigidbodyType2D.Dynamic;
    
C'est un peu long, j'en ai peur, mais je continuerais avec le nommage, point souvent sous estimé par les débutants.

Avatar de l’utilisateur
jmhoubre
Messages : 856
Inscription : 05 Oct 2019 22:05

Re: [résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par jmhoubre » 13 Déc 2022 17:11

Le nommage, ou comment perdre un peu de temps pour en gagner beaucoup.

Il y a 2 aspects dans le choix des identifiants : le sens porté par le nom, et les règles de nommage ou conventions de nommage.

Le sens de l'identifiant est très important.
Voici un bout de code :

Code : Tout sélectionner

public class Exemple : MonoBehaviour
{
	private List<Data> temp;
	public void Test(DateTime d)
	{
		foreach (var item in temp)
		{
			if (item.d > d)
			{
				Debug.Log ($"{item.n} {item.N} périmés.");
			}
		}
	}
}

public struct Data
{
	public int ID;
	public DateTime d;
	public int n;
	public string N;
}
Au moment où il est conçu, son sens est probablement très clair pour l'auteur. Mais dans 15 jours ? Ou 6 mois ? Par un autre programmeur ?

Voici le même code, plus amical :

Code : Tout sélectionner

public class Exemple : MonoBehaviour
{
	private List<ItemData> inventory;
	public void Test (DateTime inventoryDate)
	{
		foreach (var item in inventory)
		{
			if (item.expirationDate > inventoryDate)
			{
				Debug.Log ($"{item.quantity} {item.name} périmés.");
			}
		}
	}
}

public struct ItemData
{
	public int ID;
	public DateTime expirationDate;
	public int quantity;
	public string name;
}
Il est important de donner du sens aux noms des identifiants (appeler un chat un chat !). Si tu es obligée de mettre un commentaire pour expliquer à quoi sert la variable, c'est (très) mal parti. A quelques exceptions près, une variable, un champ, un classe, une méthode doivent avoir plusieurs caractères. Les noms longs ne doivent pas te rebuter, Visual Studio fournit la complétion du nom.
Quelques exceptions :
- les compteurs dans une boucle -> for (int i = 0; i<length; i++)
- les calculs mathématiques -> float c = Mathf.Sqrt (a * a + b * b);
- ID pour un identifiant
Ces exceptions n'empêchant pas l'utilisation d'un nom long :

Code : Tout sélectionner

for (int angle = 0; angle < 360; angle += 30)
		{
			print (angle);
		}
Les conventions de nommage ne sont que des conventions. Elles sont souvent obligatoires dans les entreprises, mais ont-elles de l'intérêt pour un programmeur isolé ?

Dans l'exemple précédent, le programmeur avait choisi n et N : n, pour le nombre d'objets, et N pour le Nom. C# différencie n et N, ce qui syntaxiquement est correct. Mais c'est un risque d'erreur important.

Parmi les nombreuses manières d'écrire un identifiant, 2 sont relativement universelles : PascalCase (on dit aussi CamelCase) et camelCase (voir Wikipédia pour plus). Chaque identifiant est écrit en minuscules, sauf la première lettre de chaque mot. camelCase débute également par une minuscule.
PascalCase : PoupouleControle, CurrentHealth, ...
camelCase : i, number, currentHealth.

Les conventions les plus courantes utilisent le plus souvent PascalCase. C'est le cas des conventions préconisées par Microsoft, qui sont très largement utilisées.
On peut ou pas les respecter. Le plus important, pour limiter les sources d'erreur, c'est d'avoir un modèle clair, et de s'y tenir. La logique d'un code est parfois compliquée, inutile d'ajouter des confusions possibles. En particulier, les 3 types d'identifiants suivants doivent avoir des modèles différents :
  • Champs publics en PascalCase : CurrentHealth
  • Champs privés en camelCase + préfixe "_" : _currentHealth
  • Variable locale ou paramètre en camelCase : currentHealth
A noter qu'Unity préfixe parfois ses champs par m_ : l'inspecteur affiche alors le nom sans le préfixe. Compare ce qu'affiche l'inspecteur pour ce code :

Code : Tout sélectionner

public class Exemple : MonoBehaviour
{
	public int m_Total; // -> Total
	public int p_Total;  // -> P_Total
}
On trouve également cette convention dans quelques tutos.

Pour aller un peu plus loin : Instructions de nommage de Microsoft.

On peut indiquer à Visual Studio les règles utilisées afin qu'il les contrôle : https://learn.microsoft.com/fr-fr/dotne ... ming-rules

Avatar de l’utilisateur
jmhoubre
Messages : 856
Inscription : 05 Oct 2019 22:05

Re: [résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par jmhoubre » 13 Déc 2022 17:59

En vrac :
  • Bien utiliser Awake et Start : ces deux méthodes s'exécutent une seule fois, mais sont quand même un peu différentes :
    - Awake : est toujours appelée avant les fonctions Start au démarrage de la scène ou quand un prefab est instancié. L'awake d'un objet inactif n'est exécutée que lorsqu'il devient actif. En revanche, l'awake d'un objet actif dont le script est désactivé est exécutée.
    - Start : est appelée avant la 1ère update si le script est actif.
    - Donc, on utilise l'awake pour initialiser le gameobject (GetComponent, variables, ...) et seulement dans le start, on peut discuter avec d'autres gameobjects, dont on est sûr qu'ils sont initialisés.
  • On ne peut pas faire de suppositions sur l'ordre d'exécution des différents scripts : l'awake d'un objet A peut être exécutée avant ou après l'awake d'un objet B. Pour enfoncer le clou, :hurt1: , l'awake de l'objet A sera toujours exécutée avant la start de l'objet B (et de l'objet A bien sûr).
  • Plus généralement, connaître le mieux possible l'ordre d'exécution des fonctions événementielles décrites dans Order of execution for event functions.
  • OnEnable s'exécute à chaque fois que l'objet est activé. Cela peut servir à réinitialiser un objet qui respawne ou qui sort d'un pool.

Avatar de l’utilisateur
poupoule_h5n1
Messages : 48
Inscription : 28 Nov 2022 20:24

Re: [résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par poupoule_h5n1 » 13 Déc 2022 21:19

Merci c'est très intéressant.
Je vais essayer de clarifier au possible mon code
tu as raison d'en parler ce n'est pas le genre d'info que l'on trouve dans les tutos vidéos

Répondre

Revenir vers « Scripting »