{"id":46,"date":"2014-02-20T22:03:00","date_gmt":"2014-02-20T21:03:00","guid":{"rendered":"http:\/\/oneiricworlds.com\/en\/index.php\/2014\/02\/20\/world-of-thieves-goes-open-world\/"},"modified":"2016-02-27T11:26:36","modified_gmt":"2016-02-27T10:26:36","slug":"world-of-thieves-goes-open-world","status":"publish","type":"post","link":"https:\/\/oneiricworlds.com\/fr\/2014\/02\/world-of-thieves-goes-open-world\/","title":{"rendered":"World of Thieves aura un monde ouvert"},"content":{"rendered":"<p>Salut les amis,<\/p>\n<p><b>[Attention: Cet article est vraiment technique. Continuez \u00e0 lire si vous \u00eates fous uniquement]<\/b><\/p>\n<p>Comme promis dans le dernier post, voici un article assez technique qui explique le genre de probl\u00e8me que je rencontre pour vous donner une id\u00e9e de comment je passe mes journ\u00e9es \u00e0 m&rsquo;arracher les cheveux. Celui-ci est particuli\u00e8rement complexe et m&rsquo;a occup\u00e9 2 semaines, car j&rsquo;ai du changer beaucoup de choses dans le jeu, m\u00eame si, \u00e0 la base, je m&rsquo;\u00e9tais dit \u00ab\u00a0C&rsquo;est bon, pas de soucis, j&rsquo;ai tout calcul\u00e9\u00a0\u00bb&#8230; Quelle na\u00efvet\u00e9&#8230;<\/p>\n<p>Le <strong>but final<\/strong> et d&rsquo;avoir un <strong>monde ouvert<\/strong> et continu <strong>sans temps de chargement<\/strong> entre les diff\u00e9rentes zones.<\/p>\n<p>Pour un monde ouvert me demanderez-vous? Parce que, lorsque j&rsquo;ai commenc\u00e9 ce jeu, je me suis impos\u00e9 3 lignes directrices fondamentales:<\/p>\n<p>&#8211; lierbt\u00e9<br \/>\n&#8211; humour<br \/>\n&#8211; onirisme<\/p>\n<p>Et chaque choix que je fais \u00e0 chaque seconde du d\u00e9veloppement du jeu essaie au maximum de suivre ces 3 \u00ab\u00a0r\u00e8gles\u00a0\u00bb. Ca permet d&rsquo;assurer une certaine coh\u00e9rence et une ligne artistique au jeu, m\u00eame s&rsquo;il n&rsquo;est \u00e9videmment pas parfait. Et donc, avoir un monde ouvert contribue ENORMEMENT au sentiment de libert\u00e9 que je veux instiller dans le jeu. Et c&rsquo;est un challenge technique un peu fou, et je suis quelqu&rsquo;un d&rsquo;un peu fou.<\/p>\n<p>Comme vous l&rsquo;avez peut \u00eatre d\u00e9j\u00e0 vu dans des vid\u00e9os et d\u00e9mos post\u00e9es sur ce cite, le monde du jeu est un immense oc\u00e9an recouvert d&rsquo;\u00eeles (oui comme dans Zelda Windwaker). A un moment, le joueur a la possibilit\u00e9 de silloner l&rsquo;oc\u00e9an \u00e0 dos de tortue pour aller o\u00f9 il le souhaite. Cela signifie que les \u00eeles\/niveaux doivent \u00eatre charg\u00e9s dynamiquement en fonction de la position du joueur dans le monde.<\/p>\n<h3>I &#8211; Les limites de Unity (oui j&rsquo;ai enfin rencontr\u00e9 des limites)<\/h3>\n<p>J&rsquo;utilise Unity pour cr\u00e9er mon jeu et (heureusement?), Unity propose 2 fonctions pour charger un nouveau niveau \u00ab\u00a0en arri\u00e8re-plan\u00a0\u00bb, de telle sorte qu&rsquo;on ne remarque pas de ralentissement pendant ledit chargement:<\/p>\n<ul>\n<li><b>LoadLevelAsync<\/b>: charge le niveau en background (arri\u00e8re-plan). Une fois charg\u00e9, le niveau remplace le niveau actuel.<\/li>\n<li><b>LoadLevelAdditiveAsync<\/b>: La m\u00eame chose, mais le contenu du niveau charg\u00e9 s&rsquo;ajoute au niveau actuel. C&rsquo;est \u00e9videmment \u00e7a qui m&rsquo;int\u00e9resse ici.<\/li>\n<\/ul>\n<p>Mais \u00e7a, c&rsquo;est en th\u00e9orie. Unity est vraiment un bon logiciel, mais plusieurs points sont encore en d\u00e9veloppement&#8230; Et ces fonctions en font partie. Et \u00e7a impacte le jeu d&rsquo;une mani\u00e8re dont je n&rsquo;avais pas id\u00e9e: \u00e7a crashe l&rsquo;intelligence artificielle (IA) des ennemis.<\/p>\n<p>Cela se produit car l&rsquo;IA utilise un \u00ab\u00a0NavMesh\u00a0\u00bb (= Navigation Mesh = Maillage de navigation) pour repr\u00e9senter les zones praticables d&rsquo;un niveau. L&rsquo;IA ne recherche des chemins pour les ennemis QUE sur le NavMesh. Le probl\u00e8me, c&rsquo;est que Unity ne peut stocker qu&rsquo;un seul NavMesh en m\u00e9moire simultan\u00e9ment et on ne peut pas charger de NavMesh avec LoadLevelAdditiveSync. Limitation technique de Unity, je ne peux rien faire.<\/p>\n<div style=\"clear: both; text-align: center;\"><a style=\"margin-left: 1em; margin-right: 1em;\" href=\"http:\/\/3.bp.blogspot.com\/-SIXRJn8i_CM\/UwZp6vAIGRI\/AAAAAAAAHo4\/VyCYYkHfB1U\/s1600\/20140220_navMesh.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/3.bp.blogspot.com\/-SIXRJn8i_CM\/UwZp6vAIGRI\/AAAAAAAAHo4\/VyCYYkHfB1U\/s1600\/20140220_navMesh.jpg\" alt=\"\" width=\"640\" height=\"371\" border=\"0\" \/><\/a><\/div>\n<div style=\"text-align: center;\"><i>Le NavMesh: les ennemis ne peuvent se d\u00e9placer que sur la zone bleue. Le calcul d&rsquo;un NavMesh est une op\u00e9ration relativement complexe.<\/i><\/div>\n<p>&nbsp;<\/p>\n<h3>II &#8211; L&rsquo;heure des Hacks<\/h3>\n<p>J&rsquo;ai trouv\u00e9 un \u00ab\u00a0hack\u00a0\u00bb (une mani\u00e8re pas tr\u00e8s propre de contourner le probl\u00e8me) sur un <a href=\"http:\/\/answers.unity3d.com\/questions\/303007\/dynamic-levels-navmesh.html\">forum<\/a>: utiliser LoadLevelAsync (qui, lui, charge EFFECTIVEMENT le NavMesh), et tagger les objets du niveau courant comme ne devant pas \u00eatre d\u00e9truits (une fonctionnalit\u00e9 bien cool que j&rsquo;ai d&rsquo;ailleurs d\u00e9couvert gr\u00e2ce \u00e0 ces forums. Quelle comunaut\u00e9 autour de ce logiciel!)<br \/>\nC&rsquo;est cens\u00e9 r\u00e9soudre le probl\u00e8me, mais en fait, \u00e7a soul\u00e8ve 2 autres questions:<\/p>\n<ul>\n<li>LoadLevelAsync n&rsquo;est en fait pas vraiment ex\u00e9cut\u00e9 en arri\u00e8re plan. Ca fige le jeu pendant quelques ms et c&rsquo;est VRAIMENT visible.<\/li>\n<li>Cool, le NavMesh est effectivement OK pour le nouveau niveau, l&rsquo;IA aussi, mais qu&rsquo;est-ce qu&rsquo;il se passe si je reviens vers le 1er niveau, qui est toujours visible, mais qui n&rsquo;a plus de NavMesh (puisque ce dernier a \u00e9t\u00e9 remplac\u00e9 par celui du nouveau niveau) et plus d&rsquo;IA? Si je veux recharger uniquement le NavMesh du 1er niveau, il est impossible de le faire sans recharger l&rsquo;int\u00e9gralit\u00e9 du niveau en question, ce qui risque provoquer des clignotements des objets et des bugs, une charge inutile du CPU et surement d&rsquo;autres ralentissements.<\/li>\n<\/ul>\n<p>A ce stade, je suis face \u00e0 des bugs de Unity que je ne peux pas corriger. Voil\u00e0 les options qui s&rsquo;offrent \u00e0 moi:<\/p>\n<ul>\n<li><b>Attendre une correction du bug<\/b> de Unity sur ce probl\u00e8me NavMesh+LoadLevelAdditiveAsync. Je ne pense pas que \u00e7a arrivera avant que je sorte mon jeu. Les gars de chez Unity ont des tonnes de trucs \u00e0 g\u00e9rer, et \u00e7a ne semble pas \u00eatre une priorit\u00e9.<\/li>\n<li><b>Utiliser une librairie annexe\/tierce<\/b>. Je dois en trouver une qui g\u00e8re la g\u00e9n\u00e9ration de NavMesh et le Pathfinding (recherche de chemin), en temps r\u00e9el, et qui g\u00e8re le chargement dynamique des donn\u00e9es.<\/li>\n<li><b>Tout recoder<\/b>. Ce n&rsquo;est pas impossible (j&rsquo;ai d\u00e9j\u00e0 cod\u00e9 un algo de pathfinding A* pour <a href=\"http:\/\/home.oneiricworlds.com\/search\/?q=label:WorldOfNinjas+label:Demo\">World of Ninjas<\/a>, mais c&rsquo;\u00e9tait une grille 2D)&#8230; mais ce n&rsquo;est pas tr\u00e8s r\u00e9aliste. Des gens s\u00e9rieux passent des mois \u00e0 d\u00e9velopper des syst\u00e8mes bien plus fiables que ce que je pourrais faire en quelques semaines.<\/li>\n<li><b>Trouver un autre hack<\/b>. Je n&rsquo;ai rien trouv\u00e9 en passant plusieurs heures sur les forums et les FAQs<\/li>\n<li><b>Abandonner<\/b>. C&rsquo;est r\u00e9ellement une option. Je peux mettre en place une navigation dans le monde \u00e0 partir d&rsquo;une carte en 2D o\u00f9 on clique sur l&rsquo;endroit o\u00f9 on veut aller. Toutes les \u00eeles seront accessibles, et \u00e7a ne changera pas le gameplay sur chaque \u00eele. Peut-\u00eatre m\u00eame que c&rsquo;est ce que je choisirai de faire si j&rsquo;arrive \u00e0 cr\u00e9er un monde ouvert, mais que \u00e7a n&rsquo;apporte aucun int\u00e9r\u00eat au jeu.<\/li>\n<\/ul>\n<p>Mais avant d&rsquo;abandonner, j&rsquo;ai entendu de bonnes critiques d&rsquo;une librairie d&rsquo;IA: la librairie \u00ab\u00a0A* PathFinding\u00a0\u00bb d&rsquo;Aron Granberg.<\/p>\n<div style=\"clear: both; text-align: center;\"><a style=\"margin-left: 1em; margin-right: 1em;\" href=\"http:\/\/2.bp.blogspot.com\/-ICg8nAOpF14\/UwZs5dTiPrI\/AAAAAAAAHpI\/kpNqbHCg_gs\/s1600\/20140213_172417.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/2.bp.blogspot.com\/-ICg8nAOpF14\/UwZs5dTiPrI\/AAAAAAAAHpI\/kpNqbHCg_gs\/s1600\/20140213_172417.png\" alt=\"\" width=\"640\" height=\"360\" border=\"0\" \/><\/a><\/div>\n<div style=\"text-align: center;\"><i>Beaucoup de niveaux charg\u00e9s simultan\u00e9ment!<\/i><\/div>\n<p>&nbsp;<\/p>\n<h3>III &#8211; Une nouvelle librairie: A*<\/h3>\n<p>Cool! Une nouvelle librairie pleine de promesses. Mais avant de s&rsquo;engager pleinement l\u00e0-dedans, il faut que je teste les fonctionnalit\u00e9s basiques pour v\u00e9rifier que je retrouve bien ce que j&rsquo;avais d\u00e9j\u00e0 dans Unity.<\/p>\n<p>J&rsquo;ai commenc\u00e9 avec la version gratuite&#8230; c&rsquo;est \u00e0 dire sans g\u00e9n\u00e9ration de NavMesh (cette fonctionnalit\u00e9 n&rsquo;est disponible que dans la version \u00e0 100$). Bien s\u00fbr, je peux acheter la version payante, mais je ne sais m\u00eame pas si la librairie r\u00e9sout mon probl\u00e8me de chargement dynamique. Je dois d&rsquo;abord tester ce point.<\/p>\n<p>Je sais que Unity peut <strong>g\u00e9n\u00e9rer des NavMesh<\/strong> (je les ai d\u00e9j\u00e0 utilis\u00e9s). J&rsquo;ai donc \u00e9crit un script pour convertir les NavMesh g\u00e9n\u00e9r\u00e9s par Unity dans un format lisible par la librairie A*, ce qui m&rsquo;a permis de tester le path-finding sur mes niveaux d\u00e9j\u00e0 faits.<\/p>\n<p>Mais il y a d\u00e9j\u00e0 un probl\u00e8me: le pathfinding se comporte bizarrement et, des fois, l&rsquo;IA fait de gros d\u00e9tours. Ca semble \u00eatre un probl\u00e8me connu. Cela vient de la topologie du NavMesh: un \u00ab\u00a0bon\u00a0\u00bb NavMesh pour la librairie A* est sens\u00e9 avoir une sorte de motif en grille afin d&rsquo;\u00e9viter la juxtaposition de grand et de petits triangles. Pas de chance pour moi, Unity ne propose pas ce genre de param\u00e9trage dans son interface, ce qui signifie que je ne peux pas v\u00e9rifier si les r\u00e9sultats sont meilleurs sur un \u00ab\u00a0bon\u00a0\u00bb NavMesh.<\/p>\n<p>&nbsp;<\/p>\n<h3>IV &#8211; Une autre librarie : RAIN<\/h3>\n<p>J&rsquo;ai \u00e9galement entendu parler d&rsquo;une autre librairie: RAIN. Enti\u00e8rement gratuite, mais avec peu de documentation. Je l&rsquo;ai essay\u00e9e principalement pour \u00e9valuer son g\u00e9n\u00e9rateur de NavMesh et&#8230; Hourra! Elle peut g\u00e9n\u00e9rer des NavMesh \u00e0 motif de grille. J&rsquo;ai donc \u00e9crit un autre script pour convertir les NavMesh de RAIN en NavMesh pour A*, avec le peu de documentation que j&rsquo;ai trouv\u00e9. Pas facile! Et j&rsquo;ai quelques erreurs lors de la conversion, mais visuellement, \u00e7a a l&rsquo;air OK. J&rsquo;ai test\u00e9 avec A* et l&rsquo;IA se comporte enfin correctement.<\/p>\n<p>Donc en combinant 2 librairies diff\u00e9rentes, j&rsquo;arrive \u00e0 avoir une IA basique acceptable. Je suis \u00e0 peu pr\u00e8s au m\u00eame point qu&rsquo;avec Unity avant.<\/p>\n<p>Maintenant je dois m&rsquo;attaquer au VRAI probl\u00e8me: le chargement dynamique.<\/p>\n<p>&nbsp;<\/p>\n<h3>V &#8211; Le chargement dynamique de NavMesh<\/h3>\n<p>On dirait que la librairie A* propose un moyen d&rsquo;exporter les NavMesh dans un fichier texte et de les charger dynamiquement. Exactement ce qu&rsquo;il me faut (en th\u00e9orie). Apr\u00e8s quelques tests, on dirait que \u00e7a marche pour les fichiers relativement petits. Mais bien s\u00fbr, l\u00e0 encore, le NavMesh charg\u00e9 remplace le pr\u00e9c\u00e9dent. Je dois donc faire tr\u00e8s attention lors de l&rsquo;activation des IA. C&rsquo;est bien engag\u00e9, mais \u00e7a signifie que je dois encore \u00e9crire un script qui converti un NavMesh en fichier texte pendant la g\u00e9n\u00e9ration du niveau.<\/p>\n<div style=\"clear: both; text-align: center;\"><a style=\"margin-left: 1em; margin-right: 1em;\" href=\"http:\/\/3.bp.blogspot.com\/-w9pdyuPfX-E\/UwZuoqHTWII\/AAAAAAAAHpU\/9sBsfWyxJlA\/s1600\/20140220_220709.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/3.bp.blogspot.com\/-w9pdyuPfX-E\/UwZuoqHTWII\/AAAAAAAAHpU\/9sBsfWyxJlA\/s1600\/20140220_220709.png\" alt=\"\" width=\"640\" height=\"307\" border=\"0\" \/><\/a><\/div>\n<div style=\"text-align: center;\"><i>Le niveau de test habituel pour l&rsquo;IA.<\/i><\/div>\n<p>&nbsp;<\/p>\n<h3>VI &#8211; Tout int\u00e9grer<\/h3>\n<p>OK. Tous les tests que j&rsquo;ai fait jusqu&rsquo;\u00e0 pr\u00e9sent ont \u00e9t\u00e9 r\u00e9alis\u00e9s sur des niveaux et des objets temporaires. Je dois maintenant r\u00e9\u00e9crire le code des VRAIS ennemis que j&rsquo;utilise dans mon jeu, et utiliser la librairie A* en remplacement du syst\u00e8me de Unity. Et bien s\u00fbr, j&rsquo;ai quelques soucis car A* ne propose pas exactement la m\u00eame approche que Unity pour la gestion des \u00e9tats de calcul (le chemin est en cours de calcul, l&rsquo;IA est arriv\u00e9 \u00e0 destination, etc&#8230;). Mais finalement, \u00e7a marche! Comme avant, mais avec le chargement dynamique des niveaux et un comportement correct de l&rsquo;IA! Pfiouuuu!<\/p>\n<p>&nbsp;<\/p>\n<h3>VII &#8211; Surprise finale: activation progressive<\/h3>\n<p>Mais&#8230; pour des niveaux de grande taille, on dirait que le chargement \u00ab\u00a0lagge\u00a0\u00bb (ralentit le jeu). Comment est-ce possible? Est-ce que j&rsquo;aurais fait tout \u00e7a pour me rendre compte finalement que la fonction LoadLevelAdditiveAsync n&rsquo;est pas REELLEMENT ex\u00e9cut\u00e9e en arri\u00e8re-plan? Est-ce que j&rsquo;ai mal fait un truc?<\/p>\n<p>Et en effet, apr\u00e8s plusieurs tests, on dirait que ce n&rsquo;est pas le chargement en lui-m\u00eame qui fige le jeu. C&rsquo;est en r\u00e9alit\u00e9 l&rsquo;activation de tous les objets du niveau et toutes les fonctions \u00ab\u00a0Start&rsquo; qui s&rsquo;ex\u00e9cutent en m\u00eame temps (IA\/vegetation\/animaux&#8230;).<\/p>\n<p>Je dois donc d\u00e9sactiver tous les objets par d\u00e9faut et les activer un par un \u00e0 chaque affichage pour \u00e9viter cette charge CPU trop importante. Mais cela am\u00e8ne \u00e0 30 secondes pour activer un niveau de 1800 \u00e9l\u00e9ments. Je dois donc optimiser pour essayer d&rsquo;activer plusieurs objets en un affichage s&rsquo;ils ne sont pas trop gourmands en temps de calcul (les caisses par exemple), et n&rsquo;en activer qu&rsquo;un \u00e0 la fois dans le cas d&rsquo;objets complexes (les ennemis). Ainsi, j&rsquo;ai pu r\u00e9duire \u00e0 3 secondes le temps de chargement et d&rsquo;activation pour ce m\u00eame niveau de 1800 \u00e9l\u00e9ments.<\/p>\n<p>&nbsp;<\/p>\n<h3>VIII &#8211; Tout automatiser<\/h3>\n<p>Cool! Tout \u00e7a a l&rsquo;air de marcher sur les 1ers niveaux que j&rsquo;ai plac\u00e9s \u00ab\u00a0\u00e0 la main\u00a0\u00bb dans le monde. Mais au final j&rsquo;aurai beaucoup de niveaux, et il se peut que leur emplacement change. Je dois mettre en place un syst\u00e8me qui fait tout \u00e7a de mani\u00e8re automatique pour chaque nouveau niveau.<\/p>\n<p>J&rsquo;ai donc cr\u00e9\u00e9 un fichier sp\u00e9cial dans Blender pour positionner pr\u00e9cis\u00e9ment chaque niveau dans le monde. Les niveaux eux-m\u00eame sont quant \u00e0 eux stock\u00e9s dans des fichier Blender s\u00e9par\u00e9s et sont centr\u00e9s en (0,0,0) au sein de ces fichiers s\u00e9par\u00e9s.<\/p>\n<p>&nbsp;<\/p>\n<div style=\"clear: both; text-align: center;\"><a style=\"margin-left: 1em; margin-right: 1em;\" href=\"http:\/\/1.bp.blogspot.com\/-fco-vNu-xVo\/UwZ4p0N7Y2I\/AAAAAAAAHp4\/dYYW6JPEs_8\/s1600\/20140220_worldMesh.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/1.bp.blogspot.com\/-fco-vNu-xVo\/UwZ4p0N7Y2I\/AAAAAAAAHp4\/dYYW6JPEs_8\/s1600\/20140220_worldMesh.jpg\" alt=\"\" width=\"640\" height=\"352\" border=\"0\" \/><\/a><\/div>\n<div style=\"text-align: center;\"><i>Le fichier qui localise tous les niveaux dans Blender. Les grandes et petites sph\u00e8res repr\u00e9sentent respectivement les zones de chargement et d&rsquo;activation.<\/i><\/div>\n<div style=\"text-align: center;\"><\/div>\n<p>Quand je charge un niveau de Blender dans Unity, voici ce qui se passe de mani\u00e8re (presque) automatique:<\/p>\n<ul>\n<li>Rechercher la position du niveau dans le monde gr\u00e2ce au fichier sp\u00e9cial<\/li>\n<li>Bouger l&rsquo;int\u00e9gralit\u00e9 du niveau vers sa position finale dans le monde (en tenant compte des conventions de coordonn\u00e9es)<\/li>\n<li>Transformer les objets Blender en objets intelligents\/script\u00e9s dans Unity.<\/li>\n<li>Cr\u00e9er un NavMesh en utilisant Unity ou RAIN<\/li>\n<li>Convertir le NavMesh Unity\/RAIN en NavMesh A*<\/li>\n<li>Utiliser ce fichier dans le gestionnaire de pathfinding A*<\/li>\n<li>Convertir le NavMesh A* en fichier texte<\/li>\n<li>D\u00e9sactiver tous les objets de la sc\u00e8ne pour ne pas qu&rsquo;ils s&rsquo;initialisent tous en m\u00eame temps apr\u00e8s un chargement dynamique.<\/li>\n<\/ul>\n<p>&#8230; Et c&rsquo;est \u00e0 peu pr\u00e8s tout&#8230; Pour la partie \u00ab\u00a0\u00e9dition de niveau\u00a0\u00bb que je fais dans Unity.<\/p>\n<p>En revanche, il se passe encore plein de choses lors de l&rsquo;ex\u00e9cution du jeu:<\/p>\n<ul>\n<li>Si on rentre dans une zone de chargement, le niveau est charg\u00e9 dynamiquement, mais rien n&rsquo;est encore activ\u00e9. Seuls sont visibles les plus gros objets qui constituent la forme principale de l&rsquo;\u00eele.<\/li>\n<li>Si on se rapproche, le fichier texte du NavMesh est charg\u00e9, et l&rsquo;activation progressive d\u00e9marre ensuite, donnant vie \u00e0 tout le niveau en quelques secondes.<\/li>\n<li>Quand on quitte une zone d&rsquo;activation, tous les objets sont d\u00e9sactiv\u00e9s, mais le NavMesh est gard\u00e9 en m\u00e9moire (au cas o\u00f9 on reviendrait).<\/li>\n<li>Quand on quitte une zone de chargement, la totalit\u00e9 du niveau est d\u00e9truit.<\/li>\n<\/ul>\n<p>J&rsquo;ai du \u00e9norm\u00e9ment r\u00e9fl\u00e9chir sur les distances de chargement et d&rsquo;activation, car je ne veux pas commencer \u00e0 activer les niveaux si on est trop loin, mais je veux quand m\u00eame qu&rsquo;on puisse les voir d&rsquo;une certaine distance. Je dois \u00e9galement faire attention \u00e0 la distance qui s\u00e9pare les \u00eeles: si 2 zones d&rsquo;activation se recouvrent, plusieurs niveaux pourraient \u00eatre charg\u00e9s et activ\u00e9s en m\u00eame temps, ce qui risque de s\u00e9rieusement ralentir le jeu. En bref, c&rsquo;est une question d&rsquo;\u00e9quilibre.<\/p>\n<p>Enfin! Nous y sommes arriv\u00e9s! Ca a \u00e9t\u00e9 une exp\u00e9dition bien difficile au milieu de probl\u00e8mes complexes, mais maintenant le jeu propose un monde ouvert et tourne en moyenne \u00e0 50 fps avec des chutes \u00e0 20 fps lors de chargements. Maintenant vous savez pourquoi il y a aussi peu de changements entre 2 versions cons\u00e9cutives du jeu!<\/p>\n<p>Pour les gens courageux qui seraient arriv\u00e9s jusqu&rsquo;ici, voil\u00e0 une vid\u00e9o du chargement dynamique des niveaux. J&rsquo;utilise un super grappin pour me d\u00e9placer d&rsquo;une \u00eeles \u00e0 l&rsquo;autre, mais \u00e7a demande une vis\u00e9e assez pr\u00e9cise. Et vous pourrez remarquer que la distance entre les \u00eeles est peut-\u00eatre un peu grande.<\/p>\n<p>&nbsp;<\/p>\n<div style=\"text-align: center;\">\n<p><iframe loading=\"lazy\" title=\"World of Thieves - Open World\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/9JiAX03hLXQ?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<\/div>\n<div style=\"text-align: center;\"><i>Pour \u00e9viter que les \u00eeles apparaissent subitement lorsque le joueur entre dans une zone de chargement, j&rsquo;ai ajout\u00e9 du brouillard (un truc assez r\u00e9pandu dans les jeux vid\u00e9o).<\/i><\/div>\n<div style=\"text-align: center;\"><\/div>\n<h3>IX &#8211; Encore plus de probl\u00e8mes!<\/h3>\n<p>Pour \u00e9viter de tout rendre encore plus compliqu\u00e9, j&rsquo;ai \u00e9vit\u00e9 de parler de certains probl\u00e8mes additionnels. Mais si certaines personnes veulent mettre en place le m\u00eame proc\u00e9d\u00e9, vous devez savoir quelques trucs:<\/p>\n<ul>\n<li>La librairie A* semble avoir une sorte de cache pour les NavMesh, et il faut parfois \u00ab\u00a0rebaker\/rescanner\u00a0\u00bb un NavMesh apr\u00e8s l&rsquo;avoir charg\u00e9. Mais c&rsquo;est tr\u00e8s tr\u00e8s lourd comme op\u00e9ration! Apr\u00e8s plusieurs tests, on dirait que cela se produit uniquement dans l&rsquo;\u00e9diteur, mais pas avec un ex\u00e9cutable export\u00e9.<\/li>\n<li>LoadLevelAdditiveAsync n&rsquo;est absolument pas asynchrone dans l&rsquo;\u00e9diteur. Ca fige le jeu. Il faut faire un export du jeu pour que ce soit r\u00e9ellement temps r\u00e9el.<\/li>\n<li>Charger plusieurs niveaux simultan\u00e9ment a totalement alt\u00e9r\u00e9 le chargement automatique de s\u00e9quences vid\u00e9os\/dialogues ou autre qui \u00e9tait d\u00e9j\u00e0 en place. J&rsquo;ai du corriger tout ce qui se d\u00e9clenchait alors que j&rsquo;\u00e9tais tr\u00e8s loin des \u00eeles en question.<\/li>\n<li>Maintenant que je charge des niveaux dynamiquement, je dois enregistrer toutes les actions du joueur de mani\u00e8re dynamique \u00e9galement: si le joueur prend un item et ouvre une porte, je dois garder une trace de ces \u00e9v\u00e9nements si le niveau est d\u00e9charg\u00e9 avant que le joueur ne sauve la partie.<\/li>\n<li>Quelques objets ne supportent pas l&rsquo;activation dynamique: les v\u00eatements\/tissus (\u00ab\u00a0clothes\u00a0\u00bb dans Unity). Ca ruine totalement la simulation physique dans le meilleur des cas, et dans le pire, \u00e7a crashe totalement le jeu. J&rsquo;ai trouv\u00e9 une alternative qui consiste \u00e0 d\u00e9sactiver uniquement le composant \u00ab\u00a0Clothe\u00a0\u00bb et non pas l&rsquo;objet, ce qui fait que mon code est tr\u00e8s moche.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<div style=\"clear: both; text-align: center;\"><a style=\"margin-left: 1em; margin-right: 1em;\" href=\"http:\/\/1.bp.blogspot.com\/-HsOnzxS24pM\/UwZviQ5H8NI\/AAAAAAAAHpc\/7t8-GfT48q0\/s1600\/20140220_221057.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/1.bp.blogspot.com\/-HsOnzxS24pM\/UwZviQ5H8NI\/AAAAAAAAHpc\/7t8-GfT48q0\/s1600\/20140220_221057.png\" alt=\"\" width=\"640\" height=\"307\" border=\"0\" \/><\/a><\/div>\n<div style=\"text-align: center;\"><i>J&rsquo;ai utilis\u00e9 la simulation de v\u00eatement pour rajouter de grands drapeaux au dessus de la Guilde des Voleurs (le seul changement graphique en 2 semaines&#8230;)<\/i><\/div>\n<div style=\"text-align: center;\"><\/div>\n<p>Voil\u00e0! Ce sera tout pour le probl\u00e8me d\u00e9lirant du moment.<\/p>\n<p>A+<\/p>\n<p>Paix!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Salut les amis, [Attention: Cet article est vraiment technique. Continuez \u00e0 lire si vous \u00eates fous uniquement] Comme promis dans le dernier post, voici un article assez technique qui explique le genre de probl\u00e8me que je rencontre pour vous donner une id\u00e9e de comment je passe mes journ\u00e9es \u00e0 m&rsquo;arracher les cheveux. Celui-ci est particuli\u00e8rement [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":227,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[],"class_list":["post-46","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dev"],"_links":{"self":[{"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/posts\/46","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/comments?post=46"}],"version-history":[{"count":7,"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/posts\/46\/revisions"}],"predecessor-version":[{"id":385,"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/posts\/46\/revisions\/385"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/media\/227"}],"wp:attachment":[{"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/media?parent=46"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/categories?post=46"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oneiricworlds.com\/fr\/wp-json\/wp\/v2\/tags?post=46"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}