[DB - AL] Heritages/Polymorphism unity

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
Zarkhein
Messages : 5
Inscription : 20 Nov 2023 21:57

[DB - AL] Heritages/Polymorphism unity

Message par Zarkhein » 23 Nov 2023 14:30

Bonjour j'ai un petit soucis.
J'ai essayé de faire un system de Compétence pour bien explique la logique que j'ai derriere je voudrais faire.
Une classe Compétences qui va avoir en propriétées un scriptableObject ou des proprietes simples comme : nomCompétence,niveauCompétence,ratioDégatAd,ratioDégatAp...

En réalisant un héritage ça me permet de faire des competences de tout genre a la volé exemple

Script FrappeDuChaos : Compétence qui va posseder une seule methode c'est sa competence avec les proprietes de competences.

Script SoinDeMilou : Compétence qui va posseder une seule methode c'est sa competence avec les proprietes de competences.

puis un autre script pour finir qui se nommera BarreCompétence/GestionCompétencesPlayer qui sera un monoBehaviour qui possedera un tableau de type competence[4] c'est un peu comme une barre de sorts dans un moba ( sauf que plus tard si le joueur veut changer sa competence[1] avec une competenceX il pourra)

Voici mes scripts ! :)

Compétences.cs

Code : Tout sélectionner

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

public class Competences
{
    [Header("Information de la competence")]
    public string nomCompetence;
    public string resumeCompetence;
    public Sprite imgCompetence;

    [Header("Niveau de la competence")]
    public int niveauCurrent;
    public int niveauMax;

    [Header("Type damage")]
    public int physicalDamage;
    public int magicDamage;
    public int trueDamage;

    [Header("Le temps")]
    public int cooldown;
    public bool isCooldown;


    [Header("Ratio des damages")]
    public float ratioPhysicalDamage;
    public float ratioMagicDamage;

    public Competences()
    {
        nomCompetence = "Compétence de base";
        resumeCompetence = "Resume de base";
        niveauCurrent = 1;
        niveauMax = 5;
        physicalDamage = 0;
        magicDamage = 0;
        trueDamage = 0;
        cooldown = 0;
        isCooldown = false;
        ratioPhysicalDamage = 0;
        ratioMagicDamage = 0;
    }
    
    public virtual void UtiliserCompetences()
    {
    	Debug.log("Competence null");
    }
    
}
La compétence FrappeDuDragon.Cs

Code : Tout sélectionner

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

public class FrappeDuDragon : Competences
{
   public FrappeDuDragon()
    {
        nomCompetence = "Frappe du dragon";
        resumeCompetence = "Frappe du dragon du chevalier";
        niveauCurrent = 1;
        niveauMax = 5;
        physicalDamage = 0;
        magicDamage = 0;
        trueDamage = 0;
        cooldown = 0;
        isCooldown = false;
        ratioPhysicalDamage = 0;
        ratioMagicDamage = 0;
    }


    public override void UtiliserCompetences()
    {
        Debug.Log("E");
    }
}

Code : Tout sélectionner

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

public class GestionCompétences : MonoBehaviour
{

    public Competences[] BarreDeCompetence;
    // Start is called before the first frame update
    void Start()
    {
        BarreDeCompetence = new Competences[4];
        BarreDeCompetence[0] = new FrappeDuDragon();
    }

    // Update is called once per frame
    void Update()
    {
        BarreDeCompetence[0].UtiliserCompetences()
    }
}
Sauf le problème que j'ai si je veux instancier un GameObject dans UtiliserCompetences bah il ne veut pas il trouve pas la methode Instantiate() ça marche pas :(
Voila merci beaucoup en tout cas !

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

Re: [DB - AL] Heritages/Polymorphism unity

Message par jmhoubre » 23 Nov 2023 20:21

Bonsoir,

UtiliserCompetences est dans la classe Competences, qui n'est pas un MonoBehaviour, donc tu n'as pas accès aux méthodes de MonoBehaviour (dont Instantiate).

Si tu montres un peu plus de code qu'un Debug.log dans UtiliserCompetences (comment tu veux utiliser Instantiate, pour Intancier quel prefab, ...) je pourrais peut-être t'aider.

Zarkhein
Messages : 5
Inscription : 20 Nov 2023 21:57

Re: [DB - AL] Heritages/Polymorphism unity

Message par Zarkhein » 23 Nov 2023 23:06

Bonsoir !
Deja merci beaucoup pour ton message !
En cherchant dans la soirée j’avais vu que vu que si j’ai pas Monobehaviour je pourrais pas utiliser les méthodes souhaitées :/
Yep pas de soucis je te montre un peu plus le code demain car je suis sur téléphone
Mais merci beaucoup 😁

