Se connecter

Informatique

Création de Jeux

Sujet : [Unity] Comment structurer son code/design patterns/couches ?
1
MedialKneePain
Niveau 9
19 novembre 2020 à 17:18:53

Je cherche des bouquins, vidéo, tutoriels (peu importe en fait) qui montrerait des bonnes pratiques à adopter quant à la programmation sous Unity :(
C'est à dire des conseils généraux quand il s'agit de créer un code solide, robuste et maintenable :oui:

Je sais que vous allez me dire que cela dépend d'abord du type de jeu, de son scope, etc, ...
Mais je suis suis qu'il y a des guidelines que je peux suivre pour n'importe quel type de jeu.

Je cherche aussi des infos ou plus spécifiquement des exemples d'utilisations de design patterns toujours lié à la programmation de jeu :oui:

Pareil pour les structures de codes. à l'instar du MVC pour les web app, est-ce qu'il y a une architecture de code vivement conseillée pour certaines parties du développement de jeu ? :(

IndepGameDev
Niveau 10
19 novembre 2020 à 18:51:20

Un seul mot, à tous les niveaux d'abstraction (code, architecture, etc...) : découplage.

Déjà, sans parler de spécifique au jeu :

Avant l'archi générale du projet, il y a le code lui même, quand on parle de ça on parle souvent de "clean code", tiré de l'excellent bouquin du même nom. Dans le livre c'est du java, mais ça importe assez peu.
Comment créer de bonnes méthodes avec la bonne granularité, bien nommer les éléments, gérer correctement les exceptions etc...

Pas mal d'acronymes existent pour faire référence aux bonnes pratiques architecturales, un des classique est SOLID, mais ce n'est pas le plus abordable.
Il fait en autre référence à la responsabilité d'une méthode / classe et l'inversion de contrôle (qui existe dans Unity, mais pas sous forme d'injection de dépendance comme on la connait dans le web).

Quand tu codes, garde en tête aussi le KISS : Keep it simple, stupid. Faire compliqué c'est se créer un truc imbitable quelques jours plus tard.

On peut rajouter DRY : don’t repeat yourself. Il faut réutiliser, mais attention à ne pas vouloir tout réutiliser non plus, ça vient avec l'expérience (au début on factorise rien, puis on factorise tout, puis après on préfère finalement 2 méthodes pour 2 choses presque pareil mais finalement pas vraiment...).
Le tout début c'est déjà de ne pas mettre ce qu'on appel des magic string mais plutôt créer une constante qu'on utilise à plusieurs endroits (facilite le renommage, évite faute de frappe, etc...), de ne pas copier coller du code comme un sauvage.

Pour les design pattern, ils ne sont pas forcément spécifique au dev de jeu. Le bouquin le plus connu est "gang of four design pattern". Mais franchement, les design pattern, c'est finalement assez rare d'en avoir besoin, et on utilise toujours les mêmes.

Plus orienté jeux video, il y a un très bon bouquin qui est 100% gratuit en version en ligne : https://gameprogrammingpatterns.com/contents.html

Je suis également en monté en compétence sur la partie archi unity, mais une des pierres angulaire est le scriptableObject, il y a un paquet de ressources à ce sujet, de mémoire ce guide fr résume un peu les choses : https://www.esprit-unity.fr/nouvelle-technique-pout-structurer-son-projet-unity3d/
Les coroutines sont aussi très importantes dans le code unity.

En ressource il y a tout ce qui est sur le site unity (ici et d'autres endroits, c'est un peu le bordel chez eux) : https://learn.unity.com/search?k=%5B%22tag%3A5814655a090915001868ebec%22%5D

Une des solutions pour apprendre aussi (et c'est hyper efficace), c'est de lire du code. Du bon et même du moins bon (mais il faut un peu plus de recule)

Unity a lancé un projet opensource, c'est la commu qui code, mais via la relecture de pull request et autre j'imagine que le code est de qualité (je me suis noté de regarder) : https://github.com/UnityTityTechnologies/open-project-1

Unity a aussi leur projet d'exemple, un des plus récent est celui là : https://blogs.unity3d.com/2019/12/18/download-our-new-2d-sample-project-lost-crypt/

boucif
Niveau 24
19 novembre 2020 à 22:28:07

Sympa les scriptableobject en plus je vois que l'article a été écrit par Alex un ex-collègue :rire:
Je le trouve pas assez complet par contre
https://unity.com/fr/how-to/architect-game-code-scriptable-objects

MedialKneePain
Niveau 9
20 novembre 2020 à 13:45:51

Le 19 novembre 2020 à 18:51:20 IndepGameDev a écrit :
Un seul mot, à tous les niveaux d'abstraction (code, architecture, etc...) : découplage.

Déjà, sans parler de spécifique au jeu :

Avant l'archi générale du projet, il y a le code lui même, quand on parle de ça on parle souvent de "clean code", tiré de l'excellent bouquin du même nom. Dans le livre c'est du java, mais ça importe assez peu.
Comment créer de bonnes méthodes avec la bonne granularité, bien nommer les éléments, gérer correctement les exceptions etc...

Pas mal d'acronymes existent pour faire référence aux bonnes pratiques architecturales, un des classique est SOLID, mais ce n'est pas le plus abordable.
Il fait en autre référence à la responsabilité d'une méthode / classe et l'inversion de contrôle (qui existe dans Unity, mais pas sous forme d'injection de dépendance comme on la connait dans le web).

Quand tu codes, garde en tête aussi le KISS : Keep it simple, stupid. Faire compliqué c'est se créer un truc imbitable quelques jours plus tard.

On peut rajouter DRY : don’t repeat yourself. Il faut réutiliser, mais attention à ne pas vouloir tout réutiliser non plus, ça vient avec l'expérience (au début on factorise rien, puis on factorise tout, puis après on préfère finalement 2 méthodes pour 2 choses presque pareil mais finalement pas vraiment...).
Le tout début c'est déjà de ne pas mettre ce qu'on appel des magic string mais plutôt créer une constante qu'on utilise à plusieurs endroits (facilite le renommage, évite faute de frappe, etc...), de ne pas copier coller du code comme un sauvage.

Pour les design pattern, ils ne sont pas forcément spécifique au dev de jeu. Le bouquin le plus connu est "gang of four design pattern". Mais franchement, les design pattern, c'est finalement assez rare d'en avoir besoin, et on utilise toujours les mêmes.

Plus orienté jeux video, il y a un très bon bouquin qui est 100% gratuit en version en ligne : https://gameprogrammingpatterns.com/contents.html

Je suis également en monté en compétence sur la partie archi unity, mais une des pierres angulaire est le scriptableObject, il y a un paquet de ressources à ce sujet, de mémoire ce guide fr résume un peu les choses : https://www.esprit-unity.fr/nouvelle-technique-pout-structurer-son-projet-unity3d/
Les coroutines sont aussi très importantes dans le code unity.

En ressource il y a tout ce qui est sur le site unity (ici et d'autres endroits, c'est un peu le bordel chez eux) : https://learn.unity.com/search?k=%5B%22tag%3A5814655a090915001868ebec%22%5D

Une des solutions pour apprendre aussi (et c'est hyper efficace), c'est de lire du code. Du bon et même du moins bon (mais il faut un peu plus de recule)

Unity a lancé un projet opensource, c'est la commu qui code, mais via la relecture de pull request et autre j'imagine que le code est de qualité (je me suis noté de regarder) : https://github.com/UnityTityTechnologies/open-project-1

Unity a aussi leur projet d'exemple, un des plus récent est celui là : https://blogs.unity3d.com/2019/12/18/download-our-new-2d-sample-project-lost-crypt/

Merci beaucoup pour ton post :oui:
Ouai en fait je connais un peu tous ces acronymes, j'ai juste besoin de pratiquer à mort, je pensais que peut-être il y aurait quelques part une sorte de guide magique ou une méthode générale à appliquer qu'on pout tweaker à notre manière selon nos besoins mais bon :hap:

IndepGameDev
Niveau 10
20 novembre 2020 à 14:02:51

je pensais que peut-être il y aurait quelques part une sorte de guide magique ou une méthode générale à appliquer qu'on pout tweaker à notre manière selon nos besoins mais bon

Je pense qu'unity est un système trop complexe pour avoir une seule méthodologie, et dans les système complexe, il n'y a pas vraiment de bonnes architectures, il y a celle qui répond au besoin.

Dans unity si tu fais un petit projet, tu peux découper tes assets par type, un dossier material, un dossier prefabs, un dossier scripts...

Mais si 20 personnes travaillent sur le projet depuis 3 ans, je pense que cette architecture de dossier à ses limites, alors que pour une gamejam c'est peut être la bonne architecture.

Pareil, si tu fais un prototype, pourquoi ne pas mettre dans la même classe la gestion des inputs, de l'affichage et de la physique ? Il n'y a pas de raison de séparer, ça n'ajoute pas vraiment de valeur et ça prend du temps.

Par contre, si tu as 50 méthodes et 3000 lignes dans ta classe, tu as perdu un des attributs que tu voulais (maintenabilité), donc tu aurais dû découper.

boucif
Niveau 24
20 novembre 2020 à 15:55:52

Le 20 novembre 2020 à 14:02:51 IndepGameDev a écrit :

je pensais que peut-être il y aurait quelques part une sorte de guide magique ou une méthode générale à appliquer qu'on pout tweaker à notre manière selon nos besoins mais bon

En même temps Unity ne respecte déjà pas les bonnes pratiques du C#....

TheRealMarco
Niveau 10
21 novembre 2020 à 11:18:00

Pareil, si tu fais un prototype, pourquoi ne pas mettre dans la même classe la gestion des inputs, de l'affichage et de la physique ? Il n'y a pas de raison de séparer, ça n'ajoute pas vraiment de valeur et ça prend du temps.

Le sujet c'est de faire du code propre, de découper par fonctionnalité. Si tu mélanges tout à cause de contraintes de temps (gamejam) c'est hors sujet.

IndepGameDev
Niveau 10
21 novembre 2020 à 12:32:50

Le sujet c'est de faire du code propre, de découper par fonctionnalité. Si tu mélanges tout à cause de contraintes de temps (gamejam) c'est hors sujet.

Justement ce n'est pas si binaire, déjà parce qu'on a toujours une contrainte de temps (même si une gamejam est particulier). Et je voulais surtout dire que ça ne sert à rien de faire de l'over-engineerin.

C'est pour ça qu'un projet demande environ 30% de temps de refactoring, parce qu'il faut adapter en permanence l'architecture à la taille du projet.

Il n'y a aucun mal à faire (au contraire) :

- Une classe avec 1 méthode qui gère l'affichage les inputs et la physique
- Puis dès que cette méthode est trop grande (15-20 lignes), découper en 3 méthodes privates dans la même classe.
- Puis re-diviser ces mêmes méthodes dès qu'elles sont trop grandes.
- Puis dès que la classe dépasse une taille raisonnable et qu'on a du mal à s'y retrouver entre les méthodes et ce qu'elles font (affichage, etc.), créer de nouvelles classes pour y déporter le code.

ThetaTauTau
Niveau 8
21 novembre 2020 à 13:07:54

Il n'y a aucun mal à faire (au contraire) :

- Une classe avec 1 méthode qui gère l'affichage les inputs et la physique

Ça prends pas beaucoup plus de temps de faire 3 classes (1 ou 2 minutes quoi).
Et faire des classes qui ne font qu'une seule chose permet de faire évoluer le jeu plus facilement.
Typiquement dans ton exemple input/affichage/physique, on peut remplacer le script input par un script "IA" pour faire des ennemis.

Et justement pendant le prototypage le gameplay évolue beaucoup donc avoir un code modulaire permet d'itérer plus vite. A chaque fois que j'ai fais du code "monolithique" j'ai fini par regretter.

L'autre avantage c'est que des scripts bien modulaires peuvent être utilisés d'une façon non prévue à la base, ce qui permet de les réutiliser à différents endroits voire dans différents projets.

Par exemple dans mon projet actuel j'ai des scripts Heal, Damage, ModifyAttribute etc. (dérivés d'une classe Effect). A la base c'était pour les sorts, mais au final c'est utilisé pour pleins de trucs comme les consommables (potions) et les objets interactifs sur la carte (et possibilité de les utiliser dans des pièges, dialogues etc. dans le futur).

geoffroypir
Niveau 5
22 novembre 2020 à 08:47:29

Il y a aussi la facon dont tu utilises unity.
:
Si tu utilises Unity de manière classique, en utilisant des monobehaviour un peu partout, des scriptable objects pour tes données, les scenes et que tu solicittes une approche plus "drag and drop".
Ou bien
Si tu es contraint de developper ton propre moteur conjointement avec unity, du coup utilisant ce dernier comme une sorte de librairie sous stéroides.

Aussi la modularité est vraiment qqchose d'important. L'idéal est de programmer des modules pouvant etre utilisé d'un programme à un autre. C'est un avantage sur tout les tableaux.

Je sais que c'est pas très orthodoxe de dire ca mais l'héritage (à outrance) n'est pas un prérequis pour faire un gros programme robuste et modulaire. D'une part j'utilise l'heritage au sein meme d'un seul module, ce qui limite sa profondeur, et je préfère souvent redéclarer les attributs et methodes afin d'avoir une vue sur tout les attributs et méthodes sur un seul fichier. Ca limite aussi les situation ou il faut courir après les defnition d'overrides eparpillé un peu partout. C'est assez pratique dans un très très gros programme de pouvoir utiliser la fonction recherche sur un seul fichier. C'est purement une question de clareté.
Aussi l'héritage peut empecher de découper son programme correctement car il faut maintenir le lien parent/enfants.

Je n'ai fait aucune théorie, j'ignore quelles sont les pratique académiques enseignées, mais de ce que j'ai pu observer en pratique, une POO "light" associé aux meilleurs pratiques de la programmation procédurale est (discutablement) la meilleur approche.
Dans certain coin d'internet, la POO est une religion qui requiert d'avoir une structure de classe ressemblant a l'abre généalogique des capétiens pour être considérer comme un programmeur. :(

IndepGameDev
Niveau 10
22 novembre 2020 à 10:10:27

Ça prends pas beaucoup plus de temps de faire 3 classes (1 ou 2 minutes quoi).

Ce n'est pas si simple, il faut créer des liens entre les classes (pour que la physique réponde aux inputs par exemple), et donc dans ce cas là tu risques finalement de créer un couplage.

Tu fais quoi, tu références ton scripts d'affichage dans l'input ? l'inverse ? dans ce cas là tu couples fortement. Tu crées un système d'évènement d'input auquel s'abonne l'affichage pour déclencher des méthodes d'affichage ? C'est déjà mieux, mais ça ne prend pas 2 minutes, et ça ajoute du code.

Ce que je veux dire par cette exemple de remise en cause, c'est que l'archi d'un projet ça évolue avec le projet.
On pourrait passer 4 mois à créer une architecture digne d'un jeu triple A, mais on sait bien que ça ne sert à rien, car c'est bien trop compliqué pour le besoin d'un solo dev par exemple.

L'architecture c'est là pour encaisser une complexité projet, plus l'architecture est évoluée et complexe, plus ça coute de développer dans le projet.

Je sais que c'est pas très orthodoxe de dire ca mais l'héritage (à outrance) n'est pas un prérequis pour faire un gros programme robuste et modulaire

Je parle avec mon expérience plus côté gros système web moderne : c'est même plutôt un prérequis de ne pas faire d'héritage pour avoir un système modulaire.

La composition est souvent une alternative à l'héritage (A contient un objet B plutôt que A hérite B), ça réduit le couplage.

la POO, on en fait toute une histoire, mais finalement dans le web moderne on n'en fait presque pas, en tout cas pas de la manière dont on apprend à l'école.

La grande partie des classes n'ont pas d'état (stateless) et pas de propriétés public (on appel ça des services). Une autre grande partie des classes ne sont finalement que des DTO (data transfert object) avec 0 méthodes. Et finalement quelques classes sont un peu plus POO, mais c'est finalement assez rare.

Après dans Unity je pense que la POO a un peu plus sa place, mais je pense que beaucoup de classes qui implémentent des mécaniques (gestion des inputs, de la physique, de l'affichage, etc..) n'ont pas besoin d'état.

ThetaTauTau
Niveau 8
22 novembre 2020 à 10:44:47

Ce n'est pas si simple, il faut créer des liens entre les classes (pour que la physique réponde aux inputs par exemple), et donc dans ce cas là tu risques finalement de créer un couplage.

Tu fais quoi, tu références ton scripts d'affichage dans l'input ? l'inverse ? dans ce cas là tu couples fortement. Tu crées un système d'évènement d'input auquel s'abonne l'affichage pour déclencher des méthodes d'affichage ? C'est déjà mieux, mais ça ne prend pas 2 minutes, et ça ajoute du code.

J'utilise des UnityEvent pour que les différents MonoBehaviour puissent communiquer entre eux sans créer de dépendances.

Exemple simple :
public class Trigger : MonoBehaviour { public UnityEvent OnEnter; private void OnTriggerEnter(Collider other) { if(OnEnter) OnEnter.Invoke() } }

J'ai aussi des ScriptableObject qui contiennent un event ce qui permet à plusieurs Monobehaviour de prefabs différents d'avoir une référence au même event sans créer de dépendance entre eux.

boucif
Niveau 24
22 novembre 2020 à 10:53:38

Le 22 novembre 2020 à 10:44:47 ThetaTauTau a écrit :

Ce n'est pas si simple, il faut créer des liens entre les classes (pour que la physique réponde aux inputs par exemple), et donc dans ce cas là tu risques finalement de créer un couplage.

Tu fais quoi, tu références ton scripts d'affichage dans l'input ? l'inverse ? dans ce cas là tu couples fortement. Tu crées un système d'évènement d'input auquel s'abonne l'affichage pour déclencher des méthodes d'affichage ? C'est déjà mieux, mais ça ne prend pas 2 minutes, et ça ajoute du code.

J'utilise des UnityEvent pour que les différents MonoBehaviour puissent communiquer entre eux sans créer de dépendances.

Exemple simple :
public class Trigger : MonoBehaviour { public UnityEvent OnEnter; private void OnTriggerEnter(Collider other) { if(OnEnter) OnEnter.Invoke() } }

J'ai aussi des ScriptableObject qui contiennent un event ce qui permet à plusieurs Monobehaviour de prefabs différents d'avoir une référence au même event sans créer de dépendance entre eux.

Si tu as un exemple de projet à partager je suis intéressé.

Parfois je fais du pur c# avec Unity, heritage, event ...

IndepGameDev
Niveau 10
02 décembre 2020 à 09:18:35

Quelques ressources sur lesquels je suis tombé il y a peu :

Guide global de bonnes pratiques :

https://docs.google.com/document/d/1eTRYnxrII3b_vce9EytjGA7PU8HCLVjG8qCyW19kqcA/edit

Assets :

https://www.reddit.com/r/gamedev/comments/k4k6ej/my_free_tools_for_programmers_that_i_use_in/

https://forums.tigsource.ce.com/index.php?topic=69950.0

MedialKneePain
Niveau 9
03 décembre 2020 à 14:36:31

Le 02 décembre 2020 à 09:18:35 IndepGameDev a écrit :
Quelques ressources sur lesquels je suis tombé il y a peu :

Guide global de bonnes pratiques :

https://docs.google.com/document/d/1eTRYnxrII3b_vce9EytjGA7PU8HCLVjG8qCyW19kqcA/edit

Assets :

https://www.reddit.com/r/gamedev/comments/k4k6ej/my_free_tools_for_programmers_that_i_use_in/

https://forums.tigsource.ce.com/index.php?topic=69950.0

Merci pour les liens :bave:

1
Sujet : [Unity] Comment structurer son code/design patterns/couches ?
   Retour haut de page
Consulter la version web de cette page