[DB-AL]c# - Utiliser une Classe

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
CROUK
Messages : 6
Inscription : 15 Jan 2018 12:23

[DB-AL]c# - Utiliser une Classe

Message par CROUK » 15 Jan 2018 13:10

Bonjour, Je commence a apprendre le C# pour Unity. Voici 2 script que j'ai créer pour en apprendre les rouage.
Dans unity , j'ai un cube. j'ai appliquer 2 script en composant sur ce cube.
Un 1er script RandomPerCent renvoye une valeur true/false en fonction d'un certain pourcentage indiquer en argument.
un 2nd script effectue une action qui renvoi en debug.log true ou false quand j'appuie sur un bouton.
Je souhaite que la console me renvoi t/f avec un poucentage de chance que ce soit true indiqué en surcharge de RandomPerCent
il s'agit d'importer la méthode du script 1 dans le script 2 (c'est précisément ça ce que j'essaye de faire).
... et ça ne marche pas.

Code : Tout sélectionner

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



public class RandomPerCent : MonoBehaviour
{

    public RandomPerCent(float PerCent) {  } //constructeur

    public float PerCent; //en entrée: indique le pourcentage de chance qu'un evenement se produise

    public bool Action; // en sortie , le dite action



    private float Calcul(float nbr)
    {
        float factor;
        factor = nbr / 100;
        return factor;
    }


    public void Start()
    {

        if (PerCent < 0)
            PerCent = 0;

        if (PerCent > 100)
            PerCent = 100;

        float a;
        a = Calcul(PerCent);

        float rdm;
        rdm = Random.value; // donne une valeur aleatoire entre  0 et 1

        if (rdm <= a)
        {
            Action = true;
        }
        else
        {
            Action = false;
        }

        


    }

}

Code : Tout sélectionner

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


public class Test: MonoBehaviour {



    public bool Action;
    
   

    // Use this for initialization)
    void Start () {
        
        
        
    }
    public void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))

        {   
            RandomPerCent Chance = new RandomPerCent(50);
           
            Action = Chance;
            Debug.Log(Action);
        }
    }

}
Unity me dit:
You are trying to create a MonoBehaviour using the 'new' keyword. This is not allowed. MonoBehaviours can only be added using AddComponent(). Alternatively, your script can inherit from ScriptableObject or no base class at all
UnityEngine.MonoBehaviour:.ctor()
RandomPerCent:.ctor(Single) (at Assets/RandomPerCent.cs:10)
Test:Update() (at Assets/Test.cs:25)
J'ai donc essayer de retirer le MonoBehaviour a la class RandomPerCent: mais du coup Visual studio me dit: "impossible de convertir RandomPerCent en Bool.
J'ai donc essayer de retirer le MonoBehaviour a la class Test: mais du coup Unity me dit: "The class named 'Test' is not derived from MonoBehaviour or ScriptableObject!"

En continuant mes recherches , j'ai lu aussi que je pouvais supprimer l'injonction de New par GameObject.AddComponent mais la doc du unity me dit que c'est obsolète et en plus j'ai pas compris comment m'en servir.