Zarkhein
Messages : 5
Inscription : 20 Nov 2023 21:57

Re: [DB - AL] Heritages/Polymorphism unity

Message par Zarkhein » 24 Nov 2023 21:43

Voila ce que j'ai fais en attendant

Code : Tout sélectionner

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

public class FrappeDuDragon : Competences
{

    public GameObject lance;
    public Transform playerPos;

    public FrappeDuDragon()
    {
        nomCompetence = "Frappe du dragon";
        resumeCompetence = "Frappe du dragon du chevalier";
        niveauCurrent = 1;
        niveauMax = 5;
        physicalDamage = 0;
        magicDamage = 0;
        trueDamage = 0;
        cooldown = 0;
        isCooldown = false;
        ratioPhysicalDamage = 0;
        ratioMagicDamage = 0;
    }


    public override void UtiliserCompetences()
    {
        GameObject newLance = Instantiate(lance, new Vector2(playerPos.position.x, playerPos.position.y + 1), quaternion.identity);
        StartCoroutine(MaCoroutine(newLance));
    }

    IEnumerator MaCoroutine(GameObject go)
    {
        float duration = 2f; 
        float elapsed = 0f;

        Vector3 startPosition = go.transform.position;
        Vector3 endPosition = startPosition + new Vector3(5, 0, 0);

        while (elapsed < duration)
        {
            float t = elapsed / duration;
            go.transform.position = Vector3.Lerp(startPosition, endPosition, t);
            elapsed += Time.deltaTime;
            yield return null;
        }

        go.transform.position = endPosition; 
        Debug.Log("Déplacement Terminé");
    }
}
Biensur il y a des erreurs comme il y a pas le monoBehaviour mais j'ai vu sur le web que je pouvais passer par des interfaces et faire du polymorphisme

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

Re: [DB - AL] Heritages/Polymorphism unity

Message par jmhoubre » 25 Nov 2023 15:34

Bonjour,

en préambule, voici quelques erreurs que j'ai pu relever et quelques conseils :

Erreurs
  • GestionCompétences : dans la méthode Update, il manque le ";" après BarreDeCompetence[0].UtiliserCompetences ()
  • Competences : dans la méthode UtiliserCompetences, le log de Debug doit commencer par une majuscule.

Conseils
  • GestionCompétences : évite d'utiliser des accents dans des noms de scripts, méthodes, variables.
  • Competences : si tu veux affecter des valeurs dans cette classe (je supppose que c'est le cas, puisqu'il y a des [Header]), tu dois marquer cette classe avec [Serializable] pour qu'Unity l'affiche. Dans ce cas, la méthode Start du script GestionCompetences est inutile. Autrement dit, soit tu spécifies les compétences dans l'éditeur en rendant la classe Competences serializable, soit tu les spécifies à l'exécution, et les Header sont inutiles.
