[MY-AL] Armes customisables, ScriptableObject, Delegate et IEnumerator

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
Vinchont
Messages : 62
Inscription : 18 Sep 2014 14:48

[MY-AL] Armes customisables, ScriptableObject, Delegate et IEnumerator

Message par Vinchont » 20 Mars 2017 15:39

Bonjour,

Toujours dans le cadre de mon moteur de rail Shooter(Rail Editor, oui, je bosse encore dessus), je cherche une manière simple (à utiliser, pas forcement à concevoir) de configurer mes armes comme je le souhaite, et j'ai besoin d'un 2eme regard sur une solution:

D'un coté j'ai mon script d'utilisation de l'arme dans un monobehaviour; Script de base, qui catch le MouseButtonDown(), lance le raycast, récup le collider, cherche le healthScript du GO et appelle la méthode qui le blesse.

De l'autre, j'ai mon ScriptableObject, qui contient les variables de mon arme, munitions max, sons divers, valeur des degats, vitesse de recharge, etc...

Cas d'école.

Pour mon évol, je souhaite décomposer le comportement de mon arme (lancement du raycast, appel de la méthode) et stocker chaque partie de l'action dans une méthode différente, pouvoir affecter ces méthodes à différents évènements souris (principalement buttonDown et buttonUp), afin de pouvoir générer des armes rapidement en croisant des morceaux de comportements.

J'ai donc sorti le raycast et la méthode blesse de mon monobehaviour, créé deux méthodes dans mon ScriptableObject pour les stocker séparement, créé 2 ou 3 autres méthodes du genre "Charge", "AutoFire" ou "Explode", ainsi qu'un Dictionary<InputEnum, UnityEvent> pour stocker ma liste d'actions pour cette arme. L'inspector permettra d'affecter les actions voulues aux évènements souris.

Coté Monobehaviour, j'ai une méthode SetWeapon pour récupérer toutes les variables de mon ScriptableObject, et affecter les comportements issus de mon Dictionary à un Delegate. ET j'ai mis dans mon update mes Input(Mousebutton()) de toutes les couleurs pour lancer le delegate correspondant à l'input demandé.

Est-il mieux de passer par des delegates au chargement de l'arme puis un appel du dit delegate? ou par un parcours de mon dictionary et un invoke() des unityEvent à chaque input correspondant?

Je crois devoir utiliser des coroutines pour mes actions "longues" qui nécessitent un clic maintenu (charge, autofire), et j'ai lu qu'on ne peut executer qu'une seul coroutine dans un delegate à la fois (la dernière ajoutée je crois), ce que je trouve contraignant (si je veux mettre 2+ actions sur un seul évènement).

Le seul inconvénient des invoke que j'ai pu trouver est la propreté du code.

Quelle option vous semble la plus viable/propre/simple à implémenter/réalisable?

Je manque rex coté technique sur le sujet et je pars avec beaucoup de suppositions sur ce fonctionnement et je prendrais bien un avis extérieur ou deux avant de partir gravir cette montagne.

Voici ce que j'ai déjà fait pour aider à visualiser:

Le ScriptableObject:

Code : Tout sélectionner

    public enum InputSelector{ONMOUSEDOWN0, ONMOUSEDOWN1, ONMOUSEDOWN2,ONMOUSEUP0, ONMOUSEUP1,ONMOUSEUP2}

    // Structure of every weapon
    [CreateAssetMenu]
    public class Weapon : ScriptableObject{

        public enum Availiability { SECONDS, AMMO }

        // Metadatas 	/////////////////////////
        // Identifier of the weapon
        public string id;
        // List of actions for different inputs
        public Dictionary<InputSelector, UnityEvent> actionsList;
        ...

        // Weapon inner datas	//////////////////
        // Force of bullet impact on ennemy, 10 if none
        public int strength = 10;
        // Maximum capacity of a clip, 8 if none
        [Range(1, 150)]
        public int capacity = 8;
        ...

        // external resources	//////////////////
        // Sound effect to use, default if none
        public AudioClip ShootingSound;
        ...

        public void AutoFireCharge(){}
        public void AimCharge(){}
        public void ZoomCharge(){}

        public KeyValuePair<Ray, RaycastHit> ShootAction(){}
        public void ThrowAction(){Vector3 vector}
        public KeyValuePair<Ray, RaycastHit> HomingAction(){}

        public void HitEffect(RaycastHit target){}
        public void SprayEffect(RaycastHit target, int strength, float span){}
        public void ExplodeEffect(RaycastHit target, int strength, float radius){}
        ...
    }
}
Et le monobehaviour:

Code : Tout sélectionner

    public class PlayerWeaponScript : MonoBehaviour {
       // Target GameObject that is an NPC or inherited class
        public GameObject           currentTarget;
        // Current Weapon used by the player
        public Weapon               currentWeapon;
        void Start() {
                SetWeapon();
	}
        void Update() {
            if (lockWeapon){ return();}
            if (currentBullets <= 0){return();}
            currentAudioSrc.Play();
            DepleteWeapon();
            if (Input.GetMouseButtonDown(0)) {/*Appel du delegate correspondant*/}
            if (Input.GetMouseButtonDown(0)) {/*Appel du delegate correspondant*/}
            if (Input.GetMouseButtonUp(1)) {/*Appel du delegate correspondant*/}
            if (Input.GetMouseButtonUp(1)) {/*Appel du delegate correspondant*/}
        }
        public void SetWeapon(Weapon localWeapon){
        	// Vidage des delegate de l'arme en cours
        	// Renseignement des nouveaux delegates
        }
    }
    
 