La solution ce trouve peut être dans l'utilisation des Get et des Set. mais je n'ai pas encore tout compris de leur utilisation ( j'ai commencer a apprendre la semaine dernière)

Je suis perdu , Pouvez vous m'aider a comprendre ce que j'ai oublié .

Fasol0
Messages : 64
Inscription : 07 Avr 2015 11:43

Re: [DB-AL]c# - Utiliser une Classe

Message par Fasol0 » 17 Jan 2018 16:34

Salut,

Ta question montre qu'il te manque des notions fondamentales de POO (pas de souci, on passe tous par là) mais je te conseille vivement de suivre des cours/tutos sur la base de la programmation orientée objet si tu veux te lancer sur Unity.

Pour ta question, les instances de classe héritant de MonoBehaviour doivent être associées à des objets de ta scene (GameObjects) en tant que composants. C'est pourquoi si tu veux créer une instance de classe, tu l'associe à un GameObject via la méthode GameObject.AddComponent<NomDeTaClasse>(); . En utilisant new, tu crée une instance de classe non associée à un objet. En pratique cela fonctionne, tu n'aura qu'un avertissement et non une erreur. Mais pour le faire proprement, tu peux soit modifier le nom de la classe héritée "MonoBehaviour" par "ScriptableObject", pour hériter de toutes les méthodes de ScriptableObject (que tu trouvera dans la doc), sans les contraintes d'avoir à associer ton instance à un GameObject, soit complètement supprimer l'héritage de ta classe en retirant " : MonoBehaviour" après le nom de ta classe.

Dans ton code, il y a quelques soucis:

Ton constructeur de "RandomPerCent" prends comme argument un float appelé PerCent, mais ne l'assigne pas à l'attribut PerCent de ta classe, car il ne contient pas d'instructions. Quelque soit la valeur entrée en argument dans le constructeur, l'Attribut PerCent sera donc toujours initialisé avec la valeur par défaut (0).

il faudrait que tu changes le nom de ton argument de constructeur pour éviter les ambiguités, et l'assigner à ton attribut:

Code : Tout sélectionner

public RandomPerCent(float perCnt) // constructeur
{
	PerCent = perCnt;
 } 
Ensuite, dans ta classe "Test", tu crées une instance de ta classe RandomPerCent que tu appelles Chance,
puis tentes d'assigner cette instance de classe à ton attribut Action qui est un Booléen en faisant (Action = Chance), alors évidemment Unity n'est pas content, en te disant qu'il ne peut converir une instance de RandomPerCent en bool.
Ce que tu veux, c'est accéder à l'attribut Action de ton instance Chance de la classe RandomPercent. Du coup, il te faut faire:

Code : Tout sélectionner

Update()
    {
        if (Input.GetKeyDown(KeyCode.A))

        {   
            RandomPerCent Chance = new RandomPerCent(50);
           
            Action = Chance.Action;
            Debug.Log(Action);
        }
    }
Autrement, je te conseille vivement de suivre une convention pour différencier les attributs des méthodes.
Tu peux simplement commencer le nom de tes méthodes par une majuscule, et celui de tes attributs par une minuscule.
Pour plus de clarté et ne pas se mélanger les pinceaux, essaies aussi d'éviter de nommer deux attributs de deux classes différentes avec les mêmes noms. là tu as un attribu "Action" dans tes deux classes.

En ce qui concerne les méthodes Get() et Set(), Elles sont très utiles pour structurer un code et respecter les règles d'encapsulation (Pour faire simple, tes attributs sont déclarés privés, et tu déclares des méthodes public pour les consulter (Get()) ou les modifier (Set() ), mais ne t'attardes pas dessus pour le moment, et essaies dans un premier temps de bien comprendre les restrictions d'accès (private, public, protected) et la notion de méthode et attributs "static", qui te permettront de mieux structurer tes classes.

Au passage

vu que ton instance de classe n'est pas associée à un GameObject,
la fonction Start() qui détermine Action dans RandomPerCent ne s'exécutera pas. Donc action prendra également une valeur par défaut, indépendante de PerCent.

Dans ton cas, il serait plus facile de définir une méthode static (accessible directement, sans instance de la classe) dans ta classe RandomPerCent, qui retourne l'action:

Code : Tout sélectionner

public static bool GetAction(float percent)
{	
	if (percent < 0) percent = 0;
	else if (percent > 100) percent = 100;
	float rdm = Random.value;
	float a = Calcul(percent);
	if (rdm<=a) return true;
	else return false;
}
En prenant soin d'ajouter le mot clé "static" à ta méthode "Calcul" car on ne peut faire appel à une méthode non static depuis une méthode static.
Puis, dans ta classe test, récupérer le résultat en faisant:

Code : Tout sélectionner

	Update()
    {
        if (Input.GetKeyDown(KeyCode.A))

        {  
            Action = RandomPerCent.GetAction(50) ; //Pas besoin de créer d'instance puisqu'on fait appel à une méthode static
            Debug.Log(Action);
        }
    }
et du coup dans ce cas, les attribus "Action" et "PerCent" de ta classe RandomPercent ne sont plus utiles.

CROUK
Messages : 6
Inscription : 15 Jan 2018 12:23

Re: [DB-AL]c# - Utiliser une Classe

Message par CROUK » 19 Jan 2018 21:39

bonsoir !
je te remercie d'avoir pris de temps d'analyser et de répondre a ma question !
j'ai besoin d'un peu de temps pour assimiler et tester tout ça .
c'est vraiment super, tu m'a enseigner beaucoup de chose en un seul message. :shock: :-D
je risque de poser encore pas mal de question très basique les prochain temps :roll:

Répondre

Revenir vers « (C#) CSharp »