Pour faire mes tests, j'ai apporté 2 modifications mineures :
  • Dans GestionCompetences, dans l'Update (pour ne pas être encombré de messages) :

    Code : Tout sélectionner

    if (Input.GetKeyDown (KeyCode.U))
    {
    	BarreDeCompetence[0].UtiliserCompetences ();
    }
    
  • Dans FrappeDuDragon (en prévision de l'ajout de Lance) :

    Code : Tout sélectionner

    public override void UtiliserCompetences ()
    {
    	Debug.Log (nomCompetence);
    }
    
Je publie déjà cela, je vais ajouter Lance (je préfère garder FrappeDuDragon qui fonctionne et créer une nouvelle compétence). Je constate que l'absence de MonoBehaviour crée une autre difficulté : pas de coroutine. Une petite erreur également : Quaternion est un type et s'écrit avec une majuscule.

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

Re: [DB - AL] Heritages/Polymorphism unity

Message par jmhoubre » 25 Nov 2023 16:41

Je pense à 2 pistes pour régler le problème d'instantiate :
  • ajouter la lance au prefab de ton joueur, désactivée. Il suffirait alors de l'activer en début de coroutine, et de la désactiver à la fin.
  • utiliser GameObject.Instantiate qui est dans UnityEngine, piste que je vais utiliser.
Dans les 2 cas, il faut accéder au GameObject lance, que tu ne peux pas renseigner dans l'éditeur. Je vais donc ajouter le prefab dans GestionCompetences, et le passer en paramètre de la compétence. Voici le code des scripts modifiés, j'ai un peu commenté. Cela fonctionne.

Reste à traiter le problème de la coroutine. Connais-tu await et async ? C'est un concept remplaçant avantageusement les coroutines, mais un peu plus compliqué il me semble.

Sinon, c'est gérable avec Update, mais au prix d'une astuce : Lance ne connaissant pas Update, il faut utiliser l'Update de GestionCompetences. Je vais donc suposer que tu es débutant (3 messages seulement, et pas de présentation), et faire la seconde méthode.

Code : Tout sélectionner

using UnityEngine;

public class GestionCompetences : MonoBehaviour
{
	private Competences[] BarreDeCompetence; // Ne pas utiliser public inutilement !

	[SerializeField] private Transform lance; // Ajouter cette ligne pour chaque compétence utilisant un objet.
	
	private void Start ()
	{
		BarreDeCompetence = new Competences[4];
		BarreDeCompetence[0] = new FrappeDuDragon ();
		BarreDeCompetence[1] = new Lance ();
	}
	
	private void Update ()
	{
		// On passe la position du joueur, et éventuellement un objet.
		// Frappe du dragon
		if (Input.GetKeyDown (KeyCode.F))
		{
			BarreDeCompetence[0].UtiliserCompetences (transform.position); // Pas d'objet pour cette compétence.
		}

		// Lance
		if (Input.GetKeyDown (KeyCode.L))
		{
			BarreDeCompetence[1].UtiliserCompetences (transform.position, lance);
		}
	}
}

Code : Tout sélectionner

using UnityEngine;

public class Competences
{
	// Information de la compétence (avec un accent cette fois :)
	public string nomCompetence;
	public string resumeCompetence;
	public Sprite imgCompetence;

	// Niveau de la compétence.
	public int niveauCurrent;
	public int niveauMax;

	// Type de dommage (faut être cohérent : en français ou en anglais, mais pas les deux...).
	public int physicalDamage;
	public int magicDamage;
	public int trueDamage;

	// Le temps.
	public int cooldown;
	public bool isCooldown;

	// Ratio des dommages.
	public float ratioPhysicalDamage;
	public float ratioMagicDamage;

	public Competences ()
	{
		nomCompetence = "Compétence de base";
		resumeCompetence = "Description de la compétence";
		niveauCurrent = 1;
		niveauMax = 5;
		physicalDamage = 0;
		magicDamage = 0;
		trueDamage = 0;
		cooldown = 0;
		isCooldown = false;
		ratioPhysicalDamage = 0;
		ratioMagicDamage = 0;
	}

	public virtual void UtiliserCompetences (Vector3 playerPosition, Transform skillObject = null)
	{
		//Debug.Log ("Competence null");
	}
}

Code : Tout sélectionner

using UnityEngine;

public class FrappeDuDragon : Competences
{
	public FrappeDuDragon ()
	{
		nomCompetence = "Frappe du dragon";
		resumeCompetence = "Frappe du dragon du chevalier";
		niveauCurrent = 1;
		niveauMax = 5;
		physicalDamage = 0;
		magicDamage = 0;
		trueDamage = 0;
		cooldown = 0;
		isCooldown = false;
		ratioPhysicalDamage = 0;
		ratioMagicDamage = 0;
	}

	public override void UtiliserCompetences (Vector3 playerPosition, Transform skillObject = null)
	{
		Debug.Log (nomCompetence);
	}
}

Code : Tout sélectionner

using System.Collections;

using UnityEngine;

public class Lance : Competences
{
	public Lance ()
	{
		nomCompetence = "Lance du chevalier";
		resumeCompetence = "Frappe de la lance du chevalier";
		niveauCurrent = 1;
		niveauMax = 5;
		physicalDamage = 0;
		magicDamage = 0;
		trueDamage = 0;
		cooldown = 0;
		isCooldown = false;
		ratioPhysicalDamage = 0;
		ratioMagicDamage = 0;
	}

	public override void UtiliserCompetences (Vector3 playerPosition, Transform skillObject = null)
	{
		GameObject newLance = GameObject.Instantiate (skillObject.gameObject, new Vector2 (playerPosition.x, playerPosition.y + 1), Quaternion.identity);
		//StartCoroutine (MaCoroutine (newLance));
		Debug.Log (nomCompetence);
	}
}

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

Re: [DB - AL] Heritages/Polymorphism unity

Message par jmhoubre » 25 Nov 2023 17:33

Voilà, la coroutine est remplacée par une méthode Tick(), elle-même appelée par l'update de GesTionCompetences. Cella fonctionne, même si le mouvement de la lance devra être corrigé en fonction de tes besoins. Ma lance est un cuble d'échelle (0.1, 2, 0.1). Code des parties modifiées.

GestionCompetences

Code : Tout sélectionner

private void Update ()
{
	// Lance les pseudo-update des compétences.
	foreach (Competences skill in BarreDeCompetence)
	{
		if (skill == null) continue;

		skill.Tick ();
	}
}
Competences

Code : Tout sélectionner

	public virtual void Tick () { }
FrappeDuDragon

Code : Tout sélectionner

	// Pas d'override pour Tick, pas besoin pour cette compétence).
Lance

Code : Tout sélectionner

using UnityEngine;

public class Lance : Competences
{
	private const float LANCE_DURATION = 2f;

	private float tickTimer; // Non nul, la méthode Tick() est exécutée.
	private Vector3 startPosition;
	private Vector3 endPosition;
	private GameObject newLance;
	
	public override void UtiliserCompetences (Vector3 playerPosition, Transform skillObject = null)
	{
		newLance = GameObject.Instantiate (skillObject.gameObject, new Vector2 (playerPosition.x, playerPosition.y + 1), Quaternion.identity);

		// Remplace le lancement de la coroutine.
		tickTimer = LANCE_DURATION;
		startPosition = newLance.transform.position;
		endPosition = startPosition + new Vector3 (5, 0, 0);

		Debug.Log (nomCompetence);
	}

	public override void Tick ()
	{
		// "Coroutine" finie ?
		if (tickTimer <= 0) 
		{ 
			if (newLance != null)
			{
				GameObject.Destroy (newLance);
			}
			return;
		}		
		else		
		{
			float t = 1 - (tickTimer / LANCE_DURATION);
			newLance.transform.position = Vector3.Lerp (startPosition, endPosition, t);
			tickTimer -= Time.deltaTime;
		}
	}
}

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

Re: [DB - AL] Heritages/Polymorphism unity

Message par boubouk50 » 27 Nov 2023 09:52

Peut-être faut-il simplement revoir l'architecture du code ou l'héritage ?
Typiquement, la classe Competence n'a l'air finalement d'être que des données, donc elle pourrait être une classe ScriptableObjects. Dans ce cas, les classes qui héritent de Compétence ne le font plus, donc elles peuvent hériter de MonoBehaviour pour avoir accès à l'Update, à la Coroutine, à l'Instantiate, etc.
Sinon, pourquoi ne pas faire que Competence hérite elle-même de MonoBehaviour ?
Il existe aussi les Interfaces pour forcer les classes filles à définir des fonctions obligatoires, chaque classe peut hériter de plusieurs interfaces.
"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

Zarkhein
Messages : 5
Inscription : 20 Nov 2023 21:57

Re: [DB - AL] Heritages/Polymorphism unity

Message par Zarkhein » 27 Nov 2023 11:44

J'avais pensé au début à utiliser un Scriptable Object pour passer mes données, ainsi que la méthode UtiliserCompetences, mais après avoir consulté la documentation, j'ai réalisé qu'on ne peut pas inclure de méthode dans un SO. De ce que je comprends : Tu voudrais que je crée un ScriptableObject, par exemple CompetencesData, qui possédera toutes mes données d'une compétence. Ensuite, un script, par exemple FrappeDuDragon.cs, MonoBehaviour, où j'appelle mon SO et j'implémente ma méthode.

Cependant, le problème que je ne comprends pas totalement est comment je vais gérer mon tableau Competences[4] dans le script GestionsCompetences, puisque Competence est devenu un SO. (Je veux dire le tableau sera de quelle type ? un type Object[] = Comptences = new Object[4]; ?

J'étais en train d'étudier la piste des interfaces, mais comme je ne les ai jamais utilisées, je suis en train de me documenter à ce sujet. Je suis encore novice sur Unity, donc il est possible que mon algorithme ne soit pas le meilleur ou très bien réfléchi, mais merci ! :)

@JmHoubre Excuse-moi de prendre du temps pour te répondre. Ce weekend, j'étais malade, donc j'ai préféré me reposer. Je m'y pencherai ce soir, mais merci de ta réponse :D

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

Re: [DB - AL] Heritages/Polymorphism unity

Message par jmhoubre » 27 Nov 2023 12:06

Bonjour,

j'ai modifié ton code pour qu'il fonctionne, mai je suis assez d'accord avec Boubouk : ce n'est pas la meilleure façon de faire. De plus, un SO peut avoir des méthodes.

Répondre

Revenir vers « (C#) CSharp »