D'avance merci pour vois conseils.
Dernière édition par Vinchont le 20 Mars 2017 17:29, édité 1 fois.

Avatar de l’utilisateur
evereal
Messages : 109
Inscription : 06 Nov 2015 18:46

Re: Armes customisables, ScriptableObject, Delegate et IEnumerator

Message par evereal » 20 Mars 2017 16:51

Hello,
Je ne suis pas sur d'avoir tout suivis, je pense que pour ton raisonnement tu devrais rajouter une variable (et p-e meme plusieurs) du style EnumMouseClick mouseClickZero, EnumMouseClick mouseClickOne. Avec du coup une classe Enum

Code : Tout sélectionner

public enum EnumMouseClick {
    charge, autofire, explode
}
Et pour ta classe PlayerWeaponScript

Code : Tout sélectionner

    public class PlayerWeaponScript : MonoBehaviour {
       // Target GameObject that is an NPC or inherited class
        public GameObject           currentTarget;
        // Current Weapon used by the player
        public Weapon               currentWeapon;
        void Start() {
                SetWeapon();
   }
 void Update() {
 if (lockWeapon){ return();}
 if (currentBullets <= 0){return();}
  currentAudioSrc.Play();
 DepleteWeapon();
  if (Input.GetMouseButtonDown(0)) {
    if (currentWeapon.mouseClickZero == EnumMouseClick.charge) {
       charge();
     } else if (currentWeapon.mouseClickZero == EnumMouseClick.autofire) {
	autofire();
     } else if (currentWeapon.mouseClickZero == EnumMouseClick.autofire) {
         explode();
     }
}
if (Input.GetMouseButtonDown(1)) {
    if (currentWeapon.mouseClickUn == EnumMouseClick.charge) {
       charge();
     } else if (currentWeapon.mouseClickUn == EnumMouseClick.autofire) {
	autofire();
     } else if (currentWeapon.mouseClickUn == EnumMouseClick.autofire) {
         explode();
     }
}
        public void SetWeapon(Weapon localWeapon){
           // Vidage des delegate de l'arme en cours
           // Renseignement des nouveaux delegates
      }
}
Je n'aime pas trop cette façon de faire, personnellement je pencherais pour une interface arme IWeapon et de la j'implémenterai plusieurs classes d'arme suivant leur comportement
“La théorie, c'est quand on sait tout et que rien ne fonctionne. La pratique, c'est quand tout fonctionne et que personne ne sait pourquoi. Ici, nous avons réuni théorie et pratique : Rien ne fonctionne... et personne ne sait pourquoi !”

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

Re: [MY-AL] Armes customisables, ScriptableObject, Delegate et IEnumerator

Message par Vinchont » 20 Mars 2017 17:43

Bonjour,

Merci pour ta réponse, mais je crois qu'elle n'ira pas, tout simplement parce qu'elle implique une modification de ma classe PlayerWeaponScript à chaque fois que j'ajouterai un nouveau champ à l'enum du ScriptableObject, et ça c'est pas terrible.
Ne mettre de if() que sur les Input MouseButton comme je l'ai fait m'assure de n'avoir à jamais (ou presque) modifier cette classe une fois finie.
Aussi, ça charge énormément le Update(), ce qui ne me plait pas du tout. Les tests que tu mets sur le enum sont tout à fait sortable de la boucle, et optimisables en dehors de la classe (le transformer en switch ou autre).
personnellement je pencherais pour une interface arme IWeapon et de la j'implémenterai plusieurs classes d'arme suivant leur comportement
Dans un autre langage, j'y aurais surement pensé aussi, mais là je tente le coup d'utiliser les outils Unity pour apporter un peu de simplicité et de modularité. En utilisant le Dictionary, les delegates et et le scriptableObject, j'assure à l'utilisateur de pouvoir créer une arme en seulement quelques clics via l'inspecteur Unity.

En tout cas, merci pour ton avis.

Avatar de l’utilisateur
evereal
Messages : 109
Inscription : 06 Nov 2015 18:46

Re: [MY-AL] Armes customisables, ScriptableObject, Delegate et IEnumerator

Message par evereal » 21 Mars 2017 09:40

Je me suis souvenu d'un ancien post que j'avais vu sur le site d'Unity sur un système de compétences personnalisables en utilisant un système de factory.
http://answers.unity3d.com/questions/85 ... tions.html
Je pense que ca peux valoir le coup que tu y jette un œil.
“La théorie, c'est quand on sait tout et que rien ne fonctionne. La pratique, c'est quand tout fonctionne et que personne ne sait pourquoi. Ici, nous avons réuni théorie et pratique : Rien ne fonctionne... et personne ne sait pourquoi !”

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

Re: [MY-AL] Armes customisables, ScriptableObject, Delegate et IEnumerator

Message par Vinchont » 22 Mars 2017 10:35

Merci.
Je suis en train de voir la faisabilité de plusieurs methodes.
Je n'aime pas l'interface parce telle que présentée, elle implique de coder chaque nouvelle arme, et je veux eviter de faire coder l'utilisateur, mais devant l'impossibilité apparente de faire transiter des données entre mes delegates, comme une liste de NPCs, je me tate a retourner vers les interfaces. Tout en gardant mes idees de base.
Donc on verra.
Merci pour ta reponse.

Répondre

Revenir vers « (C#) CSharp »