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){}
...
}
}
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
}
}