RTS Terrain Studio 1.0.0
Manuel · Version 1.0.0

RTS Terrain Studio

Créez des cartes dans le style des RTS classiques, avec plateaux, falaises nettes, rampes, sol peint, forêts, eau et décors, dans l’éditeur Unity comme dans votre jeu. Le brouillard de guerre, la recherche de chemin et les requêtes sur le terrain sont intégrés.

Unity 6.3 LTSURP 17.3Éditeur et en jeuMirror, A* Pathfinding Project, Unity NavMesh

Vue d’ensemble

RTS Terrain Studio est un éditeur de cartes pour jeux de stratégie en temps réel de style classique, conçu pour Unity 6.3 LTS et l’Universal Render Pipeline (URP) 17.3. Il vous permet de sculpter des plateaux bordés de falaises verticales nettes, de peindre le sol, de planter des forêts, de remplir d’eau des lacs et des rivières, de placer des éléments de décor, de marquer les positions de départ des joueurs et de vérifier où les unités peuvent passer et où les bâtiments peuvent être construits. Une fois votre travail terminé, la même carte est prête pour le gameplay : brouillard de guerre, recherche de chemin et requêtes sur le terrain sont disponibles, sans qu’aucun collider soit nécessaire.

L’éditeur fonctionne à deux endroits, et tous deux utilisent les mêmes outils et le même format de fichier de carte (.rtsmap) :

  • Dans l’éditeur Unity, avec la fenêtre Tools ▸ RTS Terrain Studio ▸ Editor Window et la Scene View. C’est là que vous créez les cartes livrées avec votre jeu.
  • En jeu, avec le composant RTSRuntimeEditor. Il s’agit d’un éditeur complet doté d’une interface UI Toolkit. Vos joueurs et vos moddeurs peuvent l’utiliser dans votre jeu publié pour créer des cartes, les enregistrer, les charger et les tester en jeu.

Le package ne contient aucune ressource graphique tierce. À la place, une seule commande de menu génère un ensemble complet de contenu de démo : textures, arbres et accessoires low-poly, deux tilesets, trois cartes et trois scènes prêtes à jouer. Moins d’une minute après l’import du package, vous avez déjà de quoi explorer.

La scène Gameplay Demo : une carte à plateaux avec des falaises, des rivières, des forêts et des unités d’exemple sous le brouillard de guerre
La scène RTS Terrain Studio - Gameplay Demo sur la carte de démo Two Rivers (1v1).

Ce manuel s’adresse à tous, de la création de votre première carte jusqu’à l’extension du code source. Si vous débutez, suivez la section Vos cinq premières minutes ci-dessous, puis lisez les chapitres dans l’ordre. Si vous êtes programmeur, sachez que le code source est entièrement commenté, que chaque type public possède une documentation XML et que la section Arborescence des dossiers indique où se trouve chaque élément.

Comment une carte est construite

Si vous avez déjà utilisé l’éditeur de cartes d’un RTS classique, la plupart de ces notions vous sembleront familières. Une carte est une grille de cellules carrées (2 m de large par défaut). Les coins des cellules sont les vertices, et la plupart des données sont stockées par vertex ou dans des textures haute résolution qui couvrent la carte.

NotionDéfinition
Niveau de falaiseUn palier de hauteur entier, de 0 à 15, défini pour chaque vertex. Des vertices voisins situés à des niveaux différents forment une paroi de falaise verticale. La hauteur de niveau par défaut est de 2 m, et les nouvelles cartes commencent au niveau 2, ce qui vous permet de creuser en dessous pour former des lacs et des rivières.
Hauteur fineUn décalage de hauteur continu qui s’ajoute au niveau de falaise et sert à former collines et vallées. La hauteur du sol d’un vertex vaut CliffLevel × CliffLevelHeight + Height.
RampeLes cellules dont les coins portent l’indicateur de rampe passent en douceur d’un niveau au suivant, ce qui permet aux unités de les gravir.
Type de falaiseLe matériau des parois de falaise (par exemple des falaises rocheuses ou herbeuses). Un tileset en compte jusqu’à 4.
Calque de solUne texture de sol peinte, parmi 16 au maximum (herbe, terre, roche…), stockée dans les splat maps.
EauUne hauteur de surface de l’eau par vertex. La profondeur détermine s’il s’agit d’eau peu profonde (praticable) ou d’eau profonde (non praticable).
Détails et arbresDe l’herbe et des fleurs peintes (densité par texel), ainsi que des arbres placés individuellement.
DécorTout prefab que vous placez sur la carte : rochers, ruines, caisses, clôtures, bâtiments.
CheminementPour chaque cellule de cheminement : praticable, constructible, survolable, eau peu profonde ou profonde, falaise, bloquée ou escarpée. Ces informations sont déduites automatiquement de la carte, et vous pouvez peindre des surcharges par-dessus.
MarqueursDes régions nommées (rectangles dotés de propriétés clé/valeur pour la logique de votre jeu), les positions de départ des joueurs et des points nommés, comme des positions de caméra.
TilesetUn asset RTSTileset qui définit l’apparence : calques de sol, types de falaise et style de l’eau, à la manière des tilesets « Summer » ou « Winter » des éditeurs de cartes des RTS classiques.
BibliothèquesUne bibliothèque RTSVegetationLibrary (détails et arbres) et une bibliothèque RTSDecorLibrary (prefabs de décor). Ce sont les palettes dans lesquelles vous choisissez ce que vous peignez et placez.

Dans une scène, une carte se trouve sur un GameObject doté du composant RTSTerrain. Le menu GameObject ▸ RTS Terrain Studio ▸ RTS Terrain y ajoute aussi les composants des sous-systèmes (RTSVegetationRenderer, RTSWaterRenderer et RTSDecorManager). Le terrain lit la carte depuis un fichier .rtsmap de votre projet (un RTSMapAsset). Les meshes des chunks, l’herbe et l’eau qu’il affiche sont générés à partir de ce fichier. Ils ne sont jamais enregistrés dans la scène, si bien que vos scènes restent légères.

Vos cinq premières minutes

C’est le moyen le plus rapide de voir tout fonctionner. Hormis l’import du package, aucune configuration n’est nécessaire.

  1. Ouvrez Tools ▸ RTS Terrain Studio ▸ Validate Project et cliquez sur Fix All. Cette action configure URP, la renderer feature du brouillard de guerre, les textures de caméra utilisées par l’eau et l’espace colorimétrique. Avant toute modification, une boîte de dialogue de confirmation vous explique ce qui va changer.
  2. Lancez Tools ▸ RTS Terrain Studio ▸ Create Demo Content. Une barre de progression s’affiche pendant la génération des textures, des modèles, des tilesets, des cartes et des scènes. Une fois l’opération terminée, la scène RTS Terrain Studio - Gameplay Demo est sélectionnée dans la fenêtre Project.
  3. Double-cliquez sur cette scène pour l’ouvrir, puis appuyez sur Play.
  4. Sélectionnez vos unités avec le bouton gauche de la souris (clic, ou glisser pour tracer un rectangle) et cliquez avec le bouton droit sur le sol pour les déplacer. Déplacez la caméra avec WASD ou les touches fléchées, zoomez avec la molette de la souris et appuyez sur F1 pour afficher toutes les commandes.
  5. Quittez le Play Mode et ouvrez la scène RTS Terrain Studio - Editor Playground. Ouvrez Tools ▸ RTS Terrain Studio ▸ Editor Window, choisissez un outil et peignez dans la Scene View. Maintenez Shift enfoncée pour obtenir l’effet inverse (par exemple abaisser au lieu d’élever). Appuyez sur Ctrl+Z pour annuler.
  6. Ouvrez la scène RTS Terrain Studio - In-Game Editor Demo et appuyez sur Play. Voici l’éditeur dont disposeront vos joueurs. Appuyez sur F5 pour tester la carte en jeu avec des unités, et sur F2 pour afficher ou masquer l’éditeur.

La fenêtre Tools ▸ RTS Terrain Studio ▸ Welcome s’ouvre une fois par projet et présente les mêmes étapes sous forme de boutons. Vous pouvez la rouvrir depuis le menu à tout moment.

Par où commencer

Je veux…Commencez ici
Configurer correctement un projetConfiguration du projet et Tools ▸ RTS Terrain Studio ▸ Validate Project
Créer ma première carte pas à pasDémarrage rapide et Tools ▸ RTS Terrain Studio ▸ New Map Wizard...
Découvrir la fenêtre de l’éditeur et chaque outilFenêtre de l’éditeur et Scene View
Permettre aux joueurs de créer des cartes dans mon jeuÉditeur en jeu
Publier mon jeu ou l’éditeur de cartes pour navigateur webBuilds Web (WebGL)
Masquer la carte jusqu’à ce que les unités l’explorentBrouillard de guerre
Utiliser Mirror, A* Pathfinding Project ou Unity NavMeshIntégrations
Interroger le terrain ou écrire mes propres outils en C#Programmation
Corriger un problème d’affichage ou de fonctionnementDépannage

Fonctionnalités

Chacun des outils d’édition ci-dessous existe à la fois dans l’éditeur Unity et dans l’éditeur en jeu, car les deux utilisent les mêmes classes d’outils (des sous-classes de RTSTool). Les noms de cette liste sont ceux que vous voyez dans l’interface utilisateur.

La fenêtre de l’éditeur RTS Terrain Studio avec l’onglet Decor ouvert
La fenêtre RTS Terrain Studio : catégories d’outils, boutons d’outils, paramètres de symétrie et palette de décors avec ses miniatures générées.

Terrain et falaises

  • Des cartes de 16 à 1024 cellules de côté, par pas de 16. Le New Map Wizard propose les préréglages Tiny (64), Small (96), Medium (128), Large (192), Huge (256), Epic (384) et Epic XL (512), ou n’importe quelle taille personnalisée. La taille de cellule et la hauteur des niveaux de falaise se règlent librement.
  • 16 niveaux de falaise (0–15) avec des parois arrondies générées de façon procédurale. Un contour est tracé sur une sous-grille à l’intérieur de chaque cellule de falaise, et le bruit ainsi que l’inclinaison donnent aux parois l’aspect de la roche naturelle (tout cela se règle dans RTSTerrainSettings).
  • Des hauteurs fines par-dessus les niveaux, pour que les plateaux puissent accueillir des collines. Le sol lisse peut utiliser de 1 à 4 quads par côté de cellule : 1 donne l’aspect RTS classique, 2 à 4 des collines plus douces.
  • Outils Height : Raise / Lower, Smooth, Flatten, Set Height, Noise, Terrace, Erode.
  • Outils Cliffs : Raise / Lower Level, Set Level, Ramp, Cliff Type, Clean Cliffs.
  • Jusqu’à 4 types de falaise par tileset, peints par vertex, avec une projection triplanaire des textures sur les parois.
  • Un MeshCollider facultatif par chunk, sur le layer de votre choix. Les requêtes qui n’utilisent pas le moteur physique fonctionnent aussi sans lui : GetHeight, GetNormal, Raycast, GetCliffLevel, IsWater, GetPathing, IsWalkable et IsBuildable.
  • Autant de terrains que vous le souhaitez dans une même scène. Chaque terrain a sa propre position et sa propre rotation autour de l’axe Y. RTSTerrain.FindAt(worldPosition) et RTSTerrain.RaycastAll(ray, out hit) trouvent le bon terrain.
  • Redimensionnez une carte dans les deux sens (pour l’agrandir ou la réduire) à l’aide d’une ancre. Importez et exportez des heightmaps en PNG 16-bit ou en RAW 16-bit, et exportez les splat maps en PNG.

Peinture

  • 16 calques de sol par tileset, peints dans quatre splat maps RGBA. Par défaut, chaque cellule compte 4 texels de splat (vous pouvez choisir de 1 à 8), si bien que les bordures peintes sont bien plus fines que la grille des cellules.
  • Outils de peinture : Paint Layer (pinceau doux), Tile Paint (peinture à bords nets, alignée sur les cellules, dans le style des RTS classiques), Fill / Replace, Smooth Paint et Auto Paint.
  • La fonction Auto Paint peint selon des règles stockées dans un asset RTSAutoPaintProfile. Une règle peut porter sur la hauteur, la pente, le niveau de falaise, la distance aux falaises, la distance à l’eau et le bruit. Utilisez l’outil Auto Paint comme un pinceau, ou laissez le générateur de cartes appliquer un profil à toute la carte.
  • Fondu par hauteur entre les calques, anti-tiling par calque, macro-variation à l’échelle du tileset, ainsi que teinte, lissage, métallicité et intensité des normales réglables pour chaque calque.
  • Un calque peut modifier le cheminement là où il domine. Par exemple, les tilesets de démo rendent les calques Rock et Blight non constructibles, comme les tuiles non constructibles des RTS classiques.
  • Pinceaux : Circle, Square, Diamond, ou Custom avec n’importe quelle texture comme tampon (assets RTSBrushShape). Vous pouvez régler le rayon, l’intensité, la dureté, une courbe d’atténuation facultative, la rotation, la rotation aléatoire, l’espacement et le décalage aléatoire.
  • Peinture symétrique pour des cartes compétitives équitables : Mirror X, Mirror Z, Mirror XZ, Rotate 2 (symétrie centrale, 180°), Rotate 4 (90°, cartes carrées uniquement) et Mirror Diagonal (cartes carrées uniquement). La symétrie fonctionne avec tous les outils, y compris le placement d’objets.

Végétation

  • Des détails comme l’herbe, les fleurs et les petites plantes, peints sous forme de densité par couche, dessinés sur le GPU en tant que meshes ou quads croisés et animés par le vent.
  • Des arbres placés un par un ou dispersés au pinceau. Un arbre peut être dessiné par instanciation GPU (avec un proxy de collider facultatif) ou apparaître sous forme de GameObject pour les besoins du gameplay, comme la récolte de bois.
  • Les arbres bloquent automatiquement le cheminement grâce à leur emprise.
  • Outils de végétation : Paint Details, Erase Details, Place Trees, Erase Trees.
  • Le shader RTS Terrain Studio/Vegetation ajoute le vent, la translucidité et une teinte propre à chaque instance. Tout autre matériau utilisant l’instanciation GPU fonctionne aussi.
  • Paramètres de qualité sur RTSVegetationRenderer : multiplicateurs de densité de détails, de distance d’affichage des détails et de distance d’affichage des arbres.

Eau

  • Une hauteur d’eau par vertex, pour que des lacs puissent se trouver à des hauteurs différentes. L’eau est dessinée sous forme de meshes transparents découpés en chunks, construits par des jobs Burst.
  • L’eau peu profonde et l’eau profonde se distinguent par la profondeur (WaterProfile.shallowDepthLimit). L’eau peu profonde est praticable, l’eau profonde ne l’est pas, comme dans les RTS classiques.
  • Le shader RTS Terrain Studio/Water propose une couleur selon la profondeur, des normales défilantes, des vagues, la réfraction, ainsi que de l’écume et un fondu doux sur le rivage. Le style provient du WaterProfile du tileset.
  • Outils d’eau : Paint Water, Erase Water, Flood Fill.

Décor (doodads)

  • N’importe quel prefab peut servir de décor. Les prototypes se trouvent dans une bibliothèque RTSDecorLibrary, avec des miniatures générées automatiquement.
  • Chaque prototype apparaît sous forme de GameObject (pour les objets avec lesquels le gameplay interagit) ou est dessiné par instanciation GPU (pour les accessoires statiques en grand nombre).
  • Rotation, échelle et teinte aléatoires, alignement sur la pente, magnétisme de grille et emprise de cheminement (cercle ou boîte).
  • Outils de décor : Place Decor (placement unique ou dispersé), Erase Decor, Select Decor (déplacer, faire pivoter, mettre à l’échelle, dupliquer, supprimer).

Cheminement et recherche de chemin

  • Une carte de cheminement déduite automatiquement et tenue à jour pendant que vous éditez. Elle tient compte des falaises, de la pente, de la profondeur d’eau, de l’emprise des arbres et des décors, ainsi que des règles des calques de sol.
  • Outils de cheminement : Paint Pathing (surcharges comme non praticable, non constructible ou praticable forcé) et Clear Pathing. Les superpositions de cheminement des éditeurs affichent le résultat.
  • Un module de recherche de chemin intégré (RTSPathfinder) : A* compilé avec Burst sur la grille de cheminement, à 8 voisins, sans couper les angles, avec prise en compte du rayon des unités (dégagement) et lissage des chemins. Il ne nécessite aucun package tiers.
  • Requêtes de chemin asynchrones pour de nombreuses unités via RTSPathfindingService.

Brouillard de guerre

  • Règles des RTS classiques : chaque équipe a sa propre visibilité, et les zones explorées sont mémorisées. Par défaut, une unité ne voit que son propre niveau de falaise et les niveaux inférieurs. Les arbres et les décors peuvent aussi bloquer la vue (LineOfSightMode et l’option blocksVision d’un prototype).
  • Jusqu’à 32 équipes, vision partagée entre alliés (RTSFogOfWarManager.SetAlliance), une texture de brouillard de guerre lisse et floutée, et la prise en charge de la mini-carte.
  • Une renderer feature URP (RTSFogOfWarRendererFeature) assombrit tout ce qui s’affiche à l’écran, quel que soit le matériau utilisé. En l’absence de cette renderer feature, les shaders du package appliquent eux-mêmes le brouillard de guerre.
  • Les unités dotées de RTSFogOfWarRevealer révèlent la carte, et les objets dotés de RTSFogOfWarHideable sont masqués tant qu’ils ne sont pas visibles. Les bâtiments et les accessoires peuvent rester visibles sous forme de « fantômes » une fois découverts.
  • La visibilité est calculée par des jobs Burst.

Éditeur en jeu

  • Ajoutez-le avec GameObject ▸ RTS Terrain Studio ▸ In-Game Editor. Il s’agit d’une interface UI Toolkit comprenant une barre de menus, des barres de catégories et d’outils, un panneau d’outil avec palettes et miniatures, une barre d’état, des info-bulles et des notifications.
  • Commandes New, Open, Save et Save As, avec un explorateur de cartes. Par défaut, les cartes sont enregistrées sous Application.persistentDataPath et, dans les builds web, dans le stockage du navigateur ; les commandes Download et Import permettent alors de les transférer entre le navigateur et votre ordinateur. Vous pouvez aussi générer une carte, en modifier les informations et la redimensionner.
  • Annulation et rétablissement avec un budget mémoire, raccourcis clavier, symétrie, et superpositions de grille, de cheminement et de marqueurs.
  • Un test en jeu qui s’active et se désactive avec F5 : il lance le gameplay d’exemple sur la carte en cours d’édition, puis vous ramène à l’éditeur.
  • Sa propre caméra d’éditeur (RTSRuntimeEditorCamera) et ses propres gizmos, sans aucune dépendance à l’API UnityEditor : il fonctionne donc dans les builds de joueur.

Générateur de cartes

  • Un générateur procédural basé sur une graine (RTSMapGenerator), avec les préréglages de style Plains, Hills, Highlands, Islands, Canyon et Arena.
  • Il prend en charge les plateaux et les falaises, les rampes (avec vérification de la connectivité), les lacs et les mers, la bordure de la carte, la peinture automatique, les détails, les forêts, les décors et les positions de départ, dans n’importe quel mode de symétrie.
  • La même graine donne toujours la même carte. Vous pouvez enregistrer les paramètres sous forme d’assets RTSMapGeneratorPreset.
  • Vous pouvez le lancer depuis le New Map Wizard, la fenêtre de l’éditeur, l’éditeur en jeu ou votre propre code.

Gameplay d’exemple

  • Une caméra RTS (panoramique, défilement par les bords, zoom, rotation, limites de la carte), la sélection d’unités (clic, rectangle, Shift, double-clic, groupes de contrôle) et des ordres (déplacement en formation, file d’ordres, arrêt, maintien de position, patrouille).
  • Des unités de substitution qui suivent la hauteur du terrain, dissipent le brouillard de guerre et utilisent n’importe quel fournisseur de chemins.
  • Une mini-carte sur laquelle un clic déplace la caméra, un HUD, une démo de placement de bâtiments qui respecte l’indicateur de constructibilité, et une démo de récolte d’arbres.
  • RTSDemoGame met tout cela en place sur n’importe quel terrain doté de positions de départ. Ajoutez-le avec GameObject ▸ RTS Terrain Studio ▸ Demo Game.

Intégrations

Elles sont facultatives. Chacune n’est compilée que si sa dépendance est installée : supprimer la dépendance ne casse donc jamais votre projet.

IntégrationCe qu’elle apporte
Mirror (multijoueur)L’hôte transmet sa carte en streaming aux clients qui le rejoignent, ce qui permet de jouer en ligne sur des cartes créées par les joueurs, et les cartes téléchargées sont mises en cache. Le serveur fait autorité sur les unités, chaque client a le brouillard de guerre de sa propre équipe, et RTSFogOfWarInterestManagement n’envoie jamais les ennemis cachés par le brouillard de guerre (protection anti-maphack).
A* Pathfinding ProjectDes graphes en grille générés à partir de la carte de cheminement RTS et mis à jour de façon incrémentale après chaque modification, un graphe par taille d’unité, et des unités déplacées par AIPath avec évitement local RVO.
Unity AI Navigation (NavMesh)Un NavMesh construit à partir des chunks du terrain et de la carte de cheminement, mis à jour de façon incrémentale après les modifications, et un fournisseur de chemins qui renvoie des chemins NavMesh ou pilote des composants NavMeshAgent.

Flux de travail dans l’éditeur

  • Une seule fenêtre RTS Terrain Studio ancrable, avec des onglets pour les 8 catégories d’outils, ainsi que Map et Settings. Elle propose de grands boutons d’outils avec icônes, des paramètres contextuels, des palettes avec miniatures et une barre d’état.
  • Intégration à la Scene View. Le pinceau est dessiné par le shader de terrain et projeté sur le terrain. S’y ajoutent des superpositions de grille et de cheminement, des repères de symétrie et des raccourcis : [ / ] taille du pinceau, - / = intensité, 1–8 catégories d’outils, G grille, P superposition de cheminement et R rotation aléatoire. Vous pouvez les réaffecter dans Edit ▸ Shortcuts... (sous macOS, Unity ▸ Shortcuts...).
  • Les modifications de la carte font partie de l’historique d’annulation de Unity : Ctrl+Z et Ctrl+Y fonctionnent donc comme d’habitude et affichent le nom des étapes. Le budget mémoire d’annulation est configurable.
  • Des inspecteurs personnalisés pour les tilesets (calques en glisser-déposer, aperçus, construction automatique des tableaux de textures), les bibliothèques de végétation et de décors, les formes de pinceau, les profils de peinture automatique et le composant RTSTerrain. L’importeur .rtsmap affiche un aperçu de la mini-carte.
  • Une fenêtre Welcome, un New Map Wizard et un validateur de projet avec corrections en un clic.

Performances

  • Les meshes du terrain sont découpés en chunks de 16, 32 (par défaut) ou 64 cellules. Ils sont construits avec Mesh.MeshDataArray dans des jobs Burst, et seuls les chunks que vous modifiez sont reconstruits.
  • Les traitements lourds s’exécutent dans des jobs compilés avec Burst (Unity Jobs System) : opérations de pinceau, génération des meshes, calcul du cheminement, dégagement, A*, brouillard de guerre, instances de végétation, meshes d’eau, générateur de cartes, peinture automatique et précalcul de la mini-carte.
  • Les détails sont dessinés de façon procédurale avec Graphics.RenderMeshPrimitives. Les arbres et les décors instanciés utilisent Graphics.RenderMeshInstanced. Tous font l’objet d’un culling par patch, selon le frustum et la distance.
  • Les shaders sont compatibles avec le SRP Batcher, et un seul matériau de terrain est partagé par tous les chunks.
  • Les tableaux de textures sont compressés pour la plateforme active (BC7, ASTC 6×6, ETC2 ou DXT5) à la résolution de votre choix (256–2048).
  • Aucune allocation générant du garbage à chaque frame dans les chemins critiques, et toute la mémoire native est libérée quand les composants sont désactivés.

Les choix de conception en un coup d’œil

Voici les questions que l’on pose le plus souvent sur les outils de terrain pour RTS, et les réponses qu’y apporte RTS Terrain Studio.

QuestionRéponse
Combien de textures de sol une carte peut-elle utiliser ? 16 calques de sol et 4 types de falaise par tileset, et vous pouvez créer autant de tilesets que vous le souhaitez. Cette limite a une raison technique : 16 calques tiennent exactement dans 4 splat maps RGBA (un canal par calque), et les 16 calques de sol et les 4 calques de falaise sont regroupés dans deux tableaux de textures (albédo/hauteur et normales, 20 tranches chacun), si bien qu’un seul matériau de terrain assure le rendu de tous les chunks.
Le terrain a-t-il des colliders ? Puis-je l’interroger sans passer par la physique ? Oui, dans les deux cas. Chaque chunk peut recevoir un MeshCollider sur un layer de votre choix (RTSTerrainSettings.colliderMode). L’API de requête (GetHeight, GetNormal, Raycast, GetCliffLevel, IsWater, TryGetWaterHeight, GetPathing, IsWalkable, IsBuildable) n’utilise pas du tout la physique. Elle fonctionne en Edit Mode, à l’exécution et avec les colliders désactivés, et elle renvoie exactement la surface que vous voyez.
Puis-je construire de grands mondes à partir de plusieurs cartes ? Oui. Une scène peut contenir autant de composants RTSTerrain que vous le voulez, chacun avec sa propre position et sa propre rotation autour de l’axe Y. RTSTerrain.All, RTSTerrain.FindAt et RTSTerrain.RaycastAll fonctionnent sur l’ensemble de ces terrains. Grâce au rendu par chunks, des cartes de 512×512 cellules restent tout à fait exploitables.
Le pinceau agit-il bien sous le curseur, même avec une mise à l’échelle de l’affichage ? Oui. L’éditeur Unity utilise HandleUtility.GUIPointToWorldRay, qui gère correctement la mise à l’échelle DPI, et l’éditeur en jeu utilise Camera.ScreenPointToRay avec la position du pointeur fournie par l’Input System. Le curseur du pinceau est dessiné par le shader de terrain et projeté sur la surface : ce que vous voyez correspond donc exactement à l’endroit où vous peignez.
Quels formats et quelles tailles de texture puis-je utiliser ? Des textures Unity ordinaires, de n’importe quelle taille et de n’importe quel format. L’Inspector du tileset les redimensionne et les regroupe pour vous dans des tableaux Texture2DArray (de 256 à 2048 pixels par tranche, compressés ou non). La disposition des canaux est documentée : albédo en RGB avec une hauteur facultative dans le canal alpha ou dans une texture de hauteur séparée, plus une normal map.
Dois-je placer le package dans un dossier précis ? Non. L’éditeur trouve la racine du package grâce à la définition d’assembly de son code d’exécution : vous pouvez donc déplacer RTSTerrainStudio n’importe où sous Assets (par exemple Assets/Plugins/RTSTerrainStudio).
Puis-je modifier la taille de la carte plus tard ? Oui. Choisissez n’importe quelle taille dans le New Map Wizard : vous pourrez ensuite agrandir ou réduire la carte avec la commande Resize. Vous choisissez une ancre qui détermine de quels côtés les cellules sont ajoutées ou supprimées.
Puis-je lire et modifier le code ? Oui. Le code est réparti en définitions d’assembly, chacune avec un seul espace de noms. L’API publique dispose d’une documentation XML, le code interne est commenté, les jobs Burst se trouvent dans des fichiers *Jobs.cs séparés, et des tests unitaires EditMode sont fournis.

Premier aperçu de l’API

Pour donner aux programmeurs une idée de l’API, voici un script complet. Il interroge le terrain sur le point où vous cliquez et calcule un chemin jusqu’à ce point avec le module de recherche de chemin intégré. Il ne nécessite ni colliders ni composants supplémentaires : placez-le sur n’importe quel GameObject d’une scène qui contient un RTSTerrain.

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

/// <summary>Click on the ground: logs what the terrain knows about that point and plans a path to it.</summary>
public class ClickInfoExample : MonoBehaviour
{
    // Reused for every click, so no new list is allocated each time.
    readonly List<Vector3> path = new List<Vector3>();

    void Update()
    {
        // RTSInput works with the Input System package and with the old Input Manager.
        if (!RTSInput.GetMouseButtonDown(0) || Camera.main == null) return;

        Ray ray = Camera.main.ScreenPointToRay(RTSInput.PointerPosition);

        // Analytic ray cast against every RTSTerrain in the scene. Colliders are not needed.
        if (!RTSTerrain.RaycastAll(ray, out RTSTerrainHit hit)) return;
        RTSTerrain terrain = hit.terrain;

        // Gameplay questions, answered from the map data and the pathing map.
        int level = terrain.GetCliffLevel(hit.point);
        bool buildable = terrain.IsBuildable(hit.point);
        bool water = terrain.IsWater(hit.point, out float depth);
        Debug.Log($"Cell {hit.cell}: cliff level {level}, buildable {buildable}, water {water} ({depth:0.00} m)");

        // Built-in Burst A* on the pathing map, for a unit with a radius of 0.6 m.
        PathStatus status = RTSPathfinder.FindPath(terrain, transform.position, hit.point,
                                                   PathRequestOptions.ForUnit(0.6f), path);
        Debug.Log($"Path from {name}: {status}, {path.Count} waypoints");
    }
}

PathStatus vaut Success, Partial (jusqu’au point accessible le plus proche), NoPath ou InvalidStart. Le chapitre Guide de programmation présente l’ensemble de l’API.

Configuration requise

Unity et pipeline de rendu

ExigenceVersionRemarques
Unity6.3 LTS (6000.3) ou plus récentDéveloppé et testé avec 6000.3.3f1.
Universal Render Pipeline17.3 (la version fournie avec Unity 6.3)Un asset URP doit être actif dans les paramètres Graphics et Quality. Développé avec le chemin de rendu Forward+. Le shader de terrain dispose aussi d’une passe GBuffer pour le chemin de rendu Deferred.
Espace colorimétriqueLinearL’espace Gamma fonctionne, mais les couleurs, l’éclairage et l’eau paraissent alors délavés.
Matériel graphiqueShader Model 3.5 ou supérieurLes shaders de terrain, de végétation, de détails et d’eau ciblent #pragma target 3.5 : ils fonctionnent donc aussi sous WebGL 2.0 et OpenGL ES 3.0. Seules la passe GBuffer du terrain (chemin de rendu Deferred) et la variante du shader de détails basée sur les structured buffers utilisent le Shader Model 4.5, lorsque le GPU le prend en charge.

Le Built-in Render Pipeline et HDRP ne sont pas pris en charge. Tous les shaders sont écrits pour URP, et la renderer feature du brouillard de guerre utilise l’API RenderGraph d’URP.

Package importé dans un projet sans URP ? Le package reste alors inactif au lieu de remplir la fenêtre Console d’erreurs : ses scripts ne sont pas compilés, ses shaders sont ignorés et votre projet continue de fonctionner comme avant. Une fois par session de l’éditeur, la boîte de dialogue RTS Terrain Studio requires URP vous indique la marche à suivre :

  • Built-in Render Pipeline : cliquez sur Install URP. Une fois le package compilé par Unity, ouvrez Tools ▸ RTS Terrain Studio ▸ Validate Project et cliquez sur Use URP : ce bouton crée un asset URP et l’assigne dans les paramètres Graphics et Quality.
  • URP antérieur à la version 17.3 : cliquez sur Open Package Manager et mettez à jour le package Universal Render Pipeline vers la version fournie avec votre éditeur.
  • Unity antérieur à la version 6.3 : URP 17.3 nécessitant Unity 6.3 LTS, la boîte de dialogue ne propose que Open Manual et Later. Ouvrez le projet avec Unity 6.3 LTS ou une version plus récente.
  • HDRP ou pipeline de rendu personnalisé : importez plutôt le package dans un projet URP, par exemple un nouveau projet créé à partir du modèle Universal 3D.

Le menu Tools ▸ RTS Terrain Studio ▸ Set Up Universal Render Pipeline... affiche de nouveau la boîte de dialogue. Unity peut aussi consigner des avertissements indiquant que les shaders du package ne sont pas pris en charge ; ils disparaissent dès qu’URP est installé.

Packages requis

Ces packages proviennent du Unity Registry (Window ▸ Package Manager ▸ Unity Registry). La fenêtre Tools ▸ RTS Terrain Studio ▸ Validate Project détecte les packages manquants et les installe en un clic (vérification Burst, Collections and Mathematics).

PackageNomVersion testéeSert à
Burstcom.unity.burst1.8.27Compiler les jobs en code natif rapide.
Collectionscom.unity.collections2.6.2Fournir des conteneurs natifs pour les données de carte et les jobs.
Mathematicscom.unity.mathematics1.3.3Effectuer les calculs vectoriels dans les jobs et le modèle de données.
Universal RPcom.unity.render-pipelines.universal17.3.0Assurer le rendu.

Gestion des entrées

Toutes les entrées à l’exécution passent par la classe statique RTSInput. Elle prend en charge les deux systèmes d’entrée :

  • Package Input System (com.unity.inputsystem, testé avec 1.17.0). Il est utilisé lorsque le package est installé et que le paramètre Active Input Handling est réglé sur Input System Package (new) ou Both.
  • Input Manager (old). Il sert de solution de repli lorsque le projet utilise l’ancienne gestion des entrées.

Ce paramètre se trouve dans Edit ▸ Project Settings ▸ Player ▸ Other Settings ▸ Active Input Handling. La vérification Input handling du Project Validator indique quel mode est actif ; voir Gestion des entrées dans le chapitre Configuration du projet.

Packages optionnels pour les intégrations

IntégrationDépendanceVersionDétection
MirrorMirror (Asset Store ou GitHub)96 ou plus récentSymbole de définition MIRROR, que Mirror ajoute lui-même.
A* Pathfinding Projectcom.arongranberg.astarPro 5.4.4 jusqu’à 6.0 (exclue), testé avec 5.4.7Symbole RTS_ASTAR défini par les Version Defines. Ajoutez RTS_ASTAR_DISABLED pour désactiver l’intégration (nécessaire avec la version gratuite, qui utilise le même nom de package).
Unity NavMeshAI Navigation, com.unity.ai.navigation2.0 ou plus récent, testé avec 2.0.9Symbole RTS_AI_NAVIGATION défini par les Version Defines.

Les intégrations de recherche de chemin nécessitent la version Pro d’A* Pathfinding Project, car l’intégration utilise l’évitement local RVO et TraversalConstraint. Avant de supprimer Mirror, consultez la section Supprimer Mirror : Mirror laisse derrière lui ses symboles de définition, et RTS Terrain Studio contient une petite assembly d’éditeur qui les supprime.

Paramètres de projet recommandés

Le Project Validator vérifie tous ces points et peut les corriger pour vous :

ParamètrePourquoi
Asset URP actifLes shaders du package ne s’affichent qu’avec URP.
Options Depth Texture et Opaque Texture activées sur l’asset URPL’eau utilise la texture de profondeur pour que sa couleur de profondeur, son écume et le fondu de son rivage tiennent compte des objets qui se trouvent dans l’eau, et la texture opaque pour la réfraction. Le réglage propre à une caméra prime sur celui de l’asset, et l’eau respecte le réglage de chaque caméra. Les caméras de démo activent elles-mêmes ces deux options : les scènes de démo s’affichent donc correctement dans la Game View même sans ce paramètre (la Scene View utilise toujours l’asset URP).
Renderer feature du brouillard de guerre sur le rendererAssombrit tout ce qui se trouve dans le brouillard de guerre, y compris vos propres matériaux. Sans elle, seuls les shaders du package affichent le brouillard de guerre.
Modes de brouillard atmosphérique conservés dans les builds de joueurUnity supprime les variantes de shader du brouillard atmosphérique qu’aucune scène du build n’utilise, alors que RTSEnvironment active ce brouillard à l’exécution. Si ces modes ne sont pas conservés, les cartes dotées d’un brouillard atmosphérique n’en affichent aucun dans les builds.
Espace colorimétrique LinearPour obtenir des couleurs et un éclairage corrects.
Références de shaders et tableaux de textures des tilesets à jourLes shaders et les tableaux compressés sont ainsi inclus dans les builds de joueur. Avant chaque build de joueur, l’asset de références de shaders est en outre actualisé et les tableaux de textures obsolètes sont reconstruits automatiquement.

Plateformes

Le code d’exécution n’a aucune dépendance réservée à l’éditeur : les cartes se chargent, s’affichent et peuvent être modifiées dans les builds de joueur sur toutes les plateformes qu’URP prend en charge, y compris les builds Web (WebGL 2.0). Les shaders ciblent le Shader Model 3.5, le niveau le plus bas qui prend en charge les tableaux de textures. La passe GBuffer du terrain pour le chemin de rendu Deferred nécessite le Shader Model 4.5 et est ignorée sur les API basées sur OpenGL, tout comme la passe GBuffer du shader Lit fourni avec URP. Le stockage des instances de l’herbe (détails) est choisi à l’exécution : des structured buffers lorsque le GPU les prend en charge, et une texture à virgule flottante sous WebGL 2.0 et OpenGL ES 3 (le rendu est identique).

Le module de précalcul des tableaux de textures choisit la compression selon la cible de build active : BC7 pour les ordinateurs de bureau et les consoles, ASTC 6×6 pour Android, iOS, tvOS et visionOS, la compression de textures définie dans les paramètres du build pour le Web (DXT5, ASTC 6×6 ou ETC2), et DXT5 pour tout le reste. L’éditeur en jeu fonctionne sur toutes les plateformes et il est conçu pour être utilisé à la souris et au clavier. Ses commandes pour afficher le dossier des cartes et pour quitter l’application n’apparaissent que sur les plateformes qui les prennent en charge : seuls les builds pour ordinateur de bureau et l’éditeur peuvent afficher des dossiers, et WebGL, iOS et Android ne permettent pas de quitter l’application. Les builds Web présentent quelques autres différences ; consultez Builds Web (WebGL).

Arborescence des dossiers

Le package se trouve dans un seul dossier, par défaut Assets/RTSTerrainStudio. Vous pouvez déplacer ou renommer ce dossier : l’éditeur trouve la racine du package grâce à l’emplacement de RTSTerrainStudio.Runtime.asmdef, et le contenu de démo ainsi que la documentation sont retrouvés à partir de celle-ci.

RTSTerrainStudio/
├── Runtime/                 Core, rendering, tools and runtime systems (RTSTerrainStudio.Runtime)
├── Editor/                  Editor window, Scene View, inspectors, setup, demo content (RTSTerrainStudio.Editor)
├── Shaders/                 URP shaders and HLSL includes
│   ├── Hidden/              Internal shaders (fog blur, minimap fog, gizmos, texture array blit)
│   └── Include/             Shared HLSL (fog of war, brush cursor, wind, terrain, vegetation, water)
├── Samples/
│   ├── Scripts/             Sample gameplay: camera, units, selection, orders, minimap, HUD (RTSTerrainStudio.Samples)
│   └── Scenes/              Demo scenes (created by Create Demo Content)
├── Integrations/
│   ├── Mirror/              Multiplayer (compiled only with Mirror)
│   ├── AStarPathfinding/    A* Pathfinding Project (compiled only with A* Pro 5.4.4+)
│   └── UnityNavMesh/        Unity AI Navigation (compiled only with com.unity.ai.navigation 2.0+)
├── Content/                 Generated demo content (empty until you run Create Demo Content)
├── Resources/
│   └── RTSTerrainStudio/    Runtime UI style sheets and theme, shader references, panel settings
├── Documentation/           This manual (index.html) and its images
└── Tests/
    └── Editor/              EditMode unit tests (RTSTerrainStudio.Tests.Editor)

Dossiers de premier niveau

DossierContenuPuis-je le supprimer ?
RuntimeTout ce qui s’exécute dans un jeu : le composant RTSTerrain, les données de carte, le rendu, tous les outils d’édition, la végétation, l’eau, les décors, le brouillard de guerre, le cheminement, la génération, l’éditeur en jeu, les icônes et les entrées.Non.
EditorUniquement des fonctionnalités de l’éditeur Unity. Rien de ce dossier n’est inclus dans les builds de joueur.Non.
ShadersRTS Terrain Studio/Terrain, RTS Terrain Studio/Vegetation, RTS Terrain Studio/Water, Hidden/RTS Terrain Studio/Detail, Hidden/RTS Terrain Studio/FogOfWarFullscreen, les shaders internes dans Hidden et les includes HLSL dans Include (RTSCommon.hlsl contient les variables globales du brouillard de guerre, du curseur de pinceau et du vent).Non.
SamplesLes scripts de gameplay d’exemple et les scènes de démo. L’assembly de l’éditeur et les intégrations référencent l’assembly des exemples (par exemple pour RTSUnit et RTSDemoGame).Uniquement en même temps que les intégrations. Les scènes peuvent être supprimées à tout moment.
IntegrationsUn dossier par intégration tierce, chacun avec ses propres assemblies, un README.md et un dossier Editor contenant les générateurs de scènes de démo. Les scènes de démo sont créées dans un sous-dossier Demo.Oui, chaque dossier d’intégration séparément. Lisez d’abord les étapes concernant Mirror.
ContentContenu de démo : textures, matériaux, meshes, prefabs, tilesets, bibliothèques, formes de pinceau, cartes et paramètres de rendu. Tout ce qui se trouve ici est généré.Oui, vous pouvez le régénérer à tout moment. Vos propres cartes ne doivent alors pas l’utiliser.
Resources/RTSTerrainStudioUI/RTSRuntimeEditor.uss et UI/RTSRuntimeTheme.tss (style de l’interface en jeu). L’asset de références de shaders (créé et actualisé automatiquement par l’éditeur) et UI/RTSRuntimePanelSettings.asset (créé par Create Demo Content) y sont ajoutés. Ils garantissent que les shaders du package et les shaders d’exécution d’UI Toolkit sont inclus dans les builds.Non.
DocumentationCe manuel. Tools ▸ RTS Terrain Studio ▸ Documentation et chaque bouton ? l’ouvrent.Oui, mais les boutons d’aide n’ont alors plus rien à ouvrir.
TestsTests EditMode pour les données de carte, la géométrie, les pinceaux, la symétrie, l’annulation, le sérialiseur, le cheminement, le générateur, les requêtes de terrain, le registre d’outils et les icônes. Exécutez-les dans Window ▸ General ▸ Test Runner.Oui.

Contenu du dossier Runtime

DossierContenu
CoreRTSTerrain (composant principal, cycle de vie de la carte, suivi des modifications, requêtes), MapData, MapTypes, MapGeometryView (la surface de référence utilisée par les meshes, les requêtes et le cheminement), PathingMap, RTSTerrainSettings, les identifiants des propriétés de shader, RTSShaderReferences, RTSRuntimeEditorEvents.
DataTypes d’assets : RTSTileset, RTSVegetationLibrary, RTSDecorLibrary, RTSMapAsset.
SerializationRTSMapSerializer : le format binaire .rtsmap (sections, compression deflate) et les entrées/sorties de fichiers.
BrushesBrushSettings, RTSBrushShape, SymmetrySettings, BrushUtility.
ToolsRTSTool (classe de base), RTSEditSession, MapUndo et un sous-dossier par catégorie : Height, Cliffs, Paint, Vegetation, Decor, Water, Pathing, Markers.
MeshLa génération de la géométrie des chunks et ses jobs Burst.
RenderingLa partie rendu de RTSTerrain, RTSTerrainChunk, les textures de splat, les données de calques et RTSTextureArrayBuilder.
VegetationRTSVegetationRenderer, RTSTreeInstance.
WaterRTSWaterRenderer, RTSWaterChunk, les jobs de mesh de l’eau.
DecorRTSDecorManager, RTSDecorInstance.
FogOfWarRTSFogOfWarManager, RTSFogOfWarRevealer, RTSFogOfWarHideable, RTSFogOfWarRendererFeature.
PathingLa partie cheminement de RTSTerrain, RTSPathingSettings, PathingMapBuilder, ClearanceMap, RTSPathfinder, RTSPathfindingService, les superpositions de cheminement.
GenerationRTSMapGenerator, MapGeneratorSettings, RTSMapGeneratorPreset, RTSAutoPaintProfile, RTSAutoPaint, HeightmapIO et l’outil Auto Paint.
MinimapRTSMinimapBaker.
EnvironmentRTSEnvironment (applique le soleil, la lumière ambiante et le brouillard atmosphérique de la carte).
ValidationMapValidator (recherche les problèmes d’une carte, comme des positions de départ inaccessibles).
RuntimeEditorL’éditeur en jeu : RTSRuntimeEditor, RTSRuntimeEditorCamera, RuntimeToolGizmos et son interface UI Toolkit.
InputRTSInput et RTSKey.
UIRTSIcons : des icônes procédurales partagées par l’éditeur et l’interface en jeu.
Plugins/WebGLPlugins JavaScript (.jslib) utilisés uniquement par les builds Web : stockage dans le navigateur, téléchargements, imports et avertissement avant de quitter la page (RTSWebFileSystem.jslib), dispositions de clavier et raccourcis du navigateur (RTSWebKeyboard.jslib), et sortie du pointeur hors de la page (RTSPointer.jslib).
link.xmlConserve les outils d’édition dans les builds avec élagage du code (voir Élagage du code et outils personnalisés).

Contenu du dossier Editor

DossierContenu
CoreRTSEditorContext (la session d’édition partagée et les options d’affichage), RTSEditorPaths, la persistance des paramètres des outils.
WindowLa fenêtre RTS Terrain Studio (RTSTerrainStudioWindow) et ses pages.
SceneViewLa peinture dans la Scene View, le dessin du pinceau et des gizmos, les overlays, les raccourcis et le pont vers le système d’annulation de Unity.
InspectorsLes inspectors du tileset, des bibliothèques, des formes de pinceau, des profils de peinture automatique et des composants.
ImportersL’importeur de fichiers .rtsmap, son aperçu et l’entrée de menu Assets ▸ Create ▸ RTS Terrain Studio ▸ Map (.rtsmap).
BuildingLe module de précalcul des tableaux de textures compressés, la vérification qui reconstruit les tableaux de textures obsolètes avant les builds de joueur, le générateur de miniatures et la fabrique d’assets.
SetupLa fenêtre Welcome, le New Map Wizard, le Project Validator, le menu de création GameObject, l’outil de mise à jour des références de shaders, ainsi que le modèle Web (WebGLTemplate) et son outil d’installation.
RequirementsLe message d’information affiché lorsque le projet ne dispose pas d’URP 17.3 (voir Unity et pipeline de rendu). Hormis le nettoyage des symboles de définition Mirror, c’est la seule partie du package qui se compile sans URP.
RuntimeEditorSupportLe menu GameObject ▸ RTS Terrain Studio ▸ In-Game Editor.
DemoContentLe générateur procédural de contenu de démo (RTSDemoContent).

Assemblies

Le code est réparti en définitions d’assembly : il se compile ainsi rapidement, et les parties optionnelles peuvent être supprimées. Chaque assembly possède un seul espace de noms.

Assembly (asmdef)DossierEspace de nomsPlateformesCompilée quand
RTSTerrainStudio.RuntimeRuntimeRTSTerrainStudioToutesURP 17.3 ou plus récent est installé (RTS_URP). Définit RTS_INPUT_SYSTEM lorsque le package Input System est installé.
RTSTerrainStudio.SamplesSamples/ScriptsRTSTerrainStudio.SamplesToutesURP 17.3 ou plus récent est installé.
RTSTerrainStudio.EditorEditorRTSTerrainStudio.EditorÉditeurURP 17.3 ou plus récent est installé.
RTSTerrainStudio.Requirements.EditorEditor/RequirementsRTSTerrainStudio.RequirementsÉditeurUniquement tant qu’URP 17.3 ou plus récent est absent. Elle affiche le message d’information indiquant que le package nécessite URP.
RTSTerrainStudio.Tests.EditorTests/EditorRTSTerrainStudio.TestsÉditeurUNITY_INCLUDE_TESTS est défini (Unity Test Framework).
RTSTerrainStudio.Integrations.Mirror
RTSTerrainStudio.Integrations.Mirror.Editor
Integrations/MirrorRTSTerrainStudio.Integrations.MirrorToutes / ÉditeurMIRROR est défini.
RTSTerrainStudio.Integrations.Mirror.DefineCleanup.EditorIntegrations/Mirror/Editor/DefineCleanupRTSTerrainStudio.Integrations.MirrorÉditeurToujours. Elle ne dépend pas de Mirror et retire les symboles de définition Mirror obsolètes une fois Mirror supprimé.
RTSTerrainStudio.Integrations.AStar
RTSTerrainStudio.Integrations.AStar.Editor
Integrations/AStarPathfindingRTSTerrainStudio.Integrations.AStarToutes / ÉditeurRTS_ASTAR est défini (A* installé, version 5.4.4 ou plus mais inférieure à 6.0) et RTS_ASTAR_DISABLED ne l’est pas.
RTSTerrainStudio.Integrations.NavMesh
RTSTerrainStudio.Integrations.NavMesh.Editor
Integrations/UnityNavMeshRTSTerrainStudio.Integrations.NavMeshToutes / ÉditeurRTS_AI_NAVIGATION est défini (AI Navigation 2.0 ou plus récent installé).

Les assemblies de test et d’intégration nécessitent elles aussi URP 17.3 ou plus récent, en plus de la condition indiquée. Sans URP, seuls le nettoyage des symboles de définition Mirror et le message d’information sur la configuration requise sont compilés : le package ne provoque donc aucune erreur de compilation.

RTSTerrainStudio.Runtime, RTSTerrainStudio.Samples et RTSTerrainStudio.Editor sont référencées automatiquement. Les scripts de l’assembly par défaut de votre projet (Assembly-CSharp) peuvent les utiliser sans aucune configuration. Si votre code possède sa propre définition d’assembly, ajoutez une référence à RTSTerrainStudio.Runtime (et à RTSTerrainStudio.Samples si vous utilisez les classes de gameplay d’exemple).

L’éditeur en jeu se trouve dans Runtime/RuntimeEditor. Si votre jeu n’en a pas besoin, vous pouvez supprimer ce dossier : les outils de l’éditeur Unity et le générateur de contenu de démo continuent de compiler, et la scène In-Game Editor Demo est alors créée sans éditeur en jeu.

Contenu du package

Le package est livré sous forme de code source, de shaders et de ce manuel. Tout le contenu visuel (textures, modèles, tilesets, cartes et scènes) est généré sur votre machine par un script. Le téléchargement reste ainsi léger, et le contenu est soumis exactement à la même licence que le code.

Générateur de contenu de démo

La commande Tools ▸ RTS Terrain Studio ▸ Create Demo Content exécute RTSDemoContent.CreateAll. Elle génère tous les assets de démo de façon procédurale, avec des graines fixes, de sorte que chaque exécution produit le même résultat :

  • Elle n’écrit que dans ses propres dossiers : Content, Samples/Scenes et deux assets dans Resources/RTSTerrainStudio. Elle ne touche jamais à vos propres assets.
  • Si vous la relancez, elle régénère les assets sur place, si bien que les références qui pointent vers eux restent valides. Les fichiers de carte dont le contenu n’a pas changé ne sont pas réécrits : votre contrôle de version n’affiche donc aucune modification.
  • Elle ne ferme jamais vos scènes ouvertes. Les scènes de démo sont ouvertes en mode additif pendant leur construction.
  • À la fin, elle propose d’ajouter les scènes de démo aux paramètres de build. Rien n’est ajouté tant que vous ne cliquez pas sur Add Scenes.
Élément généréEmplacement (sous la racine du package)Contenu
TexturesContent/Textures/ (Ground, Cliffs, Water, Details, Props, Brushes)Textures raccordables de sol, de falaise, d’eau et d’accessoires (512 px), sprites d’herbe et de fleurs et tampons de pinceau (256 px), avec les normal maps correspondantes.
Matériaux, meshes, prefabsContent/Materials, Content/Meshes, Content/PrefabsArbres, rochers, ruines et accessoires low-poly, avec leurs matériaux.
TilesetsContent/Tilesets/Summer.asset, Winter.assetDeux tilesets comptant chacun 10 calques de sol et 2 types de falaise. Summer : Grass, Lush Grass, Dirt, Rocky Dirt, Sand, Cobblestone, Dark Forest Floor, Rock, Snow et Blight, avec Rock Cliff et Grassy Cliff. Winter : les versions gelées, avec Ice Cliff et Snowy Cliff.
Profil de peinture automatiqueContent/Tilesets/Summer Auto Paint.assetRègles pour le tileset Summer, par exemple des plaques de terre sur les pentes douces et du sable le long des rivages.
Bibliothèque de végétationContent/Libraries/Demo Vegetation.assetDétails : Grass, Tall Grass, Flowers Yellow, Flowers Purple, Fern. Arbres : Pine, Broadleaf, Dead Tree, Bush.
Bibliothèque de décorsContent/Libraries/Demo Decor.assetRock A, Rock B, Rock C, Boulder, Ruined Pillar, Crate, Barrel, Fence, Tree Stump, Mushrooms. Ces objets mêlent prototypes instanciés et prototypes GameObject, et possèdent des emprises de cheminement.
Formes de pinceauContent/BrushesTampons personnalisés : Noise Blob, Splatter, Star, Soft Square.
CartesContent/MapsTrois fichiers .rtsmap (voir ci-dessous).
Paramètres de renduContent/SettingsUn profil de volume de post-traitement utilisé par les scènes de démo.
ScènesSamples/ScenesTrois scènes de démo (voir ci-dessous).
RessourcesResources/RTSTerrainStudioL’asset de références de shaders et UI/RTSRuntimePanelSettings.asset, afin que les shaders et l’interface soient inclus dans les builds.

Cartes de démo

Les trois cartes utilisent des cellules de 2 m, une hauteur de niveau de falaise de 2 m et le tileset Summer.

CarteTailleSymétrieDescription
Two Rivers (1v1).rtsmap128 × 128 cellulesRotate 2Deux joueurs, deux rivières. Des gués peu profonds permettent de traverser les rivières partout, tandis que le lac central est profond. Des rampes mènent à des plateaux boisés parsemés de ruines et de camps abandonnés.
Four Kingdoms (4p).rtsmap192 × 192 cellulesRotate 4Quatre royaumes, chacun sur ses propres hauteurs. Des rampes descendent vers les basses terres communes, et le centre est un sol corrompu où se dressent les ruines d’un ancien temple.
Sandbox.rtsmap96 × 96 cellulesNoneUne petite carte, presque entièrement plate, pour essayer les outils.
Vue de dessus d’une carte de démo avec plateaux, rivières, forêts et positions de départ
Vue de dessus d’une carte de démo.

Scènes de démo

ScèneCarteCe qui est affiché
RTS Terrain Studio - Gameplay DemoTwo Rivers (1v1)Appuyez sur Play pour jouer : unités aux positions de départ (les ennemis errent sur la carte), brouillard de guerre, caméra RTS, sélection, ordres, mini-carte, HUD, placement de bâtiments (B) et récolte d’arbres (T).
RTS Terrain Studio - In-Game Editor DemoSandboxL’éditeur en jeu, en Play Mode. Modifiez la carte, puis appuyez sur F5 pour la tester en jeu avec des unités.
RTS Terrain Studio - Editor PlaygroundFour Kingdoms (4p)Une carte sans gameplay, pour essayer les outils d’édition dans la Scene View de l’éditeur Unity.

Chaque scène de démo contient un soleil, un volume de post-traitement, une caméra qui demande la texture de profondeur et la texture opaque, ainsi qu’un terrain doté de RTSTerrain, RTSVegetationRenderer, RTSWaterRenderer, RTSDecorManager et RTSEnvironment.

Chaque intégration possède son propre générateur de scène de démo. Il nécessite le contenu de démo et crée sa scène dans le dossier Demo de l’intégration :

  • Tools ▸ RTS Terrain Studio ▸ Integrations ▸ Mirror ▸ Create Demo Scene crée RTS Mirror Demo.unity.
  • Tools ▸ RTS Terrain Studio ▸ Integrations ▸ A* Pathfinding ▸ Create Demo Scene crée RTS AStar Demo.unity.
  • Tools ▸ RTS Terrain Studio ▸ Integrations ▸ Unity NavMesh ▸ Create Demo Scene crée RTS NavMesh Demo.unity.

Scripts d’exemple

Le dossier Samples/Scripts (RTSTerrainStudio.Samples) est un petit framework RTS lisible, qui peut vous servir de support d’apprentissage ou de base de travail :

DomaineClasses
AmorçageRTSDemoGame, RTSUnitSpawner
Unités et déplacementRTSUnit, RTSUnitFactory, RTSUnitRegistry, RTSFormation, RTSWanderAI
Fournisseurs de cheminsIRTSUnitPathProvider, RTSBuiltinPathProvider, RTSUnitPathProviderComponent, RTSUnitPathProviderRegistry
Caméra, entrées, sélection, ordresRTSCameraController, RTSGameInput, RTSSelectionManager, RTSCommandController
Interface utilisateurRTSMinimapUI, RTSDemoHUD, RTSRuntimeUI
Démos de gameplayRTSBuildingPlacementDemo, RTSDemoBuilding, RTSTreeHarvestDemo, RTSFallingTreeEffect
UtilitairesRTSMoveMarker, RTSGroundRing, RTSSampleMaterials, RTSSampleMeshes, RTSSampleUtility

Icônes

Toutes les icônes de la fenêtre de l’éditeur, des Inspectors et de l’éditeur en jeu sont dessinées de façon procédurale par RTSIcons : elles restent nettes à toutes les tailles et fonctionnent dans les builds sans aucun asset de texture.

Planche de toutes les icônes de RTS Terrain Studio : catégories d’outils, outils et actions
Le jeu d’icônes utilisé par l’éditeur et par l’interface en jeu.

Les menus en un coup d’œil

Élément de menuRôle
Tools ▸ RTS Terrain Studio ▸ Editor WindowOuvre la fenêtre d’édition principale.
Tools ▸ RTS Terrain Studio ▸ New Map Wizard...Crée une nouvelle carte étape par étape (taille, tileset, carte plate ou générée).
Tools ▸ RTS Terrain Studio ▸ Create Demo ContentGénère le contenu de démo décrit ci-dessus.
Tools ▸ RTS Terrain Studio ▸ Validate ProjectVérifie URP, les paramètres du projet, les packages, le contenu et la scène, et propose des corrections.
Tools ▸ RTS Terrain Studio ▸ Install WebGL TemplateInstalle et sélectionne le modèle Web qui remplit la fenêtre du navigateur (voir Le modèle pleine fenêtre).
Tools ▸ RTS Terrain Studio ▸ WelcomeÉtapes de démarrage rapide, liens et état des intégrations.
Tools ▸ RTS Terrain Studio ▸ DocumentationOuvre ce manuel.
Tools ▸ RTS Terrain Studio ▸ Integrations ▸ …Générateurs de scènes de démo et utilitaires des intégrations installées.
GameObject ▸ RTS Terrain Studio ▸ RTS TerrainCrée un GameObject RTS Terrain doté de RTSTerrain, Vegetation Renderer, Water Renderer et Decor Manager, avec le tileset et les bibliothèques par défaut du projet, ainsi qu’un nouveau fichier .rtsmap contenant une carte plate.
GameObject ▸ RTS Terrain Studio ▸ Fog of War ManagerCrée le gestionnaire du brouillard de guerre et propose d’ajouter la renderer feature.
GameObject ▸ RTS Terrain Studio ▸ EnvironmentCrée un RTSEnvironment (et un soleil si la scène n’en a pas).
GameObject ▸ RTS Terrain Studio ▸ In-Game EditorAjoute l’éditeur en jeu à la scène.
GameObject ▸ RTS Terrain Studio ▸ Demo GameAjoute RTSDemoGame, qui transforme n’importe quel terrain doté de positions de départ en démo jouable.
Assets ▸ Create ▸ RTS Terrain Studio ▸ …Map (.rtsmap), Tileset, Vegetation Library, Decor Library, Brush Shape, Auto Paint Profile, Map Generator Preset et Advanced ▸ Shader References. Vous aurez rarement besoin de ce dernier : le validateur et les builds de joueur créent et mettent à jour RTSShaderReferences.asset automatiquement.

Les éléments du menu GameObject sont désactivés en Play Mode, car ils créent des assets et des objets de scène qui doivent être enregistrés.

Démarrage rapide

Ce chapitre vous accompagne d’un projet Unity vide jusqu’à une carte que vous aurez construite vous-même et sur laquelle vous aurez joué avec des unités, le brouillard de guerre et une mini-carte. Aucune connaissance en programmation n’est nécessaire. Suivez les étapes numérotées dans l’ordre. Chaque étape indique précisément le menu, la fenêtre ou le bouton à utiliser.

PartieCe que vous faitesDurée
Installation et configurationImportez le package, laissez le Project Validator corriger les paramètres URP, puis générez le contenu de démo.environ 5 min
Scènes de démoJouez sur une carte terminée, essayez l’éditeur en jeu, explorez la scène Editor Playground.5 min
Votre première carteCréez un terrain, peignez les hauteurs, les falaises, les textures, les arbres et l’eau, placez les positions de départ et enregistrez.10 min
Votre premier test en jeuJouez sur votre carte avec le jeu de démo, ou modifiez-la et testez-la directement dans le jeu en cours d’exécution.5 min
Tutoriel de 10 minutesConstruisez de A à Z une carte 1v1 équilibrée grâce à la peinture symétrique.10 min

Vous pouvez ouvrir ce chapitre à tout moment grâce au lien Quick Start Guide de la fenêtre Welcome (Tools ▸ RTS Terrain Studio ▸ Welcome). Le manuel complet s’ouvre avec Tools ▸ RTS Terrain Studio ▸ Documentation.

Installation et configuration

Configuration requise

ÉlémentVersionRemarques
Unity6.3 LTS (6000.3)Utilisez la version de l’éditeur pour laquelle le package a été conçu.
Universal Render Pipeline17.3Obligatoire. Tous les shaders de terrain, d’eau, de végétation et de brouillard de guerre sont des shaders URP. Si vous créez un nouveau projet, partez du modèle de projet Universal 3D. Sans URP, le package reste inactif et affiche un message d’information (voir Configuration requise).
Burst, Collections, Mathematicsdepuis le Unity RegistryObligatoires. Les traitements lourds (construction des meshes, pinceaux, cheminement, brouillard de guerre, recherche de chemin) s’exécutent dans des jobs Burst.
Input Systemdepuis le Unity RegistryRecommandé. Utilisé par l’éditeur en jeu, la caméra RTS et les exemples. L’ancien Input Manager sert de solution de repli.
Mirror, A* Pathfinding Project, AI NavigationfacultatifsNécessaires uniquement pour l’intégration correspondante. Les intégrations se compilent automatiquement dès que le package concerné est installé. Voir Intégrations.

Importer le package

  1. Ouvrez votre projet dans Unity 6.3. Vérifiez qu’il utilise URP (c’est déjà le cas des nouveaux projets créés à partir du modèle Universal 3D).
  2. Ouvrez Window ▸ Package Manager, sélectionnez My Assets, recherchez RTS Terrain Studio, cliquez sur Download, puis sur Import.
  3. Dans la boîte de dialogue d’import, laissez tout coché et cliquez sur Import. Le package est installé dans Assets/RTSTerrainStudio.
  4. Attendez que Unity ait terminé la compilation. La fenêtre Welcome s’ouvre d’elle-même (voir ci-dessous).

Vous pouvez déplacer le dossier RTSTerrainStudio n’importe où dans Assets. Le package retrouve ses propres fichiers où que se trouve le dossier : rien ne casse lorsque vous réorganisez votre projet.

Si la fenêtre Console affiche des erreurs de compilation juste après l’import, la cause la plus probable est l’absence de l’un des packages Burst, Collections ou Mathematics. Installez-les via Window ▸ Package Manager ▸ Unity Registry. Les erreurs disparaissent une fois ces packages installés.

Si la boîte de dialogue RTS Terrain Studio requires URP apparaît à la place de la fenêtre Welcome, le projet ne dispose pas d’URP 17.3. Le package reste alors inactif et ne modifie rien. Suivez les étapes indiquées dans la boîte de dialogue, ou consultez Unity et pipeline de rendu.

La fenêtre Welcome

La fenêtre Welcome s’ouvre automatiquement la première fois que le package est chargé dans un projet. Vous pouvez la rouvrir à tout moment avec Tools ▸ RTS Terrain Studio ▸ Welcome. Cochez Show at startup en bas de la fenêtre si vous souhaitez qu’elle s’affiche à chaque démarrage de Unity. Ce paramètre est stocké par utilisateur et par projet : il ne se retrouve donc jamais dans le contrôle de version.

La colonne de gauche contient une liste de démarrage rapide, avec un bouton par étape :

ÉtapeBoutonRôle
1. Validate & fix the projectValidateOuvre le Project Validator. Sous l’étape, une ligne d’état affiche « Project is ready » ou le nombre d’erreurs et d’avertissements détectés.
2. Create the demo contentCreateExécute Tools ▸ RTS Terrain Studio ▸ Create Demo Content.
3. Open a demo sceneliste des scènes + OpenListe les scènes de démo dès qu’elles existent et ouvre celle que vous choisissez (en vous proposant d’abord d’enregistrer vos scènes ouvertes).
4. Create your own mapNew MapOuvre le New Map Wizard.
5. Start editingEditor WindowOuvre la fenêtre RTS Terrain Studio.

La colonne de droite contient les liens Learn vers ce manuel (Documentation, Quick Start Guide, Scripting API, Integrations, Troubleshooting) et une liste Integrations qui indique si Mirror, A* Pathfinding Project et Unity AI Navigation sont installés dans le projet.

Valider le projet

Le Project Validator vérifie tout ce dont le package a besoin et corrige la plupart des problèmes en un clic. Lancez-le une fois après l’import, puis chaque fois que quelque chose semble anormal (matériaux roses, eau plate, unités visibles à travers le brouillard de guerre).

  1. Ouvrez Tools ▸ RTS Terrain Studio ▸ Validate Project, ou cliquez sur Validate dans la fenêtre Welcome.
  2. Lisez le résumé en haut. Chaque vérification apparaît sous forme de panneau doté d’un badge d’état (OK, Info, Warning ou Error). Dépliez la section Details d’un panneau pour voir précisément ce qui a été détecté.
  3. Cliquez sur Fix All. Avant toute modification, une boîte de dialogue liste chacun des changements prévus. Cliquez sur Apply Fixes.
  4. Cliquez sur Run Again et vérifiez qu’il ne reste ni erreur ni avertissement. Les panneaux Info ne posent pas de problème : ils ne font que vous informer.

Fix All procède en plusieurs passes. Si URP n’était pas encore actif, la première passe bascule le projet vers URP, et les corrections des textures de caméra et du brouillard de guerre, qui nécessitent URP, sont appliquées dans le même clic. Chaque panneau possède aussi son propre bouton de correction si vous préférez corriger les problèmes un par un.

VérificationNiveau de gravitéBouton de correctionEffet de la correction et intérêt
Rendering
Universal Render Pipeline is activeErrorUse URPAssigne un asset URP du projet (ou en crée un) comme pipeline de rendu par défaut, ainsi qu’à chaque niveau de qualité qui utilise un autre pipeline. Sans URP, le terrain, l’eau et la végétation s’affichent en rose, voire pas du tout.
Depth and Opaque Texture enabledWarningEnable BothActive Depth Texture et Opaque Texture sur chaque asset URP utilisé par un niveau de qualité. L’eau utilise la texture opaque pour la réfraction, et la texture de profondeur pour que sa couleur selon la profondeur, son écume et sa ligne de rivage tiennent compte des objets qui se trouvent dans l’eau. Sans elles, l’eau a un rendu plus simple. Les caméras peuvent toujours remplacer ces paramètres dans leur section Rendering.
Fog of War renderer featureWarningAdd FeatureAjoute la renderer feature RTS Fog Of War au renderer par défaut de chaque asset URP utilisé par le projet, et lui assigne son shader. Sans elle, seuls les shaders du package affichent le brouillard de guerre ; les unités et les accessoires dotés d’autres matériaux restent visibles.
Fog kept in player buildsWarningKeep Fog ModesCette vérification apparaît lorsqu’un RTSEnvironment présent dans une scène du build ou dans une scène ouverte applique un brouillard atmosphérique. Règle Project Settings ▸ Graphics ▸ Fog Modes sur Custom et conserve les modes de brouillard utilisés. Sinon, Unity retire les variantes de shader du brouillard atmosphérique, et les cartes qui en utilisent un ne l’affichent pas dans les builds. Voir Brouillard atmosphérique dans les builds de joueur.
Project
Linear color spaceWarningSwitch to LinearRègle Player Settings ▸ Other Settings ▸ Color Space sur Linear. En espace Gamma, les couleurs, l’éclairage et l’eau paraissent délavés. Le changement réimporte toutes les textures.
Burst, Collections and MathematicsErrorInstallAjoute les packages manquants via le Package Manager. Sans eux, les scripts du package ne se compilent pas.
Input handlingInfoaucunIndique si le package Input System est installé et quelle gestion des entrées est active. L’ancien Input Manager fonctionne également.
WebGL (uniquement lorsque Web est la plateforme de build active)
Web quality levels have Depth and Opaque TextureWarningEnable BothActive Depth Texture et Opaque Texture sur les assets URP des niveaux de qualité utilisés par les builds Web. L’éditeur effectue souvent le rendu avec un niveau de qualité destiné aux ordinateurs de bureau : sans cette vérification, vous ne verriez l’eau simplifiée que dans le navigateur.
MSAA is off for Web buildsErrorTurn MSAA OffDésactive le MSAA dans les assets URP des niveaux de qualité Web qui utilisent aussi Depth Texture ou Opaque Texture. URP ne peut pas effectuer le rendu de cette combinaison sur WebGL 2 : le jeu n’afficherait alors qu’un écran noir dans le navigateur.
Web template fills the browser windowWarningInstall TemplateInstalle le modèle Web du package et le sélectionne. Les modèles Default et Minimal de Unity affichent le jeu dans un petit cadre de taille fixe, où l’éditeur en jeu, le HUD et la mini-carte sont difficiles à lire. Voir Le modèle pleine fenêtre.
Content
Package shaders compileErrorReimportRéimporte les shaders du package qui présentent des erreurs de compilation (utile s’ils ont été importés avant la fin du chargement d’URP). Si des shaders manquent complètement, réimportez le package depuis l’Asset Store.
Shaders included in buildsErrorUpdateCrée ou met à jour RTSShaderReferences.asset et le matériau DecorPlaceholder dans le dossier Resources du package. Les shaders créés uniquement par le code sont retirés des builds de joueur si rien ne les référence, et le terrain serait alors rose dans votre build. Cet asset est aussi actualisé automatiquement après chaque rechargement des scripts, lorsque des shaders changent et avant chaque build de joueur.
Tileset texture arrays builtInfoBuild ArraysConstruit les tableaux de textures compressés des tilesets qui n’en ont pas ou dont les tableaux sont obsolètes. Les tilesets fonctionnent sans eux, mais l’éditeur construit alors des tableaux non compressés au chargement de la carte, ce qui coûte de la mémoire et du temps de chargement. Lors d’un build de joueur, les tableaux obsolètes sont reconstruits automatiquement ; les tilesets dont les tableaux n’ont jamais été construits utilisent des tableaux non compressés dans les builds de joueur comme dans l’éditeur.
GPU instancing on instanced prototypesWarningEnable InstancingCoche Enable GPU Instancing sur les matériaux utilisés par les arbres, les détails ou les objets de décor instanciés.
Scene (scènes ouvertes uniquement)
Terrains have a tilesetWarningAssign '<tileset>'Assigne un tileset à chaque terrain qui n’en a pas (annulable). Sans tileset, un terrain affiche un aspect neutre de substitution.
Terrains save to a map fileInfoCreate Map FilesEnregistre la carte de chaque terrain dépourvu d’asset .rtsmap dans un nouveau fichier placé à côté de sa scène, puis l’assigne. Sans fichier de carte, les modifications sont perdues à la fermeture de la scène.

Les corrections de scène ne sont pas proposées en Play Mode. Quittez d’abord le Play Mode.

Créer le contenu de démo

Le package est livré sans fichiers graphiques binaires volumineux. À la place, il génère un ensemble complet d’assets de démo dans votre projet : tout fonctionne sans configuration et vous pouvez commencer à peindre tout de suite.

  1. Choisissez Tools ▸ RTS Terrain Studio ▸ Create Demo Content, ou cliquez sur Create dans la fenêtre Welcome.
  2. Une barre de progression passe par les étapes suivantes : Textures, Materials, Meshes and prefabs, Tilesets, libraries and brushes, Shader references and UI settings, Demo maps, Demo scenes. Lors de la première exécution, cela peut prendre un peu de temps.
  3. À la fin, une boîte de dialogue vous demande si les scènes de démo doivent être ajoutées aux paramètres de build. Cliquez sur Not Now, sauf si vous voulez générer un build de joueur avec les démos (vous pourrez les ajouter plus tard dans File ▸ Build Profiles). Seul le bouton Add Scenes modifie les paramètres de build.
  4. La scène Gameplay Demo est sélectionnée dans la fenêtre Project. Vos scènes ouvertes restent ouvertes ; rien n’est remplacé.

Ce qui est généré :

Dossier (dans le dossier du package)Contenu
Content/TexturesTextures de sol, de falaise, d’eau, de détails, d’accessoires et de pinceaux.
Content/Materials, Content/Meshes, Content/PrefabsArbres, buissons, rochers et accessoires low-poly, avec leurs matériaux.
Content/TilesetsLes tilesets Summer et Winter, ainsi que le profil Summer Auto Paint. Summer comprend les calques de sol Grass, Lush Grass, Dirt, Rocky Dirt, Sand, Cobblestone, Dark Forest Floor, Rock, Snow et Blight, ainsi que les types de falaise Rock Cliff et Grassy Cliff.
Content/LibrariesDemo Vegetation (herbe, herbe haute, fleurs, fougère ; arbres Pine, Broadleaf, Dead Tree et Bush) et Demo Decor (rochers, blocs rocheux, souches et autres accessoires).
Content/BrushesTampons de formes de pinceau.
Content/MapsTrois cartes : Two Rivers (1v1).rtsmap (128 × 128, symétrie centrale), Four Kingdoms (4p).rtsmap (192 × 192, symétrie de rotation d’ordre 4) et Sandbox.rtsmap (96 × 96, presque entièrement plate, avec un plateau et un étang).
Samples/ScenesLes trois scènes de démo décrites ci-dessous.
Resources/RTSTerrainStudioLes références de shaders et les paramètres de panneau de l’interface d’exécution.

Lorsque vous relancez le générateur, il vous laisse le choix entre Regenerate et Cancel. Seuls les assets de démo générés et les scènes de démo sont écrasés ; vos propres assets ne sont jamais modifiés. Les fichiers dont le contenu n’a pas changé ne sont pas réécrits.

Le générateur ajoute aussi la renderer feature du brouillard de guerre à votre renderer URP si elle manque. Il ne modifie pas les paramètres de texture de profondeur et de texture opaque de votre asset URP : les caméras de démo demandent elles-mêmes ces textures. Pour l’eau de vos propres scènes, lancez Validate Project comme décrit ci-dessus.

Ouvrir les scènes de démo

Les scènes de démo se trouvent dans RTSTerrainStudio/Samples/Scenes. Ouvrez-en une en double-cliquant dessus dans la fenêtre Project, ou choisissez-la à l’étape 3 de la fenêtre Welcome et cliquez sur Open.

La scène Gameplay Demo : des unités sur la carte Two Rivers, avec brouillard de guerre et mini-carte
La scène Gameplay Demo sur la carte Two Rivers (1v1).
ScèneCarteContenuEssayez ceci
RTS Terrain Studio - Gameplay Demo Two Rivers (1v1) Caméra RTS, brouillard de guerre et un objet RTS Demo Game qui lance la partie automatiquement. Appuyez sur Play. Vos unités (joueur 1) apparaissent à votre position de départ ; les unités ennemies errent sur la carte, apparaissant et disparaissant dans le brouillard de guerre.
RTS Terrain Studio - In-Game Editor Demo Sandbox L’éditeur de cartes en jeu (objet RTS In-Game Editor), ainsi que les mêmes systèmes de gameplay, qui restent désactivés jusqu’à ce que vous lanciez un test en jeu. Appuyez sur Play, peignez avec l’éditeur en jeu, puis appuyez sur Play Test (F5). Appuyez sur Esc pour revenir à l’éditeur.
RTS Terrain Studio - Editor Playground Four Kingdoms (4p) Uniquement le terrain, la lumière et la caméra, sans gameplay. Restez en Edit Mode, ouvrez Tools ▸ RTS Terrain Studio ▸ Editor Window et essayez les outils sur une carte terminée.

Commandes de la démo de gameplay

SaisieAction
W A S D / touches fléchées, bord de l’écran, glisser avec le bouton du milieuDéplacer la caméra. Lorsque des unités sont sélectionnées, S les arrête au lieu de déplacer la vue ; les touches fléchées déplacent toujours la caméra.
Molette de la sourisZoomer
Q / E, Alt + glisser avec le bouton droitFaire pivoter la vue
Clic gauche / glisser avec le bouton gaucheSélectionner une unité / tracer un rectangle de sélection
Shift + clicAjouter ou retirer des unités
Double-clic, Ctrl + clicSélectionner toutes les unités de ce type visibles à l’écran
Clic droitSe déplacer en formation (Shift met l’ordre en file d’attente)
S / H / PArrêter / tenir la position / patrouiller
Ctrl + 0…9, Shift + 0…9, 0…9Enregistrer un groupe de contrôle / y ajouter la sélection / le rappeler (appuyez deux fois pour centrer la caméra)
Mini-carteLe clic gauche déplace la caméra, le clic droit déplace les unités sélectionnées
B, DeletePlacer un bâtiment / supprimer le bâtiment sous le curseur
T, clic droit sur un arbreAbattre l’arbre sous le curseur / le faire couper par les ouvriers sélectionnés
EscAnnuler le mode en cours ou vider la sélection
F1Afficher ou masquer le panneau d’aide

Votre première carte

Une carte est rattachée à un GameObject RTS Terrain de votre scène et stockée dans un fichier .rtsmap de votre projet. La scène ne fait que référencer ce fichier ; c’est dans ce fichier que vos modifications sont enregistrées. Commencez avec une nouvelle scène pour pouvoir expérimenter librement :

  1. Choisissez File ▸ New Scene et sélectionnez un modèle de scène URP (par exemple Basic (URP)).
  2. Enregistrez la scène tout de suite avec Ctrl+S, par exemple sous Assets/MyMaps/FirstMap.unity. Les nouveaux fichiers de carte sont créés à côté de la scène enregistrée : votre carte et votre scène restent ainsi regroupées.

Créer un terrain

Il existe deux méthodes. Toutes deux créent le même objet RTS Terrain, avec les composants RTSTerrain, RTSVegetationRenderer, RTSWaterRenderer et RTSDecorManager déjà configurés.

MéthodeMenuÀ utiliser quand
En un clicGameObject ▸ RTS Terrain Studio ▸ RTS TerrainVous voulez commencer à peindre immédiatement. Vous obtenez une carte plate de 128 × 128 cellules (cellules de 2 m, niveau de falaise 2) avec le tileset et les bibliothèques par défaut du projet, placée au pivot de la Scene View et sélectionnée. Un nouveau fichier de carte nommé <Scene name> Map.rtsmap est créé à côté de la scène (ou Assets/Maps/New Map.rtsmap si la scène n’est pas enregistrée).
GuidéeTools ▸ RTS Terrain Studio ▸ New Map Wizard...Vous voulez choisir le nom, la taille, le tileset et la texture de base, ou générer une carte jouable aléatoire.

Si le projet ne contient encore aucun tileset, le menu en un clic propose d’abord Create Demo Content. Avec Continue Without, le terrain affiche un damier neutre jusqu’à ce que vous lui assigniez un tileset.

Le New Map Wizard comporte cinq étapes. Utilisez Next et Back, ou cliquez sur une étape dans la barre du haut :

ÉtapeParamètres
1. BasicsMap Name (sert aussi de nom de fichier), Author (mémorisé pour la carte suivante), Description, Players (1–16 ; les cartes compétitives sont généralement conçues pour 2, 4 ou 8 joueurs).
2. SizePanneaux de taille : Tiny 64 (duels 1v1 rapides et tests), Small 96 (1v1 et 2v2), Medium 128 (2 à 4 joueurs), Large 192 (4 à 6 joueurs), Huge 256 (6 à 8 joueurs), Epic 384 (8 joueurs et plus, campagnes), Epic XL 512 (très grands mondes) ou Custom (multiples de 16). S’y ajoutent Cell Size (m) (gardez 2 m en cas de doute), Cliff Level Height (m), Base Cliff Level (2 par défaut, ce qui permet de creuser vers le bas pour former des lacs, comme dans les cartes des RTS classiques) et une section repliable Advanced qui contient les résolutions de texture, de détails et de cheminement.
3. LookTileset (cliquez sur une texture de sol pour en faire le calque BASE qui couvre la carte au départ), Vegetation Library, Decor Library. Sans tileset, un bouton Create Demo Content s’affiche.
4. TerrainFlat (une carte vide et plate au niveau de falaise de base, idéale pour apprendre les outils) ou Generate (plateaux, rampes, eau, positions de départ, végétation et décors générés à partir des paramètres Preset et Seed, avec les options Symmetry, Start Locations, Scatter Vegetation, Scatter Decor et un bouton Preview).
5. CreateNew terrain object ou Replace map of selected terrain, le chemin Map File (Browse...), Add Environment (soleil, lumière ambiante et brouillard atmosphérique issus de la carte ; crée une lumière Sun si la scène n’en a pas), Open Editor Window et un récapitulatif. Cliquez sur Create Map.

L’assistant écrit le fichier de carte, crée le terrain, le cadre dans la Scene View et ouvre la fenêtre de l’éditeur. Vous pourrez modifier chaque paramètre plus tard dans l’onglet Map de la fenêtre de l’éditeur.

Ouvrir la fenêtre de l’éditeur

Ouvrez Tools ▸ RTS Terrain Studio ▸ Editor Window (l’assistant et la fenêtre Welcome peuvent l’ouvrir pour vous, et l’Inspector du composant RTS Terrain propose un bouton Open RTS Terrain Studio). Ancrez-la à côté de l’Inspector pour voir la Scene View en même temps.

La fenêtre de l’éditeur RTS Terrain Studio avec l’onglet Cliffs ouvert
La fenêtre de l’éditeur avec l’onglet Cliffs ouvert : outils de falaise, description de l’outil, paramètres du pinceau et symétrie.
ZoneCe qui est affiché
En-têteSélecteur de terrain, nom de la carte (un point signale des modifications non enregistrées), Save, Save As…, Open…, Reload, Undo / Redo avec le nom de l’étape, un bouton d’aide et l’interrupteur Editing On / Editing Off.
Barre d’ongletsHuit catégories d’outils (Height, Cliffs, Paint, Vegetation, Decor, Water, Pathing, Markers), puis Map et Settings. Un point signale la catégorie de l’outil actif.
Page des outilsGrands boutons d’outils, un panneau qui décrit l’outil actif avec son état en direct, les panneaux Brush et Symmetry, ainsi que les paramètres et les palettes propres à l’outil (calques, niveaux de falaise, joueurs, arbres, décors).
Barre d’étatCellule sous le curseur, niveau de falaise, hauteur et cheminement sous la souris, et mémoire d’annulation.

Les huit catégories et leurs outils :

ToucheCatégorieOutils
1HeightRaise / Lower, Smooth, Flatten, Set Height, Noise, Terrace, Erode
2CliffsRaise / Lower Level, Set Level, Ramp, Cliff Type, Clean Cliffs
3PaintPaint Layer, Tile Paint, Fill / Replace, Smooth Paint, Auto Paint
4VegetationPaint Details, Erase Details, Place Trees, Erase Trees
5DecorPlace Decor, Erase Decor, Select Decor
6WaterPaint Water, Erase Water, Flood Fill
7PathingPaint Pathing, Clear Pathing
8MarkersStart Locations, Regions, Markers

Chaque outil est décrit en détail dans son propre chapitre (par exemple Outils de hauteur et Outils de falaise) ; la fenêtre elle-même est décrite dans La fenêtre RTS Terrain Studio.

Les bases de la peinture

  1. Cliquez sur un bouton d’outil dans la fenêtre de l’éditeur. L’édition s’active (l’en-tête affiche Editing On). Un nouveau clic sur l’outil actif désactive l’édition.
  2. Déplacez la souris sur le terrain dans la Scene View. Le cercle du pinceau est dessiné directement sur le sol, exactement là où vous allez peindre.
  3. Maintenez le bouton gauche de la souris enfoncé et faites glisser pour peindre.
Saisie (Scene View)Action
Bouton gauchePeindre un trait (ou cliquer, pour les outils à clic comme Start Locations)
Shift + bouton gaucheAction inverse : abaisser, effacer, supprimer
Ctrl + clicPrélever une valeur sous le curseur (hauteur, calque de sol, hauteur d’eau…) pour les outils qui le permettent
[ / ]Pinceau plus petit / plus grand
- / =Diminuer / augmenter l’intensité
1 … 8Passer à une catégorie d’outils (appuyez de nouveau pour parcourir ses outils)
G / PAfficher ou masquer la grille / faire défiler les modes de la superposition de cheminement (Off, Walkability, Buildability, Combined)
RActiver ou désactiver la rotation aléatoire du pinceau
Ctrl+Z / Ctrl+YAnnuler / rétablir les modifications du terrain (le menu Edit affiche le nom des étapes)
EscAnnuler le trait en cours ou arrêter l’édition

La Scene View affiche aussi l’overlay RTS Terrain Studio, avec l’interrupteur d’édition, les boutons de catégories et d’outils, les curseurs Size et Strength et le paramètre Symmetry, ainsi qu’une ligne d’état en bas qui indique la cellule survolée, le niveau de falaise et la hauteur. Vous pouvez rester dans la Scene View pour l’essentiel de votre travail.

La navigation de la caméra dans la Scene View fonctionne comme d’habitude (glisser avec le bouton droit pour voler, Alt + glisser avec le bouton gauche pour tourner en orbite, glisser avec le bouton du milieu pour faire un panoramique). Si l’outil Hand de Unity (Q) est actif, glisser avec le bouton gauche déplace la vue au lieu de peindre ; appuyez sur W pour peindre de nouveau. Tous les raccourcis de RTS Terrain Studio peuvent être réaffectés dans Edit ▸ Shortcuts... (sous macOS, Unity ▸ Shortcuts...), dans la catégorie RTS Terrain Studio (pratique si, dans votre disposition, 2 entre en conflit avec le raccourci de Unity qui active ou désactive le mode 2D).

Peindre les hauteurs

  1. Ouvrez l’onglet Height (1) et cliquez sur Raise / Lower.
  2. Faites glisser sur le terrain pour former des collines. Maintenez le bouton enfoncé pour continuer à surélever le terrain. Maintenez Shift enfoncée pour abaisser.
  3. Passez à Smooth et faites glisser sur les reliefs trop anguleux pour les adoucir.
  4. Essayez Noise pour obtenir un sol accidenté et Flatten (Ctrl+clic pour prélever la hauteur) pour les zones de construction.

Les hauteurs sont un détail fin qui s’ajoute aux niveaux de falaise : une colline sur un plateau reste sur ce plateau.

Peindre des falaises et des rampes

Les falaises sont au cœur d’une carte de RTS classique. La carte s’organise en niveaux de falaise, de 0 à 15, et démarre au niveau de base (2 par défaut). Chaque niveau correspond à une marche de falaise verticale et nette.

  1. Ouvrez l’onglet Cliffs (2) et cliquez sur Raise / Lower Level.
  2. Cliquez sur le terrain : le sol monte d’un niveau de falaise. Gardez le bouton enfoncé et faites glisser pour étendre, au même niveau, le plateau sur lequel vous avez commencé.
  3. Cliquez à l’intérieur du plateau et faites glisser de nouveau pour empiler un deuxième niveau par-dessus.
  4. Maintenez Shift enfoncée pour abaisser le sol d’un niveau. En descendant sous le niveau de base, vous creusez des bassins pour les lacs et les rivières.
  5. Cliquez sur Ramp et peignez en travers d’un bord de falaise d’un seul niveau pour le transformer en pente praticable. Les quatre coins d’une cellule doivent être en rampe ; peignez donc généreusement de part et d’autre du bord. Shift supprime une rampe.
  6. Passez l’outil Clean Cliffs sur les bords irréguliers pour supprimer les piliers et les trous d’un seul vertex. L’outil Cliff Type peint un autre matériau de falaise (par exemple Grassy Cliff au lieu de Rock Cliff).

Peindre les textures

  1. Ouvrez l’onglet Paint (3) et cliquez sur Paint Layer.
  2. Cliquez sur un calque de sol dans la palette des calques, par exemple Dirt.
  3. Faites glisser sur le terrain pour peindre des chemins et des clairières. Shift efface le calque ; Ctrl+clic prélève le calque sous le curseur.
  4. Pour des tuiles aux bords nets, dans le style des RTS classiques, utilisez Tile Paint. Pour les grandes zones, utilisez Fill / Replace.
  5. Pour obtenir rapidement un rendu naturel, utilisez le panneau Auto Paint Whole Map de l’onglet Paint avec Profile réglé sur Summer Auto Paint : il peint de la terre près des falaises, du sable sur les rivages, de la roche sur les pentes escarpées, et ainsi de suite.

Placer des arbres et de l’herbe

  1. Ouvrez l’onglet Vegetation (4) et cliquez sur Place Trees.
  2. Dans la liste Trees, choisissez un ou plusieurs types d’arbres, par exemple Pine et Broadleaf. Si vous en choisissez plusieurs, ils sont mélangés aléatoirement.
  3. Laissez le paramètre Mode sur Scatter et faites glisser le long des bords de la carte pour planter des forêts. Density détermine le nombre d’arbres ajoutés par empreinte. Aucun arbre n’est placé sur les pentes plus raides que Max Slope ni sous l’eau (Avoid Water).
  4. Réglez Mode sur Single pour placer un arbre par clic. Shift supprime des arbres.
  5. Cliquez sur Paint Details, choisissez Grass ou Flowers Yellow dans la liste Details, puis peignez des prairies. Target Density définit la densité appliquée par le pinceau.

Les outils de végétation nécessitent une bibliothèque de végétation sur le terrain. Les terrains créés après Create Demo Content reçoivent automatiquement la bibliothèque Demo Vegetation. Les décors fonctionnent de la même façon, avec l’outil Place Decor dans l’onglet Decor (5) et la bibliothèque Demo Decor.

Ajouter de l’eau

L’eau recouvre le sol situé sous une hauteur de surface cible. Le plus simple consiste à creuser un bassin avec les outils de falaise, puis à le remplir.

  1. Dans l’onglet Cliffs, utilisez Raise / Lower Level avec Shift pour creuser un lac ou une rivière un niveau sous le niveau de base (niveau 1 sur une carte par défaut).
  2. Ouvrez l’onglet Water (6) et cliquez sur Flood Fill.
  3. Pour Water Height, conservez le mode par défaut (niveau de falaise plus décalage) avec Level réglé sur 1. Le décalage par défaut place la surface de l’eau juste sous le niveau de base : le bassin se remplit et les terres alentour restent sèches.
  4. Cliquez à l’intérieur du bassin. Il se remplit en un seul clic. Shift+clic vide l’étendue d’eau contiguë.
  5. Utilisez Paint Water pour peindre de l’eau à la main et Erase Water pour l’effacer.

L’eau peu profonde et l’eau profonde sont déduites automatiquement de la profondeur et influent sur le cheminement : les unités terrestres peuvent traverser l’eau peu profonde (on ne peut rien y construire, car la construction exige un sol sec), tandis que l’eau profonde les bloque.

Si l’eau n’a pas de réfraction et que son rivage ne tient pas compte des objets posés dans l’eau, c’est que les textures Depth et Opaque de l’URP sont désactivées. Lancez Tools ▸ RTS Terrain Studio ▸ Validate Project et appliquez la correction Enable Both.

Placer les positions de départ

Les positions de départ sont les points d’apparition des joueurs. Le jeu de démo y fait apparaître les unités de chaque joueur.

  1. Ouvrez l’onglet Markers (8) et cliquez sur Start Locations.
  2. Dans la palette des joueurs, choisissez P1 (joueur 1, rouge).
  3. Cliquez sur le terrain à l’endroit où le joueur 1 doit commencer. Chaque joueur n’a qu’une seule position de départ : un nouveau clic la déplace donc. Utilisez Yaw pour définir l’orientation.
  4. Choisissez le joueur suivant et cliquez de nouveau. Shift+clic supprime la position de départ la plus proche.

Avec la symétrie activée, un seul clic place tous les joueurs à la fois : les copies symétriques sont attribuées aux joueurs suivants (P1, P2…) tant que la case Symmetry Assigns Next Players est cochée. Voir le tutoriel de 10 minutes.

Placez les positions de départ sur un sol plat et sec, à l’écart des bords de falaise. Le bouton Validate Map de l’onglet Map (panneau Validation) signale les positions de départ manquantes, celles qui se trouvent sur un bord de falaise ou en eau profonde, entre autres problèmes.

Enregistrer la carte

Vos modifications restent en mémoire jusqu’à ce que vous les enregistriez dans le fichier .rtsmap :

  • Cliquez sur Save dans l’en-tête de la fenêtre de l’éditeur. Le bouton est mis en évidence tant qu’il y a des modifications non enregistrées, et un point apparaît à côté du nom de la carte.
  • Save As… écrit un nouveau fichier .rtsmap n’importe où dans Assets et l’assigne au terrain.
  • L’enregistrement de la scène (Ctrl+S) enregistre aussi les cartes de ses terrains. Vous pouvez désactiver ce comportement dans le menu d’options de l’overlay de la Scene View (Save Maps When Saving the Scene).
  • L’Inspector du composant RTS Terrain et le menu de l’overlay de la Scene View proposent aussi les entrées Save et Save As.

Si vous passez en Play Mode, fermez une scène ou quittez Unity alors que la carte comporte des modifications non enregistrées, une boîte de dialogue vous demande s’il faut les enregistrer. Sélectionnez un fichier .rtsmap dans la fenêtre Project pour voir l’aperçu de sa mini-carte et un bouton Open In Scene.

Un terrain sans fichier de carte ne conserve sa carte qu’en mémoire. Si la boîte de dialogue « The map of '…' is not saved as a map asset yet » apparaît, choisissez Save As… pour créer le fichier.

Votre premier test en jeu

Il existe deux façons de jouer sur votre carte : avec le Demo Game en Play Mode, ou dans le jeu en cours d’exécution avec l’éditeur en jeu et son bouton Play Test.

Jouer avec le Demo Game

  1. Ouvrez la scène qui contient votre terrain. Vérifiez qu’elle comporte au moins une position de départ (sinon, les unités apparaissent dans deux coins opposés).
  2. Choisissez GameObject ▸ RTS Terrain Studio ▸ Demo Game. Un objet RTS Demo Game est créé et sélectionné.
  3. Appuyez sur Play. Enregistrez la carte quand on vous le demande.
  4. Le jeu de démo met en place tout ce dont il a besoin : brouillard de guerre, caméra RTS, sélection, ordres de déplacement, mini-carte, HUD, placement de bâtiments et récolte d’arbres. Vos unités (joueur 1) apparaissent à votre position de départ ; les unités des autres joueurs errent au hasard.
  5. Appuyez sur F1 pour afficher le panneau d’aide. Les commandes sont listées dans la section Commandes de la démo de gameplay.
  6. Quittez le Play Mode. Les arbres abattus pendant la partie sont restaurés : la carte reste telle que vous l’avez créée.

Le composant RTS Demo Game propose des options comme Local Team, Units Per Player, Unit Prefabs (si ce champ est vide, des unités de substitution sont utilisées), Fog Of War, Minimap et Hud. La caméra utilisée est la caméra principale de la scène.

Si les unités restent visibles dans le brouillard de guerre, c’est que la renderer feature RTS Fog Of War est absente. Lancez Validate Project et appliquez la correction Add Feature.

Éditer et tester la carte en jeu

L’éditeur en jeu offre les mêmes outils, directement dans votre jeu en cours d’exécution, avec sa propre interface. Grâce à lui, les joueurs et les moddeurs peuvent créer des cartes et y jouer dans un jeu publié.

  1. Ouvrez la scène qui contient votre terrain et une caméra. Si elle ne contient pas encore de RTS Demo Game, ajoutez-en un comme décrit plus haut.
  2. Choisissez GameObject ▸ RTS Terrain Studio ▸ In-Game Editor.
  3. Appuyez sur Play. L’éditeur s’ouvre avec une barre supérieure (File, Map, annuler et rétablir, Symmetry, Grid, Pathing, Markers, Play Test), une barre de catégories et d’outils à gauche, le panneau de l’outil à droite et une barre d’état. Le jeu de démo attend que vous lanciez un test en jeu.
  4. Peignez comme dans l’éditeur Unity : bouton gauche, Shift pour inverser, Ctrl+clic pour prélever, [ ] et - = pour le pinceau, 1…8 pour les catégories. Déplacez la caméra avec W A S D, en faisant glisser avec le bouton droit ou celui du milieu, avec Q/E et avec la molette de la souris.
  5. Cliquez sur Play Test ou appuyez sur F5. Les unités apparaissent, et le brouillard de guerre ainsi que la caméra RTS s’activent.
  6. Appuyez sur Esc pour revenir à l’éditeur. La carte retrouve l’état qu’elle avait avant le test en jeu.

Touches utiles dans l’éditeur en jeu : F1 aide, F2 afficher ou masquer tout l’éditeur, H masquer les panneaux, G grille, P superposition de cheminement, M marqueurs, F centrer la vue sur le point sous le curseur, Ctrl+Z / Ctrl+Y annuler et rétablir.

Dans l’éditeur en jeu, File ▸ Save (Ctrl+S) et File ▸ Save As... (Ctrl+Shift+S) écrivent les fichiers de carte dans le dossier des cartes du jeu (par défaut, un dossier Maps dans Application.persistentDataPath), exactement comme le ferait un jeu publié. Lorsque vous quittez le Play Mode dans l’éditeur Unity après avoir fait des modifications, une boîte de dialogue demande « Save map changes made in Play Mode? » : Save les écrit dans l’asset .rtsmap du terrain, Discard les abandonne.

L’éditeur en jeu est décrit en détail dans Éditeur en jeu.

Pour les programmeurs : réagir à un test en jeu

Votre propre code de gameplay peut écouter le même événement que le jeu de démo. Cet exemple écrit dans la fenêtre Console la position de départ de chaque joueur lorsqu’un test en jeu commence :

using RTSTerrainStudio;
using UnityEngine;

// Add this component to any GameObject in a scene with an RTS Terrain and an in-game editor.
public class PlaytestStartLogger : MonoBehaviour
{
    void OnEnable()
    {
        // Raised by the in-game editor when a play test starts (true) or stops (false).
        RTSRuntimeEditorEvents.PlaytestChanged += OnPlaytestChanged;
    }

    void OnDisable()
    {
        RTSRuntimeEditorEvents.PlaytestChanged -= OnPlaytestChanged;
    }

    void OnPlaytestChanged(bool playing)
    {
        if (!playing) return;

        // The first enabled terrain of the scene.
        RTSTerrain terrain = RTSTerrain.Main;
        if (terrain == null || terrain.Map == null) return;

        foreach (StartLocation start in terrain.Map.StartLocations)
        {
            // Start locations are stored in map-local coordinates: convert to world space
            // and move the point onto the ground.
            var local = new Vector3(start.position.x, start.position.y, start.position.z);
            Vector3 world = terrain.SnapToGround(terrain.LocalToWorld(local));
            Debug.Log($"Player {start.player + 1} starts at {world}, facing {start.yaw:0} degrees");
        }
    }
}

Consultez le Guide de programmation pour les requêtes sur le terrain, le chargement de cartes et l’API des outils.

Tutoriel de 10 minutes : votre première carte 1v1

Dans ce tutoriel, vous créez une petite carte équilibrée pour deux joueurs : chaque joueur dispose d’une base sur un plateau doté d’une rampe, une rivière sépare les deux moitiés et des forêts encadrent la carte. La peinture symétrique garantit que les deux côtés sont identiques : vous ne construisez donc qu’une seule moitié.

Vue de dessus d’une carte symétrique pour deux joueurs
Une carte 1v1 à symétrie centrale vue de dessus : tout ce que vous peignez d’un côté apparaît de l’autre, tourné de 180°.

Avant de commencer : le projet doit être validé et le contenu de démo doit exister (voir Installation et configuration).

1. Créer la carte (1 minute)

  1. Choisissez File ▸ New Scene, sélectionnez un modèle URP et enregistrez la scène sous Assets/MyMaps/Duel.unity.
  2. Ouvrez Tools ▸ RTS Terrain Studio ▸ New Map Wizard....
  3. Basics : Map Name Duel, votre nom dans Author, Players 2. Cliquez sur Next.
  4. Size : cliquez sur Small (96 × 96, 1v1 et 2v2). Conservez Cell Size à 2 m et Base Cliff Level à 2. Cliquez sur Next.
  5. Look : Tileset Summer, cliquez sur Grass comme calque de base, Vegetation Library Demo Vegetation, Decor Library Demo Decor. Cliquez sur Next.
  6. Terrain : choisissez Flat. Cliquez sur Next.
  7. Create : conservez New terrain object, cochez Add Environment et Open Editor Window, puis cliquez sur Create Map.

2. Activer la symétrie (10 secondes)

  1. Dans la fenêtre de l’éditeur, ouvrez l’onglet Cliffs. Repérez le panneau Symmetry sous le panneau Brush.
  2. Choisissez Rotate 180°. Laissez le centre de symétrie au centre de la carte (0.5, 0.5).
  3. Déplacez la souris sur le terrain : un second pinceau apparaît désormais du côté opposé de la carte, et les repères de symétrie sont dessinés dans la Scene View.

La symétrie est commune à tous les outils : elle reste donc active quand vous changez d’outil. Les modes :

Mode (fenêtre)CopiesUsage typique
Off1Cartes de campagne ou scénarisées
Mirror X2Miroir gauche-droite
Mirror Z2Miroir haut-bas
Mirror XZ4Miroir sur les deux axes (4 joueurs)
Rotate 180°2Symétrie centrale, l’agencement 1v1 classique (coin contre coin)
Rotate 90°4Rotation d’ordre 4 pour 4 joueurs ; carte carrée requise
Diagonal2Miroir selon la diagonale ; carte carrée requise

L’overlay de la Scene View et l’éditeur en jeu proposent les mêmes modes (l’overlay affiche les noms de l’énumération, par exemple Rotate 2 pour Rotate 180°).

3. Construire les bases (2 minutes)

  1. Cliquez sur Raise / Lower Level. Avec [ et ], choisissez un grand pinceau.
  2. Dans le quart inférieur gauche de la carte, cliquez et faites glisser pour peindre un plateau large d’environ un quart de la carte. Le même plateau apparaît dans le quart supérieur droit.
  3. Cliquez sur Ramp et peignez en travers du bord du plateau tourné vers le centre de la carte. Donnez à la rampe une largeur d’au moins deux ou trois cellules pour que des groupes d’unités puissent passer.
  4. Cliquez sur Clean Cliffs et peignez une fois sur le contour du plateau pour supprimer les bosses isolées d’un seul vertex.

4. Creuser la rivière (2 minutes)

  1. Toujours avec Raise / Lower Level, maintenez Shift enfoncée et tracez une rivière du coin supérieur gauche vers le centre de la carte. La copie symétrique la prolonge depuis le coin inférieur droit : la rivière traverse ainsi toute la carte.
  2. Laissez un ou deux passages terrestres près du centre pour que les joueurs puissent se rejoindre.
  3. Ouvrez l’onglet Water, cliquez sur Flood Fill, conservez Level 1 et cliquez dans le lit de la rivière. Cliquez de nouveau dans chaque partie qui n’est pas encore remplie.

5. Peindre le sol (2 minutes)

  1. Ouvrez l’onglet Paint. Dans le panneau Auto Paint Whole Map, réglez Profile sur Summer Auto Paint (s’il reste vide, des règles intégrées, adaptées aux noms des calques du tileset, sont utilisées) et cliquez sur Auto Paint Whole Map. Confirmez la boîte de dialogue ; l’ensemble de cette nouvelle peinture constitue une seule étape d’annulation. La terre apparaît près des falaises, le sable sur les rivages de la rivière et la roche sur les pentes escarpées.
  2. Cliquez sur Paint Layer, choisissez Cobblestone et peignez un carré sur chaque plateau, à l’emplacement du futur bâtiment principal (une seule empreinte suffit, la copie symétrique peint l’autre base).
  3. Choisissez Dirt et peignez un chemin de la rampe de la base jusqu’au passage terrestre.
  4. Facultatif : dans l’onglet Height, utilisez Raise / Lower avec une faible intensité (-) pour ajouter quelques collines douces entre les bases, puis Smooth pour les adoucir.

6. Forêts, herbe et rochers (2 minutes)

  1. Ouvrez l’onglet Vegetation et cliquez sur Place Trees. Choisissez Pine et Broadleaf, et conservez le mode Scatter.
  2. Peignez des forêts le long de la bordure de la carte et derrière chaque base. Laissez les rampes, les chemins et les passages terrestres dégagés ; Shift supprime des arbres.
  3. Cliquez sur Paint Details, choisissez Grass et Flowers Yellow, puis peignez quelques prairies.
  4. Ouvrez l’onglet Decor, cliquez sur Place Decor, choisissez quelques rochers et cliquez près des rivages de la rivière.

7. Placer les positions de départ (30 secondes)

  1. Ouvrez l’onglet Markers et cliquez sur Start Locations.
  2. Choisissez le joueur P1 et vérifiez que la case Symmetry Assigns Next Players est cochée.
  3. Cliquez une fois au milieu de la base inférieure gauche. P1 y est placé et P2 apparaît sur la base opposée, tous deux tournés vers le centre si vous choisissez une valeur de Yaw orientée vers celui-ci.

8. Valider, enregistrer et jouer (1 minute)

  1. Ouvrez l’onglet Map et cliquez sur Validate Map dans le panneau Validation. Corrigez les erreurs signalées (par exemple une position de départ sur un bord de falaise).
  2. Cliquez sur Save dans l’en-tête de la fenêtre. La carte est écrite dans Assets/MyMaps/Duel.rtsmap.
  3. Choisissez GameObject ▸ RTS Terrain Studio ▸ Demo Game et appuyez sur Play.
  4. Sélectionnez vos unités, faites un clic droit pour leur faire franchir le passage terrestre et regardez l’ennemi surgir du brouillard de guerre.

Vous voulez quatre joueurs ? Créez une carte carrée (par exemple Medium 128 × 128), choisissez Rotate 90° et réglez Players sur 4. Un seul clic avec l’outil Start Locations place alors P1 à P4. Vous pouvez aussi laisser le générateur s’en charger : à l’étape Terrain de l’assistant, choisissez Generate, réglez Symmetry et Start Locations, cliquez sur Preview, puis affinez le résultat à la main.

Pour aller plus loin

  • Fenêtre de l’éditeur : chaque onglet, panneau et paramètre en détail, y compris l’onglet Map (redimensionnement, générateur, import et export de heightmaps, mini-carte, environnement).
  • Les chapitres consacrés aux outils, un par catégorie : Height, Cliffs, Paint, Vegetation, Decor, Water, Pathing, Markers.
  • Éditeur en jeu : livrez l’éditeur avec votre jeu et laissez les joueurs créer leurs propres cartes.
  • Programmation : interrogez les hauteurs, les niveaux de falaise et le cheminement par le code, chargez des cartes à l’exécution et réagissez aux modifications.
  • Intégrations : le multijoueur avec Mirror, la recherche de chemin avec l’A* Pathfinding Project ou Unity NavMesh.
  • Dépannage : matériaux roses, eau plate, décalages lors de la peinture et autres problèmes courants.

Configuration du projet

RTS Terrain Studio a besoin de quelques paramètres de projet : l’Universal Render Pipeline avec deux textures de caméra, la renderer feature du brouillard de guerre, l’espace colorimétrique Linear et trois packages Unity. La fenêtre Tools ▸ RTS Terrain Studio ▸ Validate Project les vérifie tous et corrige la majorité d’entre eux en un clic ; la plupart des utilisateurs n’ont donc jamais besoin des étapes manuelles de ce chapitre. Poursuivez la lecture si une vérification reste rouge, si vous voulez savoir ce que change une correction ou si vous configurez un projet à la main.

Le bouton d’aide de chaque panneau du Project Validator ouvre la section correspondante de ce chapitre.

Le Project Validator

Ouvrez Tools ▸ RTS Terrain Studio ▸ Validate Project, ou cliquez sur Validate dans la fenêtre Welcome. Les vérifications s’exécutent dès l’ouverture de la fenêtre. Elles sont réparties en cinq catégories :

CatégorieCe qui est vérifié
RenderingURP est actif, Depth Texture et Opaque Texture sont activées, la renderer feature du brouillard de guerre est installée, les builds de joueur conservent les modes de brouillard atmosphérique utilisés par RTS Environment.
ProjectEspace colorimétrique Linear ; Burst, Collections et Mathematics sont installés ; mode de gestion des entrées actif.
WebGLUniquement lorsque Web est la plateforme de build active : les niveaux de qualité des builds Web ont Depth Texture et Opaque Texture, et le modèle Web remplit la fenêtre du navigateur (voir Vérifications Web dans le Project Validator).
ContentLes shaders du package se compilent et sont inclus dans les builds, les tableaux de textures des tilesets sont construits, l’instanciation GPU est activée sur les prototypes instanciés.
SceneChaque RTS Terrain des scènes ouvertes possède un tileset et un fichier de carte.

Chaque résultat a l’un des quatre états suivants :

ÉtatSignification
OKTout est correctement configuré.
InfoUne indication ou une recommandation. Rien n’est cassé.
WarningUne fonctionnalité n’est disponible qu’en mode dégradé, par exemple l’eau sans réfraction. Une correction est recommandée.
ErrorUn paramètre requis manque. Certaines parties du package ne fonctionneront pas.

Le bouton Fix All applique toutes les corrections disponibles. Une boîte de dialogue récapitule d’abord toutes les modifications, et rien n’est changé tant que vous n’avez pas cliqué sur Apply Fixes. Les corrections qui nécessitent URP (les textures de caméra et la renderer feature du brouillard de guerre) s’exécutent automatiquement une fois le pipeline assigné : un seul clic suffit donc à configurer un nouveau projet. Le bouton Run Again relance les vérifications. La liste complète des vérifications, avec leurs boutons de correction, figure dans Valider le projet.

Le Project Validator vérifie votre projet. Pour vérifier une seule carte (positions de départ, accessibilité, prototypes manquants, limites de performances), utilisez le validateur de cartes de l’onglet Map ; voir Validation des cartes.

Exécuter les vérifications par le code

RTSProjectValidator.RunChecks() renvoie les résultats sans rien modifier, et RTSProjectValidator.FixAll() applique les corrections. Vous pouvez les utiliser dans un script de build ou dans un job d’intégration continue. L’exemple doit être placé dans un dossier Editor.

using UnityEditor;
using UnityEngine;
using RTSTerrainStudio.Editor;

// Command line: Unity -batchmode -projectPath <path> -executeMethod ProjectSetupCheck.Run -quit
public static class ProjectSetupCheck
{
    public static void Run()
    {
        // Runs every check. Nothing is modified.
        var results = RTSProjectValidator.RunChecks();

        // Applies every available fix without dialogs, then checks again.
        int applied = RTSProjectValidator.FixAll(results, interactive: false);
        if (applied > 0) results = RTSProjectValidator.RunChecks();

        // Logs warnings and errors ("[Status] Title: Message").
        foreach (var result in results)
            if (result.IsProblem) Debug.LogWarning(result.ToString());

        // Fails the job when a required setting is still missing.
        if (RTSProjectValidator.WorstStatus(results) == RTSValidationStatus.Error)
            EditorApplication.Exit(1);
    }
}

La correction Install pour les packages manquants ne fait que lancer une requête au Package Manager, et les scripts du package ne peuvent pas se compiler tant qu’elle n’est pas terminée. Installez Burst, Collections et Mathematics avant d’exécuter le package en mode batch.

Universal Render Pipeline

Tous les shaders du package sont écrits pour URP. Sans lui, le terrain, l’eau et la végétation s’affichent en rose, voire pas du tout. La correction Use URP utilise un asset URP existant du projet (ou crée Assets/Settings/RTS URP.asset avec un renderer) et l’assigne comme pipeline de rendu par défaut, ainsi qu’à chaque niveau de qualité qui utilise un autre pipeline. Pour faire la même chose à la main :

  1. Si le projet n’a pas encore d’asset URP, créez-en un dans la fenêtre Project avec Create ▸ Rendering ▸ URP Asset (with Universal Renderer).
  2. Assignez-le comme Default Render Pipeline dans Edit ▸ Project Settings ▸ Graphics.
  3. Ouvrez Edit ▸ Project Settings ▸ Quality. Pour chaque niveau de qualité qui remplace le pipeline via Render Pipeline Asset, vérifiez que l’asset indiqué est lui aussi un asset URP.

Depth Texture et Opaque Texture

L’eau utilise la texture de profondeur de la caméra pour que sa couleur de profondeur, son écume et le fondu de son rivage suivent les objets posés dans l’eau, et la texture opaque pour la réfraction. Sans elles, l’eau paraît plus simple. Sélectionnez chaque asset URP utilisé par vos niveaux de qualité et cochez Depth Texture et Opaque Texture dans sa section Rendering, ou cliquez sur Enable Both dans le validateur.

Une caméra peut surcharger ces deux paramètres dans la section Rendering de son propre Inspector, et l’eau suit le réglage de chaque caméra qui l’affiche. Si l’eau reste plus simple que prévu dans la Game View, vérifiez que votre caméra de jeu ne les désactive pas. La Scene View utilise toujours les réglages de l’asset URP. Voir aussi la configuration URP requise pour l’eau.

La renderer feature du brouillard de guerre

La renderer feature RTS Fog Of War (RTSFogOfWarRendererFeature) dessine le brouillard de guerre par-dessus tout ce qui est à l’écran, y compris les unités et les accessoires qui utilisent vos propres matériaux. Sans elle, seuls les shaders du package affichent le brouillard de guerre. Le bouton Add Feature l’ajoute au renderer par défaut de chaque asset URP utilisé. Pour l’ajouter à la main, sélectionnez l’asset Universal Renderer Data, cliquez sur Add Renderer Feature et choisissez RTS Fog Of War. Les détails figurent dans Rendu : renderer feature et shader de repli.

Espace colorimétrique

Le package est conçu pour l’espace colorimétrique Linear, la valeur par défaut d’URP. En espace Gamma, les couleurs, l’éclairage et l’eau paraissent délavés par rapport aux captures d’écran. Réglez Edit ▸ Project Settings ▸ Player ▸ Other Settings ▸ Color Space sur Linear, ou cliquez sur Switch to Linear dans le validateur.

Changer d’espace colorimétrique réimporte toutes les textures. Dans un grand projet, cela peut prendre un certain temps.

Packages requis

L’assembly d’exécution utilise Burst (com.unity.burst), Collections (com.unity.collections) et Mathematics (com.unity.mathematics) pour ses jobs et son modèle de données. Les scripts du package ne se compilent pas tant que l’un d’eux manque. Installez-les depuis Window ▸ Package Manager ▸ Unity Registry, ou cliquez sur Install dans le validateur, qui ajoute tous les packages manquants en une seule requête au Package Manager. Les versions testées sont indiquées dans Packages requis.

Si l’import affiche des erreurs de compilation et que le menu Tools ▸ RTS Terrain Studio est absent, le validateur ne peut pas s’exécuter non plus, car il fait partie du package. Installez les trois packages à la main, puis ouvrez le validateur.

Gestion des entrées

Toutes les entrées à l’exécution (l’éditeur en jeu, la caméra et les unités d’exemple) passent par la classe statique RTSInput. Lorsque le package Input System (com.unity.inputsystem) est installé, l’assembly d’exécution est compilée avec le symbole RTS_INPUT_SYSTEM et utilise ce package. Sinon, ou lorsque le projet n’utilise que l’ancien Input Manager, RTSInput se rabat sur l’ancienne API UnityEngine.Input.

Active Input HandlingInput System installéRésultat
Input System Package (new)ouiOK. L’Input System est utilisé.
BothouiOK. L’Input System est utilisé.
Input Manager (old)ouiInfo. La solution de repli est utilisée.
toute valeurnonInfo. La solution de repli est utilisée. Elle fonctionne, mais n’est pas recommandée pour les nouveaux projets.

Ce paramètre se trouve dans Edit ▸ Project Settings ▸ Player ▸ Other Settings ▸ Active Input Handling. Unity demande de redémarrer l’éditeur lorsque vous le modifiez. La vérification Input handling ne modifie jamais ce paramètre à votre place, car le bon choix dépend de votre jeu. Voir aussi Gestion des entrées dans la configuration requise.

Shaders et contenu

  • Package shaders compile. Si un shader du package présente des erreurs de compilation (les objets concernés s’affichent en rose), le bouton Reimport permet de le réimporter. C’est utile lorsque les shaders ont été importés avant la fin du chargement d’URP. Si des shaders requis manquent complètement, réimportez le package depuis l’Asset Store. Voir Dépannage.
  • Shaders included in builds. Voir Générer le build de votre jeu.
  • Tileset texture arrays built. Les tilesets sans tableaux construits à jour fonctionnent quand même, mais tant que les tableaux ne sont pas reconstruits, l’éditeur construit des tableaux sans compression au chargement de la carte, ce qui coûte de la mémoire et du temps de chargement. Le bouton Build Arrays les construit pour chaque tileset obsolète. La génération d’un build de joueur reconstruit automatiquement les tableaux obsolètes ; dans les builds de joueur aussi, les tilesets dont les tableaux n’ont jamais été construits utilisent des tableaux sans compression. Voir Tableaux de textures et Tableaux de textures dans les builds de joueur.
  • GPU instancing on instanced prototypes. Les matériaux des arbres instanciés, des détails en mode Mesh et des objets de décor instanciés doivent avoir l’option Enable GPU Instancing cochée. Sinon, ils sont dessinés au moyen de copies temporaires, et leurs variantes d’instanciation peuvent être supprimées des builds de joueur. Le bouton Enable Instancing coche cette option sur chaque matériau listé qui peut être modifié. Les matériaux contenus dans un modèle ou dans un package sont en lecture seule : extrayez-les d’abord. Voir Instanciation GPU.
  • Terrains have a tileset. Un terrain sans tileset affiche un aspect neutre de substitution. La correction assigne un tileset du projet à chaque terrain qui n’en a pas (opération annulable). Voir Tilesets.

Les corrections de scène ne sont pas proposées en Play Mode, car les modifications apportées à la scène en Play Mode sont perdues à la sortie de ce mode.

Fichiers de carte des terrains de scène

Un RTS Terrain conserve sa carte dans un asset .rtsmap (son champ Map Asset). Un terrain qui n’en a pas ne garde sa carte qu’en mémoire, et vos modifications sont perdues à la fermeture de la scène. La vérification Terrains save to a map file liste ces terrains. Le bouton Create Map Files enregistre la carte actuelle de chaque terrain listé dans un nouveau fichier .rtsmap, placé dans le dossier de sa scène (ou dans Assets/Maps si la scène n’est pas encore enregistrée), puis l’assigne au terrain.

Les terrains créés avec le New Map Wizard ou avec le contenu de démo ont déjà un fichier de carte. Pour comprendre le fonctionnement des assets de carte et des commandes Save et Save As, lisez Assets de carte et fichiers de carte.

Générer le build de votre jeu

Unity n’intègre des shaders dans un build de joueur que si un matériau du build les utilise. RTS Terrain Studio crée les matériaux du terrain, de l’eau et du brouillard de guerre par le code à l’exécution ; les shaders sont donc référencés depuis l’asset Resources/RTSTerrainStudio/RTSShaderReferences.asset, situé dans le dossier du package. Cet asset référence aussi le matériau DecorPlaceholder, qui conserve dans le build les variantes d’instanciation d’URP Lit. L’asset est vérifié et mis à jour automatiquement après chaque rechargement des scripts, à chaque import de shaders et avant chaque build de joueur. Si la vérification Shaders included in builds est rouge, cliquez sur Update.

Avant de générer le build, passez en revue les points suivants :

  1. Exécutez Tools ▸ RTS Terrain Studio ▸ Validate Project et corrigez toutes les erreurs et tous les avertissements.
  2. Vérifiez que chaque niveau de qualité de votre plateforme cible utilise un asset URP avec Depth Texture et Opaque Texture, et que son renderer possède la renderer feature RTS Fog Of War si vous utilisez le brouillard de guerre.
  3. Construisez une première fois les tableaux de textures de vos tilesets (Build Arrays dans le validateur, ou Build Texture Arrays dans l’Inspector du tileset), afin que le terrain n’ait pas à les construire sans compression au chargement. Les tableaux obsolètes sont reconstruits automatiquement avant chaque build de joueur (voir ci-dessous).
  4. Si vos cartes utilisent le brouillard atmosphérique, assurez-vous que la vérification Fog kept in player builds indique OK (voir Brouillard atmosphérique dans les builds de joueur).
  5. Validez vos cartes dans l’onglet Map (voir Validation des cartes).
  6. Ajoutez vos scènes à la liste des scènes de votre profil de build. Les cartes assignées à un RTS Terrain dans une scène sont incluses comme n’importe quel autre asset référencé.
  7. Si vous livrez l’éditeur en jeu, lisez Livrer l’éditeur en jeu avec votre jeu. Les cartes que les joueurs enregistrent à l’exécution sont placées dans le dossier Maps de RTSMapSerializer.StorageRoot (Application.persistentDataPath ou, dans les builds Web, le stockage du navigateur) ; voir Fichiers de carte à l’exécution.
  8. Si vous réglez Managed Stripping Level sur un niveau supérieur à Minimal et que vous avez écrit vos propres outils d’édition, lisez Élagage du code et outils personnalisés.
  9. Pour un build Web, lisez aussi Builds Web (WebGL).

Ne déplacez pas et ne renommez pas RTSShaderReferences.asset ni le dossier Resources du package : le package charge ces assets avec Resources.Load à l’exécution.

Tableaux de textures dans les builds de joueur

Un build de joueur utilise tels quels les tableaux de textures construits d’un tileset, car seul l’éditeur peut les comparer aux textures sources. Pour qu’un build ne livre jamais d’anciennes textures de sol, chaque tileset dont les tableaux ont déjà été construits est vérifié juste avant le début d’un build de joueur :

  • Les tableaux qui ne correspondent plus aux textures, à la résolution ou à la compression, ou qui ont été construits pour une autre plateforme ou une autre compression de textures, sont reconstruits avec une qualité de compression normale. Une barre de progression indique l’avancement.
  • Les tilesets qui n’ont jamais été construits ne sont pas modifiés. Les builds de joueur construisent pour eux des tableaux sans compression au chargement d’une carte.
  • Si une reconstruction est annulée ou échoue alors que les textures ou les paramètres ont changé, une boîte de dialogue propose Try Again, Cancel Build et Build Anyway. Les tableaux dont seul le format diffère affichent quand même les bonnes textures : dans ce cas, seul un avertissement est consigné.
  • Un build en mode batch s’arrête dans ce cas. Ajoutez -rtsAllowOutdatedTextureArrays à la ligne de commande pour générer le build malgré tout, avec un avertissement par tileset.
  • Un éditeur sans périphérique graphique (-nographics, fréquent sur les serveurs de build) ne peut pas construire de tableaux. Le build continue alors avec un avertissement par tileset obsolète, et les builds de joueur utilisent les tableaux tels qu’ils ont été construits la dernière fois. Construisez les tableaux dans l’éditeur avant un tel build.
  • Les tableaux ne sont reconstruits que pour la plateforme de build active. Si vous générez un build pour une autre plateforme, le build consigne un avertissement à la place : passez d’abord sur cette plateforme.
  • Les asset bundles et le contenu Addressables que vous construisez séparément ne déclenchent pas cette vérification. Construisez d’abord les tableaux.

La détection des tableaux obsolètes s’appuie sur l’état d’import des textures sources, qui peut changer lors d’une mise à jour de Unity. Le premier build de joueur après une mise à jour peut donc reconstruire les tableaux de tous les tilesets construits, y compris ceux des tilesets de démo.

Les tableaux construits sont stockés dans l’asset du tileset sous une forme lisible par le CPU. Les builds de joueur libèrent cette copie CPU à la première utilisation des tableaux, ce qui économise environ 14 Mo par tileset à 512 px et environ 56 Mo à 1024 px.

Brouillard atmosphérique dans les builds de joueur

RTSEnvironment active le brouillard atmosphérique stocké dans une carte pendant l’exécution du jeu. Unity supprime les variantes de shader des modes de brouillard qu’il juge inutilisés : lorsque Project Settings ▸ Graphics ▸ Shader Stripping ▸ Fog Modes est réglé sur Automatic, il ne conserve que le brouillard des scènes du build enregistrées avec le brouillard activé. RTS Environment rétablit le brouillard propre à la scène avant chaque enregistrement : son brouillard n’est donc pas pris en compte, et les cartes avec brouillard atmosphérique n’afficheraient aucun brouillard dans un build.

La vérification Fog kept in player builds parcourt les scènes du build du profil de build actif ainsi que les scènes ouvertes, et liste les modes de brouillard qu’y utilise RTS Environment. Le bouton Keep Fog Modes (également inclus dans Fix All) règle Fog Modes sur Custom et conserve exactement ces modes, en plus de ceux qui étaient déjà conservés. Chaque mode conservé ajoute des variantes de shader au build ; les modes inutilisés ne sont donc pas ajoutés. Si le profil de build actif surcharge les paramètres Graphics, vérifiez aussi son réglage Fog Modes.

Builds Web (WebGL)

RTS Terrain Studio fonctionne dans un navigateur web : le terrain, la végétation, l’eau, les décors, le brouillard de guerre, l’éditeur en jeu et les exemples. Un navigateur ne fonctionne cependant pas comme une plateforme de bureau : le joueur ne peut ouvrir aucun dossier, certaines touches appartiennent au navigateur, tout le code s’exécute sur un seul thread et l’ensemble du jeu partage un unique tas mémoire de taille limitée. Cette section explique comment le package gère ces contraintes et comment générer, tester et publier un build Web.

En bref :

  1. Ouvrez File ▸ Build Profiles, sélectionnez Web et cliquez sur Switch Platform (ou faites de votre profil de build Web le profil actif).
  2. Exécutez Tools ▸ RTS Terrain Studio ▸ Validate Project et cliquez sur Fix All. Lorsque Web est actif, le validateur installe aussi le modèle pleine fenêtre et vérifie les niveaux de qualité des builds Web.
  3. Si vos cartes utilisent le brouillard atmosphérique, vérifiez que Fog kept in player builds indique OK.
  4. Cliquez sur Build And Run. Unity génère le build du jeu et l’ouvre dans votre navigateur.

Ce qui fonctionne dans le navigateur

SujetPrise en charge
API graphiqueWebGL 2.0, la valeur par défaut des builds Web (Auto Graphics API). Tous les shaders du package y fonctionnent. Cette section décrit WebGL 2.0 ; WebGPU, que Unity propose en option, n’est pas traité.
NavigateursLes navigateurs de bureau actuels pris en charge par la plateforme Web de Unity, utilisés avec une souris et un clavier.
Téléphones et tablettesLa page se charge, mais l’éditeur en jeu, la caméra RTS et les unités d’exemple sont conçus pour une souris et un clavier. La saisie tactile n’est pas prise en charge. Le modèle Web du package affiche un message sur les appareils mobiles.
RenduLe terrain, la végétation, l’eau, les décors et le brouillard de guerre ont le même aspect que sur les plateformes de bureau. L’herbe est stockée dans une texture float au lieu d’un structured buffer (voir Rendu et performances).
Éditeur en jeuTous les outils, l’explorateur de cartes et le test en jeu. Les cartes sont conservées dans le stockage du navigateur et peuvent être téléchargées et importées (voir Les cartes dans le navigateur). La taille de la carte et la mémoire d’annulation ont des limites plus basses (voir L’éditeur en jeu dans le navigateur).
ThreadsLes builds Web n’ont pas de threads de travail : tous les jobs s’exécutent donc l’un après l’autre sur le thread principal.

Le modèle pleine fenêtre

La page qui entoure un build Web provient d’un modèle Web. Les modèles Default et Minimal de Unity affichent le jeu dans un cadre de taille fixe sur les navigateurs de bureau (960 × 600 pixels, sauf si vous modifiez cette valeur). L’éditeur en jeu, le HUD et la mini-carte s’adaptent à ce cadre, si bien que leur texte devient difficile à lire. Le package fournit donc son propre modèle :

  • Le jeu remplit la fenêtre du navigateur au-dessus d’un fin pied de page qui contient le nom du jeu et le bouton plein écran, et se redimensionne avec la fenêtre. Sur les téléphones et les tablettes, il occupe toute la page.
  • La barre de chargement (avec un pourcentage), le bouton plein écran et les bannières de message de Unity sont conservés.
  • Sur les écrans haute résolution, la résolution de rendu est plafonnée à 1.5 fois la taille en pixels CSS, ce qui préserve la fréquence d’images. Pour l’ajuster, modifiez maxDevicePixelRatio dans le fichier index.html du modèle installé (des valeurs plus basses, jusqu’à 1, sont plus rapides ; des valeurs plus hautes donnent une image plus nette).
  • Les fichiers que le jeu enregistre, comme les cartes de l’éditeur en jeu, sont écrits immédiatement dans le stockage du navigateur.
  • La page n’envoie aucune requête à d’autres serveurs ; ses icônes sont intégrées à la page.

Pour l’installer :

  1. Choisissez Tools ▸ RTS Terrain Studio ▸ Install WebGL Template, ou cliquez sur Install Template dans le panneau Web template fills the browser window du Project Validator.
  2. Le modèle est copié dans Assets/WebGLTemplates/RTSTerrainStudio (Unity ne trouve les modèles que dans Assets/WebGLTemplates) et sélectionné dans Player Settings ▸ Resolution and Presentation ▸ Web Template.
  3. Si le modèle est déjà installé, le menu vous demande s’il faut conserver et sélectionner votre copie (Keep and Select) ou la remplacer par la version du package (Replace). La copie appartient à votre projet : modifiez-la librement, le package ne l’écrase jamais sans vous le demander.

Profils de build : un profil de build peut surcharger les Player Settings ; il conserve alors son propre choix de modèle. Activez votre profil de build Web avant d’installer le modèle, afin que le réglage soit enregistré dans ce profil. Si vous l’avez installé alors qu’une autre plateforme était active, sélectionnez à la main le modèle RTSTerrainStudio dans les surcharges des Player Settings de votre profil de build Web.

Le modèle est basé sur le modèle Default de Unity et n’utilise que les variables de modèle propres à Unity : aucun nouveau réglage n’apparaît donc dans les Player Settings. Sur les téléphones et les tablettes, il affiche le message This game is best played on a computer with a mouse and keyboard. pendant quelques secondes ; supprimez cette ligne de index.html si votre jeu prend en charge la saisie tactile.

Depuis un script d’éditeur (par exemple un script de build), RTSWebGLTemplateInstaller.InstallAndSelect(false) installe le modèle sans boîte de dialogue, conserve une copie existante et la sélectionne. IsInstalled et IsSelected indiquent l’état actuel.

Vérifications Web dans le Project Validator

Lorsque Web est la plateforme de build active, le validateur affiche un groupe WebGL qui contient ces trois vérifications.

VérificationCorrectionCe qui est vérifié
Web quality levels have Depth and Opaque TextureEnable BothLes niveaux de qualité cochés dans la colonne Web de Project Settings ▸ Quality (le niveau par défaut de Web apparaît en premier) et l’asset URP avec lequel chacun d’eux effectue le rendu. L’éditeur effectue généralement le rendu avec un niveau de qualité de bureau : un build Web peut donc avoir une eau plus simple, sans que vous le voyiez jamais dans l’éditeur. Chaque texture coûte une copie plein écran par image. La vérification générale Depth and Opaque Texture enabled peut signaler le même asset ; Fix All corrige les deux.
MSAA is off for Web buildsTurn MSAA OffUne erreur lorsqu’un niveau de qualité Web effectue le rendu avec un asset URP qui combine le MSAA avec Depth Texture ou Opaque Texture. URP ne peut pas effectuer le rendu de cette combinaison sur WebGL 2 : le canvas reste noir et la console du navigateur affiche Render Graph Execution error. La correction désactive le MSAA dans ces assets. Les niveaux de qualité de bureau qui partagent un tel asset perdent eux aussi le MSAA ; donnez donc à la plateforme Web un niveau de qualité doté de son propre asset URP.
Web template fills the browser windowInstall Template / ReinstallUn avertissement pour les modèles Default et Minimal de Unity, une erreur si le modèle du package est sélectionné mais que son dossier manque (le build échouerait), et OK pour le modèle du package. Le modèle PWA remplit lui aussi la fenêtre et est OK, mais son service worker met le build en cache : augmentez Player Settings ▸ Version à chaque mise en ligne. Tout autre modèle personnalisé reçoit une information sans correction.

La vérification Fog kept in player builds de la catégorie Rendering s’exécute pour toutes les plateformes et compte aussi pour les builds Web (voir Brouillard atmosphérique dans les builds de joueur).

Paramètres de build recommandés

ParamètreEmplacementRecommandation
Texture CompressionVotre profil de build WebUse Player Settings ou DXT pour les navigateurs de bureau. Pour un build destiné aux navigateurs mobiles, choisissez ASTC ou ETC2. Les tableaux de textures des tilesets suivent ce paramètre (DXT5, ASTC 6×6 ou ETC2 RGBA8) et sont reconstruits avant le build. Si un navigateur ne peut pas utiliser le format choisi, Unity lui fournit les textures décompressées, ce qui demande environ quatre fois plus de mémoire.
Maximum Memory SizePlayer Settings ▸ Publishing SettingsConservez la valeur par défaut de 2048 Mo. Les limites de l’éditeur en jeu dans le navigateur sont prévues pour ce tas mémoire.
Compression FormatPlayer Settings ▸ Publishing SettingsBrotli produit le plus petit téléchargement, mais ne fonctionne qu’en HTTPS. Gzip fonctionne aussi en HTTP. Les deux nécessitent les bons en-têtes côté serveur (voir Publier sur un site web).
Decompression FallbackPlayer Settings ▸ Publishing SettingsActivez-le si vous ne pouvez pas définir les en-têtes du serveur, par exemple sur les portails de jeux. Le jeu se charge alors partout, avec un démarrage légèrement plus long.
Data CachingPlayer Settings ▸ Publishing SettingsActivé. Le navigateur conserve les données du jeu téléchargées : la visite suivante démarre donc plus vite.
Enable ExceptionsPlayer Settings ▸ Publishing SettingsExplicitly Thrown Exceptions Only (valeur par défaut) pour les builds de production. Dans ce mode, une référence nulle n’est pas signalée comme exception : utilisez donc un build de développement avec Full With Stacktrace lorsque vous cherchez un bug.
Managed Stripping LevelPlayer Settings ▸ Other Settings ▸ OptimizationTous les niveaux conviennent au package. Les niveaux plus élevés réduisent la taille du téléchargement ; les outils d’édition personnalisés ont alors besoin de [Preserve] (voir Élagage du code et outils personnalisés).
Niveaux de qualité et asset URPProject Settings ▸ QualityDécochez la colonne Web des niveaux de qualité de bureau que vous n’utilisez pas dans le navigateur, afin que leurs assets URP n’ajoutent pas de variantes de shader au build. Dans l’asset URP utilisé pour Web, laissez les light cookies et le fondu des reflection probes désactivés, sauf si vos scènes en ont besoin : WebGL 2.0 n’autorise que 16 textures par draw call (voir Remarques pour les mobiles). Laissez Anti Aliasing (MSAA) désactivé dans cet asset : combiné à Depth Texture ou Opaque Texture, il empêche URP d’effectuer le rendu sur WebGL 2.
Web TemplatePlayer Settings ▸ Resolution and PresentationRTSTerrainStudio (voir Le modèle pleine fenêtre).

Tester un build Web sur votre ordinateur

  • Build And Run est la méthode la plus simple. Unity démarre un petit serveur web local et ouvre le jeu dans votre navigateur par défaut.
  • Double-cliquer sur le fichier index.html généré ne fonctionne pas. Les navigateurs n’exécutent pas les builds Web depuis des adresses file://, et la page n’affiche qu’un message d’erreur.
  • Pour rouvrir plus tard un dossier de build terminé, servez-le avec n’importe quel serveur web local. Un serveur simple qui ne définit aucun en-tête de compression ne peut servir que des builds avec Decompression Fallback activé, ou sans compression.
  • Testez une fois les touches dans le navigateur que vous ciblez : F1, F5, Ctrl+S, Alt+N et Esc en plein écran (voir L’éditeur en jeu dans le navigateur).

Publier sur un site web

  • Mettez en ligne tout le dossier du build : index.html, Build et TemplateData.
  • Les builds compressés nécessitent deux en-têtes sur les fichiers de Build : Content-Encoding: br pour Brotli ou Content-Encoding: gzip pour Gzip, et le bon Content-Type, par exemple application/wasm pour le fichier .wasm. Sans Content-Encoding, la page affiche un message d’erreur, et un Content-Type incorrect ralentit le démarrage. Si vous ne pouvez pas configurer le serveur, activez Decompression Fallback.
  • Les portails de jeux comme itch.io affichent le jeu dans une iframe. Mettez en ligne un fichier ZIP avec index.html à la racine. Une iframe en sandbox nécessite allow-downloads pour Download Map et allow-modals pour la question Leave site?. Vérifiez les deux sur la page réelle.
  • Les cartes enregistrées appartiennent au site web. Le navigateur les conserve par adresse de site (protocole, hôte et port). Une nouvelle mise en ligne sur le même site les conserve ; le même jeu sur un autre site démarre sans cartes.
  • Safari peut supprimer les données stockées d’un site web inutilisé depuis sept jours, et Safari sur iPhone et iPad ignore la question Leave site?. Conseillez à vos joueurs de télécharger les cartes qu’ils veulent conserver.
  • Dans une iframe, le jeu ne reçoit les touches qu’après que le joueur a cliqué dedans, et Esc quitte toujours le plein écran du navigateur (voir plus bas).

Les cartes dans le navigateur

Dans un navigateur, Application.persistentDataPath est un système de fichiers en mémoire. Il n’est copié dans la base de données du navigateur (IndexedDB) que sur demande. Le modèle Web du package fait cette demande après chaque modification. Avec d’autres modèles, le package la fait lui-même après chaque enregistrement, suppression et import, afin que les cartes enregistrées soient toujours là après un rechargement de la page. Dans votre propre code, faites de même avec RTSWebFileSystem.Flush() (voir API de script pour les builds Web).

persistentDataPath dépend de l’adresse de la page : une nouvelle mise en ligne sous une autre adresse (les portails de jeux en utilisent souvent une nouvelle à chaque mise en ligne) démarrerait ainsi sans cartes. C’est pourquoi, dans les builds Web, les cartes sont conservées dans RTSMapSerializer.StorageRoot, un dossier du même stockage du navigateur, nommé d’après le nom de la société et le nom du produit définis dans les Player Settings. Sur toutes les autres plateformes, StorageRoot est persistentDataPath. Le dossier des cartes de l’éditeur en jeu est le sous-dossier Maps de ce dossier.

Comme les joueurs ne peuvent pas ouvrir ce stockage comme un dossier, l’éditeur en jeu transfère lui-même les cartes entre le navigateur et l’ordinateur :

CommandeEmplacementRôle
Download MapMenu FileDemande au navigateur de télécharger la carte actuelle, modifications non enregistrées comprises, sous forme de fichier .rtsmap (généralement dans le dossier Téléchargements).
Import Map...Menu FileOuvre le sélecteur de fichiers du navigateur. Le fichier .rtsmap choisi est ajouté aux cartes enregistrées dans ce navigateur, puis ouvert après la question habituelle sur les modifications non enregistrées.
Import...Explorateur de cartes (Open)Identique à Import Map, à côté de la ligne d’emplacement.
DownloadExplorateur de cartes (Open)Télécharge le fichier de carte sélectionné.
Glisser-déposerCanvas du jeuUn fichier .rtsmap déposé sur le jeu est importé et ouvert. Les autres fichiers sont refusés avec un message, afin que le navigateur ne quitte pas la page pour les afficher.
  • Le fichier entier est vérifié avant d’être stocké, et les fichiers jusqu’à 128 Mo sont acceptés.
  • Un import ne remplace jamais une autre carte. Importer de nouveau le même fichier réutilise la carte existante ; un autre fichier portant le même nom est enregistré sous Nom (2), Nom (3), etc. Une image d’aperçu est écrite à l’ouverture de la carte.
  • L’explorateur de cartes affiche Saved in this browser. Use Download to keep a copy on your computer. au lieu d’un chemin de dossier. Les commandes Show Maps Folder et Quit n’existent pas dans le navigateur.
  • Effacer les données de navigation du site web supprime aussi les cartes enregistrées.

L’éditeur en jeu dans le navigateur

Fermer l’onglet avec des modifications non enregistrées

Tant que la carte contient des modifications non enregistrées et que Confirm Quit With Unsaved Changes est activé, le navigateur demande Leave site? avant que l’onglet soit fermé ou rechargé. Le texte de cette question est choisi par le navigateur. Avec les modèles propres à Unity, qui n’écrivent pas les fichiers immédiatement, il pose aussi la question tant qu’un enregistrement est encore en cours d’écriture dans le stockage du navigateur, indépendamment de cette option.

Rouvrir l’éditeur après l’avoir fermé

Dans les navigateurs, les touches de fonction servent souvent de touches multimédias (sur les Mac et de nombreux ordinateurs portables), et les téléphones n’en ont pas. Lorsque le joueur ferme l’éditeur avec son bouton de fermeture (×), un bouton Open Map Editor (F2) apparaît donc en bas à gauche et permet de le rouvrir. Sans clavier, ou lorsque Toggle Key est réglé sur None, le bouton affiche Open Map Editor. Le bouton n’apparaît qu’après utilisation du bouton de fermeture ; lorsque le code de votre jeu masque l’éditeur, c’est votre jeu qui décide comment il réapparaît. Dans le navigateur, le bouton de fermeture est disponible même lorsque Toggle Key est réglé sur None.

Clavier
  • New Map correspond à Alt+N. Les navigateurs réservent Ctrl+N à l’ouverture d’une nouvelle fenêtre et ne le transmettent jamais à la page. Alt+N fonctionne aussi sur les plateformes de bureau. Ctrl+T et Ctrl+W n’atteignent jamais une page non plus.
  • Les raccourcis du navigateur sont interceptés. Tant que l’éditeur est activé, le navigateur ne réagit ni aux touches F1 à F10 ni à Ctrl (ou Cmd) + S, O, D et A, qui fonctionnent ainsi comme raccourcis de l’éditeur. F11, F12, Ctrl+F5, Ctrl+R, copier, coller et les touches saisies dans les champs de texte de la page restent gérés par le navigateur.
  • F5 démarre et termine le test en jeu : vous ne dépendez donc pas de Esc.
  • Esc en plein écran : les navigateurs utilisent Esc pour quitter le plein écran. Dans Chrome et Edge, sur une page sécurisée (HTTPS ou localhost) qui n’est pas dans une iframe, un appui bref sur Esc parvient au jeu, et maintenir Esc enfoncée quitte le plein écran. Ailleurs, le premier appui sur Esc quitte le plein écran. Autres solutions : F5 ou Back to Editor termine un test en jeu, le bouton × ferme une boîte de dialogue, et Ctrl+Z annule un trait. La fenêtre d’aide (F1) le rappelle aussi.
  • Dispositions de clavier : les raccourcis à lettre (Ctrl+Z, G, P…) suivent la lettre imprimée sur la touche, y compris sur les claviers allemands (QWERTZ) et français (AZERTY). Les touches du pinceau suivent le caractère saisi : [ fonctionne donc aussi là où il s’obtient avec AltGr+8. Il en va de même sur les plateformes de bureau.
  • Démo de gameplay : dans la plupart des navigateurs, Ctrl+1 à Ctrl+9 (groupes de contrôle) changent d’onglet. Choisissez d’autres touches pour un jeu web.
Limites

La carte, ses textures et l’historique d’annulation partagent un unique tas mémoire de 2 Go au maximum (la valeur par défaut de Maximum Memory Size), et ce tas ne diminue jamais. L’éditeur applique donc des limites plus basses dans le navigateur :

LimiteNavigateurAutres plateformes
Plus grande carte dans New Map et Resize2048 ÷ résolution de splat, en cellules par côté : 512 avec la résolution de splat par défaut de 4, 256 avec 8. Les préréglages plus grands ne sont pas proposés, et les boîtes de dialogue indiquent In the browser, maps can be up to N x N cells. La commande Resize conserve la taille d’une carte plus grande ouverte depuis un fichier, mais ne l’agrandit pas.1024
Mémoire d’annulation192 Mo au maximum. Une valeur plus basse de Undo Memory MB est conservée.Undo Memory MB (512 par défaut)
Fichier de carte importé128 MoPas de commande d’import
Autres différences
  • L’interface ne descend jamais sous 85 %, mesurés en pixels CSS : elle reste ainsi lisible sur les écrans haute résolution et dans les petites fenêtres.
  • Le défilement par les bords de la caméra de l’éditeur et de la caméra RTS d’exemple s’arrête lorsque la souris quitte la page ou l’iframe du jeu.

Rendu et performances

  • Herbe : WebGL 2.0 ne dispose pas de structured buffers. Le renderer de détails stocke donc les instances de chaque patch dans une texture float (deux texels par instance). Il choisit cette solution à l’exécution, et l’herbe a le même aspect.
  • Terrain : la passe forward utilise 10 des 16 textures que WebGL 2.0 autorise par draw call. Gardez l’asset URP des builds Web léger (voir Remarques pour les mobiles).
  • Un seul thread : sans threads de travail, les opérations sur l’ensemble de la carte prennent nettement plus de temps que sur les plateformes de bureau, et la page ne réagit plus pendant ce temps : Generate, New Map, Resize, l’ouverture d’une grande carte et Apply to Whole Map d’Auto Paint. Les cartes de 128 à 256 cellules de côté restent confortables.
  • Tableaux de textures : utilisez des tableaux construits dans le format de votre build Web (voir Paramètres de build recommandés). Les builds de joueur libèrent la copie CPU des tableaux construits, ce qui compte dans la mémoire limitée d’une page.
  • Résolution de rendu : le modèle pleine fenêtre plafonne le ratio de pixels à 1.5 ; baissez-le pour obtenir une fréquence d’images plus élevée.

Élagage du code et outils personnalisés

Les outils d’édition sont trouvés et créés par réflexion (RTSToolRegistry) : aucun code n’y fait donc directement référence. Avec un Managed Stripping Level supérieur à Minimal, courant pour obtenir des builds Web et IL2CPP plus légers, Unity ne voit pas qu’ils sont utilisés et les supprimerait. Le fichier Runtime/link.xml du package conserve toutes les classes de l’espace de noms RTSTerrainStudio dont le nom se termine par Tool : les outils intégrés sont donc toujours conservés.

Marquez vos propres classes d’outils avec [UnityEngine.Scripting.Preserve], qui conserve la classe et son constructeur sans paramètre, ou listez-les dans un fichier link.xml de votre projet. Un build de joueur qui ne trouve aucun outil consigne le message No editing tools were found in this build.

using RTSTerrainStudio;
using UnityEngine.Scripting;

// [Preserve] keeps the tool in builds with a high Managed Stripping Level.
[Preserve]
public sealed class CraterTool : RTSTool
{
    // ...
}

API de script pour les builds Web

MembreDescription
RTSWebFileSystem.IsSupportedVaut true dans un build de joueur WebGL. Sur les autres plateformes et dans l’éditeur Unity, la classe ne fait rien.
RTSWebFileSystem.Flush()Copie le système de fichiers de la page dans le stockage du navigateur, afin que les fichiers écrits ou supprimés avec System.IO survivent à un rechargement. Tous les appels d’une même image sont regroupés en une seule écriture. RTSMapSerializer.SaveToFile l’appelle pour vous.
RTSWebFileSystem.DownloadFile(fileName, data, mimeType)Demande au navigateur de télécharger des octets sous forme de fichier. Renvoie false sur les autres plateformes ou si le navigateur a refusé le téléchargement.
RTSMapSerializer.StorageRootDossier des fichiers conservés d’une session à l’autre : Application.persistentDataPath et, dans les builds Web, un dossier du stockage du navigateur qui ne dépend pas de l’adresse de la page.
RTSMapSerializer.DefaultMapsFolderMaps dans StorageRoot.
RTSRuntimeEditor.RunsInBrowserVaut true dans les builds Web, où l’éditeur applique les limites du navigateur et utilise Alt+N pour New Map.
RTSRuntimeEditor.StoresMapsInBrowserVaut true lorsque les cartes sont conservées dans le stockage du navigateur (builds de joueur WebGL).
RTSRuntimeEditor.HasReliableFunctionKeysVaut false dans les navigateurs web et sur les plateformes mobiles, où le bouton de fermeture fait apparaître le bouton de réouverture.
editor.DownloadMap(), editor.ImportMap()Les commandes du menu File. Les navigateurs n’affichent le sélecteur de fichiers qu’en réponse à un clic ou à un appui sur une touche : appelez donc ImportMap depuis un gestionnaire de clic.
RTSInput.SetBrowserShortcutGuard(bool)Bloque l’action propre au navigateur pour F1 à F10 et Ctrl+S/O/D/A, et laisse un appui bref sur Esc parvenir au jeu en plein écran (Chrome, Edge). Chaque appel avec true doit être suivi d’un appel correspondant avec false. L’éditeur en jeu et RTSDemoHUD l’activent tant qu’ils sont actifs. Ne fait rien sur les autres plateformes.
RTSInput.GetKeyDownByLabel(RTSKey)Comme GetKeyDown, mais pour la touche qui porte cette lettre sur la disposition de clavier du joueur. Utilisez-la pour les raccourcis à lettre comme Ctrl+Z.
RTSInput.GetCharacterDown(char)Vaut true lorsque le caractère a été saisi pendant cette image, quelle que soit la disposition de clavier. Utilisez-la pour les touches de symboles comme [ ] - +. Les caractères saisis dans un champ de texte qui a le focus arrivent aussi ici : vérifiez donc d’abord le focus de l’interface.
RTSInput.PointerInsideScreenVaut true tant que le pointeur se trouve dans la fenêtre du jeu. Dans les builds Web, la souris doit en outre encore survoler la page.
using System.IO;
using RTSTerrainStudio;

public static class MyGameFiles
{
    // Kept between sessions on every platform; in Web builds in the storage of the browser.
    static string SettingsPath => Path.Combine(RTSMapSerializer.StorageRoot, "settings.json");

    public static void SaveSettings(string json)
    {
        Directory.CreateDirectory(RTSMapSerializer.StorageRoot);
        File.WriteAllText(SettingsPath, json);

        // Web builds: write the change to the browser storage, so it survives a reload.
        // Does nothing on other platforms.
        RTSWebFileSystem.Flush();
    }

    /// <summary>Lets the player keep a copy of the current map on the computer (Web builds only).</summary>
    public static bool DownloadMap(RTSTerrain terrain)
    {
        if (!RTSWebFileSystem.IsSupported || terrain.Map == null) return false;
        byte[] bytes = RTSMapSerializer.Serialize(terrain.Map);
        return RTSWebFileSystem.DownloadFile("My Map" + RTSMapSerializer.FileExtension, bytes);
    }
}

Concepts fondamentaux

Ce chapitre explique comment RTS Terrain Studio conçoit une carte : ce qui est stocké, dans quelles unités de mesure, comment la surface visible est construite à partir de ces données, et quels assets (tilesets, bibliothèques, fichiers de carte) lui sont associés. Vous n’avez pas besoin de le lire avant votre première carte, mais revenez-y lorsque vous voudrez comprendre pourquoi tel ou tel élément se comporte ainsi, ou lorsque vous commencerez à écrire du code qui exploite les données de la carte.

En bref :

  • Une carte est une grille de cellules carrées. Les hauteurs, les niveaux de falaise et l’eau sont stockés sur les coins (vertices) des cellules.
  • Les niveaux de falaise sont des nombres entiers de 0 à 15. Là où des coins voisins ont des niveaux différents, une paroi de falaise verticale apparaît, sauf si les quatre coins de la cellule sont marqués comme rampe.
  • Les textures de sol, la densité de l’herbe et les surcharges de cheminement sont des couches raster comportant plusieurs texels par cellule.
  • Les arbres, les décors, les régions, les positions de départ et les marqueurs sont des listes d’objets en coordonnées locales de la carte.
  • L’apparence provient d’un tileset (textures de sol, de falaise et d’eau) ; les objets proviennent d’une bibliothèque de végétation et d’une bibliothèque de décors. Les cartes ne stockent que des indices et des identifiants : vous pouvez donc changer l’apparence sans toucher à la carte.
  • Tout est enregistré dans un seul fichier binaire compact .rtsmap, utilisé à la fois par l’éditeur Unity et par l’éditeur en jeu.

Le modèle de carte

Toutes les données d’une carte résident dans un seul objet de la classe MapData (espace de noms RTSTerrainStudio). Un composant RTSTerrain possède un MapData (terrain.Map), en assure le rendu sous forme de meshes de chunks, tient à jour la carte de cheminement qui en dérive et répond à des requêtes comme « à quelle hauteur se trouve le sol ici ? ».

Cellules et vertices

La carte est une grille de Width × Height cellules. Chaque cellule possède quatre vertices, un à chaque coin, et les cellules voisines partagent leurs coins. Une carte de 4 × 2 cellules compte donc 5 × 3 vertices :

 z
 2   v10 ---- v11 ---- v12 ---- v13 ---- v14
      |  cell  |  cell  |  cell  |  cell  |
      | (0,1)  | (1,1)  | (2,1)  | (3,1)  |
 1   v5 ----- v6 ----- v7 ----- v8 ----- v9
      |  cell  |  cell  |  cell  |  cell  |
      | (0,0)  | (1,0)  | (2,0)  | (3,0)  |
 0   v0 ----- v1 ----- v2 ----- v3 ----- v4
     x=0      1        2        3        4

 vertex index = z * VertexCountX + x      (VertexCountX = Width + 1)
  • Les couches par vertex (hauteur fine, niveau de falaise, indicateurs, type de falaise, hauteur de l’eau) comptent (Width + 1) × (Height + 1) entrées, stockées ligne par ligne. Utilisez map.VertexIndex(x, z).
  • La taille de cellule (map.CellSize, 2 m par défaut) est la taille réelle d’une cellule. Une carte de 128 × 128 cellules de 2 m couvre 256 × 256 m (map.WorldSize).
  • Une position appartient à la cellule floor(localXZ / CellSize) ; map.LocalToCell(localXZ) effectue ce calcul et limite le résultat aux bornes de la carte.
  • Pour le rendu, les cellules sont regroupées en chunks (16, 32 ou 64 cellules par côté, paramètre Chunk Size du composant RTSTerrain, 32 par défaut). Seuls les chunks touchés par une modification sont reconstruits. La taille de chunk ne modifie pas les données de la carte.

Dimensions de la carte

Les dimensions sont choisies à la création de la carte (dans le New Map Wizard, dans la boîte de dialogue New Map de l’éditeur en jeu ou avec MapCreationSettings dans le code). Les valeurs situées hors de la plage autorisée sont corrigées par MapCreationSettings.Validate().

ParamètrePar défautValeurs autoriséesDescription
width, height12816–1024, arrondi à un multiple de 16Nombre de cellules selon X et Z. Le New Map Wizard propose des préréglages allant de Tiny (64) à Epic XL (512).
cellSize2≥ 0.1Taille réelle d’une cellule, en mètres.
cliffLevelHeight2≥ 0.05Hauteur réelle d’un niveau de falaise, en mètres.
baseCliffLevel20–15Niveau de falaise initial de chaque vertex. Le niveau 2 laisse de la place pour creuser des lacs et des rivières.
baseGroundLayer00–15Calque de sol qui recouvre initialement toute la carte.
splatResolution41, 2, 4, 8Nombre de texels de texture de sol (splat) par côté de cellule.
detailResolution21, 2, 4Nombre de texels de densité de détails (herbe) par côté de cellule.
pathingResolution21, 2, 4Nombre de cellules de cheminement par côté de cellule de carte.
name« New Map »texte libreNom de la carte (stocké dans les informations de la carte).

Les résolutions qui ne sont pas une puissance de deux sont arrondies à la puissance supérieure (3 devient 4). La taille de cellule, la hauteur de niveau et les trois résolutions raster sont figées une fois la carte créée. La fonction Resize (RTSTerrain.ResizeMap) ne modifie que le nombre de cellules ; elle conserve le contenu en le décalant d’une valeur donnée et remplit les nouvelles zones avec un niveau de falaise et un calque de sol choisis.

MapData.Resize(newWidth, newHeight, offsetCells, fillCliffLevel, fillGroundLayer) renvoie une nouvelle carte (l’originale n’est pas modifiée). Les arbres, les objets de décor et les positions de départ situés hors des nouvelles limites sont supprimés. Les marqueurs et les régions sont décalés mais conservés, même s’ils se retrouvent à l’extérieur. Les tailles sont limitées à 16–1024 (MapData.MinSize–MaxSize), mais ne sont pas arrondies à un multiple de 16 lorsque vous appelez cette méthode par le code. RTSTerrain.ResizeMap remplace la carte (l’événement MapLoaded est déclenché), la marque comme non enregistrée et efface l’historique d’annulation des sessions d’édition.

Contenu d’une carte

Chaque type de données possède un indicateur correspondant dans l’énumération MapLayers. Ces indicateurs servent aux notifications de modification, à l’enregistrement des annulations et à la sérialisation.

DonnéesStocké parMembre de MapDataTypeIndicateur MapLayers
Hauteur finevertexHeightsNativeArray<float>, en mètresHeights
Niveau de falaisevertexCliffLevelsNativeArray<byte>, 0–15CliffLevels
Indicateurs de vertex (rampe, eau)vertexVertexFlagsNativeArray<byte> de VertexFlagsVertexFlags
Type de falaisevertexCliffTypesNativeArray<byte>, 0–3CliffTypes
Hauteur de la surface de l’eauvertexWaterHeightsNativeArray<float>, Y local à la carteWater
Poids des calques de soltexel de splatSplatMaps[0..3]NativeArray<Color32> × 4Splat
Densité d’herbe / de plantestexel de détailDetailLayersun DetailLayer (un octet par texel) par prototypeDetails
ArbresinstanceTrees, TreePrototypeIdsList<TreeInstanceData>Trees
Décor (doodads)instanceDecor, DecorPrototypeIdsList<DecorInstanceData>Decor
Surcharges manuelles de cheminementcellule de cheminementPathingOverridesNativeArray<byte> de PathingOverridePathingOverrides
RégionslisteRegionsList<MapRegion>Regions
Positions de départlisteStartLocationsList<StartLocation>StartLocations
MarqueurslisteMarkersList<MapMarker>Markers
Informations de la cartecarteInfoMapInfoInfo
Environnement (éclairage)carteEnvironmentEnvironmentSettingsEnvironment

Deux indicateurs combinés sont pratiques : MapLayers.Geometry (hauteurs, niveaux, indicateurs de vertex, types de falaise) et MapLayers.PathingInputs (tout ce qui influe sur la carte de cheminement). MapLayers.All couvre l’ensemble.

La carte de cheminement (terrain.Pathing, classe PathingMap) est une donnée dérivée : elle est calculée à partir des couches ci-dessus et n’est jamais enregistrée. Voir Carte de cheminement.

VertexFlags.User0 et VertexFlags.User1 sont réservés à votre propre code. Le package ne les utilise jamais, et ils sont enregistrés avec la carte : vous pouvez donc marquer des vertices particuliers (par exemple « zone d’apparition des creeps ») sans section de fichier personnalisée.

MapData utilise de la mémoire native. Une carte que vous créez ou chargez vous-même (MapData.Create, RTSMapSerializer.LoadFromFile, RTSMapAsset.LoadMap, map.Clone()) doit être libérée avec Dispose(), sauf si vous la confiez à un terrain avec terrain.SetMap(map) : le terrain en devient alors propriétaire et la libère lorsque la carte est remplacée ou que le composant est désactivé.

Niveaux de falaise, hauteurs fines et types de falaise

Le terrain des RTS classiques comporte deux sortes de hauteur : de grandes marches discrètes (les falaises) et de petites variations douces (les collines). RTS Terrain Studio stocke les deux séparément sur chaque vertex.

Niveaux de falaise

  • Chaque vertex possède un niveau de falaise compris entre 0 et 15 (MapData.MaxCliffLevel = 15).
  • Un niveau mesure CliffLevelHeight mètres de haut (2 m par défaut).
  • Les nouvelles cartes démarrent au niveau 2 : il reste ainsi deux niveaux sous le sol pour les lacs, les rivières et les canyons, et treize au-dessus pour les plateaux.
  • Modifiez les niveaux avec les outils de falaise : Raise / Lower Level, Set Level, Ramp, Cliff Type et Clean Cliffs.
  • Le brouillard de guerre utilise les niveaux de falaise pour la ligne de vue : les unités voient leur propre niveau et ceux du dessous, tandis que les terrains plus élevés bloquent leur vision.

Hauteurs fines

En plus du niveau, chaque vertex possède une hauteur fine en mètres (Heights), positive ou négative. Les outils de hauteur (Raise / Lower, Smooth, Flatten, Set Height, Noise, Terrace, Erode) ne modifient que la hauteur fine, ce qui vous permet de créer des collines sur un plateau sans qu’elles deviennent des falaises. La hauteur du sol d’un vertex vaut :

vertex height = CliffLevels[i] × CliffLevelHeight + Heights[i]      (map-local Y, metres)

Exemple : au niveau 3, avec une hauteur de niveau de 2 m et une hauteur fine de 0.4 m, le vertex se trouve à 6.4 m au-dessus de l’origine de la carte. map.GetVertexHeight(x, z) et map.GetVertexPosition(x, z) effectuent ce calcul pour vous.

Types de falaise

Un tileset peut contenir jusqu’à 4 calques de falaise (par exemple « Rock » et « Grassy Cliff »). Chaque vertex indique lequel utiliser (CliffTypes, 0–3, peint avec l’outil Cliff Type). Une paroi de falaise utilise le type de falaise du coin le plus haut de sa cellule. Si un indice de type de falaise ne correspond à aucun calque du tileset, la paroi se rabat sur le calque de falaise 0.

Construction de la surface (la surface de référence)

La structure MapGeometryView définit la seule et unique surface du terrain. Les meshes des chunks, les requêtes de gameplay (GetHeight, Raycast, …), la carte de cheminement et le brouillard de guerre suivent tous les mêmes règles, si bien que ce que vous voyez est exactement le sol sur lequel marchent les unités. Chaque cellule est classée d’après ses quatre coins :

Type de celluleConditionSurface
Cellule lisseLes quatre coins ont le même niveau de falaise.Surface bilinéaire passant par les hauteurs des quatre coins.
Cellule de rampeLes quatre coins portent l’indicateur VertexFlags.Ramp (les niveaux peuvent différer).Surface bilinéaire : les niveaux se fondent progressivement en une pente. Voir Rampes.
Cellule de falaiseLes coins ont des niveaux différents et la cellule n’est pas une cellule de rampe.Terrasses planes séparées par une paroi verticale qui suit un contour arrondi.

Contours arrondis. Dans une cellule de falaise, pour chaque seuil de niveau t, la fonction indicatrice « niveau du coin ≥ t » (1 ou 0) est interpolée de façon bilinéaire sur la cellule. Un point appartient au niveau le plus élevé dont l’indicatrice interpolée vaut au moins 0.5 (MapGeometryView.LevelAt). Il s’agit d’une règle de type marching squares : un coin surélevé isolé produit un quart de cercle au lieu d’une diagonale, et les longues lignes de falaise restent droites. La paroi elle-même se dresse verticalement sur le contour. Les hauteurs fines sont toujours interpolées de façon bilinéaire et ajoutées par-dessus, y compris dans les cellules de falaise.

L’aspect des parois rendues se règle sur le composant RTSTerrain (Settings) :

ParamètrePar défautDescription
Surface Subdivisions2Nombre de quads par côté de cellule sur un sol lisse (1 = aspect RTS classique, 2–4 = collines plus douces).
Cliff Subdivisions4Résolution de la sous-grille qui sert à tracer le contour arrondi dans une cellule de falaise.
Cliff Noise0.18Déplacement horizontal aléatoire des vertices de la paroi (fraction de cellule) pour un aspect de roche naturel.
Cliff Noise Scale1.6Échelle du bruit de falaise, en unités du monde.
Cliff Slant0.12Recul du bord supérieur d’une paroi, qui rend les parois légèrement inclinées (fraction de cellule).
Cliff Wall Segments3Nombre de segments verticaux de la géométrie de paroi par niveau de falaise.

Obtenez une vue avec map.GetGeometryView(). Il s’agit d’une structure de tableaux natifs, que vous pouvez donc aussi transmettre à des jobs Burst. Tous les membres attendent des positions locales à la carte :

MembreDescription
SampleHeight(localXZ)Hauteur du sol (Y local à la carte).
SampleHeightInCell(cell, uv), SampleLevelHeightInCell(cell, uv)Idem, dans une cellule connue (uv 0–1), avec ou sans la hauteur fine.
SampleNormal(localXZ), SampleSlope(localXZ)Normale de la surface ; pente en degrés.
SampleCliffLevel(localXZ)Niveau de falaise à une position donnée.
SampleWater(localXZ, out waterHeight), SampleWaterDepth(localXZ)Présence d’eau et hauteur de sa surface ; profondeur d’eau, ou 0 sur un sol sec.
IsCliffCell(cell), IsRampCell(cell)Classification d’une cellule (voir le tableau ci-dessus).
LocateCell(localXZ, out cell, out uv)Cellule contenant une position et position 0–1 à l’intérieur de celle-ci.
Raycast(origin, direction, maxDistance, out hitPoint, out hitDistance)Raycast analytique contre la surface de référence, sans nécessiter de collider.
static LevelAt(l00, l10, l01, l11, uv), static Bilerp(v00, v10, v01, v11, uv)Règle de niveau dans une cellule de falaise et interpolation bilinéaire.
width, height, cellSize, cliffLevelHeight, WorldSizeTaille de la carte en cellules, taille de cellule, hauteur de niveau et taille réelle.

Les paramètres Cliff Noise et Cliff Slant ne déplacent les vertices rendus des parois que d’une fraction de cellule. Les requêtes utilisent le contour exact, si bien que, juste au bord d’une falaise, la roche visible et la surface de référence peuvent légèrement différer. La carte de cheminement en tient compte grâce à son paramètre Cliff Margin, qui maintient une fine bande non praticable le long de chaque paroi.

Rampes

Une rampe permet aux unités de passer à pied d’un niveau de falaise au suivant. La règle est simple :

Une cellule est une rampe lorsque ses quatre coins portent l’indicateur de rampe. S’il manque l’indicateur ne serait-ce qu’à un seul coin, la cellule reste une cellule de falaise avec une paroi verticale.

  • L’indicateur est VertexFlags.Ramp, posé sur chaque vertex. L’outil Ramp (id cliff.ramp) le peint ; maintenez Shift enfoncée pour le retirer.
  • Une cellule de rampe forme une pente bilinéaire lisse entre les hauteurs de ses coins (niveau plus hauteur fine).
  • Les rampes donnent les meilleurs résultats lorsqu’elles franchissent exactement un niveau. Des rampes plus raides sont autorisées, mais la barre d’état signale les cellules de rampe qui s’étendent sur plus d’un niveau.
  • Cheminement : pour une rampe valide d’un seul niveau, la praticabilité n’est testée que sur la pente due aux hauteurs fines (le dénivelé entre les niveaux qu’elle relie ne la rend pas « trop escarpée »). Les rampes ne sont jamais constructibles.
  • Sur une rampe, GetCliffLevel renvoie le niveau interpolé, arrondi : le niveau inférieur sur la moitié basse, le niveau supérieur sur la moitié haute.
  1. Surélevez un plateau d’un niveau avec l’outil Raise / Lower Level.
  2. Sélectionnez l’outil Ramp et peignez en travers du bord de falaise, à l’endroit où la rampe doit se trouver. Le pinceau doit couvrir au moins les vertices des deux côtés de la paroi, afin que tous les coins des cellules intermédiaires reçoivent l’indicateur.
  3. La paroi disparaît et une pente apparaît. Élargissez la rampe en peignant d’autres vertices le long du bord.

Calques de sol et splat maps

Les textures de sol sont peintes dans des splat maps : quatre textures RGBA (MapData.SplatMapCount = 4) de SplatWidth × SplatHeight texels. Chacun des 16 canaux contient le poids d’un calque de sol du tileset :

Splat mapRGBA
SplatMaps[0]calque 0calque 1calque 2calque 3
SplatMaps[1]calque 4calque 5calque 6calque 7
SplatMaps[2]calque 8calque 9calque 10calque 11
SplatMaps[3]calque 12calque 13calque 14calque 15
  • Le calque i est stocké dans la splat map i / 4, canal i % 4. C’est pourquoi un tileset compte exactement 16 calques de sol : 4 splat maps × 4 canaux.
  • La somme des poids d’un texel vaut toujours 255 sur l’ensemble des 16 canaux. Tous les outils de peinture respectent cet invariant ; le code qui écrit des données de splat doit le respecter lui aussi.
  • La résolution de splat est le nombre de texels par côté de cellule (4 par défaut). Avec des cellules de 2 m, cela donne un texel tous les 0.5 m.
  • Le centre du texel (x, z) se trouve en ((x + 0.5), (z + 0.5)) × CellSize / SplatResolution, en XZ local à la carte. La même formule s’applique aux texels de détail et de cheminement, avec leur propre résolution.
  • Méthodes utilitaires : map.SplatIndex(x, z), map.GetSplatWeight(texelIndex, layer), map.GetDominantLayer(texelIndex), MapData.GetChannel / SetChannel et map.FillSplat(layer).

Les cartes référencent les calques de sol par leur indice (0–15), et non par leur nom. Réorganiser ou supprimer des calques de sol dans le tileset modifie l’affichage des cartes déjà peintes. Ajoutez les nouveaux calques à la fin lorsque des cartes utilisent déjà le tileset.

using RTSTerrainStudio;
using Unity.Mathematics;
using UnityEngine;

public static class SplatExample
{
    /// <summary>Paints one map cell 100 % with a ground layer (like the Tile Paint tool, without undo).</summary>
    public static void PaintCell(RTSTerrain terrain, int2 cell, int layer)
    {
        MapData map = terrain.Map;
        if (map == null || !map.IsValidCell(cell.x, cell.y)) return;
        layer = math.clamp(layer, 0, MapData.MaxGroundLayers - 1);

        int res = map.SplatResolution;
        for (int tz = cell.y * res; tz < (cell.y + 1) * res; tz++)
        {
            for (int tx = cell.x * res; tx < (cell.x + 1) * res; tx++)
            {
                int texel = map.SplatIndex(tx, tz);
                for (int m = 0; m < MapData.SplatMapCount; m++)
                {
                    // All channels 0, except the one of our layer: the sum stays exactly 255.
                    var c = new Color32(0, 0, 0, 0);
                    if (layer / 4 == m) MapData.SetChannel(ref c, layer % 4, 255);
                    map.SplatMaps[m][texel] = c;
                }
            }
        }

        // Tell the terrain which data changed and where (in cells). Textures and pathing update in LateUpdate.
        terrain.NotifyChanged(MapLayers.Splat, new RectInt(cell.x, cell.y, 1, 1));
    }
}

Eau

  • Un vertex est sous l’eau lorsqu’il porte l’indicateur VertexFlags.Water. La hauteur de la surface de l’eau (Y local à la carte, en mètres) est stockée dans WaterHeights ; cette valeur n’a de sens que là où l’indicateur est présent.
  • Un point est immergé lorsque la couverture bilinéaire des indicateurs d’eau des quatre coins de sa cellule vaut au moins 0.5. Dans une cellule immergée, les coins sans eau utilisent la hauteur d’eau la plus élevée de la cellule, si bien que les rivages restent horizontaux.
  • La profondeur d’eau = surface de l’eau − hauteur du sol. La profondeur détermine le cheminement : une eau plus profonde que le paramètre Shallow Depth Limit du tileset (0.9 m par défaut) est de l’eau profonde (non praticable), une eau moins profonde est de l’eau peu profonde (praticable, mais non constructible par défaut).
  • Les outils d’eau sont Paint Water, Erase Water et Flood Fill. Les modifications d’eau ne notifient que MapLayers.Water, si bien que les chunks du terrain ne sont pas reconstruits pendant que vous peignez de l’eau.
  • Requêtes : terrain.IsWater(world, out depth) et terrain.TryGetWaterHeight(world, out waterWorldY).

L’aspect de l’eau (couleurs, vagues, écume) provient du profil d’eau du tileset ; voir Profil d’eau.

Densité de détails (herbe et petites plantes)

  • Les détails ne sont pas des objets individuels. Chaque prototype de détail utilisé sur la carte dispose d’un DetailLayer dans map.DetailLayers : un octet par texel de détail (DetailWidth × DetailHeight, 2 texels par côté de cellule par défaut).
  • Une densité de 0 signifie vide, et 255 correspond à Max Density instances par texel (un champ du prototype de détail, 6 par défaut). Chaque texel fait apparaître density / 255 × maxDensity instances ; le moteur de rendu les disperse de manière déterministe, si bien qu’une même carte a toujours le même aspect.
  • Les couches sont associées à la bibliothèque de végétation par leur prototypeId. map.GetOrAddDetailLayer(id) crée une couche à la demande ; map.FindDetailLayer(id) renvoie null si le prototype n’est pas utilisé.
  • Peignez-les avec l’outil Paint Details et effacez-les avec l’outil Erase Details.

Arbres et instances de décor

Les arbres (TreeInstanceData) et les objets de décor (DecorInstanceData) sont stockés sous forme de simples listes. Au lieu d’un nom de prototype, chaque instance stocke un petit index de palette qui pointe vers une liste d’identifiants de bibliothèque enregistrée dans la carte :

map.TreePrototypeIds = [ "a3f0…", "77c1…" ]        <- ids of TreePrototype entries in the vegetation library
map.Trees[n].prototype = 1                          <- this tree uses "77c1…"
  • Utilisez map.GetOrAddTreePrototype(id) / map.GetOrAddDecorPrototype(id) pour obtenir l’index de palette d’un identifiant de bibliothèque (il est ajouté s’il manque).
  • Comme les cartes font référence aux prototypes par leur identifiant, vous pouvez renommer, réorganiser ou compléter une bibliothèque sans risque. Un prototype absent de la bibliothèque est ignoré par le composant de rendu de la végétation, et le gestionnaire de décors l’affiche sous la forme d’un cube magenta de substitution ; ajouter un prototype portant le même identifiant le fait réapparaître. Pour le cheminement, les arbres dont le prototype manque ne sont pas dessinés, mais continuent de bloquer un cercle de rayon PathingMapBuilder.DefaultTreeFootprintRadius (0.8 m) × leur échelle. Les substituts de décor n’inscrivent aucune emprise dans la carte de cheminement tant que le prototype n’est pas revenu.
  • Chaque instance possède un id unique et stable au sein de la carte. Obtenez de nouveaux identifiants avec map.AllocateInstanceId().
  • Les positions sont locales à la carte. Les rotations suivent partout la même convention : en degrés, dans le sens horaire vu de dessus, 0 = +Z, 90 = +X (comme la rotation Y de Unity).

La convention position.y

position.y est un décalage supplémentaire au-dessus du sol, normalement 0. Ce n’est pas la hauteur absolue. Les composants de rendu échantillonnent le sol à chaque rafraîchissement : les arbres et les décors restent donc posés au sol lorsque vous modifiez le terrain en dessous.

ObjetHauteur de rendu (Y local de la carte)
Arbrehauteur du sol + position.y
Décorhauteur du sol + position.y + le Y Offset du prototype
Décor avec DecorFlags.KeepHeightposition.y comme hauteur absolue dans l’espace local de la carte (ne suit pas les modifications du terrain)

Ne copiez jamais le yOffset du prototype dans position.y : il est ajouté au moment du rendu. DecorMath.ComputeLocalPosition et DecorMath.ToStoredHeight convertissent les positions stockées en positions de rendu, et inversement.

ChampTreeInstanceDataDecorInstanceData
iduint, unique dans la carteuint, unique dans la carte
prototypeushort, index dans TreePrototypeIdsushort, index dans DecorPrototypeIds
variant–byte, 0 = prefab principal, 1… = entrées de variants
flags–DecorFlags : IgnorePathing, Locked (les outils ne peuvent ni le sélectionner ni l’effacer), KeepHeight
positionfloat3, local à la carte, y = décalagefloat3, local à la carte, y = décalage (ou absolu avec KeepHeight)
rotationyaw en degrésrotation, un quaternion local à la carte
échellescale, float uniformescale, float3
tintColor32 multiplié par la couleur du matériauColor32 multiplié par la couleur du matériau
using RTSTerrainStudio;
using Unity.Mathematics;
using UnityEngine;

public static class InstanceExample
{
    /// <summary>Adds a tree of the first tree prototype of the terrain's vegetation library at a world position.</summary>
    public static uint AddTree(RTSTerrain terrain, Vector3 worldPosition, float yawDegrees)
    {
        MapData map = terrain.Map;
        RTSVegetationLibrary library = terrain.VegetationLibrary;
        if (map == null || library == null || library.trees.Count == 0) return 0;

        Vector3 local = terrain.WorldToLocal(worldPosition);
        var tree = new TreeInstanceData
        {
            id = map.AllocateInstanceId(),
            prototype = map.GetOrAddTreePrototype(library.trees[0].id), // palette index of the library id
            position = new float3(local.x, 0f, local.z),                 // y = offset above the ground, normally 0
            yaw = yawDegrees,                                             // clockwise from above, 0 = +Z
            scale = 1f,
            tint = new Color32(255, 255, 255, 255)
        };
        map.Trees.Add(tree);

        // Notify the cell that changed: vegetation, pathing (tree footprint) and fog blockers update.
        int2 cell = map.LocalToCell(new float2(local.x, local.z));
        terrain.NotifyChanged(MapLayers.Trees, new RectInt(cell.x, cell.y, 1, 1));
        return tree.id;
    }

    /// <summary>Adds a decor object (by library id) standing upright on the ground.</summary>
    public static uint AddDecor(RTSTerrain terrain, string decorPrototypeId, Vector3 worldPosition, float yawDegrees)
    {
        MapData map = terrain.Map;
        if (map == null) return 0;

        Vector3 local = terrain.WorldToLocal(worldPosition);
        var decor = new DecorInstanceData
        {
            id = map.AllocateInstanceId(),
            prototype = map.GetOrAddDecorPrototype(decorPrototypeId),
            variant = 0,                                  // main prefab
            flags = DecorFlags.None,
            position = new float3(local.x, 0f, local.z),  // the prototype's yOffset is added at render time
            rotation = DecorMath.Yaw(yawDegrees),
            scale = new float3(1f, 1f, 1f),
            tint = new Color32(255, 255, 255, 255)
        };
        map.Decor.Add(decor);

        int2 cell = map.LocalToCell(new float2(local.x, local.z));
        terrain.NotifyChanged(MapLayers.Decor, new RectInt(cell.x, cell.y, 1, 1));
        return decor.id;
    }
}

Les modifications apportées directement à MapData par le code ne sont pas enregistrées dans l’historique d’annulation. Pour rendre annulables les changements effectués depuis des scripts d’éditeur, exécutez-les via la session d’édition avec RTSEditSession.RunOperation(name, layers, operation), qui enregistre les couches indiquées en une seule étape d’annulation.

Carte de cheminement

La carte de cheminement répond aux questions « Une unité peut-elle marcher ici, un bâtiment peut-il y être placé ? ». C’est une grille de cellules de cheminement (PathingResolution par côté de cellule de carte, 2 par défaut, soit des cellules de cheminement de 1 m sur une carte à cellules de 2 m), chacune portant un octet PathingFlags. Elle est dérivée automatiquement et reconstruite de façon incrémentale dès qu’une de ses données d’entrée change (géométrie, eau, calques de sol, arbres, décors, surcharges). Elle n’est jamais enregistrée : seules les surcharges manuelles le sont.

PathingFlagsSignification
WalkableLes unités terrestres peuvent marcher ici.
BuildableDes bâtiments peuvent être placés ici.
FlyableLes unités aériennes peuvent voler ici. Activé partout, sauf si un effet Unflyable le retire : une surcharge de cheminement peinte, la règle du calque de sol dans le tileset ou le Footprint Effect d’un prototype de décor.
ShallowWaterEau peu profonde (praticable, non constructible par défaut).
DeepWaterEau profonde (unités navales uniquement).
CliffLa cellule touche une paroi de falaise.
BlockedBloquée par l’emprise d’un arbre ou d’un décor.
SteepTrop escarpée pour les unités terrestres.

Comment les indicateurs sont dérivés

  1. Terrain : les parois de falaise (ainsi que la marge Cliff Margin) activent Cliff ; les pentes supérieures à Max Walkable Slope (42° par défaut) activent Steep ; l’eau active ShallowWater ou DeepWater selon sa profondeur ; Flyable est activé partout ; Buildable = praticable, pente ≤ Max Buildable Slope (18° par défaut) et au sec (ou en eau peu profonde quand Shallow Water Buildable est activé). Ensuite, le Pathing Effect du calque de sol dominant est appliqué (par exemple « Unbuildable » sur de la roche accidentée).
  2. Emprises : les arbres bloquent un cercle (Footprint Radius × échelle de l’arbre × Tree Footprint Scale) ; les décors appliquent leur Footprint Effect dans un cercle ou dans un rectangle pivoté, sauf si l’instance possède DecorFlags.IgnorePathing.
  3. Les surcharges manuelles, peintes avec les outils Paint Pathing / Clear Pathing, sont appliquées en dernier.

Les paramètres de ces règles se trouvent sur le composant RTSTerrain (RTSPathingSettings, propriété terrain.PathingSettings).

PathingOverrideEffet
UnwalkableRetire Walkable (et Buildable), active Blocked.
UnbuildableRetire Buildable.
UnflyableRetire Flyable.
ForceWalkableActive Walkable, même si les règles dérivées disent le contraire.
ForceBuildableActive Buildable, même si les règles dérivées disent le contraire.

Les mêmes indicateurs PathingOverride servent aux effets de cheminement des calques de sol, aux effets d’emprise des décors et aux surcharges peintes. Interrogez le résultat avec terrain.GetPathing(world), terrain.IsWalkable(world) et terrain.IsBuildable(world), ou lisez directement terrain.Pathing.Flags.

Régions, positions de départ et marqueurs

Ce sont des objets légers destinés à la logique de votre jeu. Ils ne sont pas affichés en jeu ; les éditeurs les dessinent sous forme de gizmos.

TypeChampsUsage typique
MapRegion (outil Regions)name, rect (rectangle XZ local à la carte, en mètres : rect.x = X, rect.y = Z), color, properties (liste clé/valeur)Déclencheurs, zones d’apparition, camps de creeps. Contains(localXZ), GetProperty(key, fallback).
StartLocation (outil Start Locations)player (numéroté à partir de zéro), position, yawPoints d’apparition des joueurs. Le script d’exemple chargé de faire apparaître les unités s’en sert.
MapMarker (outil Markers)name, tag (texte libre, comme « camera » ou « goldmine »), position, rotation, propertiesCaméras de cinématiques, points d’intérêt, points d’apparition scriptés.

Les outils stockent position.y = 0 pour les positions de départ et les marqueurs, et le traitent comme un décalage au-dessus du sol, comme pour les arbres.

using RTSTerrainStudio;
using Unity.Mathematics;
using UnityEngine;

public static class RegionExample
{
    /// <summary>Returns the "gold" property of the first region that contains the world position, or 0.</summary>
    public static int GetGoldAt(RTSTerrain terrain, Vector3 worldPosition)
    {
        if (terrain.Map == null) return 0;
        Vector3 local = terrain.WorldToLocal(worldPosition);
        foreach (MapRegion region in terrain.Map.Regions)
        {
            // Regions are rectangles in map-local XZ.
            if (region.Contains(new float2(local.x, local.z)) &&
                int.TryParse(region.GetProperty("gold", "0"), out int gold))
                return gold;
        }
        return 0;
    }
}

Informations de la carte et environnement

Champ MapInfoPar défautDescription
name"New Map"Nom affiché (également stocké dans l’en-tête non compressé du fichier).
author""Nom de l’auteur.
description""Texte libre affiché dans les explorateurs de cartes.
maxPlayers2Nombre de joueurs recommandé.
tilesetId""Identifiant du tileset pour lequel la carte a été conçue (RTSTileset.tilesetId). Renseigné automatiquement lorsque le terrain possède un tileset. L’Inspector de RTSTerrain affiche un avertissement lorsque le tileset assigné ne correspond pas.
createdUtcTicks, modifiedUtcTicksdéfini automatiquementDate de création et date du dernier enregistrement (en ticks UTC). La date de modification est définie par RTSMapSerializer.Write chaque fois que la carte est sérialisée : SaveToFile, la commande Save dans l’éditeur, Serialize(map) et RTSMapAsset.CreateFromMap.

EnvironmentSettings stocke l’éclairage d’une carte. Il est appliqué à la scène par un composant RTSEnvironment (GameObject ▸ RTS Terrain Studio ▸ Environment) ; sans ce composant, les valeurs sont enregistrées mais pas utilisées.

Champ EnvironmentSettingsPar défautDescription
sunColorblanc chaud (1, 0.956, 0.84)Couleur de la lumière du soleil.
sunIntensity1.2Intensité de la lumière du soleil.
sunRotation(50, −30)Rotation du soleil en degrés (x = inclinaison, y = lacet).
ambientColor(0.45, 0.5, 0.58)Couleur de la lumière ambiante.
fogdésactivéActive le brouillard atmosphérique de distance.
fogColor(0.6, 0.68, 0.75)Couleur du brouillard atmosphérique.
fogDensity0.004Densité du brouillard atmosphérique.

Notifications de modification

Lorsque vous modifiez MapData par le code, indiquez au terrain ce qui a changé et où, en cellules :

  • terrain.NotifyChanged(MapLayers layers, RectInt cellRect) déclenche immédiatement MapChanged et met la reconstruction en file d’attente.
  • terrain.NotifyChangedAll(layers) marque toute la carte comme modifiée (après une génération ou un import).
  • Les modifications en attente sont traitées dans LateUpdate (et à chaque tick de l’éditeur hors Play Mode), ou immédiatement avec terrain.ProcessPendingChanges(). Ensuite, l’événement ChangesProcessed est déclenché : les meshes, les textures et le cheminement sont à jour.
  • Un vertex touche jusqu’à quatre cellules. Convertissez un rectangle de vertices avec BrushUtility.VertexRectToCellRect(map, vertexRect), et les rectangles de texels avec BrushUtility.TexelRectToCellRect(map, texelRect, resolutionPerCell).
using RTSTerrainStudio;
using UnityEngine;

public static class CliffExample
{
    /// <summary>Raises a square plateau by one cliff level around a world position.</summary>
    public static void RaisePlateau(RTSTerrain terrain, Vector3 worldCenter, int radiusInVertices)
    {
        MapData map = terrain.Map;
        if (map == null) return;

        // Nearest vertex to the centre (vertices sit on multiples of the cell size).
        Vector3 local = terrain.WorldToLocal(worldCenter);
        int cx = Mathf.RoundToInt(local.x / map.CellSize);
        int cz = Mathf.RoundToInt(local.z / map.CellSize);

        int x0 = Mathf.Max(0, cx - radiusInVertices), x1 = Mathf.Min(map.Width, cx + radiusInVertices);
        int z0 = Mathf.Max(0, cz - radiusInVertices), z1 = Mathf.Min(map.Height, cz + radiusInVertices);
        for (int z = z0; z <= z1; z++)
        {
            for (int x = x0; x <= x1; x++)
            {
                int i = map.VertexIndex(x, z);
                // Levels are bytes from 0 to 15: always clamp.
                map.CliffLevels[i] = (byte)Mathf.Min(map.CliffLevels[i] + 1, MapData.MaxCliffLevel);
            }
        }

        // Convert the changed vertices to the cells around them and notify the terrain.
        var vertexRect = new RectInt(x0, z0, x1 - x0 + 1, z1 - z0 + 1);
        RectInt cells = BrushUtility.VertexRectToCellRect(map, vertexRect);
        terrain.NotifyChanged(MapLayers.CliffLevels, cells);
    }
}

Coordonnées et terrains multiples

Toutes les données de la carte sont stockées dans l’espace local de la carte. Le Transform du GameObject RTSTerrain place cet espace dans le monde.

Espace local de la carte

  • L’origine est le vertex (0, 0), c’est-à-dire le coin de la cellule (0, 0). X et Z vont de 0 à map.WorldSize en mètres, Y pointe vers le haut.
  • Le vertex (x, z) se trouve à la position locale (x × CellSize, height, z × CellSize) ; le centre de la cellule (x, z) se trouve à ((x + 0.5) × CellSize, …, (z + 0.5) × CellSize).
  • Y local = 0 correspond au niveau 0 avec une hauteur fine de 0. Sur une nouvelle carte de niveau de base 2 avec des niveaux de 2 m, le sol se trouve à Y local = 4 m.
  • Les GameObjects des chunks se trouvent sous un enfant masqué du terrain nommé RTS Chunks (RTSTerrain.ChunkRoot). Cette racine n’a ni décalage local ni rotation et compense l’échelle du terrain, et la transformation locale de chaque chunk est l’identité : l’espace objet des meshes de chunk est donc l’espace local de la carte. C’est important à savoir lorsque vous écrivez des shaders pour le terrain.

Conversion entre l’espace monde et l’espace de la carte

Méthode (RTSTerrain)Description
WorldToLocal(Vector3) / LocalToWorld(Vector3)Conversion des positions entre l’espace monde et l’espace local de la carte.
WorldToLocalDirection / LocalToWorldDirectionConversion des directions (rayons, normales).
WorldToCell(Vector3)Cellule contenant une position monde (bornée aux limites de la carte).
CellCenterToWorld(int2)Position monde du centre d’une cellule, au niveau du sol.
VertexToWorld(int2)Position monde d’un vertex.
Contains(Vector3)Vrai lorsque la position monde se trouve dans la zone XZ de la carte.
WorldBoundsBoîte englobante approximative de toute la carte en espace monde, en tenant compte du niveau de falaise le plus élevé possible.
GetHeight, SnapToGround, GetNormal, GetCliffLevel, IsWater, TryGetWaterHeight, GetPathing, RaycastRequêtes qui prennent et renvoient des valeurs en espace monde et effectuent la conversion en interne.
GetGeometry()Un MapGeometryView pour des requêtes rapides dans l’espace local de la carte (y compris dans des jobs Burst).
using RTSTerrainStudio;
using Unity.Mathematics;
using UnityEngine;

/// <summary>Add to any GameObject and use the context menu to see the map data under it.</summary>
public class TerrainProbe : MonoBehaviour
{
    [ContextMenu("Probe Terrain")]
    void Probe()
    {
        // Several terrains can exist: find the one below this object.
        RTSTerrain terrain = RTSTerrain.FindAt(transform.position);
        if (terrain == null || terrain.Map == null) { Debug.Log("Not above an RTS Terrain."); return; }
        MapData map = terrain.Map;

        // World -> map-local (origin at vertex 0,0; position and Y rotation only).
        Vector3 local = terrain.WorldToLocal(transform.position);
        int2 cell = terrain.WorldToCell(transform.position);

        // Nearest vertex.
        int vx = Mathf.Clamp(Mathf.RoundToInt(local.x / map.CellSize), 0, map.Width);
        int vz = Mathf.Clamp(Mathf.RoundToInt(local.z / map.CellSize), 0, map.Height);
        int v = map.VertexIndex(vx, vz);

        // Splat texel below the object (SplatResolution texels per cell side).
        int tx = Mathf.Clamp((int)(local.x / map.CellSize * map.SplatResolution), 0, map.SplatWidth - 1);
        int tz = Mathf.Clamp((int)(local.z / map.CellSize * map.SplatResolution), 0, map.SplatHeight - 1);
        int dominantLayer = map.GetDominantLayer(map.SplatIndex(tx, tz));

        Debug.Log($"Cell {cell}, vertex ({vx},{vz}): level {map.CliffLevels[v]}, fine height {map.Heights[v]:0.00} m, " +
                  $"vertex height {map.GetVertexHeight(vx, vz):0.00} m. Ground at world Y {terrain.GetHeight(transform.position):0.00}, " +
                  $"cliff level {terrain.GetCliffLevel(transform.position)}, dominant ground layer {dominantLayer}, " +
                  $"pathing {terrain.GetPathing(transform.position)}.");
    }
}

Règles de position, de rotation et d’échelle

Partie du TransformPris en chargeRemarques
PositionOuiDéplace toute la carte. Servez-vous-en pour placer plusieurs terrains côte à côte ou à des hauteurs différentes.
Rotation YOuiFait pivoter la carte autour de son origine (vertex 0, 0). Les requêtes, les outils, le curseur du pinceau et les rotations des instances suivent cette rotation.
Rotation X / ZNonSeule la rotation Y est censée être utilisée. L’Inspector de RTSTerrain affiche un avertissement et propose le bouton Fix, qui conserve Y et réinitialise X et Z.
ÉchelleIgnoréeLes chunks compensent toute échelle appliquée au terrain ou à ses parents. L’Inspector affiche un avertissement et propose le bouton Reset Scale. Pour agrandir une carte, utilisez davantage de cellules ou une taille de cellule plus grande.

Terrains multiples

Une scène peut contenir autant de composants RTSTerrain que vous le souhaitez. Chacun possède sa propre carte, son propre tileset, ses bibliothèques, ses chunks et sa carte de cheminement.

  • RTSTerrain.All liste tous les terrains activés ; RTSTerrain.Main renvoie le premier (pratique pour les jeux à carte unique ; les terrains d’aperçu temporaires sont ignorés).
  • RTSTerrain.FindAt(worldPosition) renvoie le terrain dont la zone XZ contient une position donnée.
  • RTSTerrain.RaycastAll(ray, out hit) effectue un raycast sur tous les terrains et renvoie l’impact le plus proche (hit.terrain indique le terrain touché).
  • RTSTerrain.TerrainEnabled / TerrainDisabled sont des événements statiques destinés aux systèmes qui suivent les terrains.
  • Les terrains sont indépendants : les cartes ne sont pas raccordées à leurs bordures, et la recherche de chemin (RTSPathfinder.FindPath(terrain, …)) ne porte que sur un terrain à la fois. Pour que deux cartes se rejoignent sans raccord visible, donnez les mêmes hauteurs à leurs vertices de bordure.
using RTSTerrainStudio;
using UnityEngine;

public static class TerrainLayout
{
    /// <summary>Places "east" directly next to "west" (along west's local +X), with the same rotation.</summary>
    public static void PlaceNextTo(RTSTerrain west, RTSTerrain east)
    {
        if (west.Map == null) return;
        float widthMetres = west.Map.WorldSize.x;   // map-local X extent in metres
        east.transform.SetPositionAndRotation(
            west.transform.position + west.transform.rotation * new Vector3(widthMetres, 0f, 0f),
            west.transform.rotation);
    }
}

Assets de carte et fichiers de carte

Une carte est enregistrée sous forme de fichier .rtsmap. Le même format binaire sert dans l’éditeur Unity (comme asset de votre projet) et dans l’éditeur en jeu (comme fichier sur le disque) : les cartes créées par les joueurs peuvent donc être ouvertes dans Unity, et inversement.

Fichiers .rtsmap dans le projet

Lorsque Unity trouve un fichier .rtsmap dans le dossier Assets, l’importeur RTSMapImporter le convertit en RTSMapAsset. L’asset stocke les octets compressés du fichier, un petit en-tête (nom, auteur, taille, joueurs, identifiant du tileset) et un aperçu de la mini-carte, qui sert aussi de miniature dans la fenêtre Project.

Créer un asset de carte

  • Tools ▸ RTS Terrain Studio ▸ New Map Wizard... : configuration guidée (informations de base, taille, apparence, terrain) ; écrit le fichier et crée un terrain associé, ou l’assigne au terrain sélectionné.
  • Assets ▸ Create ▸ RTS Terrain Studio ▸ Map (.rtsmap) : crée dans le dossier sélectionné une carte plate de 128 × 128 avec les paramètres par défaut.
  • Save As… dans la fenêtre RTS Terrain Studio : écrit la carte actuelle d’un terrain dans un nouveau fichier.
  • Copiez dans le dossier Assets un fichier .rtsmap créé avec l’éditeur en jeu ; il est importé comme n’importe quel autre fichier.

L’Inspector d’un asset de carte

Sélectionnez un asset de carte pour afficher son aperçu, son nom, son auteur, sa description, sa taille, son nombre de joueurs, son tileset et sa version de format, ainsi que des statistiques (cellules, taille réelle, taille de cellule, hauteur de niveau, positions de départ, arbres, décors, régions, marqueurs, couches de détails, taille du fichier, mémoire, dernière modification).

CommandeDescription
Open In SceneAssigne la carte au terrain sélectionné (ou au seul terrain présent ; demande lequel utiliser s’il y en a plusieurs). Crée un terrain si la scène n’en contient aucun. Désactivé en Play Mode.
Menu ▾Open In New Terrain, ou Open On pour choisir un terrain précis de la scène.
Show In Explorer (Reveal In Finder sous macOS)Affiche le fichier dans l’explorateur de fichiers du système d’exploitation.
Tileset Id (Copy, Select)L’identifiant de tileset stocké dans la carte. Select sélectionne l’asset de tileset correspondant.
Preview SizeCôté le plus long de l’aperçu précalculé : 128, 256 (par défaut) ou 512 pixels.
Preview TilesetTileset utilisé pour les couleurs de l’aperçu. Vide = le tileset dont la carte stocke l’identifiant (trouvé automatiquement).
Re-bake Preview, Apply / RevertPrécalcule de nouveau l’aperçu / applique les paramètres d’importation modifiés.

L’aperçu est précalculé de nouveau automatiquement lorsque le tileset portant l’identifiant de la carte est ajouté ou supprimé, ou que ses couleurs de mini-carte changent. Reconstruire les tableaux de textures ne réimporte pas les cartes. Un fichier endommagé est importé comme asset vide, avec une icône d’erreur et une erreur d’importation dans la fenêtre Console.

Édition, Save et Save As

Assignez un asset de carte au champ Map Asset d’un RTSTerrain. Lorsque le terrain est activé, il charge la carte en mémoire, et toutes les modifications portent sur cette copie en mémoire. Le fichier de scène ne stocke que la référence à l’asset, jamais les données de la carte elles-mêmes.

  • Save (dans l’en-tête de la fenêtre RTS Terrain Studio, ou Save Map dans le menu d’options de l’overlay RTS Terrain Studio de la Scene View) réécrit la carte dans son fichier .rtsmap et la réimporte. Le bouton Save est mis en évidence tant qu’il reste des modifications non enregistrées.
  • Save As… écrit un nouveau fichier et l’assigne au terrain sans recharger la carte : votre historique d’annulation est donc conservé.
  • Open… charge un autre asset de carte ; Reload recharge la carte depuis son asset et abandonne les modifications non enregistrées.
  • Un terrain sans asset de carte crée une carte à partir de ses Default Map Settings. Cette carte n’existe qu’en mémoire tant que vous n’avez pas utilisé Save As.
  • Enregistrer la scène (Ctrl+S) enregistre aussi les cartes modifiées des terrains de cette scène, et propose Save As pour les nouvelles cartes qui n’ont pas encore de fichier. Ces deux comportements peuvent être désactivés dans le menu d’options de l’overlay de la Scene View (Save Maps When Saving the Scene, Offer Save As for New Maps).
  • Si vous entrez en Play Mode, fermez une scène ou quittez Unity alors que des modifications de carte ne sont pas enregistrées, une invite vous demande d’abord si vous voulez les enregistrer. Pour les modifications effectuées en Play Mode (outils de la Scene View ou éditeur en jeu), l’enregistrement vous est également proposé lorsque vous quittez le Play Mode.

Les modifications de carte ne font pas partie de la scène. La boîte de dialogue « Save scene? » propre à Unity ne les prend pas en compte ; les invites de RTS Terrain Studio, si. Si un fichier .rtsmap est en lecture seule ou verrouillé par le contrôle de version, Save affiche une boîte de dialogue au lieu d’écrire le fichier.

Fichiers de carte à l’exécution

Dans le build d’un jeu, les cartes sont de simples fichiers sur le disque :

  • RTSMapSerializer.DefaultMapsFolder est le dossier Maps situé dans RTSMapSerializer.StorageRoot, qui vaut Application.persistentDataPath, si bien que sous Windows, ce dossier est en général %USERPROFILE%\AppData\LocalLow\<Company>\<Product>\Maps. Dans les builds Web, StorageRoot est un dossier situé dans le stockage du navigateur (voir Les cartes dans le navigateur).
  • L’éditeur en jeu (RTSRuntimeEditor) enregistre et ouvre les cartes dans le dossier défini par son champ Maps Folder (vide = le dossier par défaut ci-dessus ; les chemins relatifs sont résolus par rapport à RTSMapSerializer.StorageRoot). Lorsque Write Preview Images est activé, il écrit à côté de chaque carte enregistrée une petite image de mini-carte Name.preview.png, destinée à son explorateur de cartes.
  • Pour partager une carte, copiez le fichier .rtsmap dans le dossier des cartes d’un autre joueur, ou dans un projet Unity. Dans un navigateur web, utilisez plutôt les commandes Download Map et Import Map de l’éditeur en jeu.
  • Les cartes que vous livrez avec le jeu peuvent tout simplement être des assets de carte référencés par un terrain ou un script ; elles sont incluses dans le build comme n’importe quel autre asset.
APIDescription
terrain.LoadFromFile(path) / terrain.SaveToFile(path)Charge un fichier dans un terrain / enregistre la carte du terrain. Les deux méthodes définissent terrain.CurrentFilePath.
terrain.MapAsset = assetAssigne un asset de carte et le charge immédiatement si le terrain est activé.
terrain.SetMap(mapData)Affiche un MapData que vous avez créé ou chargé ; le terrain en devient propriétaire.
terrain.HasUnsavedChangesVaut true si la carte a été modifiée depuis le dernier chargement ou le dernier enregistrement.
RTSMapAsset.LoadMap()Désérialise l’asset dans un nouveau MapData (vous en êtes propriétaire).
RTSMapAsset.CreateFromMap(map, preview)Crée un asset de carte en mémoire, par exemple pour transmettre une carte d’une scène à l’autre.
RTSMapSerializer.Serialize(map) / Deserialize(bytes)Conversion en octets et inversement, par exemple pour envoyer une carte sur le réseau.
RTSMapSerializer.TryReadHeaderFromFile(path, out header)Lit uniquement l’en-tête non compressé (rapide, pour afficher des listes de cartes).
RTSMapSerializer.TryReadHeader(bytes, out header)Idem pour des octets de carte en mémoire (par exemple reçus par le réseau).
terrain.CreateNewMap(MapCreationSettings)Crée et affiche une nouvelle carte plate : c’est l’équivalent, dans le code, de la boîte de dialogue New Map. Renseigne Info.tilesetId à partir du tileset du terrain, vide CurrentFilePath et marque la carte comme non enregistrée.
terrain.LoadFromAsset()Recharge la carte depuis MapAsset et abandonne les modifications non enregistrées. Si l’asset est illisible, la méthode journalise une erreur et se rabat sur une carte créée à partir de DefaultMapSettings.
terrain.SaveToMapAsset()Éditeur uniquement : réécrit la carte dans son asset .rtsmap. Renvoie false si le terrain n’a pas d’asset de carte.
terrain.PendingLayersCouches dont les modifications ont été notifiées mais pas encore traitées.
RTSMapAsset.Header / Preview / DataL’en-tête de la carte (lu sans décompresser la carte), l’aperçu de la mini-carte (peut être null) et les octets bruts du fichier.
RTSMapAsset.SetData(bytes, preview)Remplace le contenu d’un asset de carte (l’en-tête est lu à partir des octets).
using System.IO;
using RTSTerrainStudio;
using UnityEngine;

public class SimpleMapList : MonoBehaviour
{
    [SerializeField] RTSTerrain terrain;

    /// <summary>Logs all maps in the default folder without loading them, then opens the first one.</summary>
    [ContextMenu("List And Open Maps")]
    void ListAndOpen()
    {
        string folder = RTSMapSerializer.DefaultMapsFolder;
        if (!Directory.Exists(folder)) { Debug.Log("No maps folder yet: " + folder); return; }

        string[] files = Directory.GetFiles(folder, "*" + RTSMapSerializer.FileExtension);
        foreach (string path in files)
        {
            // The header is stored uncompressed, so this is fast even for big maps.
            if (RTSMapSerializer.TryReadHeaderFromFile(path, out RTSMapHeader h))
                Debug.Log($"{h.name} by {h.author}: {h.width} x {h.height} cells, {h.maxPlayers} players, saved {h.Modified}");
        }

        if (files.Length > 0 && terrain != null)
        {
            try
            {
                terrain.LoadFromFile(files[0]);   // the terrain owns and disposes the loaded map
            }
            catch (InvalidDataException e)
            {
                Debug.LogError("The map file is damaged: " + e.Message);
            }
        }
    }
}

Tilesets

Un tileset (RTSTileset) définit l’apparence d’une carte : jusqu’à 16 calques de sol, jusqu’à 4 calques de falaise et le style de l’eau, à la manière des tilesets été, hiver ou désert des éditeurs de cartes des RTS classiques. Vous pouvez avoir autant de tilesets que vous le souhaitez et changer à tout moment le tileset d’un terrain : les cartes peintes ne stockent que des indices de calques, si bien que la même carte peut s’afficher en version été comme en version hiver.

  1. Créez un tileset avec Assets ▸ Create ▸ RTS Terrain Studio ▸ Tileset.
  2. Faites glisser vos textures de sol sur la section Ground Layers de l’Inspector. Un calque est créé par texture d’albédo. Les normal maps et textures de hauteur correspondantes sont détectées grâce au suffixe de leur nom de fichier (par exemple _n, _normal, _nrm, _normalgl, _h, _height, _disp) ; les textures de rugosité, d’AO et de métallicité sont ignorées, vous pouvez donc déposer tout un dossier de textures téléchargé.
  3. Ajoutez de la même façon des calques de falaise dans Cliff Layers.
  4. Assignez le tileset au champ Tileset de votre RTSTerrain.
  5. Cliquez une fois sur Build Texture Arrays dans la section Texture Arrays (voir Tableaux de textures).

Champs du tileset

ParamètrePar défautDescription
Tileset Id (tilesetId)généréIdentifiant stable stocké dans les fichiers de carte, pour que chaque carte se souvienne du tileset pour lequel elle a été créée. Affiché en lecture seule, avec un bouton Copy.
Display Name (displayName)« New Tileset »Nom affiché dans les éditeurs.
Ground Layers (groundLayers)videJusqu’à 16 entrées GroundLayer. Les entrées en trop sont supprimées.
Cliff Layers (cliffLayers)videJusqu’à 4 entrées CliffLayer.
Water (water)bleu-vertLe WaterProfile, voir ci-dessous.
Resolution (arrayResolution)1024Taille des tranches des tableaux de textures : 256, 512, 1024 ou 2048. Les textures sources sont redimensionnées automatiquement.
Compress (compressArrays)activéCompresse les tableaux générés (BC7 / ASTC). Désactivez cette option pour itérer le plus vite possible.
Material Override (materialOverride)aucunMatériau facultatif à utiliser à la place du matériau de terrain par défaut. Il doit utiliser le shader RTS Terrain Studio/Terrain ou un shader compatible.
Macro Variation (macroVariation)0.25Variation à grande échelle qui casse la répétition des textures sur de grandes surfaces.
Triplanar Sharpness (triplanarSharpness)6Netteté du fondu triplanaire sur les parois de falaise (1–16).

Champs des calques de sol

ParamètrePar défautDescription
Name« Layer »Affiché dans les palettes.
AlbedoaucuneCouleur de base (RGB). Taille et format quelconques.
NormalaucuneNormal map en espace tangent (importez-la en tant que Normal Map).
Height MapaucuneHauteur facultative (canal R) pour le fondu par hauteur. Prend le pas sur l’alpha de l’albédo.
Height From Albedo AlphadésactivéUtilise l’alpha de l’albédo comme hauteur lorsqu’aucune texture de hauteur n’est assignée.
TintblancCouleur multipliée par l’albédo.
Tile Size6Taille réelle d’une répétition de la texture, en mètres (≥ 0.1).
Normal Strength10–2.
Smoothness0.10–1.
Metallic00–1.
Height Blend0.5Intensité du fondu par hauteur avec les calques voisins (0 = fondu linéaire). Nécessite une source de hauteur.
Anti Tiling0.3Casse la répétition visible grâce à un second échantillonnage varié (0–1).
Pathing EffectNoneRègles de cheminement appliquées là où ce calque domine, par exemple Unbuildable pour de la roche accidentée ou Unwalkable pour de la lave.
Minimap ColornoirCouleur sur la mini-carte et dans les aperçus de carte. Noir = calculée à partir de l’albédo.

Champs des calques de falaise

ParamètrePar défautDescription
Name« Cliff »Affiché dans la palette Cliff Type.
AlbedoaucuneCouleur de la paroi. Sans elle, les falaises de ce type affichent un substitut gris foncé.
NormalaucuneNormal map en espace tangent.
TintblancCouleur multipliée par l’albédo.
Tile Size4Taille réelle d’une répétition de la texture, en mètres.
Normal Strength10–2.
Smoothness0.150–1.
Top Ground Layer−1 (aucun)Calque de sol peint automatiquement sur le dessus des falaises de ce type. Utilisé par Auto Paint.
Edge Ground Layer−1 (aucun)Calque de sol que les outils de falaise peignent le long des bords des nouvelles falaises de ce type, par exemple un rebord pierreux (voir Bords de falaise automatiques). Affiché sous le nom Edge Layer dans le panneau du calque de falaise. −1 = pas de bord automatique.
Minimap ColornoirCouleur sur la mini-carte. Noir = calculée à partir de l’albédo.

Les parois de falaise sont texturées par projection triplanaire dans l’espace local de la carte : les textures de falaise ne nécessitent donc aucune disposition UV particulière.

Profil d’eau

Le profil d’eau fait partie du tileset ; il est utilisé par le rendu de l’eau, la carte de cheminement et la mini-carte.

ParamètrePar défautDescription
Shallow Color(0.22, 0.55, 0.6, 0.55)Couleur de l’eau peu profonde ; alpha = opacité.
Deep Color(0.03, 0.16, 0.27, 0.95)Couleur de l’eau profonde ; alpha = opacité.
Color Depth3Profondeur, en mètres, à laquelle la couleur de l’eau profonde est entièrement atteinte.
Shallow Depth Limit0.9Au-delà de cette profondeur, l’eau est profonde (non praticable). L’eau moins profonde est praticable, comme dans les RTS classiques.
Normal MapaucuneNormal map des vagues.
Normal Strength0.60–2.
Normal Tile Size8Taille réelle d’une répétition de la normal map, en mètres.
Flow Speed(0.03, 0.02)Vitesse de défilement de la normal map.
Wave Height0.050–1.
Smoothness0.920–1.
Refraction0.030–0.2.
Foam Colorblanc, alpha 0.8Couleur de l’écume le long du rivage.
Foam Distance0.6Distance de l’écume le long du rivage, en mètres.
Foam TextureaucuneMotif d’écume facultatif.
Minimap Color(0.1, 0.3, 0.55)Couleur de l’eau sur la mini-carte.

Modifier les tilesets par le code

Les tilesets sont des ScriptableObjects. Après avoir modifié des champs par le code, appelez tileset.NotifyChanged() pour que les terrains actualisent leurs matériaux. tileset.GetGroundLayer(index) et GetCliffLayer(index) renvoient null pour les emplacements inutilisés.

Tableaux de textures

Le shader de terrain dessine les 20 calques en une seule passe : toutes les textures de calques sont donc regroupées dans deux tableaux de textures GPU. Vous ne créez jamais ces tableaux vous-même : vous fournissez des textures Unity ordinaires, de n’importe quelle taille et de n’importe quel format, et les tableaux sont générés à partir d’elles.

Structure

TableauTranchesCanauxEspace colorimétrique
_RTS_AlbedoArray0–15 : calques de sol, 16–19 : calques de falaiseRGB = albédo, A = hauteur pour le fondu par hauteursRGB
_RTS_NormalArray0–15 : calques de sol, 16–19 : calques de falaiseRGB = normale en espace tangent remappée sur 0–1 (n × 0.5 + 0.5)linéaire
  • La première tranche de falaise est RTSTileset.CliffSliceOffset (16) ; le nombre total de tranches est RTSTileset.TotalSlices (20).
  • La hauteur (alpha) provient de la texture Height Map du calque (canal R) ; à défaut, de l’alpha de l’albédo si Height From Albedo Alpha est activé ; sinon, c’est une valeur constante de 0.5.
  • Les normales sont décodées pendant la génération : vos normal maps peuvent donc utiliser comme d’habitude l’importation de normal maps de Unity (DXT5nm / BC5). Les calques sans normal map reçoivent une normale plate.
  • Les calques sans albédo reçoivent une tranche gris neutre avec un motif discret ; le shader applique tout de même la teinte.
  • Chaque tranche possède une chaîne de mips complète et utilise le filtrage trilinéaire. Les sources de toute taille sont redimensionnées selon le paramètre Resolution choisi.

Tableaux générés et repli à l’exécution

Les tableaux peuvent voir le jour de deux manières :

Tableaux générés (recommandé)Repli à l’exécution
Créés parLe bouton Build Texture Arrays dans l’Inspector du tilesetLe renderer, automatiquement, lorsqu’il n’existe aucun tableau généré à jour
StockageSous forme de sous-assets dans l’asset du tileset (inclus dans les builds de joueur)Uniquement en mémoire GPU, reconstruits au chargement
FormatBC7 (ordinateurs de bureau, consoles), ASTC 6×6 (Android, iOS, tvOS, visionOS), la compression de textures définie pour le build Web (DXT5, ASTC 6×6 ou ETC2 RGBA8), DXT5 (autres plateformes) ; RGBA32 lorsque Compress est désactivéNon compressé (4 octets par pixel)
Mémoire à 1024 pxenviron 56 Mo en BC7 pour les deux tableauxenviron 224 Mo pour les deux tableaux

La section Texture Arrays affiche un badge d’état :

  • Not built : le terrain utilise des tableaux créés à l’exécution. Cliquez une fois sur Build Texture Arrays.
  • Up to date : le format, la taille, le nombre de mips et la mémoire utilisée sont affichés.
  • Outdated : les textures, la résolution ou la compression ont changé, ou les tableaux ont été générés pour une autre plateforme ou une autre compression de textures. Générez-les de nouveau, ou laissez le prochain build de joueur s’en charger.
  • Building : une génération est en cours ou planifiée.

La section indique aussi le format cible pour la plateforme de build active, ainsi que la taille et la durée de génération estimées, et demande une confirmation avant toute génération de plus de 256 Mo. Clear supprime les tableaux générés.

Builds de joueur

Les builds de joueur utilisent les tableaux générés tels quels, car seul l’éditeur peut les comparer aux textures sources. Les tableaux obsolètes sont donc reconstruits automatiquement juste avant chaque build de joueur, et les tilesets dont les tableaux n’ont jamais été générés continuent d’utiliser des tableaux créés à l’exécution. Les détails, notamment le mode batch et -rtsAllowOutdatedTextureArrays, sont décrits dans Tableaux de textures dans les builds de joueur. Les builds de joueur libèrent aussi la copie CPU des tableaux générés dès leur première utilisation, ce qui économise à peu près autant de mémoire que les tableaux en occupent sur le GPU.

Par le code : tileset.HasValidBuiltArrays indique si les tableaux compressés seront utilisés. Dans l’éditeur, ils doivent exister et correspondre à ComputeContentHash(). Un build de joueur considère les tableaux générés comme valides jusqu’à ce que votre code modifie à l’exécution les textures des calques, la résolution ou la compression ; il se replie alors sur des tableaux créés à l’exécution. Les valeurs de ComputeContentHash() ne sont comparables qu’au sein de l’éditeur ou au cours d’une même exécution d’un build de joueur, car l’éditeur calcule le hachage à partir de l’état d’importation des textures. Lorsque HasValidBuiltArrays vaut false, RTSTerrain crée des tableaux non compressés à l’exécution (RTSTextureArrayBuilder.Acquire). tileset.BuiltAlbedoArray / BuiltNormalArray donnent accès aux tableaux générés. Dans votre propre code d’exécution, utilisez RTSShaderReferences.FindShader(name) (et FindMaterial(name)) au lieu de Shader.Find, pour que la recherche fonctionne aussi dans les builds de joueur.

Auto Build

Lorsque Auto Build est activé (c’est le cas par défaut ; il s’agit d’une préférence de l’éditeur commune à tous les tilesets), les tableaux qui ont déjà été générés sont reconstruits une seconde après toute modification des textures, de la résolution ou de la compression, avec une compression rapide. La première génération se lance toujours manuellement. Une génération automatique annulée ou en échec n’est pas relancée tant que le contenu ou le format cible ne change pas. Le bouton Build Texture Arrays, lui, utilise la qualité de compression normale, au rendu légèrement meilleur : cliquez dessus avant de publier votre jeu.

L’estimation de la taille se calcule facilement : résolution² × 20 tranches × 2 tableaux × 4/3 pour les mips × octets par pixel (1 pour BC7, environ 0.44 pour ASTC 6×6, 4 sans compression). Sur mobile, abaissez la résolution à 512 : la mémoire est divisée par quatre.

Pour les builds de joueur, les shaders RTS Terrain Studio/Terrain et Hidden/RTS Terrain Studio/TextureArrayBlit (utilisé par le repli à l’exécution) doivent être inclus. Tools ▸ RTS Terrain Studio ▸ Validate Project crée l’asset RTSShaderReferences dans Resources/RTSTerrainStudio ; cet asset garantit que tous les shaders du package sont conservés dans les builds.

Bibliothèque de végétation

Une bibliothèque de végétation (RTSVegetationLibrary) répertorie l’herbe, les plantes et les arbres disponibles pour la peinture. Créez-en une avec Assets ▸ Create ▸ RTS Terrain Studio ▸ Vegetation Library et assignez-la au champ Vegetation Library du RTSTerrain. Pour afficher la végétation, le terrain a aussi besoin d’un composant RTSVegetationRenderer (l’Inspector de RTSTerrain propose de l’ajouter).

L’Inspector comporte deux onglets, Details et Trees, avec une grille de miniatures. Déposez-y des prefabs (arbres), des textures (quads d’herbe) ou des meshes (meshes de détail) pour ajouter des entrées. Chaque entrée reçoit un id stable, utilisé par les cartes ; les entrées dupliquées reçoivent automatiquement de nouveaux identifiants.

Prototypes de détails

Les détails sont de petites plantes présentes en grand nombre et peintes par densité (voir Densité de détails). Ils sont générés par blocs de 16 × 16 cellules et dessinés avec le shader procédural interne Hidden/RTS Terrain Studio/Detail, qui gère le vent, le brouillard de guerre et la variation de couleur.

ParamètrePar défautDescription
IdgénéréIdentifiant stable stocké dans les fichiers de carte.
Name« Grass »Affiché dans la palette.
Render ModeCrossed QuadsCrossedQuads : quads croisés texturés avec Texture (herbe classique). Mesh : utilise Mesh, texturé avec la texture principale et la couleur de Material.
MeshaucunMesh pour le mode Mesh.
MaterialaucunMatériau pour le mode Mesh. Sa texture principale, sa couleur et son seuil d’alpha (alpha cutoff) sont utilisés avec le shader de détail.
TextureaucuneTexture avec alpha pour le mode Crossed Quads.
Healthy Color / Dry Colorvert clair / pailleLes instances mélangent ces deux couleurs selon un bruit.
Min / Max Width0.6 / 1.0Plage de largeur aléatoire, en mètres.
Min / Max Height0.4 / 0.8Plage de hauteur aléatoire, en mètres.
Max Density6Nombre d’instances par texel de détail à pleine densité (255). Plage 1–32.
Color Noise Scale12Échelle du bruit qui mélange la couleur saine et la couleur sèche.
Wind Strength0.50–1. La direction et la vitesse du vent se règlent sur le RTSVegetationRenderer.
Render Distance70Les instances situées au-delà de cette distance de la caméra ne sont pas affichées (elles rétrécissent d’abord en douceur jusqu’à disparaître).
Cast ShadowsdésactivéLes ombres des détails sont coûteuses ; laissez cette option désactivée pour l’herbe.
Align To GroundactivéIncline les instances pour qu’elles suivent la normale du sol.
Max Slope40Aucune instance n’apparaît sur les pentes plus raides que cette valeur (en degrés).
Avoid WateractivéAucune instance n’apparaît sous l’eau.
IconaucuneIcône de la palette ; générée dans l’éditeur si le champ est vide.

Prototypes d’arbres

Les arbres sont des instances individuelles (voir Arbres et instances de décor), placées avec l’outil Place Trees.

ParamètrePar défautDescription
IdgénéréIdentifiant stable stocké dans les fichiers de carte.
Name« Tree »Affiché dans la palette.
PrefabaucunPrefab avec des MeshRenderers et un LODGroup facultatif (LOD0 et LOD1 sont utilisés).
Spawn ModeInstancedInstanced : instanciation GPU, sans GameObject ; c’est le mode le plus rapide. GameObject : une instance de prefab par arbre, pour des mécaniques de gameplay comme la récolte.
Min / Max Scale0.85 / 1.2Plage d’échelle uniforme aléatoire.
Random RotationactivéLacet aléatoire lors du placement.
Tint A / Tint Bblanc / vert pâlePlage de teinte aléatoire par instance.
Footprint Radius0.8Rayon, en mètres, bloqué dans la carte de cheminement (mis à l’échelle avec l’arbre).
Blocks VisionactivéLes arbres bloquent la ligne de vue pour le brouillard de guerre, comme dans les RTS classiques.
Min Spacing1.6Distance minimale par rapport aux autres arbres lors de la dispersion.
CollidersactivéMode Instanced : des proxys de collider capsule, gérés en pool, sont créés. Mode GameObject : les colliders propres au prefab sont utilisés.
Collider Radius / Height0.4 / 4Taille des proxys de collider capsule (mode Instanced).
Render Distance250Les arbres situés au-delà de cette distance de la caméra ne sont pas affichés.
Cast ShadowsactivéProjection d’ombres.
IconaucuneIcône de la palette ; générée dans l’éditeur si le champ est vide.

Instanciation GPU

Les arbres instanciés sont dessinés par instanciation GPU : l’option Enable GPU Instancing de leurs matériaux devrait donc être activée. Si elle est désactivée sur un matériau, le renderer utilise automatiquement une copie cachée de ce matériau, avec l’instanciation activée (synchronisée avec l’original pendant vos modifications), et l’Inspector de la bibliothèque affiche un message d’information avec un bouton Enable qui corrige le matériau lui-même. Les matériaux des détails n’ont pas besoin de l’instanciation, car ils sont toujours dessinés avec le shader de détail procédural.

Utilisez le shader RTS Terrain Studio/Vegetation pour les matériaux de vos prefabs d’arbres et de plantes, afin de bénéficier du vent, de la translucidité, du brouillard de guerre et de la teinte par instance. Les autres matériaux URP compatibles avec l’instanciation fonctionnent aussi, mais sans la teinte.

Par le code, vous supprimez une instance d’arbre avec RTSVegetationRenderer.RemoveTree(id) (par exemple lorsqu’un ouvrier récolte un arbre) et vous la trouvez avec TryFindNearestTree ; GetTreeObject(id) renvoie son GameObject ou son proxy de collider.

Modifier les bibliothèques par le code

Les cartes stockent une palette d’identifiants de prototypes. Pour retrouver le prototype qui correspond à un indice de palette, passez donc par la bibliothèque :

  • Arbres : vegetationLibrary.FindTree(map.TreePrototypeIds[tree.prototype]).
  • Couches de détails : vegetationLibrary.FindDetail(layer.prototypeId).
  • Décors : decorLibrary.Find(map.DecorPrototypeIds[d.prototype]). Obtenez le prefab de la variante avec prototype.GetPrefab(d.variant) : 0 correspond au prefab principal, et les variantes invalides ou vides se rabattent sur celui-ci. VariantCount inclut le prefab principal.
  • decorLibrary.GetCategories() liste les catégories dans l’ordre d’affichage (les prototypes sans catégorie sont listés sous Misc).
  • vegetationLibrary.EnsureUniqueIds() attribue de nouveaux identifiants aux entrées dupliquées.

Après avoir modifié une bibliothèque par le code, appelez library.NotifyChanged() (cette méthode déclenche l’événement Changed de la bibliothèque) : RTSTerrain déclenche alors LibrariesChanged et les renderers s’actualisent. La règle est la même que pour les tilesets.

Bibliothèque de décors

Une bibliothèque de décors (RTSDecorLibrary) liste les accessoires (doodads) que vous pouvez placer : rochers, ruines, clôtures, caisses, bâtiments ou tout autre prefab. Créez-en une avec Assets ▸ Create ▸ RTS Terrain Studio ▸ Decor Library et assignez-la au champ Decor Library du composant RTSTerrain. Un composant RTSDecorManager placé sur le terrain maintient la scène synchronisée avec les instances placées.

L’Inspector affiche les prototypes sous forme de grille, avec des miniatures générées automatiquement et un onglet par catégorie (plus All). Déposez-y des prefabs pour les ajouter à la catégorie actuelle ; cliquez avec le bouton droit sur l’onglet d’une catégorie pour le renommer. Les prototypes sans catégorie apparaissent sous Misc.

Champs des prototypes de décor

ParamètrePar défautDescription
IdgénéréIdentifiant stable enregistré dans les fichiers de carte.
Name« Decor »Affiché dans la palette.
Category« Props »Onglet de la palette dans lequel le prototype apparaît.
PrefabaucunL’objet à placer.
VariantsvidePrefabs alternatifs facultatifs ; une variante est choisie au hasard lors du placement. L’instance enregistre l’index de la variante (0 = prefab principal).
Spawn ModeGameObjectGameObject : un GameObject par instance (scripts, colliders, animations). Instanced : instanciation GPU, aucun GameObject, accessoires statiques uniquement, le mode le plus rapide.
Min / Max Scale0.9 / 1.1Plage d’échelle uniforme aléatoire.
Random YawactivéRotation aléatoire autour de l’axe vertical.
Yaw Step0Contraint le lacet à des multiples de cet angle (0 = libre), par exemple 90 pour les murs et les clôtures.
Max Random Tilt0Inclinaison aléatoire en degrés (0–45).
Align To Normal0Aligne l’axe vertical sur la normale du sol (0 = vertical, 1 = entièrement aligné).
Snap To GriddésactivéAligne la position sur les centres des cellules.
Y Offset0Décalage vertical en mètres, ajouté au moment du rendu (une valeur négative enfonce l’objet dans le sol).
Tint A / Tint Bblanc / blancPlage de teintes aléatoires par instance.
Footprint ShapeCircleNone, Circle ou Box.
Footprint Size(0.75, 0.75)Circle : X est le rayon. Box : demi-dimensions le long des axes X et Z de l’objet. Valeurs en mètres, mises à l’échelle avec l’instance.
Footprint EffectUnwalkable, UnbuildableIndicateurs PathingOverride écrits à l’intérieur de l’emprise.
Blocks VisiondésactivéBloque la ligne de vue pour le brouillard de guerre.
Min Spacing1Distance minimale par rapport aux autres objets de décor lors de la dispersion.
Cast ShadowsactivéProjection d’ombres.
IconaucuneIcône de la palette ; générée dans l’éditeur si le champ est vide.

Emprises

  • Une emprise circulaire utilise la valeur X de Footprint Size comme rayon, multipliée par la plus grande échelle horizontale de l’instance.
  • Une emprise rectangulaire suit la rotation de l’instance (ses axes X et Z projetés sur le sol) et son échelle X/Z : un mur pivoté bloque ainsi exactement sa propre surface.
  • Aucune emprise n’est écrite lorsque la forme vaut None, que l’effet vaut None ou que l’instance porte l’indicateur DecorFlags.IgnorePathing.
  • Utilisez Unbuildable seul pour les décorations plates sur lesquelles les unités peuvent marcher (fleurs, gravats), et Unwalkable pour les objets solides.

Modes d’apparition

GameObjectInstanced
Objets de scèneUn par instance, sous un enfant nommé « RTS Decor » (non enregistré avec la scène)Aucun
Scripts, colliders, animationOui (chaque racine reçoit un composant RTSDecorInstance)Non
RenduRenderers normaux du prefabGraphics.RenderMeshInstanced avec le LOD0, culling par patch
Idéal pourAccessoires interactifs, mines d’or, objets destructiblesDes milliers de rochers et de plantes statiques

Les décors instanciés se comportent comme les arbres instanciés vis-à-vis de l’instanciation GPU : les matériaux sans Enable GPU Instancing sont dessinés au moyen d’une copie masquée du matériau, avec l’instanciation activée. Les objets créés sont réutilisés via un pool ; RTSDecorManager.GetInstanceObject(id) renvoie l’objet créé pour une instance, et RTSDecorInstance.FromCollider(collider) retrouve l’instance qui correspond à un impact physique.

Le format de fichier .rtsmap

Cette section s’adresse aux programmeurs qui veulent lire des cartes avec d’autres outils, écrire des convertisseurs ou ajouter leurs propres données. Vous n’en avez pas besoin pour utiliser le package : RTSMapSerializer s’occupe de tout.

Structure binaire

Tous les nombres sont en little-endian. Les chaînes utilisent le format BinaryWriter de .NET : une longueur encodée en 7 bits, suivie des octets UTF-8.

PartieTypeContenu
Nombre magique4 octetsASCII RTSM
Version du formatint32RTSMapSerializer.CurrentVersion (actuellement 1)
Longueur de l’en-têteint32Nombre d’octets d’en-tête qui suivent
En-têteoctetsstring name, string author, string description, int32 width, int32 height, float cellSize, int32 maxPlayers, string tilesetId, int64 modifiedUtcTicks
Corpsflux deflate brut (RFC 1951, sans enveloppe zlib ni gzip) jusqu’à la fin du fichierUne suite de sections, terminée par une étiquette int32 valant 0

L’en-tête n’est pas compressé, ce qui permet aux explorateurs de cartes d’afficher le nom, l’auteur, la taille et le nombre de joueurs sans décompresser la carte (RTSMapSerializer.TryReadHeader, TryReadHeaderFromFile, structure RTSMapHeader). Les lecteurs utilisent la longueur de l’en-tête pour sauter directement à sa fin : les versions futures peuvent ainsi ajouter des champs à l’en-tête.

Sections

Chaque section a la forme [int32 tag][int32 length][payload]. Les étiquettes sont des codes FourCC stockés en little-endian : le premier caractère se trouve donc dans l’octet de poids faible (DIMS = 0x534D4944). Les tableaux de données raster sont écrits sous la forme d’un nombre d’éléments en int32, suivi des éléments bruts.

ÉtiquetteValeurCharge utile
DIMS0x534D4944int32 width, int32 height, float cellSize, float cliffLevelHeight, int32 splatResolution, int32 detailResolution, int32 pathingResolution, uint32 nextInstanceId. Doit être la première section.
INFO0x4F464E49string name, author, description ; int32 maxPlayers ; string tilesetId ; int64 createdUtcTicks, modifiedUtcTicks
HGHT0x54484748Hauteurs fines : un float par vertex
LEVL0x4C56454CNiveaux de falaise : un octet par vertex
VFLG0x474C4656Indicateurs de vertex : un octet par vertex
CTYP0x50595443Types de falaise : un octet par vertex
WATR0x52544157Hauteurs de la surface de l’eau : un float par vertex
SPLT0x544C5053Nombre de splat maps en int32 (4), puis, pour chaque splat map, un tableau d’octets RGBA par texel
DETL0x4C544544Nombre de couches en int32, puis, pour chaque couche : string prototypeId et un tableau d’octets de densité par texel de détail
TREE0x45455254Liste des id de prototypes (nombre en int32 + chaînes), nombre d’arbres en int32, puis, pour chaque arbre : uint32 id, uint16 prototype, float3 position, float yaw, float scale, 4 octets de teinte (30 octets)
DECO0x4F434544Liste des id de prototypes, nombre en int32, puis, pour chaque instance : uint32 id, uint16 prototype, byte variant, byte flags, float3 position, float4 rotation (x, y, z, w), float3 scale, 4 octets de teinte (52 octets)
PATH0x48544150Surcharges de cheminement manuelles : un octet par cellule de cheminement
REGN0x4E474552Nombre en int32, puis, pour chaque région : string name, float x, z, width, depth, float4 colour, properties
STRT0x54525453Nombre en int32, puis, pour chaque position de départ : int32 player, float3 position, float yaw
MARK0x4B52414DNombre en int32, puis, pour chaque marqueur : string name, string tag, float3 position, float4 rotation, properties
ENVR0x52564E45float4 sunColor, float sunIntensity, float2 sunRotation, float4 ambientColor, bool fog, float4 fogColor, float fogDensity

Les « properties » sont écrites sous la forme d’un nombre en int32, suivi de paires de chaînes clé/valeur. La carte de cheminement dérivée n’est pas stockée ; seules les surcharges manuelles le sont.

Sections inconnues, fichiers endommagés et gestion des versions

  • Les sections inconnues sont ignorées grâce à leur longueur. Les anciennes versions du package peuvent donc lire des fichiers plus récents qui contiennent des sections supplémentaires, et vos sections personnalisées ne perturbent jamais les autres lecteurs.
  • Si la version de format d’un fichier est plus récente que celle du lecteur, un avertissement est consigné et le fichier est tout de même lu ; les données inconnues sont ignorées.
  • Si le nombre d’éléments d’une couche raster ne correspond pas à la taille de la carte, un avertissement est consigné ; ce qui tient dans la carte est lu, le reste est ignoré.
  • Les fichiers tronqués ou endommagés déclenchent toujours le même type d’exception, System.IO.InvalidDataException. Un fichier dont le nombre magique est incorrect est signalé par le message « Not an RTS Terrain Studio map file ».
  • RTSMapSerializer.SaveToFile écrit d’abord dans <path>.tmp, puis remplace le fichier : un plantage pendant l’enregistrement ne laisse donc jamais une carte à moitié écrite.
  • Règle de compatibilité du format : les nouvelles données sont ajoutées sous forme de nouvelles sections ou de champs ajoutés à la fin de l’en-tête, jamais en modifiant des sections existantes. Faites de même avec vos propres sections et conservez un numéro de version dans votre charge utile.

Sections personnalisées

Vous pouvez stocker vos propres données dans les fichiers de carte, par exemple des règles de jeu, des déclencheurs ou des données de quête. Deux hooks statiques de RTSMapSerializer le permettent :

HookTypeMoment de l’appel
CustomSectionWriterAction<MapData, Action<int, byte[]>>Une fois par enregistrement, après les sections intégrées. Appelez l’action fournie avec votre étiquette et votre charge utile pour chaque section que vous voulez écrire.
CustomSectionReaderAction<MapData, int, byte[]>Pour chaque section que le lecteur ne connaît pas, avec son étiquette et sa charge utile. Le MapData existe déjà à ce moment-là (DIMS vient en premier).
  • Choisissez des étiquettes qui n’entrent pas en conflit avec les étiquettes intégrées ; faites-les commencer par X (par exemple XGLD). N’utilisez jamais 0, qui marque la fin des sections.
  • Les deux hooks sont de simples délégués : combinez des gestionnaires avec += et retirez-les avec -=, ce qui permet à plusieurs systèmes d’ajouter des sections.
  • Dans votre lecteur, vérifiez l’étiquette et ignorez les sections qui ne vous appartiennent pas.
  • MapData ne prévoit pas d’emplacement pour vos données. Conservez-les à côté de la carte (l’exemple utilise une ConditionalWeakTable). Les données conservées de cette façon ne sont pas copiées par MapData.Clone() ni par ResizeMap, et ne sont pas enregistrées dans l’historique d’annulation.
  • Inscrivez les hooks avant le chargement ou l’enregistrement de la moindre carte. Dans l’éditeur Unity, les cartes sont aussi lues par l’importateur et écrites par la commande Save : inscrivez-les donc aussi pour l’éditeur (l’exemple utilise InitializeOnLoadMethod).
using System;
using System.IO;
using System.Runtime.CompilerServices;
using RTSTerrainStudio;
using UnityEngine;

/// <summary>Stores a "starting gold" value in every map file, in a custom section "XGLD".</summary>
public static class StartingGoldSection
{
    // FourCC, little-endian like the built-in tags: the first character is in the lowest byte.
    const int Tag = 'X' | ('G' << 8) | ('L' << 16) | ('D' << 24);
    const int PayloadVersion = 1;

    /// <summary>Our data for one map.</summary>
    public sealed class Data
    {
        public int startingGold = 500;
    }

    // One Data object per MapData. Entries disappear automatically together with their map.
    static readonly ConditionalWeakTable<MapData, Data> s_Data = new ConditionalWeakTable<MapData, Data>();

    /// <summary>Returns the data of a map (created with defaults when the map has none).</summary>
    public static Data Get(MapData map) => s_Data.GetOrCreateValue(map);

#if UNITY_EDITOR
    [UnityEditor.InitializeOnLoadMethod]          // editor: importer and Save
#endif
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]   // player and Play Mode
    static void Register()
    {
        // Remove first so a second registration does not add the handlers twice.
        RTSMapSerializer.CustomSectionWriter -= Write;
        RTSMapSerializer.CustomSectionWriter += Write;
        RTSMapSerializer.CustomSectionReader -= Read;
        RTSMapSerializer.CustomSectionReader += Read;
    }

    static void Write(MapData map, Action<int, byte[]> writeSection)
    {
        if (!s_Data.TryGetValue(map, out Data data)) return;   // nothing to save for this map
        using (var stream = new MemoryStream())
        {
            using (var writer = new BinaryWriter(stream))
            {
                writer.Write(PayloadVersion);   // our own version, so the payload can grow later
                writer.Write(data.startingGold);
            }
            writeSection(Tag, stream.ToArray());
        }
    }

    static void Read(MapData map, int tag, byte[] payload)
    {
        if (tag != Tag) return;   // another system's section: ignore it
        using (var reader = new BinaryReader(new MemoryStream(payload)))
        {
            int version = reader.ReadInt32();
            if (version >= 1) Get(map).startingGold = reader.ReadInt32();
        }
    }
}

Dans le code du jeu, lisez la valeur avec StartingGoldSection.Get(terrain.Map).startingGold. Après avoir modifié la valeur dans l’éditeur, marquez la carte comme modifiée (par exemple terrain.NotifyChanged(MapLayers.Info, terrain.Map.CellBounds), ou définissez terrain.HasUnsavedChanges = true) pour qu’elle soit enregistrée.

Édition dans l’éditeur Unity

Ce chapitre couvre tout ce qui vous sert à construire une carte dans l’éditeur Unity : la fenêtre RTS Terrain Studio, la peinture dans la Scene View, les raccourcis clavier, les pinceaux, la symétrie, l’annulation, chaque outil d’édition avec tous ses paramètres, la peinture automatique (Auto Paint) et le composant RTS Terrain lui-même.

L’éditeur en jeu repose sur les mêmes outils et les mêmes paramètres de pinceau et de symétrie (voir Éditeur en jeu) : ce que vous apprenez ici s’y applique donc aussi.

Votre première modification en cinq étapes. Si vous n’avez encore jamais utilisé le package, essayez ceci :

  1. Créez un terrain avec GameObject ▸ RTS Terrain Studio ▸ RTS Terrain. Si le projet n’a pas encore de tileset, on vous propose de créer d’abord le contenu de démo : acceptez.
  2. Ouvrez Tools ▸ RTS Terrain Studio ▸ Editor Window.
  3. Dans l’onglet Height, cliquez sur Raise / Lower. L’édition s’active automatiquement.
  4. Placez la souris sur le terrain dans la Scene View et maintenez le bouton gauche enfoncé. Une colline se forme. Maintenez Shift enfoncée pour creuser à la place.
  5. Appuyez sur 2 pour passer aux outils de falaise, cliquez sur la colline pour élever un plateau, puis appuyez sur Esc quand vous avez terminé. Ctrl+Z annule n’importe quelle étape.

La fenêtre RTS Terrain Studio

La fenêtre est le centre de contrôle de l’éditeur. Elle ne possède aucun état d’édition propre : elle affiche et modifie la session d’édition partagée, que la Scene View, l’overlay de la Scene View et l’Inspector du composant RTS Terrain utilisent aussi. Tout ce que vous changez à un endroit se répercute immédiatement dans les autres.

Vous pouvez l’ouvrir de plusieurs façons :

  • Tools ▸ RTS Terrain Studio ▸ Editor Window
  • le bouton Open RTS Terrain Studio de l’Inspector du composant RTS Terrain
  • le bouton d’ouverture de la fenêtre dans l’overlay RTS Terrain Studio de la Scene View
La fenêtre RTS Terrain Studio avec l’onglet Decor et la palette de décors
La fenêtre RTS Terrain Studio (onglet Decor). En haut, les catégories ; en dessous, les outils, puis la description de l’outil actif, la symétrie et les paramètres avec la palette de miniatures.

La fenêtre comporte quatre zones : l’en-tête en haut, la barre d’onglets, la page défilante et la barre d’état en bas.

En-tête

L’en-tête indique le terrain et la carte que vous modifiez, et regroupe les commandes de fichier et d’annulation.

CommandeRôle
Sélecteur de terrainChoisit le terrain que modifient la fenêtre et les outils de la Scene View. Il liste tous les RTS Terrain des scènes ouvertes et comporte une entrée Create New Terrain. Sélectionner un terrain dans la fenêtre Hierarchy ou cliquer sur un autre terrain dans la Scene View change aussi le terrain modifié. Les saisies de texte en cours sont validées avant le changement.
Bouton SelectSélectionne le GameObject du terrain dans la fenêtre Hierarchy et le met en évidence.
Nom de la carte et pointLe nom de la carte (défini dans l’onglet Map). Un point à côté indique que la carte comporte des modifications non enregistrées. En dessous figurent la taille de la carte et le nom de l’asset .rtsmap.
SaveÉcrit la carte dans son asset .rtsmap. Sans asset de carte, il se comporte comme Save As. Le bouton est mis en évidence tant qu’il reste des modifications non enregistrées. Si le fichier est en lecture seule ou verrouillé, une boîte de dialogue explique le problème et propose Save As.
Save As…Enregistre la carte comme nouvel asset .rtsmap dans le projet et l’assigne au terrain.
Open…Ouvre un autre asset .rtsmap du projet sur ce terrain. Les fichiers situés hors du dossier Assets doivent d’abord être copiés dans le projet.
ReloadRecharge la carte depuis son asset et abandonne les modifications non enregistrées. Nécessite un asset de carte.
Undo / RedoAnnule ou rétablit la dernière modification du terrain. Les boutons affichent le nom de l’étape, par exemple Undo Raise / Lower. Voir Annuler et rétablir.
?Ouvre ce manuel au chapitre consacré à la fenêtre de l’éditeur.
Editing On / Editing OffActive ou désactive l’édition du terrain dans la Scene View. Si aucun outil n’est encore sélectionné, l’activation de l’édition choisit le premier outil de l’onglet affiché.

Open… et Reload demandent confirmation avant de remplacer une carte qui comporte des modifications non enregistrées ou un historique d’annulation, car le chargement d’une carte efface l’historique d’annulation. En Play Mode, un avertissement vous rappelle que les modifications sont perdues lorsque vous quittez le Play Mode, sauf si vous enregistrez la carte.

Lorsque la scène n’a pas encore de terrain, l’en-tête affiche à la place un bouton Create Terrain. Il crée un GameObject RTS Terrain doté des composants de végétation, d’eau et de décor, au moyen de l’élément de menu GameObject ▸ RTS Terrain Studio ▸ RTS Terrain.

Barre d’onglets

La barre d’onglets comporte dix onglets : les huit catégories d’outils Height, Cliffs, Paint, Vegetation, Decor, Water, Pathing et Markers, suivies de Map et Settings. Un petit point signale la catégorie de l’outil avec lequel vous peignez actuellement. La fenêtre mémorise le dernier onglet utilisé.

Lorsque la fenêtre a le focus clavier, les touches 1 à 8 (y compris celles du pavé numérique) permettent de passer d’un onglet de catégorie à l’autre. Ces touches sont ignorées pendant que vous tapez dans un champ de texte.

Pages d’outils

Chaque onglet de catégorie affiche une pile de panneaux. Vous pouvez replier chaque panneau en cliquant sur son en-tête.

PanneauContenu
Category ToolsLa grille d’outils. Cliquez sur un outil pour peindre avec lui dans la Scene View. Cliquez à nouveau sur l’outil actif pour arrêter l’édition. Survolez un outil pour lire sa description et ses touches de modification. Les outils personnalisés que vous écrivez apparaissent ici automatiquement.
Panneau de l’outilLe nom, la description et l’indication de l’outil sélectionné, un bouton ? qui ouvre la section correspondante de ce manuel, et une ligne d’état en direct. Placez la souris sur le terrain pour la voir, par exemple Ground 4.25 m | Fine +0.25 m | Level 2 pour les outils de hauteur ou Level 2 → 3 pour les outils de falaise.
Getting StartedAffiché lorsqu’aucun outil de cette catégorie n’est sélectionné. Si vous peignez avec un outil d’une autre catégorie, il indique Active tool: X et propose Go to Tool.
BrushForme, rayon, intensité, dureté, courbe d’atténuation, rotation, rotation aléatoire, espacement et décalage aléatoire. Ces paramètres sont partagés par tous les outils pinceaux. Masqué pour les outils qui n’utilisent pas le pinceau. Voir Pinceaux.
SymmetryMode et centre de symétrie (non affiché pour les outils à glissement). Voir Symétrie.
Tool SettingsLes paramètres de l’outil sélectionné, générés automatiquement à partir du code de l’outil. Ils sont mémorisés d’une session de l’éditeur à l’autre. Les tableaux de la référence des outils détaillent chaque paramètre.
Actions de catégoriePanneaux supplémentaires pour certaines catégories : Auto Paint Whole Map (Paint), Selection (Decor, lorsque Select Decor est actif), Water at Cursor (Water) et Pathing Overlay (Pathing).

Lorsque l’édition est en pause, un bandeau affiche Editing is paused – the Scene View uses Unity's tools. Son bouton Resume réactive l’édition.

Planche de toutes les icônes de RTS Terrain Studio : catégories, outils, actions, modes de symétrie et formes de pinceau
Chaque catégorie, outil, action, mode de symétrie et forme de pinceau possède sa propre icône. Les mêmes icônes sont utilisées dans la fenêtre, l’overlay et l’éditeur en jeu.

Paramètres des outils et palettes

Le panneau des paramètres choisit une commande pour chaque paramètre en fonction de son type :

Type de paramètreCommande
Nombre avec une plageCurseur avec un champ de valeur
Valeur booléenne (activé/désactivé)Case à cocher
Choix (énumération)Liste déroulante
Couleur / texteChamp de couleur / champ de texte
Calque de solPalette des calques de sol du tileset, avec des miniatures de textures. Les emplacements vides restent visibles et expliquent dans leur info-bulle comment les remplir.
Type de falaisePalette des calques de falaise du tileset.
Niveau de falaiseBoutons pour les niveaux 0 à 15. Chaque info-bulle indique la hauteur du sol de ce niveau, et la palette affiche le niveau situé sous le curseur.
JoueurLes 16 couleurs de joueur (Red, Blue, Teal, Purple, Yellow, Orange, Green, Pink, …).
Prototypes de détails, d’arbres ou de décorsGrille des prototypes de la bibliothèque avec aperçus, un champ de recherche et, pour les décors, des filtres de catégorie. Un clic sélectionne un prototype, Ctrl+clic en ajoute ou en retire un, Shift+clic sélectionne une plage. None vide la sélection ; les outils de placement utilisent alors le premier prototype de la bibliothèque.
Référence d’assetChamp d’objet (par exemple le profil de peinture automatique). Les objets de scène sont acceptés lorsque le type le permet.

Lorsqu’une palette a besoin d’un asset que le terrain ne possède pas, le panneau explique ce qui manque et propose un bouton pour le créer : Create Tileset, Create Vegetation Library ou Create Decor Library. Vous pouvez aussi assigner un asset existant dans le champ voisin. Chaque palette possède également un bouton Edit qui sélectionne le tileset ou la bibliothèque, pour que vous puissiez ajouter des entrées dans l’Inspector.

Un prélèvement par Ctrl+clic dans la Scene View modifie aussi le paramètre dans la fenêtre, par exemple le calque de sol sélectionné ou la hauteur d’aplanissement.

Barre d’état

La barre d’état, en bas de la fenêtre, affiche de gauche à droite :

  • le point situé sous la souris : cellule, position dans le monde, niveau de falaise, hauteur du sol, profondeur d’eau (s’il y a de l’eau) et nom du calque de sol dominant ;
  • les indicateurs de cheminement à cet endroit (praticable, constructible, etc.) ;
  • le pinceau, par exemple Brush 6.0 m · 50% ;
  • l’historique d’annulation, par exemple Undo 12 (+2) · 48 MB : les étapes que vous pouvez annuler, celles que vous pouvez rétablir et la mémoire qu’elles occupent.

Onglet Map

L’onglet Map regroupe les paramètres et les opérations qui portent sur toute la carte. Chaque modification peut être annulée, sauf si sa boîte de dialogue indique le contraire. Le bouton ? en haut ouvre cette section.

Map

ParamètreDescription
NameNom de la carte affiché dans les explorateurs de cartes et les salons. Il apparaît aussi dans l’en-tête de la fenêtre.
AuthorAuteur de la carte.
DescriptionCourte description présentée aux joueurs.
Max PlayersNombre de joueurs recommandé (1–16).
Map AssetL’asset .rtsmap que ce terrain charge et enregistre. Assigner un autre asset ouvre cette carte, avec la même confirmation que Open….

Sous les champs, le panneau indique la taille de la carte, la résolution par cellule des couches de splat, de détails et de cheminement, ainsi que la mémoire utilisée par la carte. La saisie dans ces champs crée une seule étape d’annulation (Edit Map Info) lorsque vous quittez le champ.

New Map

Remplace la carte du terrain par une nouvelle carte plate.

ParamètrePar défautDescription
Size presets–Boutons pour des cartes carrées de 64, 96, 128, 192, 256, 384 et 512 cellules.
Width / Heightd’après la section Default Map du terrain (128)Taille en cellules. Multiple de 16, de 16 à 1024.
Cell Size2 mTaille d’une cellule en mètres. Les cartes des RTS classiques utilisent environ 2 m.
Cliff Level Height2 mHauteur réelle d’un niveau de falaise.
Base Cliff Level2Niveau de falaise initial de toute la carte. La valeur 2 laisse de la place pour creuser des lacs et des vallées.
Base Ground Layer0Calque de sol qui recouvre initialement toute la carte.
Splat4Texels de peinture du sol par cellule (1, 2, 4 ou 8). 4 est une bonne valeur par défaut ; 8 donne une peinture très fine.
Details2Texels de densité d’herbe par cellule (1, 2 ou 4).
Pathing2Cellules de cheminement par cellule de carte (1, 2 ou 4). Des valeurs plus élevées permettent de placer les unités plus précisément.
NameNew MapNom de la nouvelle carte.

Avant que vous cliquiez sur Create New Map, une ligne de résumé indique la taille réelle qui en résultera.

La création d’une nouvelle carte efface l’historique d’annulation et ne peut pas être annulée. L’ancien asset de carte est détaché du terrain, mais il n’est pas modifié. Utilisez Save As… pour enregistrer la nouvelle carte dans son propre fichier.

Resize

Agrandit ou réduit la carte en conservant son contenu.

  1. Saisissez New Width et New Height en cellules (multiples de 16).
  2. Cliquez sur l’un des neuf boutons d’ancrage. Les flèches indiquent la direction dans laquelle la carte s’agrandit ; le contenu existant reste du côté ancré.
  3. Choisissez le Fill Level (niveau de falaise) et le Fill Layer (calque de sol) des nouvelles zones.
  4. Cliquez sur Resize Map. L’indication au-dessus du bouton précise de combien le contenu se déplace, ainsi que la nouvelle taille réelle.

La réduction supprime le terrain, les arbres, les décors et les marqueurs situés hors de la nouvelle zone. Le redimensionnement efface l’historique d’annulation.

Generator

Génère un agencement de carte complet à partir d’une graine : plateaux, rampes, eau, peinture du sol, végétation, décors et positions de départ. La même graine et les mêmes paramètres produisent toujours la même carte.

CommandeDescription
Seed, Style, SymmetryLa graine, le style (Plains, Hills, Highlands, Islands, Canyon, Arena) et la symétrie de l’agencement (Rotate 2 par défaut, c’est-à-dire l’agencement à 180° ; voir Symétrie).
Noise, Cliffs, Ramps, Water, Border, Paint, Vegetation, Decor, Start LocationsSections repliables contenant les paramètres détaillés du générateur pour chaque étape.
Randomize SeedChoisit une nouvelle graine aléatoire.
Apply Style PresetCharge les valeurs de bruit, de falaises, de rampes et d’eau du style sélectionné.
ResetRéinitialise tous les paramètres du générateur aux valeurs par défaut du style sélectionné.
GenerateRemplace les hauteurs, les falaises, l’eau, la peinture du sol, la végétation, les décors et les positions de départ. La taille de la carte est conservée. L’opération constitue une seule étape d’annulation.

Le générateur agit sur le terrain choisi dans l’en-tête de la fenêtre. Si un autre terrain est sélectionné, une boîte de dialogue vous demande de choisir d’abord ce terrain dans l’en-tête. Une barre de progression s’affiche pendant l’exécution, et un résumé de ce qui a été généré apparaît sous les boutons.

Heightmap

Importe ou exporte la hauteur du terrain sous forme de fichier PNG ou RAW 16-bit, par exemple pour travailler avec World Machine, Gaea ou Photoshop.

ParamètreDescription
Mode (import)Fine Heights Only : ajoute des collines par-dessus les niveaux de falaise existants. Cliff Levels And Fine Heights : répartit l’image entre niveaux de falaise et hauteurs fines, de sorte que le sol corresponde exactement à l’image (idéal pour les heightmaps en terrasses ; les pentes douces qui franchissent un niveau deviennent de petites falaises). Absolute Heights Keep Levels : l’image représente la hauteur absolue du sol, mais les falaises sont conservées ; utilisez ce mode pour réimporter un export Ground Height que vous avez modifié dans un autre logiciel.
Height ScaleNombre de mètres représentés par la plage 16-bit complète. 0 = automatique.
Height OffsetImport : nombre de mètres ajoutés à chaque hauteur. Export : hauteur enregistrée avec la valeur 0.
Flip VerticallyRetourne l’image selon l’axe Z. Utilisez ce paramètre si la carte apparaît en miroir.
RAW Width / RAW HeightTaille des fichiers RAW. 0 = déduite de la taille du fichier (fichiers carrés uniquement).
RAW Little EndianOrdre des octets des fichiers RAW. Windows et la plupart des outils utilisent le little endian.
Source (export)Ground Height : niveaux de falaise plus hauteur fine. Fine Heights : uniquement la hauteur fine qui s’ajoute aux niveaux.

Les boutons disponibles sont Import PNG… (PNG 8-bit ou 16-bit en niveaux de gris, JPG ou EXR), Import RAW…, Export PNG…, Export RAW… et Export Splat PNG… (une image de la peinture du sol dans les couleurs des calques dominants). Les images de taille différente sont rééchantillonnées. Une carte compte un vertex de plus que de cellules dans chaque direction : une carte 256 utilise donc 257 × 257 échantillons. Chaque import constitue une seule étape d’annulation.

Minimap

Précalcule une image de mini-carte à partir de la carte. Choisissez avec Size la taille du côté le plus long (128, 256, 512 ou 1024 px) et ajustez les Bake Options : couleurs du sol (calque dominant ou calques mélangés), luminosité des niveaux de falaise, ombrage du relief, falaises, eau, arbres, décors et positions de départ. Bake Preview affiche le résultat dans le panneau ; Save PNG… précalcule la mini-carte et l’enregistre dans un fichier. Si vous modifiez la carte après le précalcul, le panneau vous invite à relancer le précalcul.

Validation

Validate Map recherche les problèmes de la carte, comme des textures manquantes, des positions de départ inaccessibles ou des limites de performances dépassées. Chaque problème est listé comme erreur, avertissement ou information, avec une indication pour le corriger. Cliquez sur un problème associé à un emplacement pour l’afficher dans la Scene View. Si vous modifiez la carte après la validation, le panneau indique que la liste décrit la carte telle qu’elle était avant les dernières modifications.

Environment

Le soleil, la lumière ambiante et le brouillard atmosphérique sont stockés dans la carte et appliqués à la scène par le composant RTS Environment.

ParamètreDescription
Sun ColourCouleur de la lumière du soleil.
Sun IntensityIntensité de la lumière du soleil (0–8).
Sun RotationEn degrés : x = inclinaison (hauteur au-dessus de l’horizon), y = lacet.
Ambient ColourCouleur de la lumière ambiante (ciel).
FogActive le brouillard atmosphérique en fonction de la distance.
Fog Colour / Fog DensityCouleur et densité (0–0.05) du brouillard atmosphérique exponentiel.

Capture From Scene copie l’éclairage actuel de la scène dans la carte (une étape d’annulation). Apply applique immédiatement l’environnement de la carte à la scène, et Select Component sélectionne le composant RTS Environment. Si le terrain n’a pas de composant RTS Environment, le panneau propose Add Environment Component.

Onglet Settings

PanneauContenu
ViewShow Grid (la grille des cellules sur le terrain édité, également avec la touche G), Show Markers (positions de départ, régions et marqueurs, même si aucun outil de marqueur n’est actif), Pathing Overlay (Off, Walkability, Buildability, Flyability, Water, Combined) et Overlay Opacity.
Terrain ComponentL’Inspector complet du composant RTS Terrain édité (voir Le composant RTS Terrain) et un bouton Select Terrain.
Undo HistoryMax Steps (10–1000, 100 par défaut) et Memory Limit (MB) (32–4096, 512 par défaut), la mémoire actuellement utilisée et Clear History. Voir Limites et mémoire.
ShortcutsLes raccourcis de la Scene View avec leurs affectations de touches actuelles, lues dans le Shortcut Manager de Unity. Edit Shortcuts… ouvre le Shortcut Manager ; Refresh relit les affectations après que vous les avez modifiées.
Help & MaintenanceOpen Documentation, Validate Project (exécute Tools ▸ RTS Terrain Studio ▸ Validate Project) et Reset All Tool Settings, qui rétablit les valeurs par défaut du pinceau, de la symétrie et des paramètres de chaque outil, et vide l’historique d’annulation du terrain.
AboutVersion du produit et version de Unity.

Peindre dans la Scene View

Toute l’édition se fait dans la Scene View. Lorsque l’édition du terrain est activée et qu’un outil est sélectionné, le bouton gauche de la souris peint avec l’outil au lieu de sélectionner des objets. Activez l’édition avec le bouton Editing de la fenêtre, le bouton Start Editing de l’overlay, le bouton Edit Terrain de l’Inspector, ou en cliquant sur un outil. Désactivez-la avec Esc.

Souris et touches de modification

SaisieAction
Bouton gauche de la sourisPeint avec l’outil actif (appuyer, faire glisser, relâcher). Un trait constitue une étape d’annulation. De nombreux outils continuent d’agir tant que vous maintenez le bouton enfoncé sans bouger, par exemple Raise / Lower, qui fait monter la colline de plus en plus.
Shift (maintenue)Inverse l’outil : abaisser au lieu d’élever, effacer au lieu de peindre, retirer au lieu de placer. Le curseur du pinceau devient rougeâtre et le panneau d’état affiche (inverted).
Ctrl+clicPrélève une valeur sous le curseur au lieu de peindre : une hauteur, un calque de sol, un niveau de falaise, un type de falaise ou une hauteur d’eau. Les outils sans action de prélèvement affichent This tool has nothing to pick et ne peignent pas.
Alt+glisserFait orbiter la caméra comme d’habitude. Ne peint jamais.
Bouton droit / du milieuConservent leur rôle habituel dans Unity (navigation en vol libre, panoramique).
Outil Hand (Q)Avec l’outil Hand de Unity, faire glisser la souris avec le bouton gauche déplace la caméra en panoramique, sans peindre. Le panneau d’état affiche Hand tool (Q) active: press W to paint, or drag to pan.
EscExécute la première action applicable : annule le glissement en cours d’une poignée de décor, annule le trait en cours (ses modifications sont défaites), vide la sélection de décors (Select Decor) ou arrête l’édition. La touche Esc est reçue par la Scene View qui a le focus clavier (cliquez d’abord dedans) ; le simple survol ne suffit pas. Lorsque la fenêtre RTS Terrain Studio a le focus, Esc annule le trait et désactive l’édition.
Clic sur un autre terrainFait de ce terrain le terrain édité (notification Editing X). Pendant que vous le survolez, le panneau d’état affiche Click to edit 'X'.

Sur macOS, Cmd fonctionne partout où ce manuel indique Ctrl.

Le point visé sur le terrain est calculé mathématiquement, aucun collider n’est donc nécessaire. Le curseur du pinceau est dessiné par le shader de terrain exactement là où vous peignez. Si plusieurs Scene Views sont ouvertes, seule la vue située sous la souris peint, et un trait reste dans la vue où il a commencé.

L’édition ne fonctionne que sur un terrain activé, sur lequel une carte est chargée et qui appartient au stage actuel. En Prefab Mode, éditez le terrain à l’intérieur du prefab.

Overlay RTS Terrain Studio

Dès que la scène contient un RTS Terrain, un overlay compact RTS Terrain Studio apparaît dans la Scene View. Il vous donne accès aux commandes les plus utilisées sans passer par la fenêtre complète :

  • le bouton Start Editing / Editing (Esc to stop), un bouton qui ouvre la fenêtre et un menu d’options ;
  • le terrain édité (Terrain: X • unsaved lorsqu’il comporte des modifications non enregistrées) ;
  • les huit boutons de catégorie (touches 1–8) et les outils de la catégorie sélectionnée ;
  • Size (un curseur offrant un réglage fin pour les petits pinceaux, ainsi qu’un champ pour saisir la valeur exacte) et Strength ;
  • la liste déroulante Symmetry, avec un avertissement lorsque le mode nécessite une carte carrée ;
  • les boutons à bascule Grid et Markers et la liste déroulante Pathing de la superposition de cheminement.

Le menu d’options contient Show Status Panel, Save Map, Save Map As…, Save Maps When Saving the Scene, Offer Save As for New Maps, Shortcuts… et Documentation. Comme tout overlay Unity, il peut être déplacé, ancré ou replié, et Unity mémorise sa position.

L’overlay Tools de Unity

Lorsqu’un RTS Terrain est sélectionné, l’overlay Tools de Unity contient un outil RTS Terrain Studio. L’activer fait du terrain sélectionné le terrain édité et active l’édition. Passer à un autre outil Unity désactive de nouveau l’édition.

Seule exception : l’outil Select Decor. Tant qu’il est actif, les outils Move, Rotate, Scale et Transform de Unity choisissent la poignée utilisée pour la sélection de décors, si bien que l’édition reste activée. Voir Poignées de la sélection de décors.

Panneau d’état et notifications

Un panneau d’état situé en bas de la Scene View affiche deux lignes :

  1. l’outil actif, (inverted) tant que Shift est maintenue enfoncée, la taille et l’intensité du pinceau (outils pinceaux uniquement) et le mode de symétrie, avec un avertissement lorsque le mode nécessite une carte carrée ;
  2. la cellule survolée, son niveau de falaise et sa hauteur, l’état ou l’indication de l’outil, ainsi que l’effet actuel de la touche Esc (Esc: cancel stroke, Esc: cancel edit, Esc: clear selection ou Esc: stop editing).

Masquez-le ou affichez-le avec Show Status Panel dans le menu d’options de l’overlay. Les raccourcis confirment leur action par une courte notification dans la Scene View, par exemple Brush 8.0 m, Strength 55%, Grid on ou Stroke cancelled. Si l’édition était restée activée depuis votre dernière session, un message d’information affiché une seule fois au démarrage de Unity indique Terrain editing is on (Esc to stop).

Aperçus et repères

  • Curseur du pinceau : projeté sur le terrain dans la couleur de l’outil, avec une copie supplémentaire pour chaque copie symétrique.
  • Aperçus fantômes : en mode Single, Place Trees et Place Decor affichent un aperçu translucide de l’objet suivant sous le curseur.
  • Repères de symétrie : axes magenta et point central tant qu’un mode de symétrie est activé.
  • Marqueurs : positions de départ (dans les couleurs des joueurs), régions et marqueurs, dessinés tant que Show Markers est activé ou qu’un outil de marqueur est actif.
  • Grille (G) et superposition de cheminement (P) : dessinées par le shader de terrain.

Poignées de la sélection de décors

Lorsque Select Decor est actif, cliquez sur des objets pour les sélectionner, faites glisser la souris pour tracer un rectangle de sélection et maintenez Shift enfoncée pour ajouter des objets à la sélection ou inverser leur état de sélection. La sélection reçoit des poignées de style Unity au centre des objets sélectionnés :

Outil UnityPoignée
Move (W)Poignée de position.
Rotate (E)Disque de lacet : les décors ne pivotent qu’autour de l’axe vertical. Maintenez Ctrl enfoncée pour activer l’accrochage.
Scale (R)Poignée d’échelle uniforme. Lorsque Select Decor est actif, le raccourci R sélectionne cet outil au lieu d’activer ou de désactiver la rotation aléatoire.
Transform (Y)Poignée de position et disque de lacet.
Rect (T)Poignée de position.
Hand (Q)Aucune poignée ; faire glisser la souris avec le bouton gauche déplace la caméra en panoramique.

Delete supprime la sélection. Ctrl+D duplique la sélection avec un décalage d’une cellule en X et en Z pour que les copies soient visibles ; déplacez-les ensuite avec la poignée. Une notification telle que Duplicated 3 objects le confirme. Ctrl+A sélectionne tous les objets de décor non verrouillés et F cadre la sélection. Il s’agit des commandes Delete, Duplicate, Select All et Frame Selected propres à Unity : elles suivent donc vos affectations dans le Shortcut Manager. Chaque glissement de poignée constitue une étape d’annulation. Un appui sur Esc pendant un glissement l’annule sans créer d’étape. D’autres commandes se trouvent dans le panneau Selection de l’onglet Decor (voir Outils de décor).

Enregistrement et garde-fous

La carte est conservée en mémoire pendant l’édition, en dehors du fichier de scène. Les boîtes de dialogue Save scene? de Unity ne la prennent donc pas en compte. RTS Terrain Studio ajoute ses propres garde-fous :

QuandCe qui se passe
Enregistrement d’une scèneLes cartes de ses terrains sont automatiquement enregistrées dans leurs assets .rtsmap (option de l’overlay Save Maps When Saving the Scene, activée par défaut). Pour un terrain sans asset de carte, Save As… est proposé une fois par session de l’éditeur, avec les choix Not Now et Never Ask Again (option de l’overlay Offer Save As for New Maps).
Passage en Play ModeLa boîte de dialogue Save map changes before entering Play Mode? propose Save, Cancel (reste en Edit Mode) et Don't Save. Unity recharge la scène et, avec elle, la carte depuis son asset. Cette boîte de dialogue n’apparaît pas lorsque les Enter Play Mode Options désactivent à la fois le rechargement de la scène et celui du domaine.
Sortie du Play ModeLa boîte de dialogue Save map changes made in Play Mode? propose Save ou Discard. Elle apparaît lorsque la carte a été modifiée avec les outils de la Scene View pendant le Play Mode, ou chaque fois que la scène contient un In-Game Editor (RTSRuntimeEditor) et que la carte comporte des modifications non enregistrées. Dans les autres scènes, les modifications liées au gameplay, comme les arbres récoltés, ne la déclenchent pas.
Fermeture d’une scène, sortie de UnityDemande s’il faut enregistrer les cartes modifiées.

Avant d’écraser un fichier de carte, le package demande à votre système de gestion de versions de l’extraire (check-out). En cas d’échec, une boîte de dialogue explique la marche à suivre. Les garde-fous n’affichent jamais de boîte de dialogue en mode batch ni pendant la génération d’un build de joueur.

Les scripts de build et les tests de l’éditeur peuvent désactiver temporairement le garde-fou :

using RTSTerrainStudio.Editor;
using UnityEditor;

static class MyBuildSteps
{
    [MenuItem("Tools/My Project/Run Map Batch")]
    static void RunMapBatch()
    {
        // No save prompts while this scope is open. Scopes can be nested.
        using (RTSMapSaveGuard.Suppress())
        {
            // ... open scenes, edit or generate maps, enter and leave Play Mode ...
        }
    }
}

Raccourcis clavier

Les raccourcis de la Scene View sont enregistrés dans le Shortcut Manager de Unity, dans la catégorie RTS Terrain Studio. Ils ne sont actifs que si l’édition du terrain est activée, si une Scene View ou l’une des fenêtres d’éditeur de RTS Terrain Studio a le focus clavier (ou si la souris survole une Scene View), et si vous n’êtes pas en train de saisir du texte ou un nombre dans un champ. Hors édition, des touches comme R ou les touches numériques conservent leur rôle habituel dans Unity.

Touche par défautEntrée du Shortcut ManagerAction
[RTS Terrain Studio/Brush SmallerRayon du pinceau × 0.87.
]RTS Terrain Studio/Brush LargerRayon du pinceau × 1.15.
-RTS Terrain Studio/Strength DownIntensité du pinceau − 5 %.
=RTS Terrain Studio/Strength UpIntensité du pinceau + 5 %.
RRTS Terrain Studio/Toggle Random RotationActive ou désactive la rotation aléatoire du pinceau. Lorsque Select Decor est actif, sélectionne à la place l’outil Scale de Unity.
GRTS Terrain Studio/Toggle GridAffiche ou masque la grille des cellules.
PRTS Terrain Studio/Cycle Pathing OverlayFait défiler Off → Walkability → Buildability → Combined → Off.
1RTS Terrain Studio/Height ToolsSélectionne le premier outil de la catégorie. Appuyez de nouveau sur la touche pour passer d’un outil à l’autre dans cette catégorie.
2RTS Terrain Studio/Cliff Tools
3RTS Terrain Studio/Paint Tools
4RTS Terrain Studio/Vegetation Tools
5RTS Terrain Studio/Decor Tools
6RTS Terrain Studio/Water Tools
7RTS Terrain Studio/Pathing Tools
8RTS Terrain Studio/Marker Tools

Les touches et actions de la souris suivantes sont gérées par le package lui-même et ne peuvent pas être réaffectées :

ToucheEmplacementAction
Shift (maintenue)Scene ViewInverser l’outil (abaisser, effacer, retirer).
Ctrl+clic (Cmd+clic sur macOS)Scene ViewPrélever une valeur (hauteur, calque, niveau, type de falaise, hauteur d’eau).
EscScene View ayant le focus clavierAnnuler le glissement de poignée ou le trait, vider la sélection de décors ou arrêter l’édition.
1–8 (pavé numérique compris)Fenêtre RTS Terrain StudioChanger d’onglet de catégorie.
EscFenêtre RTS Terrain StudioAnnuler le trait et arrêter l’édition.
Tab, Enter, SpaceFenêtre RTS Terrain StudioDéplacer le focus entre les outils et les onglets ; activer l’élément qui a le focus.
Ctrl+clic, Shift+clicGrilles de prototypesAjouter ou retirer un prototype ; sélectionner une plage.

Les touches suivantes sont des raccourcis et des commandes propres à Unity. RTS Terrain Studio y réagit, mais elles suivent les affectations que vous leur donnez dans Edit ▸ Shortcuts..., sous les catégories de Unity (Main Menu/Edit, Tools) :

Touche par défautEmplacementAction
Ctrl+Z / Ctrl+YPartout dans UnityAnnuler / rétablir les modifications du terrain via le menu Edit de Unity.
W E YScene View, outil Select DecorOutils Move, Rotate et Transform de Unity : ils choisissent la poignée de la sélection de décors.
Delete, Ctrl+D, Ctrl+A, FScene View, outil Select DecorDelete, Duplicate, Select All (objets de décor non verrouillés) et Frame Selected.

R avec Select Decor correspond à l’entrée RTS Terrain Studio/Toggle Random Rotation propre au package : tant que Select Decor est actif, elle passe à l’outil Scale de Unity au lieu d’activer ou de désactiver la rotation aléatoire.

Réaffecter les raccourcis

  1. Ouvrez Edit ▸ Shortcuts... (sur macOS, Unity ▸ Shortcuts...) ou cliquez sur Edit Shortcuts… dans l’onglet Settings.
  2. Sélectionnez la catégorie RTS Terrain Studio.
  3. Affectez de nouvelles touches aux entrées listées ci-dessus.
  4. Cliquez sur Refresh dans l’onglet Settings pour voir les nouvelles affectations dans la fenêtre.

Si une touche entre en conflit avec un autre raccourci de votre configuration, par exemple le raccourci Toggle 2D Mode de la Scene View sur la touche 2, Unity vous demande une fois lequel utiliser. Vous pouvez réaffecter l’un ou l’autre dans le Shortcut Manager.

Pinceaux

Tous les outils pinceaux partagent un même pinceau. Vous le réglez dans le panneau Brush de n’importe quelle page d’outil, dans l’overlay (Size et Strength) ou avec les raccourcis. Le pinceau est mémorisé d’une session de l’éditeur à l’autre.

ParamètrePlagePar défautDescription
ShapeCircle, Square, Diamond, CustomCircleContour du pinceau. Les formes Square et Diamond acceptent une rotation. Custom utilise un asset Brush Shape.
Custom Shape–aucunL’asset Brush Shape utilisé par la forme Custom. Cliquez sur le bouton de forme Custom : le panneau affiche alors tous les assets Brush Shape du projet sous forme de vignettes, ainsi qu’un champ Custom Shape. Cliquez sur une vignette (ou assignez un asset dans le champ) pour l’utiliser.
Radius0.25–128 m6 mRayon du pinceau en mètres. Le curseur est logarithmique pour permettre un réglage fin des petits pinceaux. Raccourcis [ et ].
Strength0.01–10.5Effet de chaque empreinte. Raccourcis - et =.
Hardness0–10.350 = bord doux sur tout le rayon, 1 = bord net. Désactivé tant que Falloff Curve est activé.
Falloff Curveactivé/désactivédésactivéUtilise une courbe personnalisée au lieu de Hardness.
Curve–ease in-out de 1 à 0Poids depuis le centre du pinceau (x = 0) jusqu’à son bord (x = 1).
Rotation0–360°0Rotation des formes carrée, losange et personnalisée, dans le sens horaire vu de dessus. Désactivé pour la forme Circle et tant que Random Rotation est activé.
Random Rotationactivé/désactivédésactivéFait pivoter chaque empreinte de façon aléatoire. Idéal avec des tampons personnalisés. Raccourci R.
Spacing0.05–20.2Distance entre les empreintes, proportionnelle au rayon. Des valeurs plus petites donnent des traits plus lisses.
Jitter0–10Décalage aléatoire de chaque empreinte, proportionnel au rayon.

Pondération d’une empreinte

Chaque empreinte attribue à chaque vertex, texel de splat ou objet un poids compris entre 0 et 1, que l’outil multiplie par Strength. Avec Hardness, le poids vaut 1 à l’intérieur de hardness × radius, puis diminue progressivement jusqu’à 0 au bord. Lorsque Falloff Curve est activé, c’est la courbe qui définit le poids : x est la distance au centre (0 = centre, 1 = bord), y est le poids. Pour les formes carrée et losange, la « distance » suit le contour, si bien qu’un pinceau carré a la même intensité tout le long de ses côtés.

Certains outils utilisent le pinceau comme une sélection stricte : les outils de falaise, d’eau et de cheminement ne modifient que ce qui a un poids d’au moins 0.5, ou le vertex situé sous le centre du pinceau. Des bords doux signifient alors « légèrement plus petit » plutôt que « plus faible ».

Espacement, décalage aléatoire et répétition

  • Spacing : pendant que vous faites glisser la souris, une empreinte est placée tous les radius × spacing mètres le long du trajet de la souris, avec un écart d’au moins un dixième de cellule. Les outils qui s’accrochent aux vertices espacent les empreintes d’au moins une demi-cellule.
  • Jitter : chaque empreinte est déplacée d’une distance aléatoire pouvant aller jusqu’à jitter × radius. Jitter ne s’applique qu’aux outils qui utilisent le pinceau.
  • Repeat : de nombreux outils continuent d’appliquer des empreintes tant que vous maintenez le bouton enfoncé sans bouger, par exemple 30 empreintes par seconde pour Raise / Lower. Les tableaux des outils indiquent lesquels le font.

Convention de rotation

Toutes les rotations de RTS Terrain Studio (rotation du pinceau, lacet des arbres et des décors, direction des positions de départ et des marqueurs) suivent la même convention : elles s’expriment en degrés, dans le sens horaire vu de dessus, 0° pointant vers +Z (nord) et 90° vers +X (est). De ce fait, les copies symétriques d’un pinceau ou d’un objet orienté subissent exactement la même rotation et la même réflexion que leurs positions. Lorsque Random Rotation est activé, un seul angle aléatoire est tiré par empreinte et partagé par toutes ses copies symétriques, si bien que les traits symétriques restent symétriques.

Formes de pinceau personnalisées

Un asset Brush Shape transforme n’importe quelle texture en niveaux de gris en tampon de pinceau : les zones blanches appliquent l’effet complet, les zones noires aucun effet.

  1. Importez une texture en niveaux de gris, par exemple le contour d’un rocher ou une éclaboussure. Elle n’a pas besoin d’être accessible en lecture.
  2. Créez l’asset avec Assets ▸ Create ▸ RTS Terrain Studio ▸ Brush Shape et assignez-lui la texture.
  3. Vérifiez l’aperçu dans l’Inspector. Il montre le masque précalculé exactement tel que les pinceaux l’utilisent, ainsi que sa couverture.
  4. Dans le panneau Brush, cliquez sur le bouton de forme Custom. Le panneau affiche alors tous les assets Brush Shape sous forme de vignettes ; cliquez sur la vignette de la nouvelle forme.
ParamètrePar défautDescription
TextureaucuneTexture en niveaux de gris ou alpha. Blanc = effet complet.
Use Red ChannelactivéLit le canal rouge. Désactivez-le pour lire le canal alpha à la place.
InvertdésactivéInverse le masque.
Resolution64Résolution du masque précalculé (16–256).

Le masque est précalculé automatiquement après chaque modification. Bake Mask le précalcule immédiatement. Un tampon personnalisé couvre le carré entourant le centre du pinceau et reste multiplié par la dureté ou la courbe d’atténuation. Réduisez la dureté pour obtenir des bords de tampon doux, ou réglez-la sur 1 pour utiliser le tampon tel quel.

Symétrie

La symétrie répète chaque empreinte, chaque clic et chaque objet placé à des positions obtenues par réflexion ou par rotation. C’est ainsi que vous construisez des cartes compétitives équitables : chaque joueur reçoit les mêmes collines, falaises, rampes, arbres et mines d’or. Choisissez le mode dans le panneau Symmetry ou dans l’overlay. Des repères magenta dans la Scene View montrent les axes et le centre.

La symétrie s’applique aux outils pinceaux et aux outils à clic. Les outils à glissement (Regions et Select Decor) l’ignorent, et la fenêtre masque le panneau Symmetry tant que l’un d’eux est actif. Créez les régions en miroir à la main.

Nom de la fenêtreNom de l’overlay / dans le codeCopiesRôleÀ utiliser pour
OffNone1Seul le pinceau lui-même peint.Cartes libres, cartes de campagne, détails de finition qui ne doivent pas se répéter.
Mirror XMirror X (MirrorX)2Reflète gauche ↔ droite par rapport à l’axe vertical passant par le centre.Deux joueurs ou équipes face à face, ouest contre est.
Mirror ZMirror Z (MirrorZ)2Reflète haut ↔ bas par rapport à l’axe horizontal.Deux joueurs ou équipes face à face, nord contre sud.
Mirror XZMirror XZ (MirrorXZ)4Reflète selon les deux axes.Quatre bases dans les coins, ou cartes 2v2 où chaque équipe tient un côté.
Rotate 180°Rotate 2 (Rotate2)2Symétrie centrale par rapport au centre.La disposition 1v1 classique, avec les bases dans des coins opposés. Contrairement à un miroir, une rotation conserve la gauche et la droite pour les deux joueurs : un chemin situé à gauche d’un joueur se trouve aussi à gauche de l’autre joueur.
Rotate 90°Rotate 4 (Rotate4)4Symétrie de rotation par quarts de tour. Nécessite une carte carrée.Le classique chacun pour soi à quatre joueurs.
DiagonalMirror Diagonal (MirrorDiagonal)2Reflète par rapport à la diagonale (x ↔ z). Nécessite une carte carrée.Cartes 1v1 avec les bases dans les coins supérieur gauche et inférieur droit.

Centre est le centre de symétrie en coordonnées de carte normalisées : (0.5, 0.5) correspond au centre de la carte et constitue la valeur par défaut. Reset l’y ramène. Si vous déplacez le centre, certaines copies peuvent tomber hors de la carte et sont alors ignorées ; le panneau affiche un avertissement.

Rotate 90° et Diagonal échangent les axes X et Z. Sur une carte qui n’est pas carrée, des copies tombent hors de la carte ou se répartissent de façon inégale. Le panneau Symmetry, l’overlay et le panneau d’état vous avertissent. Redimensionnez la carte pour la rendre carrée ou choisissez un autre mode.

Comportement des copies

  • Les copies situées à moins d’une demi-cellule (ou d’un dixième du rayon du pinceau, selon la valeur la plus grande) d’une autre copie sont fusionnées. Peindre sur un axe de symétrie n’applique donc jamais l’effet deux fois.
  • Les arbres, décors, positions de départ et marqueurs placés pivotent avec leur copie. Les copies en miroir reçoivent des directions reflétées.
  • Les pinceaux et tampons personnalisés pivotés et reflétés tournent avec leur copie (voir Convention de rotation).
  • Start Locations : lorsque Symmetry Assigns Next Players est activé (par défaut), un clic place la position de départ du joueur sélectionné, et ses copies placent celles des joueurs suivants. Avec Rotate 90° et le joueur 1 sélectionné, un clic place les positions de départ des joueurs 1 à 4.
  • Raise / Lower Level calcule son niveau cible à partir de l’empreinte d’origine, si bien que chaque copie peint le même niveau.
  • Fill / Replace en mode Replace Dominant Layer ou Fill All agit sur toute la carte et ne s’exécute qu’une fois. Fill Connected remplit à partir de chaque copie.

Construisez la structure de la carte (falaises, rampes, eau, positions de départ) avec la symétrie activée, puis désactivez-la pour les petites décorations afin que la carte n’ait pas l’air copiée-collée. La superposition de cheminement (P) permet de vérifier rapidement que chaque base dispose des mêmes chemins.

Annuler et rétablir

Chaque modification du terrain est enregistrée dans l’historique d’annulation propre à la carte, qui est lié au système d’annulation de Unity. Ctrl+Z, Ctrl+Y et le menu Edit ▸ Undo fonctionnent pour les modifications du terrain exactement comme pour n’importe quelle autre modification, et le menu Edit affiche le nom de l’étape, par exemple Undo Raise / Lower. Les boutons Undo et Redo de l’en-tête de la fenêtre font de même et maintiennent l’historique de Unity synchronisé. Annuler entre-temps une modification d’un autre objet ne perturbe pas l’historique du terrain.

ActionÉtape d’annulation
Un trait de pinceau (de l’appui au relâchement) ou un clicUne étape portant le nom de l’outil, par exemple Paint Layer. Toutes les copies symétriques appartiennent à la même étape.
Glissement d’une poignée de décorUne étape (Move Decor, Rotate Decor, Scale Decor).
Boutons du panneau Selection (Delete, Duplicate, Lock …)Une étape par clic.
Generate, import de heightmap, Auto Paint Whole Map, Capture From SceneUne étape chacun (Generate Map, Import Heightmap, Auto Paint Map …).
Champs des informations de la carte et de l’environnementUne étape lorsque vous quittez le champ (Edit Map Info, Edit Environment).
Trait annulé avec EscAucune étape. Les modifications du trait sont défaites.
New Map, Resize, Open, Reload, passage à un autre terrainImpossible à annuler. Ces actions vident l’historique (leurs boîtes de dialogue le signalent).

Limites et mémoire

Chaque étape ne stocke que les couches qu’elle a modifiées. Les couches raster (hauteurs, niveaux de falaise, eau, splat maps, détails, surcharges de cheminement) sont stockées par tuiles de 16 × 16 cellules autour de la zone modifiée. Les couches d’objets (arbres, décors, régions, positions de départ, marqueurs, informations de la carte, environnement) sont stockées sous forme de copies de la liste entière, si bien qu’un trait d’arbres sur une carte comportant un très grand nombre d’arbres consomme de la mémoire proportionnellement au nombre total d’arbres de la carte. Un petit trait de hauteur ou de peinture ne coûte donc que quelques kilo-octets, tandis que la génération d’une carte entière stocke toutes ses couches. La barre d’état et le panneau Undo History indiquent la mémoire actuellement utilisée.

Dans l’onglet Settings, vous définissez deux limites. Les étapes les plus anciennes sont supprimées en premier dès que l’une ou l’autre est dépassée ; l’étape la plus récente est toujours conservée.

ParamètrePlagePar défautDescription
Max Steps10–1000100Nombre d’étapes d’annulation conservées.
Memory Limit (MB)32–4096512Mémoire que l’historique d’annulation peut utiliser.

Les limites sont stockées par utilisateur dans les préférences de l’éditeur et s’appliquent même lorsque la fenêtre est fermée. Clear History supprime toutes les étapes d’annulation et de rétablissement du terrain, par exemple pour libérer de la mémoire après une génération volumineuse.

Modifications annulables depuis vos propres scripts d’éditeur

RTSEditSession.RunOperation enregistre les couches indiquées de toute la carte, exécute votre code, puis ajoute le résultat à l’historique en une seule étape. Ctrl+Z fonctionne ensuite pour cette opération comme pour n’importe quel outil.

using RTSTerrainStudio;
using RTSTerrainStudio.Editor;
using UnityEditor;

static class MyTerrainCommands
{
    [MenuItem("Tools/My Project/Raise Whole Map 1 m")]
    static void RaiseWholeMap()
    {
        // The terrain edited by the RTS Terrain Studio window and the Scene View tools.
        RTSTerrain terrain = RTSEditorContext.Terrain;
        if (terrain == null || terrain.Map == null) return;

        RTSEditSession session = RTSEditorContext.Session;

        // Records the Heights layer, runs the code and pushes one undo step named "Raise Whole Map".
        session.RunOperation("Raise Whole Map", MapLayers.Heights, ctx =>
        {
            var heights = ctx.Map.Heights; // fine height per vertex, on top of the cliff level
            for (int i = 0; i < heights.Length; i++)
                heights[i] = TerrainToolUtility.ClampFineHeight(ctx.Map, heights[i] + 1f);

            // Tell the terrain which layers changed so meshes, water and pathing are rebuilt.
            ctx.Terrain.NotifyChangedAll(MapLayers.Heights);
        });
    }
}

L’éditeur en jeu utilise le même type d’historique d’annulation (MapUndoStack), avec ses propres boutons Undo et Redo. L’intégration au Ctrl+Z d’Unity n’existe que dans l’éditeur Unity.

Référence des outils

Les sections suivantes décrivent chaque outil des huit catégories. Tous les outils fonctionnent de la même façon dans l’éditeur Unity et dans l’éditeur en jeu. Quelques conventions s’appliquent à tous :

  • Id est l’identifiant unique de l’outil. Utilisez-le dans le code, par exemple RTSEditorContext.ActivateTool("height.raise").
  • Saisie : les outils Pinceau peignent pendant que vous faites glisser la souris. Les outils Clic agissent une fois par clic. Les outils Glisser s’utilisent en appuyant, en faisant glisser puis en relâchant (rectangles, sélection par rectangle).
  • Répétition : nombre d’empreintes par seconde tant que vous maintenez le bouton enfoncé sans bouger la souris.
  • Shift inverse l’effet et Ctrl+clic prélève une valeur, lorsque le tableau l’indique.
  • Chaque paramètre est indiqué avec sa plage et sa valeur par défaut. Les paramètres sont conservés d’une session de l’éditeur à l’autre. Le bouton Reset All Tool Settings de l’onglet Settings rétablit les valeurs par défaut.

Niveaux de falaise et hauteur fine

La hauteur du sol de chaque vertex se compose de deux parties. Le niveau de falaise (0–15) est défini par les outils de falaise et crée des parois de falaise verticales ; un niveau mesure Cliff Level Height mètres de haut (2 m par défaut). La hauteur fine est définie par les outils de hauteur et ajoute par-dessus le niveau des collines et des creux aux formes douces. Les hauteurs fines sont limitées à ±8 niveaux de falaise (±16 m avec des niveaux de 2 m). C’est cette séparation qui vous permet de peindre des falaises nettes, dans le style des RTS classiques, sur un terrain vallonné.

Ajouter votre propre outil

Toute classe qui dérive de RTSTool (ou de l’une des classes de base de catégorie, comme HeightTool) et qui possède un constructeur public sans paramètre apparaît automatiquement dans la fenêtre, dans l’overlay et dans l’éditeur en jeu. Les champs publics marqués de [ToolSetting] obtiennent un contrôle dans l’interface. Cet exemple élève ou abaisse le sol d’un pas fixe à chaque clic :

using RTSTerrainStudio;

// Appears on the Height tab after the built-in tools (Order 100).
public sealed class StepTool : HeightTool
{
    public override string Id => "mygame.step";
    public override string DisplayName => "Step";
    public override string Description => "Raises the ground under the brush by a fixed step per click.";
    public override string Hint => "Shift: step down";
    public override int Order => 100;

    // One dab per click; keep the brush panel visible for the radius and falloff.
    public override ToolInputMode InputMode => ToolInputMode.Click;
    public override bool UsesBrush => true;

    [ToolSetting("Step", Min = 0.05f, Max = 4f, Order = 0, Tooltip = "Height change per click in metres at full strength.")]
    public float step = 0.5f;

    // Called once per click and once for every symmetry copy.
    public override void ApplyDab(RTSToolContext ctx, in BrushDab dab)
    {
        var map = ctx.Map;
        // Computes the vertex weights and records the Heights layer for undo.
        bool any = BeginVertexEdit(ctx, dab, out var w, out var cells);
        using (w) // the weights must always be disposed
        {
            if (!any) return;
            float sign = dab.invert ? -1f : 1f; // Shift inverts
            var heights = map.Heights;
            for (int z = w.rect.yMin; z < w.rect.yMax; z++)
            for (int x = w.rect.xMin; x < w.rect.xMax; x++)
            {
                float weight = w[x, z];
                if (weight <= 0f) continue;
                int i = map.VertexIndex(x, z);
                heights[i] = TerrainToolUtility.ClampFineHeight(map, heights[i] + sign * step * dab.strength * weight);
            }
        }
        // Rebuilds the chunks, water and pathing of the changed cells.
        EndVertexEdit(ctx, cells);
    }
}

Pour l’API complète des outils (outils à glissement, prélèvement, gizmos et texte d’état), consultez le Guide de programmation. Pour les builds dont le paramètre Managed Stripping Level est réglé sur un niveau élevé, ajoutez à votre outil l’attribut [UnityEngine.Scripting.Preserve] (voir Élagage du code et outils personnalisés).

Outils de hauteur

Les outils de hauteur sculptent la hauteur fine : collines, vallées, routes et détails naturels par-dessus les niveaux de falaise. Ils ne modifient jamais les niveaux de falaise, si bien que les parois de falaise restent nettes. La ligne d’état affiche la hauteur du sol, la hauteur fine et le niveau de falaise sous le curseur.

OutilIdRôleSaisie et touches de modification
Raise / Lowerheight.raiseÉlève le sol sous le pinceau ; maintenez le bouton enfoncé pour continuer à faire monter les collines.Pinceau, répété 30 fois/s. Shift : abaisser.
Smoothheight.smoothAdoucit les bosses et les arêtes vives du sol sans estomper les parois de falaise.Pinceau, répété 20 fois/s.
Flattenheight.flattenAplanit le sol à une hauteur unique, idéal pour les emplacements de bâtiments et les routes.Pinceau, répété 20 fois/s. Ctrl+clic : prélever la hauteur.
Set Heightheight.setRègle le sol sur une hauteur exacte ; à pleine intensité, le centre du pinceau l’atteint en une seule empreinte.Pinceau, répété 20 fois/s. Ctrl+clic : prélever la hauteur.
Noiseheight.noiseAjoute des bosses, des collines ou des crêtes d’aspect naturel à partir d’un bruit procédural défini par une graine.Pinceau, répété 10 fois/s. Shift : soustraire le bruit.
Terraceheight.terraceTransforme les pentes en marches plates aux bords arrondis, comme des rizières ou de la roche stratifiée.Pinceau, répété 15 fois/s.
Erodeheight.erodeSimule le glissement de matière le long des pentes escarpées, ce qui donne aux collines un aspect naturel, patiné par le temps.Pinceau, répété 15 fois/s.

Paramètres de l’outil Raise / Lower

ParamètrePlagePar défautDescription
Speed0.01–20.15Variation de hauteur par empreinte, en mètres, à pleine intensité du pinceau.

Paramètres de l’outil Smooth

ParamètrePlagePar défautDescription
Filter Radius1–41Voisinage, en vertices, sur lequel la moyenne est calculée. Des valeurs plus élevées éliminent des reliefs plus grands.
Iterations1–82Passes de lissage par empreinte.

Paramètres de l’outil Flatten

ParamètrePlagePar défautDescription
TargetStroke Start, Fixed HeightStroke StartStroke Start utilise la hauteur sous le curseur au début du trait. Fixed Height utilise Target Height.
Target Height−32–32 m0Hauteur fine fixe, relative au niveau de falaise. Ctrl+clic la prélève. Les valeurs au-delà de la limite de hauteur fine de la carte (±8 niveaux de falaise, ±16 m avec des niveaux de 2 m) sont ramenées à cette limite au moment de l’application.
ModeFlatten, Raise Only, Lower OnlyFlattenAplanir dans les deux sens, uniquement combler le sol situé sous la cible, ou uniquement araser le sol situé au-dessus.

Paramètres de l’outil Set Height

ParamètrePlagePar défautDescription
Height−32–64 m0Hauteur à appliquer, interprétée selon Height Space. Ctrl+clic la prélève. Les valeurs au-delà de la limite de hauteur fine de la carte (±8 niveaux de falaise, ±16 m avec des niveaux de 2 m) sont ramenées à cette limite au moment de l’application.
Height SpaceFine Height, Ground HeightFine HeightHauteur fine relative au niveau de falaise, ou hauteur absolue du sol.

Paramètres de l’outil Noise

ParamètrePlagePar défautDescription
Noise TypeFbm, Ridged, BillowFbmFbm : collines ondulées. Ridged : crêtes vives. Billow : bosses arrondies.
Scale2–256 m24Taille des reliefs les plus grands.
Amplitude0.01–4 m0.25Hauteur ajoutée par empreinte à pleine intensité.
Octaves1–84Nombre de couches de détail. Plus il y a d’octaves, plus les détails ajoutés sont fins.
Roughness0.2–0.80.5Rapport d’amplitude entre les octaves. Des valeurs plus élevées donnent un sol plus accidenté.
Seed0–99991Modifie le motif. La même graine produit toujours le même motif.

Paramètres de l’outil Terrace

ParamètrePlagePar défautDescription
Step Height0.1–8 m1Hauteur d’une marche de terrasse.
Sharpness0–10.70 = marches douces et arrondies. 1 = contremarches nettes et raides.
Offset−4–4 m0Décale toutes les marches vers le haut ou vers le bas.

Paramètres de l’outil Erode

ParamètrePlagePar défautDescription
Talus Angle5–70°30Les pentes plus escarpées que cet angle s’érodent.
Erosion Strength0.05–10.5Part de la matière excédentaire déplacée à chaque itération.
Iterations1–508Passes d’érosion par empreinte.

Pour un emplacement de bâtiment, utilisez Flatten avec Target = Stroke Start : commencez le trait à l’endroit dont vous voulez reprendre la hauteur, puis peignez sur la zone. Pour une route à une hauteur exacte, faites Ctrl+clic sur un point pour prélever sa hauteur, réglez Target sur Fixed Height, puis peignez.

Outils de falaise

Les outils de falaise modifient le niveau de falaise des vertices (0–15) et l’aspect des parois de falaise entre les niveaux. Le pinceau s’aligne sur les vertices et agit comme une sélection franche : vous peignez des vertices entiers, jamais des demi-niveaux. La ligne d’état affiche le niveau survolé et le niveau que vous vous apprêtez à peindre, par exemple Level 2 → 3.

OutilIdRôleSaisie et touches de modification
Raise / Lower Levelcliff.raiseÉlève le sol d’un niveau de falaise ; faites glisser pour étendre le plateau sur lequel vous avez commencé.Pinceau. Shift : abaisser d’un niveau.
Set Levelcliff.setPeint un niveau de falaise exact, pratique pour les grands plateaux, les cuvettes et les ébauches rapides.Pinceau. Ctrl+clic : prélever le niveau.
Rampcliff.rampTransforme les bords de falaise en pentes praticables ; peignez en travers d’une falaise d’un niveau pour que les quatre coins d’une cellule soient en rampe.Pinceau. Shift : supprimer la rampe.
Cliff Typecliff.typeChange le matériau des parois de falaise, par exemple des falaises rocheuses à côté de falaises herbeuses.Pinceau. Ctrl+clic : prélever le type de falaise.
Clean Cliffscliff.smoothEdgesSupprime les piliers et les creux isolés d’un seul vertex pour que les contours des falaises restent propres.Pinceau.

Paramètres de l’outil Raise / Lower Level

Le niveau cible est déterminé à partir du vertex situé sous le curseur au début du trait : un niveau au-dessus (ou au-dessous avec Shift). En faisant glisser, vous peignez ce même niveau, ce qui vous permet d’étendre un plateau sans empiler les niveaux. L’outil ne fait qu’élever (ou qu’abaisser) les vertices.

ParamètrePlagePar défautDescription
Break Rampsactivé/désactivéactivéRetire l’indicateur de rampe des vertices dont le niveau change.
Paint Cliff Edgesactivé/désactivéactivéPeint le calque de bord du type de falaise le long des nouveaux bords de falaise à la fin du trait (voir Bords de falaise automatiques).
Edge Width0.25–4 cellules1Largeur du bord peint, mesurée à partir de la paroi de falaise.
Edge Strength0.1–10.9Degré de recouvrement du sol par le calque de bord juste à côté de la paroi.
Edge SidesBoth / Top / BottomBothPeindre le rebord du plateau, le pied de la falaise, ou les deux.
Clean Up Old Edgesactivé/désactivéactivéRetire le calque de bord là où un bord n’existe plus après le trait (falaises déplacées, nouvelles rampes).

Paramètres de l’outil Set Level

ParamètrePlagePar défautDescription
Level0–15 (palette)2Niveau de falaise à peindre.
Break Rampsactivé/désactivéactivéRetire l’indicateur de rampe des vertices dont le niveau change.
Paramètres de bordcomme ci-dessusPaint Cliff Edges, Edge Width, Edge Strength, Edge Sides et Clean Up Old Edges fonctionnent comme dans Raise / Lower Level. Ramp et Clean Cliffs disposent des cinq mêmes paramètres.

Outil Ramp

L’outil Ramp n’a aucun paramètre. Une cellule devient une rampe lorsque ses quatre vertices de coin portent l’indicateur de rampe et que la différence de niveau qu’elle couvre est d’exactement un niveau. La ligne d’état vous aide : elle compte les cellules de rampe valides sous le pinceau, signale les cellules portant l’indicateur mais sans différence de niveau, et vous avertit lorsqu’une rampe couvre plus d’un niveau (elle serait étirée).

Paramètres de l’outil Cliff Type

ParamètrePlagePar défautDescription
Cliff Type0–3 (palette)0Calque de falaise du tileset à peindre.

Paramètres de l’outil Clean Cliffs

ParamètrePlagePar défautDescription
Strictness5–88Nombre de voisins, sur 8, qui doivent partager l’autre niveau pour qu’un vertex l’adopte. Avec 8, seuls les vertices complètement isolés sont supprimés ; des valeurs plus faibles arrondissent aussi les coins dentelés. Les vertices situés sur la bordure de la carte doivent atteindre la même proportion parmi leurs voisins, moins nombreux.
Break Rampsactivé/désactivéactivéRetire l’indicateur de rampe des vertices dont le niveau change.

Bords de falaise automatiques

Dans les éditeurs de cartes des RTS classiques, élever une falaise modifie aussi le sol voisin. Les outils de falaise font de même : à la fin d’un trait, le sol situé le long de chaque nouveau bord de falaise est peint avec le calque de sol choisi dans le paramètre Edge Ground Layer du type de falaise, par exemple un rebord pierreux « Rocky Dirt ». Le rebord suit le contour arrondi de la falaise, s’estompe sur la largeur Edge Width et présente un contour légèrement irrégulier, ce qui lui donne un aspect naturel plutôt que découpé selon les cellules.

  1. Sélectionnez le tileset et ouvrez Cliff Layers. Dans chaque panneau de falaise, choisissez un calque pour Edge Layer (les tilesets de démo utilisent Rocky Dirt).
  2. Choisissez Raise / Lower Level, Set Level, Ramp ou Clean Cliffs, et laissez Paint Cliff Edges activé.
  3. Peignez les falaises comme d’habitude. Le rebord apparaît lorsque vous relâchez le bouton de la souris.
  • Une seule étape d’annulation : le changement de niveau et la peinture du bord sont annulés ensemble.
  • Symétrie : toutes les copies symétriques reçoivent leurs bords lors de la même passe.
  • Rampes : les cellules de rampe ne reçoivent jamais de rebord. Peindre une rampe en travers d’un bord y supprime le rebord lorsque Clean Up Old Edges est activé.
  • Falaises déplacées : lorsque Clean Up Old Edges est activé, le rebord d’un bord qui a disparu (plateau abaissé, plateau étendu) est de nouveau supprimé. Le calque de bord est alors retiré même si vous l’aviez peint à la main à cet endroit.
  • Facultatif : désactivez Paint Cliff Edges pour un outil, ou réglez le champ Edge Layer du type de falaise sur None pour tout le tileset. Si l’option est activée mais qu’aucun calque de bord n’est défini, la ligne d’état le signale.

Dans votre code, appelez CliffEdgePainter.PaintEdges(map, tileset, cellRect, CliffEdgeOptions.Default) après avoir modifié vous-même des niveaux de falaise (par exemple dans un générateur personnalisé), puis terrain.NotifyChanged(MapLayers.Splat, returnedRect).

Un flux de travail typique : ébauchez les plateaux avec Set Level, affinez leurs bords avec Raise / Lower Level, passez Clean Cliffs sur les contours, puis ajoutez des rampes avec Ramp là où les unités doivent pouvoir monter. Vérifiez le résultat avec la superposition de cheminement (P).

Outils de peinture

Les outils de peinture peignent les calques de sol du tileset (jusqu’à 16). Chaque texel de splat stocke les poids de tous les calques, dont la somme fait toujours 100 %. Si le calque sélectionné n’existe pas dans le tileset ou n’a pas de texture, la ligne d’état le signale au lieu de peindre silencieusement avec une solution de repli.

OutilIdRôleSaisie et touches de modification
Paint Layerpaint.layerPeint un calque de texture de sol avec des bords de pinceau doux.Pinceau, répété 10 fois/s. Shift : effacer le calque. Ctrl+clic : prélever le calque sous le curseur.
Tile Paintpaint.tilePeint des cellules entières avec un calque de sol, comme dans les éditeurs de cartes des RTS classiques. Chaque cellule dont le centre se trouve à l’intérieur du contour du pinceau est peinte à 100 %.Pinceau, aligné sur les centres des cellules. Shift : retirer le calque des cellules. Ctrl+clic : prélever.
Fill / Replacepaint.fillRemplace un calque de sol partout, remplit une zone par diffusion ou remplit toute la carte en un seul clic.Clic. Ctrl+clic : prélever.
Smooth Paintpaint.smoothFloute les transitions entre calques de sol sous le pinceau pour obtenir des fondus plus doux.Pinceau, répété 15 fois/s.
Auto Paintpaint.autoPeint les calques de sol en fonction de la hauteur, de la pente, des falaises et de l’eau, à l’aide d’un profil de peinture automatique.Pinceau, répété 8 fois/s. Shift : peindre le calque de base du profil.

Paramètres de l’outil Paint Layer

ParamètrePlagePar défautDescription
Layerpalette0Calque de sol du tileset à peindre.
Opacity0.05–11Couverture maximale que le calque peut atteindre. Des valeurs plus faibles mélangent le calque avec le sol en dessous.

Paramètres de l’outil Tile Paint

ParamètrePlagePar défautDescription
Layerpalette0Calque de sol du tileset à peindre.
Soft Borderactivé/désactivédésactivéCrée un fondu d’un texel autour des cellules peintes, pour des bords légèrement plus doux.

Paramètres de l’outil Fill / Replace

ParamètrePlagePar défautDescription
Layerpalette0Calque de sol utilisé pour remplir la zone.
ModeReplace Dominant Layer, Fill Connected, Fill AllFill ConnectedReplace Dominant Layer : tous les texels de la carte dont le calque dominant est le calque cliqué. Fill Connected : remplissage par diffusion des texels connectés ayant le calque dominant cliqué. Fill All : toute la carte.
Preserve Blendsactivé/désactivéactivéRemplace uniquement le calque cliqué par le nouveau et conserve les fondus avec les autres calques (Replace et Flood Fill).

Chaque clic constitue une seule étape d’annulation, qui n’enregistre que la zone réellement modifiée.

Paramètres de l’outil Smooth Paint

ParamètrePlagePar défautDescription
Blur Radius1–31Taille du noyau de flou, en texels de splat. Des valeurs plus élevées lissent plus rapidement.

Paramètres de l’outil Auto Paint

ParamètrePar défautDescription
ProfileaucunL’asset Auto Paint Profile avec lequel le pinceau peint. Vide = règles intégrées, mises en correspondance avec les noms des calques du tileset. Voir Peinture automatique (Auto Paint).

L’onglet Paint affiche aussi le panneau Auto Paint Whole Map, qui repeint toute la carte à partir du profil en une seule étape.

Outils de végétation

Les outils de végétation peignent l’herbe et les petites plantes (détails) et placent des arbres à partir de la Vegetation Library du terrain. Si le terrain n’en a pas, la page de l’outil propose Create Vegetation Library. Choisissez des prototypes dans la grille ; si aucun n’est sélectionné, le premier prototype de la bibliothèque est utilisé.

OutilIdRôleSaisie et touches de modification
Paint Detailsveg.detailsPeint la densité de l’herbe, des fleurs et d’autres petites plantes.Pinceau, répété 10 fois/s. Shift : effacer les détails sélectionnés.
Erase Detailsveg.detailsEraseSupprime l’herbe et les autres détails de végétation sous le pinceau.Pinceau, répété 10 fois/s.
Place Treesveg.treesDisperse des arbres avec le pinceau ou place des arbres un par un d’un clic.Scatter : pinceau, Shift supprime des arbres. Single : clic, Shift+clic supprime l’arbre le plus proche.
Erase Treesveg.treesEraseSupprime les arbres sous le pinceau. Avec une intensité plus faible, seuls les arbres proches du centre du pinceau sont effacés.Pinceau.

Paramètres de l’outil Paint Details

ParamètrePlagePar défautDescription
Detailsgrille de prototypesaucunPrototypes de détails à peindre.
Target Density0–10.6Densité vers laquelle peint le pinceau (1 = densité maximale du prototype).
ModeRaise, SetRaiseRaise ne fait qu’augmenter la densité. Set éclaircit aussi les zones plus denses jusqu’à la cible.

Paramètres de l’outil Erase Details

ParamètrePlagePar défautDescription
Only Selectedactivé/désactivédésactivéN’effacer que les prototypes de détails sélectionnés au lieu de tous les détails.
Detailsgrille de prototypesaucunPrototypes de détails à effacer lorsque Only Selected est activé.

Paramètres de l’outil Place Trees

ParamètrePlagePar défautDescription
Treesgrille de prototypesaucunPrototypes d’arbres placés au hasard.
ModeScatter, SingleScatterScatter peint des arbres avec le pinceau. Single place un arbre par clic et affiche un aperçu fantôme.
Density0.05–50.6Nombre d’arbres par 100 m² que fait apparaître chaque empreinte à pleine intensité. L’espacement minimal des prototypes s’applique toujours.
Max Slope0–90°35Les arbres dispersés ne sont pas placés sur des pentes plus escarpées.
Avoid Wateractivé/désactivéactivéNe pas disperser d’arbres sous l’eau.

Paramètres de l’outil Erase Trees

ParamètrePlagePar défautDescription
Only Selectedactivé/désactivédésactivéNe supprimer que les arbres des prototypes sélectionnés.
Treesgrille de prototypesaucunPrototypes d’arbres à supprimer lorsque Only Selected est activé.

Outils de décor

Les outils de décor placent, effacent et modifient des accessoires tels que des rochers, des ruines et des clôtures, issus de l’asset Decor Library du terrain. Si le terrain n’en a pas, la page de l’outil propose le bouton Create Decor Library. La grille de prototypes dispose d’un champ de recherche et de filtres par catégorie.

OutilIdRôleSaisie et touches de modification
Place Decordecor.placePlace des accessoires, des rochers et d’autres objets de décor un par un, ou les disperse au pinceau.Single : clic, Shift+clic supprime l’objet le plus proche. Scatter : pinceau, Shift supprime les objets de décor situés sous le pinceau.
Erase Decordecor.eraseSupprime les objets de décor situés sous le pinceau. Les objets verrouillés sont conservés. Avec une intensité plus faible, seuls les objets proches du centre du pinceau sont effacés.Pinceau.
Select Decordecor.selectSélectionne des objets de décor d’un clic ou en faisant glisser un rectangle, pour les déplacer, les faire pivoter, les mettre à l’échelle ou les supprimer.Glisser. Clic : sélectionner. Glisser : sélection par rectangle. Shift : ajouter / inverser la sélection.

Paramètres de l’outil Place Decor

ParamètrePlagePar défautDescription
ModeSingle, ScatterSingleSingle place un objet par clic, avec un aperçu fantôme. Scatter peint des objets au pinceau.
Decorgrille de prototypesaucunPrototypes de décor placés au hasard. Si aucun n’est sélectionné, le premier de la bibliothèque est utilisé.
Density0.05–50.4Scatter : nombre d’objets par 100 m² que fait apparaître chaque empreinte à pleine intensité.
Use Prototype Defaultsactivé/désactivéactivéReprend les paramètres du prototype pour le lacet aléatoire, l’alignement sur le sol et l’accrochage à la grille.
Random Yawactivé/désactivéactivéRotation aléatoire autour de l’axe vertical (si les valeurs par défaut du prototype ne sont pas utilisées).
Yaw0–360°0Rotation autour de l’axe vertical lorsque Random Yaw est désactivé.
Scale0.1–51Multiplicateur appliqué à l’échelle aléatoire du prototype.
Align To Ground0–100 = vertical, 1 = suit la pente du sol (si les valeurs par défaut du prototype ne sont pas utilisées).
Snap To Gridactivé/désactivédésactivéPlace les objets au centre des cellules.
Random Variantactivé/désactivéactivéUtilise une variante de prefab aléatoire du prototype.
Max Slope0–90°90Scatter : ignore les pentes plus escarpées que cette valeur. 90 = aucune limite.
Avoid Wateractivé/désactivédésactivéScatter : ne place aucun objet sous l’eau.

Paramètres de l’outil Erase Decor

ParamètrePlagePar défautDescription
Only Selectedactivé/désactivédésactivéNe supprime que les objets des prototypes sélectionnés.
Decorgrille de prototypesaucunPrototypes de décor à supprimer lorsque Only Selected est activé.

Paramètres de l’outil Select Decor

ParamètrePlagePar défautDescription
Pick Radius0.25–10 m1Distance minimale jusqu’à laquelle un clic sélectionne encore un objet (les objets plus grands sont sélectionnés dans les limites de leur emprise).
Select Lockedactivé/désactivédésactivéPermet de sélectionner les objets verrouillés, par exemple pour les déverrouiller.

Panneau Selection

Lorsque l’outil Select Decor est actif, l’onglet Decor affiche le panneau Selection avec le nombre d’objets sélectionnés. Chaque bouton de modification (Delete, Duplicate, Snap to Ground, Rotate 90°, Lock, Unlock) constitue une seule étape d’annulation. Select All et Clear ne modifient que la sélection.

BoutonAction
Select AllSélectionne tous les objets de décor de la carte (les objets verrouillés sont ignorés).
ClearVide la sélection.
DeleteSupprime les objets sélectionnés.
DuplicateDuplique la sélection en la décalant d’une cellule en diagonale (+X et +Z). Les copies deviennent la sélection et sont déverrouillées.
Snap to GroundRepose les objets sélectionnés sur le sol.
Rotate 90°Fait pivoter la sélection de 90° dans le sens horaire autour de son centre.
Lock / UnlockLes outils ne peuvent plus sélectionner ni effacer les objets verrouillés. Activez Select Locked pour les sélectionner et les déverrouiller. Même sélectionnés de cette manière, les objets verrouillés ne sont affectés ni par Delete ni par les poignées.

Le déplacement, la rotation et la mise à l’échelle avec les poignées sont décrits dans Poignées de la sélection de décors.

Outils d’eau

L’eau est stockée par vertex : un vertex est soit mouillé, avec une hauteur de surface de l’eau, soit sec. Comme les outils de falaise, les outils d’eau utilisent une sélection franche. Le panneau Water at Cursor affiche le niveau et la profondeur d’eau sous la souris, et indique s’il s’agit d’eau peu profonde (praticable) ou d’eau profonde, d’après la limite d’eau peu profonde du tileset.

OutilIdRôleSaisie et touches de modification
Paint Waterwater.paintPeint des lacs et des rivières à la hauteur cible ; le sol situé au-dessus de la surface de l’eau reste sec.Pinceau. Shift : effacer l’eau. Ctrl+clic : prélever la hauteur.
Erase Waterwater.eraseRetire l’eau des vertices situés sous le pinceau.Pinceau.
Flood Fillwater.floodRemplit d’eau, en un seul clic, le bassin situé sous le curseur jusqu’à la hauteur cible.Clic. Shift+clic : drainer l’eau contiguë. Ctrl+clic : prélever la hauteur.

Paramètres de hauteur d’eau (Paint Water et Flood Fill)

ParamètrePlagePar défautDescription
Water HeightCliff Level Plus Offset, Absolute Height, Picked HeightCliff Level Plus OffsetMéthode de détermination de la hauteur de la surface de l’eau.
Level0–15 (palette)1Niveau de falaise sur lequel se base la surface de l’eau (mode Cliff Level Plus Offset).
Offset−8–16 m0.6 niveauHauteur en mètres au-dessus du niveau de falaise. Tant que vous ne la modifiez pas, elle suit 0.6 × la hauteur de niveau de falaise de la carte (1.2 m avec des niveaux de 2 m).
Absolute Height−16–64 m3.2Surface de l’eau en mètres, dans l’espace local de la carte (mode Absolute Height).
Picked Height−16–64 m3.2Hauteur prélevée par Ctrl+clic (mode Picked Height). Un prélèvement relève la hauteur de la surface de l’eau si le point est mouillé, sinon celle du sol, et passe en mode Picked Height.

Paramètres de l’outil Paint Water

ParamètrePlagePar défautDescription
Forceactivé/désactivédésactivéMarque aussi comme mouillés les vertices dont le sol se trouve au-dessus de la surface de l’eau, par exemple pour des cascades ou des marécages.

Paramètres de l’outil Flood Fill

ParamètrePlagePar défautDescription
Max Vertices100–1,000,00020,000Limite de sécurité : un remplissage ou un drainage qui couvrirait davantage de vertices est annulé sans aucune modification.

La valeur par défaut (niveau 1 + 0.6 niveau) remplit les lacs creusés un niveau sous le niveau de base 2 d’une nouvelle carte. Creusez un bassin avec l’outil Raise / Lower Level en maintenant Shift enfoncée, puis cliquez à l’intérieur avec l’outil Flood Fill.

Outils de cheminement

La carte de cheminement (praticable, constructible, survolable, eau) est déduite automatiquement des pentes, des falaises, de l’eau, des calques de sol, des arbres et des décors. Par-dessus, les outils de cheminement peignent des surcharges manuelles, avec une sélection franche par cellule de cheminement. Pour voir le résultat, activez la superposition dans le panneau Pathing Overlay ou avec P.

OutilIdRôleSaisie et touches de modification
Paint Pathingpathing.paintPeint des règles de cheminement invisibles, comme des bloqueurs, des zones non constructibles ou des zones rendues praticables de force.Pinceau. Shift : supprimer la surcharge sélectionnée.
Clear Pathingpathing.clearSupprime toutes les surcharges de cheminement peintes, pour que le cheminement automatique s’applique de nouveau.Pinceau.

Paramètres de l’outil Paint Pathing

ParamètrePlagePar défautDescription
Overridevoir ci-dessousBlockerSurcharge de cheminement à peindre.
SurchargeEffet
BlockerNon praticable et non constructible : un mur invisible, typique des bordures de la carte et des zones décoratives.
UnwalkableLes unités terrestres ne peuvent pas s’y déplacer.
UnbuildableAucun bâtiment ne peut y être placé, par exemple pour garder libres les passages et les expansions.
UnflyableLes unités aériennes ne peuvent pas survoler cette zone.
Force WalkableLes unités terrestres peuvent s’y déplacer, même si la pente, l’eau ou des emprises bloqueraient le passage.
Force BuildableDes bâtiments peuvent y être placés, même si les règles déduites l’interdiraient.

Couleurs de la superposition de cheminement

SuperpositionCouleurs
WalkabilityVert = praticable, rouge = bloqué, rouge foncé = falaise, orange = trop escarpé, bleu = eau profonde, cyan = eau peu profonde.
BuildabilityVert = constructible, jaune = praticable mais non constructible, rouge / rouge foncé = non praticable.
FlyabilityBleu clair = survolable, magenta = non survolable.
WaterCyan = eau peu profonde, bleu = eau profonde.
CombinedTout à la fois, comme la vue de cheminement des éditeurs de cartes des RTS classiques.

Les règles de la partie automatique (pentes maximales, marge de falaise, etc.) se définissent dans le composant RTS Terrain ; voir Pathing Rules.

Outils de marqueurs

Les outils de marqueurs ajoutent des informations de gameplay à la carte : les positions de départ des joueurs, des régions nommées pour les déclencheurs et des points nommés comme des positions de caméra. Les marqueurs sont affichés dans la Scene View tant qu’un outil de marqueurs est actif ou que l’option Show Markers est activée.

OutilIdRôleSaisie et touches de modification
Start Locationsmarkers.startPlace le point d’apparition d’un joueur. Cliquez de nouveau pour le déplacer.Clic. Shift+clic : supprimer la position de départ la plus proche.
Regionsmarkers.regionFaites glisser des rectangles pour créer des régions nommées destinées à la logique de jeu.Glisser. Shift+clic : supprimer la région sous le curseur.
Markersmarkers.markerPlace des points nommés et orientés, par exemple des caméras ou des points de passage.Clic. Shift+clic : supprimer le marqueur le plus proche.

Paramètres de l’outil Start Locations

ParamètrePlagePar défautDescription
PlayerPlayer 1–16 (palette)Player 1 (Red)Joueur dont la position de départ est placée. Chaque joueur possède une seule position de départ.
Yaw0–360°0Orientation de la position de départ.
Symmetry Assigns Next Playersactivé/désactivéactivéAvec la symétrie, les copies placent les positions de départ des joueurs suivants. Si cette option est désactivée, seul le clic d’origine place ou déplace la position de départ.

Paramètres de l’outil Regions

ParamètrePlagePar défautDescription
Colorcouleurbleu translucideCouleur des nouvelles régions.
Snap To Cellsactivé/désactivéactivéAligne les bords des régions sur la grille des cellules.

Les nouvelles régions reçoivent automatiquement un nom unique.

Paramètres de l’outil Markers

ParamètrePlagePar défautDescription
NametexteMarkerNom des nouveaux marqueurs. Un numéro est ajouté si le nom est déjà utilisé.
TagtextevideTexte libre que le code de votre jeu utilise pour retrouver les marqueurs, par exemple camera ou waypoint.
Yaw0–360°0Orientation des nouveaux marqueurs.

Peinture automatique (Auto Paint)

La peinture automatique applique les calques de sol d’après le relief du terrain : de l’herbe sur les zones plates, de la roche sur les pentes escarpées et le long des falaises, du sable sur le rivage, des plaques de terre fragmentées par du bruit. C’est le moyen le plus rapide de donner un aspect fini à une carte fraîchement sculptée ou générée. Vous pouvez ensuite l’affiner à la main.

Il existe trois façons de l’utiliser :

  • l’outil pinceau Auto Paint de l’onglet Paint peint les règles à l’intérieur du pinceau et les mélange avec la peinture existante selon le poids et l’intensité du pinceau. Avec Shift, il peint à la place le calque de base, ce qui efface la peinture des règles ;
  • le panneau Auto Paint Whole Map de l’onglet Paint repeint chaque texel de sol de la carte en une seule étape d’annulation. Il comporte un champ Profile et un bouton Create Profile ;
  • le bouton Apply To Map dans l’Inspector du profil, ainsi que l’étape Paint du générateur.

Sans profil, des règles par défaut intégrées sont utilisées. Elles choisissent leurs calques d’après les noms des calques de sol du tileset.

Profils de peinture automatique

  1. Dans l’onglet Paint, cliquez sur Create Profile dans le panneau Auto Paint Whole Map. Cela crée un profil doté des règles par défaut adaptées au tileset du terrain, puis l’assigne. Vous pouvez aussi utiliser Assets ▸ Create ▸ RTS Terrain Studio ▸ Auto Paint Profile.
  2. Sélectionnez le profil. Dans l’Inspector, assignez un Preview Tileset pour que les panneaux de règle affichent les noms et les miniatures des calques. Il ne sert qu’à l’affichage ; le profil fonctionne avec n’importe quel tileset.
  3. Modifiez les règles, puis cliquez sur Apply To Map pour repeindre le terrain sélectionné ou en cours d’édition. S’il y a plusieurs terrains et qu’aucun n’est sélectionné, un menu vous permet d’en choisir un.
  4. Cliquez sur Use In Auto Paint Tool pour que l’outil pinceau peigne avec ce profil.
Paramètre du profilPar défautDescription
Base Layer0Calque qui recouvre chaque texel avant l’application des règles.
Start From ExistingdésactivéPart des poids de splat actuels au lieu du calque de base, ce qui conserve la peinture manuelle là où aucune règle ne s’applique.
Rules–Appliquées de haut en bas ; les règles suivantes peignent par-dessus les précédentes. Chaque panneau de règle comporte une case d’activation, un nom, son calque, ▲ / ▼ pour changer l’ordre, des boutons pour dupliquer et supprimer, ainsi qu’une section repliable Conditions. Les boutons Add Rule et Reset To Defaults se trouvent sous la liste.

Pour chaque texel de splat, la peinture automatique part de 100 % du calque de base (ou des poids existants), applique les règles activées de haut en bas, puis normalise le résultat. Chaque condition activée d’une règle donne un poids compris entre 0 et 1, avec une transition douce aux limites de la plage. Les poids sont multipliés, fragmentés par du bruit et pondérés par l’intensité de la règle.

Paramètres des règles

ParamètrePar défautDescription
NameRuleNom affiché de la règle.
Layer0Calque de sol (index dans le tileset) peint par cette règle.
EnabledactivéLes règles désactivées sont ignorées.
Use Height, Min Height, Max Heightdésactivé, 0, 20Peint uniquement là où la hauteur du sol dans l’espace local de la carte (en mètres) se situe dans la plage.
Height Falloff0.5Transition douce au-delà de la plage de hauteur, en mètres (0 = bord net).
Use Slope, Min Slope, Max Slopedésactivé, 0, 90Peint uniquement là où la pente (en degrés) se situe dans la plage.
Slope Falloff5Transition douce au-delà de la plage de pente, en degrés.
Use Cliff Level, Min Cliff Level, Max Cliff Leveldésactivé, 0, 15Peint uniquement sur ces niveaux de falaise (bord net).
Near Cliff Distance0Peint uniquement jusqu’à cette distance d’une paroi de falaise, en cellules (0 = désactivé). S’estompe sur la moitié extérieure.
Near Water Distance0Peint uniquement jusqu’à cette distance de l’eau, en cellules (0 = désactivé). S’estompe sur la moitié extérieure.
Noise Scale16Taille des motifs du bruit, en mètres.
Noise Amount0Force avec laquelle le bruit fragmente la règle (0 = aucun bruit, 1 = plaques).
Noise Seed0Des règles avec des graines différentes produisent des plaques différentes.
Strength1Intensité globale de la règle (0–1).
Blend ModeReplaceManière dont la règle se combine avec les règles situées au-dessus d’elle (voir ci-dessous).
Mode de fonduEffet
AddAjoute le calque de la règle par-dessus. Les calques existants sont réduits proportionnellement lors de la normalisation du résultat.
ReplaceFait tendre chaque calque vers le calque de la règle, selon le poids de la règle. C’est le choix habituel.
MultiplyMultiplie le poids existant du calque de la règle par le masque de la règle, ce qui retire ce calque là où la règle ne s’applique pas.

Règles par défaut

Les règles intégrées utilisent comme calque de base le calque dont le nom contient grass, meadow ou green, et recherchent les calques dirt, rock et sand à l’aide de mots-clés similaires (calques 0–3 en l’absence de tileset).

RèglePeintConditions
Dirt PatchesterrePlaques de bruit (échelle 14 m), intensité 0.55.
Sand ShoresableJusqu’à 3 cellules de l’eau, légèrement fragmenté par du bruit.
Rock SlopesrochePentes de 28° ou plus (atténuation de 8°).
Rock Near CliffsrocheJusqu’à 1.6 cellule d’une paroi de falaise, fragmenté par du bruit, intensité 0.85.

Peinture automatique par le code

using RTSTerrainStudio;
using UnityEngine;

// Repaints the whole map with a profile, for example after your own procedural edits.
public class RepaintWithProfile : MonoBehaviour
{
    public RTSTerrain terrain;
    public RTSAutoPaintProfile profile;

    void Start()
    {
        if (terrain == null || terrain.Map == null || profile == null) return;

        // Evaluates the rules for every splat texel inside the rectangle (here: the whole map).
        RTSAutoPaint.Apply(terrain.Map, profile, terrain.Map.CellBounds);

        // Let the terrain upload the new splat maps and update dependent systems (pathing ground rules).
        terrain.NotifyChangedAll(MapLayers.Splat);
        terrain.ProcessPendingChanges();
    }
}

Le composant RTS Terrain

Chaque composant RTS Terrain affiche une carte. Il construit le mesh du terrain par chunks, effectue le rendu du sol et des falaises avec le tileset, tient à jour la carte de cheminement et propose des requêtes, par exemple sur la hauteur, l’eau ou le cheminement à une position donnée de l’espace monde. Créez-le avec GameObject ▸ RTS Terrain Studio ▸ RTS Terrain, ou ajoutez-le à n’importe quel GameObject avec Add Component ▸ RTS Terrain Studio ▸ RTS Terrain.

Cet élément de menu crée un terrain prêt à être édité : un GameObject RTS Terrain doté des composants RTS Terrain, Vegetation Renderer, Water Renderer et Decor Manager, du tileset et des bibliothèques par défaut du projet, ainsi que d’un nouveau fichier .rtsmap contenant une carte plate, à côté de la scène active (ou dans Assets/Maps). Si le projet ne contient encore aucun tileset, il vous est proposé de créer d’abord le contenu de démo.

Inspector

ZoneContenu
HeaderNom de la carte, taille réelle, taille de cellule et asset de carte, un badge Unsaved changes et des statistiques en direct : Cells, Chunks, Map Memory, Trees, Decor, Detail Layers, Regions, Start Locations et Markers.
ActionsOpen RTS Terrain Studio, Edit Terrain (active ou désactive l’édition dans la Scene View pour ce terrain), Save, Save As… et Reload.
WarningsProblèmes, avec une correction en un clic lorsque c’est possible : URP inactif, shaders manquants, aucun tileset (avec un bouton pour utiliser le tileset pour lequel la carte a été créée), tableaux de textures non construits ou obsolètes (Build), carte créée pour un autre tileset, végétation ou décors présents dans la carte sans bibliothèque, terrain pivoté autour de X ou de Z (Fix) ou mis à l’échelle (Reset Scale), et composants de sous-systèmes manquants (Add).
AssetsChamps Map, Tileset, Vegetation et Decor, chacun avec un bouton New qui crée et assigne un nouvel asset.
Chunks & Geometry, Cliff Shape, Physics, RenderingLes paramètres du terrain (tableau ci-dessous).
Pathing RulesMode de déduction de la carte de cheminement (tableau ci-dessous). Elle est reconstruite automatiquement après chaque modification.
Default MapTaille et valeurs par défaut de la carte créée lorsqu’aucun asset de carte n’est assigné.
Rebuild TerrainDétruit puis recrée tous les chunks, les textures et la carte de cheminement ; la végétation, l’eau et les décors sont également reconstruits. Utilisez-le après avoir modifié des paramètres par le code ou lorsque quelque chose ne semble pas à jour.

Le même Inspector est intégré dans l’onglet Settings de la fenêtre, sous Terrain Component. L’assignation d’un tileset et les tableaux de textures sont traités dans Tilesets ; les fichiers de carte, dans Assets de carte.

Le terrain n’utilise que la rotation Y de son Transform et ignore l’échelle. Pour agrandir une carte, ajoutez des cellules avec Resize (RTSTerrain.ResizeMap), ou créez une nouvelle carte avec un paramètre Cell Size plus grand (MapCreationSettings.cellSize).

Paramètres du terrain

Ces champs appartiennent à RTSTerrainSettings (propriété RTSTerrain.Settings).

ParamètrePar défautDescription
Chunks & Geometry
Chunk Size32Nombre de cellules par côté de chunk (16, 32 ou 64). Les petits chunks se reconstruisent plus vite pendant l’édition ; les grands chunks réduisent le nombre de draw calls.
Surface Subdivisions2Nombre de quads par côté de cellule sur un sol lisse (1–4). 1 = aspect RTS classique, 2–4 = collines plus douces.
Cliff Subdivisions4Résolution de la sous-grille utilisée pour tracer des contours de falaise arrondis à l’intérieur d’une cellule de falaise (2–8).
Cliff Shape
Cliff Noise0.18Déplacement horizontal aléatoire des vertices des parois de falaise, en fraction de cellule (0–0.5). Donne un aspect de roche naturelle.
Cliff Noise Scale1.6Échelle du bruit de falaise, en unités monde (minimum 0.1).
Cliff Slant0.12Recul du bord supérieur d’une falaise, qui incline légèrement les parois, en fraction de cellule (0–0.4).
Cliff Wall Segments3Nombre de segments verticaux par niveau de falaise pour la géométrie des parois (1–8).
Physics
Collider ModeMesh ColliderNone : aucun collider ; utilisez le raycast du terrain pour les requêtes. Mesh Collider : un MeshCollider par chunk, reconstruit après chaque modification.
Chunk LayerDefault (0)Layer des GameObjects des chunks, utilisé par les colliders et les caméras.
Rendering
Cast ShadowsOnMode de projection des ombres des chunks.
Receive ShadowsactivéIndique si les chunks reçoivent des ombres.
Material OverrideaucunMatériau facultatif. S’il est vide, un matériau utilisant le shader RTS Terrain Studio/Terrain est créé.
Show GriddésactivéAffiche la grille des cellules, y compris en Play Mode et dans les builds. La touche G de l’éditeur est indépendante et n’agit que pendant l’édition.
Grid Opacity0.35Opacité de la grille (0–1).

Pathing Rules

Ces champs appartiennent à RTSPathingSettings (propriété RTSTerrain.PathingSettings). Ils déterminent comment les pentes, les falaises, l’eau et les calques de sol deviennent des zones praticables et constructibles. Les surcharges peintes avec les outils de cheminement s’appliquent par-dessus.

ParamètrePar défautDescription
Max Walkable Slope42°Un sol plus escarpé que cet angle n’est pas praticable.
Max Buildable Slope18°Un sol plus escarpé que cet angle n’est pas constructible.
Cliff Margin0.25Distance sur laquelle la zone bloquée s’étend au-delà d’une paroi de falaise, en fraction de cellule de cheminement (0–1). Des valeurs plus élevées tiennent les unités plus à l’écart des bords de falaise.
Shallow Water BuildabledésactivéAutorise les bâtiments en eau peu profonde.
Tree Footprint Scale1Multiplicateur du rayon d’emprise de cheminement de chaque arbre.
Use Ground Layer RulesactivéApplique l’effet de cheminement du calque de sol dominant, par exemple Unbuildable sur de la roche accidentée.

Default Map

Carte créée lorsqu’aucun asset de carte n’est assigné. Le panneau New Map de l’onglet Map est prérempli avec ces valeurs.

ParamètrePar défautDescription
Width / Height128 / 128Taille en cellules, multiple de 16 (16–1024).
Cell Size2Taille d’une cellule, en unités monde.
Cliff Level Height2Hauteur d’un niveau de falaise, en unités monde.
Base Cliff Level2Niveau de falaise initial de chaque vertex (0–15).
Base Ground Layer0Calque de sol qui recouvre initialement la carte.
Splat Resolution4Nombre de texels de splat par cellule (1, 2, 4 ou 8).
Detail Resolution2Nombre de texels de densité de détails par cellule (1, 2 ou 4).
Pathing Resolution2Nombre de cellules de cheminement par cellule de carte (1, 2 ou 4).

Composants des sous-systèmes

Le terrain n’affiche que le sol et les falaises. Les autres éléments de la carte sont affichés par des composants placés sur le même GameObject ou ailleurs dans la scène. L’Inspector du terrain vous avertit lorsque l’un des quatre premiers manque et propose un bouton Add.

ComposantAjouté par le menu de créationUtilité
Vegetation RendererouiAffiche l’herbe et les plantes peintes ainsi que les arbres, en instanciation GPU ou sous forme d’instances de prefabs. Ne régénère que les zones modifiées.
Water RendererouiConstruit et affiche la surface de l’eau chunk par chunk, avec l’apparence définie par le profil d’eau du tileset. Pour un rendu optimal, activez Depth Texture et Opaque Texture dans l’asset URP (ou sur la caméra).
Decor ManagerouiAffiche les objets de décor de la carte et les maintient au sol lorsque les hauteurs changent.
Environmentpar le New Map Wizard (facultatif), ou via GameObject ▸ RTS Terrain Studio ▸ EnvironmentApplique à la scène le soleil, la lumière ambiante et le brouillard atmosphérique de la carte. L’éclairage d’origine de la scène est restauré lorsque le composant est désactivé, et il n’est jamais écrit dans le fichier de scène.
Fog of War ManagerGameObject ▸ RTS Terrain Studio ▸ Fog of War ManagerCalcule le brouillard de guerre pour l’équipe locale. Un seul par scène.
Pathfinding ServiceAdd Component ▸ RTS Terrain Studio ▸ Pathfinding Service, ou créé à la demande par RTSPathfindingService.GetOrCreate()Exécute les recherches de chemin intégrées sur la carte de cheminement du terrain.

Modifier les paramètres du terrain par le code

using RTSTerrainStudio;
using UnityEngine;

public class TerrainQualityOptions : MonoBehaviour
{
    public RTSTerrain terrain;

    // Called from a graphics options menu, for example.
    public void SetSmoothHills(bool smooth)
    {
        // Settings fields can be changed directly, but the chunks are only rebuilt on request.
        // Use 1, 2 or 4: an odd value such as 3 rounds Cliff Subdivisions up to a multiple of 6 (expensive).
        terrain.Settings.surfaceSubdivisions = smooth ? 2 : 1;
        terrain.RebuildAll();
    }

    public void UseStricterSlopes()
    {
        // Assigning new pathing settings rebuilds the pathing map automatically.
        RTSPathingSettings rules = terrain.PathingSettings.Clone();
        rules.maxWalkableSlope = 35f;
        rules.maxBuildableSlope = 12f;
        terrain.PathingSettings = rules;
    }
}

Si vous modifiez les champs de l’instance PathingSettings actuelle au lieu d’en assigner une nouvelle, appelez ensuite terrain.RebuildPathing().

Éditeur en jeu

L’éditeur en jeu intègre l’éditeur de cartes de RTS Terrain Studio dans le build de votre jeu. Les joueurs et les moddeurs peuvent créer, peindre, enregistrer, charger et tester en jeu des cartes sans Unity, exactement comme avec les éditeurs de cartes fournis avec les RTS classiques. Il repose sur UI Toolkit, utilise les mêmes outils que la fenêtre de l’éditeur dans Unity (Height, Cliffs, Paint, Vegetation, Decor, Water, Pathing et Markers) et écrit les mêmes fichiers .rtsmap. Une carte créée dans votre jeu peut être copiée dans un projet Unity et y être ouverte telle quelle, et inversement.

L’éditeur de cartes en jeu en cours d’exécution dans la Game View
L’éditeur en jeu : barre supérieure, catégories d’outils et outils à gauche, pinceau et paramètres de l’outil à droite, barre d’état en bas.

Tout tient dans un seul composant, RTSRuntimeEditor. Ajoutez-le à une scène qui contient un RTS Terrain et une caméra, appuyez sur Play, et vous disposez d’un éditeur fonctionnel. Ce chapitre couvre la configuration, chaque partie de l’interface, toutes les commandes du clavier et de la souris, le bouton Play Test, la façon dont le code de votre jeu y réagit, l’emplacement de stockage des cartes, la personnalisation du style de l’interface et les points à vérifier avant de publier votre jeu.

Dans l’éditeur Unity, le bouton Open Manual de la fenêtre Shortcuts & Help (F1 ou le bouton ? de la barre supérieure) ouvre ce chapitre. Dans un build, le bouton ouvre la page que vous indiquez dans le champ Manual Url, par exemple votre propre guide de modding. Si ce champ est vide, le bouton est masqué dans les builds.

Essayez-le en deux minutes

Le moyen le plus rapide de découvrir l’éditeur en jeu est d’utiliser la scène de démo fournie avec le package.

  1. Choisissez Tools ▸ RTS Terrain Studio ▸ Create Demo Content. Cette commande génère les textures, bibliothèques, cartes et scènes de démo. Vous n’avez besoin de le faire qu’une seule fois.
  2. Dans la fenêtre Project, ouvrez Samples/Scenes/RTS Terrain Studio - In-Game Editor Demo. Cette scène contient la carte Sandbox, un objet RTS In-Game Editor, un objet RTS Demo Game et un gestionnaire de brouillard de guerre.
  3. Appuyez sur Play. L’éditeur s’ouvre avec une astuce de bienvenue. Choisissez un outil à gauche (l’outil de hauteur Raise / Lower est actif par défaut) et peignez sur le terrain avec le bouton gauche de la souris.
  4. Maintenez Shift enfoncée pendant que vous peignez pour abaisser le sol. Utilisez [ et ] pour modifier la taille du pinceau. Faites glisser la souris en maintenant le bouton droit enfoncé pour déplacer la caméra et utilisez la molette de la souris pour zoomer.
  5. Appuyez sur F5 (ou sur Play Test dans la barre supérieure). Le jeu de démo fait apparaître des unités aux positions de départ et active le brouillard de guerre. Sélectionnez des unités et cliquez avec le bouton droit pour les déplacer.
  6. Appuyez sur Esc ou F5 pour revenir à l’éditeur. La carte retrouve exactement son état d’avant le test en jeu.
  7. Appuyez sur Ctrl+S, saisissez un nom et appuyez sur Enter pour enregistrer votre carte.

Ajouter l’éditeur en jeu à votre scène

Configuration requise

  • Un RTS Terrain dans la scène, avec une carte (GameObject ▸ RTS Terrain Studio ▸ RTS Terrain).
  • Une caméra. Par défaut, l’éditeur utilise Camera.main, c’est-à-dire la caméra dotée du tag MainCamera. Vous pouvez aussi assigner n’importe quelle autre caméra.
  • Le dossier Resources/RTSTerrainStudio/UI du package. Il contient le thème et la feuille de style de l’interface.

Étapes

  1. Ouvrez votre scène et choisissez GameObject ▸ RTS Terrain Studio ▸ In-Game Editor. Cette commande crée un objet nommé RTS In-Game Editor doté du composant RTSRuntimeEditor. Si vous cliquez avec le bouton droit sur un objet dans la fenêtre Hierarchy et utilisez le menu qui s’affiche, le nouvel objet devient un enfant de cet objet.
  2. Si la fenêtre Console signale qu’il n’y a aucun RTS Terrain, ajoutez-en un. Si elle signale qu’aucune caméra n’a le tag MainCamera, attribuez ce tag à votre caméra ou assignez-la au champ Target Camera.
  3. Si vous le souhaitez, assignez explicitement le terrain et la caméra, puis ajustez les autres paramètres (voir Référence de l’Inspector).
  4. Appuyez sur Play. L’éditeur s’affiche. Si vous avez désactivé Start Visible, appuyez sur F2 pour l’ouvrir.

Cet élément de menu est désactivé en Play Mode. Si la scène contient déjà un éditeur en jeu, Unity vous demande si vous voulez en créer un autre avec Create Another ou sélectionner l’éditeur existant avec Select Existing. Un seul éditeur par scène suffit. Le composant peut aussi être ajouté via Add Component ▸ RTS Terrain Studio ▸ In-Game Editor, et un même GameObject ne peut en contenir qu’un seul.

Ce que le composant crée à l’exécution

Vous n’avez pas besoin de construire vous-même une interface ou un dispositif de caméra. Lorsqu’il est activé, RTSRuntimeEditor crée :

ObjetUtilité
RTSEditSessionLa session d’édition, accessible via Session. Elle contient les outils, le pinceau, la symétrie, la sélection et l’historique d’annulation. C’est la même classe que celle qu’utilise la fenêtre de l’éditeur dans Unity.
Objet enfant RTS In-Game Editor UIContient un UIDocument avec l’interface complète de l’éditeur. Il est détruit dès que le composant est désactivé.
RTSRuntimeEditorCameraAjouté à la caméra cible lorsque Use Built In Camera est activé. Si la caméra en possède déjà un, c’est ce composant qui est utilisé. Un composant de caméra que l’éditeur a ajouté lui-même est retiré à la destruction de l’éditeur.
RuntimeToolGizmosDessine dans la Game View les contours du pinceau, les rectangles de sélection, les aperçus de décor, les positions de départ et les repères de symétrie. Accessible via Gizmos.
PanelSettingsCréé si vous laissez Panel Settings vide. Il utilise le thème RTS et s’adapte à la taille de l’écran. Si vous assignez des Panel Settings qui s’adaptent à la taille de l’écran et n’effectuent pas leur rendu dans une texture, l’éditeur utilise à leur place une copie créée à l’exécution, sauf si l’option Enforce Minimum UI Scale est désactivée (voir Personnaliser l’interface).

Comment l’éditeur trouve le terrain et la caméra

  • Terrain : un terrain assigné est utilisé dès qu’il est activé. Si le champ est vide, l’éditeur utilise RTSTerrain.Main, le premier RTS Terrain de la scène. Tant qu’aucun terrain n’est trouvé, l’éditeur relance la recherche deux fois par seconde et affiche le message d’information No RTS Terrain found.
  • Plusieurs terrains : si la scène contient plus d’un RTS Terrain, le menu Map les liste sous Edited terrain. Passer à un autre terrain efface l’historique d’annulation.
  • Caméra : si Target Camera est vide, l’éditeur utilise Camera.main et continue de la chercher. Tant qu’aucune caméra n’existe, il affiche le message d’information No camera found.

Référence de l’Inspector

ParamètrePar défautDescription
Scene
TerrainvideLe terrain à éditer. Si le champ est vide, le premier RTS Terrain de la scène est utilisé (RTSTerrain.Main).
Target CameravideLa caméra utilisée pour détecter le point sous le curseur, pour les gizmos et pour la caméra intégrée de l’éditeur. Si le champ est vide, Camera.main est utilisée.
Use Built In CameraactivéAjoute un RTSRuntimeEditorCamera à la caméra cible et la pilote tant que l’éditeur est visible. Ce composant est désactivé pendant les tests en jeu. Désactivez cette option si votre propre script de caméra doit déplacer la caméra pendant l’édition.
Behaviour
Start VisibleactivéAffiche l’éditeur au démarrage de la scène. Si l’option est désactivée, le joueur l’ouvre avec la touche d’affichage, ou c’est votre code qui définit EditorVisible.
Toggle KeyF2Affiche ou masque l’ensemble de l’éditeur. Choisissez None pour désactiver la touche. Le bouton de fermeture de la barre supérieure est alors masqué : votre jeu doit donc ouvrir et fermer l’éditeur lui-même. Dans les navigateurs web ainsi que sur les téléphones et les tablettes, le bouton de fermeture reste affiché, car, sur ces plateformes, le bouton Open Map Editor permet de rouvrir l’éditeur.
Start Toolheight.raiseL’identifiant de l’outil actif au démarrage, par exemple paint.layer, veg.trees, decor.place ou markers.start. Si cet identifiant n’existe pas, le premier outil est utilisé.
Show First Time HintactivéAffiche l’astuce de bienvenue à la première ouverture de l’éditeur, jusqu’à ce que le joueur clique sur Got it ou la ferme. Ce choix est enregistré dans PlayerPrefs.
Show Quit CommandactivéAjoute la commande File ▸ Quit, qui ferme l’application. Dans l’éditeur Unity, elle arrête le Play Mode. Elle n’est jamais affichée sur WebGL, iOS et Android.
Confirm Quit With Unsaved ChangesactivéDemande confirmation avant la fermeture de l’application si la carte contient des modifications non enregistrées, y compris lorsque la demande de fermeture vient de l’extérieur de l’éditeur (bouton de fermeture de la fenêtre, Alt+F4, Application.Quit). L’éditeur est d’abord affiché et un test en jeu en cours est arrêté. Dans un build web, l’application ne peut pas se fermer ; c’est le navigateur qui demande alors Leave site? avant que la page soit fermée ou rechargée.
Undo Memory MB512La quantité maximale de mémoire que l’historique d’annulation peut utiliser, en mégaoctets (minimum 16). Lorsqu’elle est atteinte, les étapes les plus anciennes sont supprimées. L’historique conserve en outre 100 étapes au maximum. Les builds web utilisent au maximum 192 Mo, car le navigateur ne fournit à l’ensemble du jeu qu’un seul tas de mémoire, de taille limitée.
Manual UrlvideLa page web qu’ouvre le bouton Open Manual de la fenêtre d’aide dans un build. Si le champ est vide, le bouton est masqué dans les builds. Dans l’éditeur Unity, un champ vide ouvre ce manuel.
Files
Maps FoldervideLe dossier dans lequel les cartes sont listées, chargées et enregistrées. Si le champ est vide, le dossier Maps du dossier de stockage RTSMapSerializer.StorageRoot est utilisé. Un chemin relatif comme UserMaps est interprété par rapport au dossier de stockage. Un chemin absolu est utilisé tel quel. Le dossier de stockage est Application.persistentDataPath ; dans les builds web, il s’agit d’un dossier du stockage du navigateur qui reste le même lorsque l’adresse de la page change (voir Les cartes dans le navigateur).
Write Preview ImagesactivéÉcrit une petite image de mini-carte (192 × 192 pixels) à côté de chaque carte enregistrée. L’explorateur de cartes l’affiche.
User Interface
Panel SettingsvidePanel Settings (UI Toolkit) facultatifs. Si le champ est vide, l’éditeur crée à l’exécution des Panel Settings qui utilisent le thème RTS. Ils s’adaptent à la taille de l’écran (résolution de référence 1920 × 1080) et ne descendent jamais sous 85 %, de sorte que le texte reste lisible en 1280 × 720.
Enforce Minimum UI ScaleactivéGarde l’éditeur lisible dans les petites fenêtres et dans les canvas des navigateurs. Les Panel Settings assignés qui s’adaptent à la taille de l’écran sont copiés à l’exécution (l’asset lui-même n’est jamais modifié), et la copie ne réduit jamais l’interface en dessous de 85 %. Désactivez cette option pour utiliser l’asset assigné tel quel, par exemple lorsque l’éditeur partage un même panneau avec le HUD de votre jeu.
Ui Scale1Facteur d’échelle supplémentaire, de 0.5 à 2. Il s’applique aux Panel Settings que l’éditeur crée à l’exécution ainsi qu’à la copie, créée à l’exécution, des Panel Settings assignés.
Sorting Order1000L’ordre de tri de l’interface de l’éditeur. La valeur par défaut, élevée, place l’éditeur au-dessus du HUD de votre jeu.

Visite guidée de l’interface

L’écran est divisé en cinq zones. Chaque bouton, champ et élément d’état affiche une info-bulle lorsque vous le survolez un instant, y compris les boutons désactivés. Si vous ne savez pas à quoi sert un élément, survolez-le.

ZonePositionContenu
Barre supérieurebord supérieurMenus File et Map, annulation et rétablissement, symétrie, options d’affichage, Play Test, aide, masquage des panneaux, fermeture.
Barre d’outilsbord gaucheHuit boutons de catégorie (touches 1 à 8) et les outils de la catégorie sélectionnée.
Panneau d’outilbord droitNom et description de l’outil actif, pinceau, symétrie, paramètres de l’outil et commandes supplémentaires. Ce panneau peut être replié.
Barre d’étatbord inférieurInformations sur le point situé sous le curseur, état de l’outil, pinceau, mémoire d’annulation et nom de la carte.
Éléments superposésau-dessus de la carteNotifications, info-bulles, boîtes de dialogue, astuce de bienvenue, barre de test en jeu et messages d’information.

Barre supérieure

CommandeRôle
FileOuvre le menu File (voir ci-dessous).
MapOuvre le menu Map (voir ci-dessous).
Undo / RedoAnnuler (Ctrl+Z) et rétablir (Ctrl+Y). Leurs info-bulles indiquent le nom de l’étape, par exemple Undo "Raise / Lower". Les boutons sont grisés lorsqu’il n’y a rien à annuler ou à rétablir.
Symmetry: OffOuvre le menu de symétrie. Lorsque la symétrie est activée, chaque trait est reproduit en miroir ou par rotation, ce qui facilite la création de cartes compétitives équitables. Le bouton affiche le mode actuel, par exemple Symmetry: 180°.
GridAffiche ou masque la grille des cellules (G).
PathingOuvre le menu de superposition de cheminement. Lorsqu’une superposition est active, le bouton affiche son mode, par exemple Pathing: Walkability. P active la superposition avec le dernier mode utilisé, ou la désactive.
MarkersAffiche ou masque les positions de départ, les régions et les marqueurs lorsque d’autres outils sont actifs (M). Cette option est activée par défaut.
Play TestLance un test en jeu (F5).
Help (?)Ouvre la fenêtre Shortcuts & Help (F1).
EyeMasque les panneaux pour dégager la vue sur la carte (H). L’édition reste possible. Un petit bouton Panels hidden - press H to show them permet de les réafficher.
Close (×)Masque l’éditeur et affiche une notification indiquant la touche qui permet de le rouvrir. Ce bouton est masqué lorsque Toggle Key vaut None. Dans les navigateurs web ainsi que sur les téléphones et les tablettes, où les touches de fonction ne sont pas fiables, il fait également apparaître un bouton Open Map Editor en bas à gauche, et il reste disponible même sans touche d’affichage (voir L’éditeur en jeu dans le navigateur).

Menu File

ÉlémentRaccourciRôle
New Map...Ctrl+N (Alt+N dans les navigateurs web)Ouvre la boîte de dialogue New Map. Si la carte actuelle contient des modifications non enregistrées, l’éditeur vous demande d’abord quoi en faire. Alt+N fonctionne sur toutes les plateformes.
Open...Ctrl+OOuvre l’explorateur de cartes pour choisir une carte. Si la carte actuelle contient des modifications non enregistrées, l’éditeur vous demande d’abord quoi en faire.
SaveCtrl+SEnregistre la carte dans son fichier d’origine. La première fois, ouvre la boîte de dialogue Save Map As pour demander un nom.
Save As...Ctrl+Shift+SOuvre l’explorateur de cartes pour enregistrer la carte sous un nouveau nom.
Download MapBuilds web uniquement. Enregistre une copie de la carte, modifications non enregistrées comprises, sous forme de fichier .rtsmap sur l’ordinateur du joueur (généralement dans le dossier Téléchargements). Voir Les cartes dans le navigateur.
Import Map...Builds web uniquement. Ouvre un fichier .rtsmap depuis l’ordinateur du joueur. Ce fichier est ajouté aux cartes enregistrées dans ce navigateur, puis ouvert.
Show Maps FolderOuvre le dossier des cartes dans l’explorateur de fichiers du système d’exploitation. Cet élément n’existe que sous Windows, macOS et Linux, dans l’éditeur Unity et dans les builds pour ordinateur de bureau.
QuitFerme l’application après vous avoir interrogé sur les modifications non enregistrées. Affiché uniquement si Show Quit Command est activé, et jamais sur WebGL, iOS ou Android.

Menu Map

ÉlémentRôle
Map Info...Nom, auteur, description et nombre de joueurs recommandé.
Resize...Agrandit ou réduit la carte.
Generate...Crée un agencement de carte aléatoire à partir d’une graine. Vous pouvez l’annuler en une seule étape.
Frame Whole MapDéplace la caméra de l’éditeur pour que toute la carte soit visible. Disponible uniquement avec la caméra intégrée.
Edited terrainAffiché uniquement si la scène contient plus d’un RTS Terrain. Permet de choisir le terrain à éditer. Changer de terrain efface l’historique d’annulation.

Menu de symétrie

ModeCopiesUsage typique
Off1Peindre sans symétrie.
Mirror Left / Right2Reflète par rapport à l’axe central vertical.
Mirror Top / Bottom2Reflète par rapport à l’axe central horizontal.
Mirror 4-Way4Reflète selon les deux axes.
Rotate 180°2Symétrie centrale autour du centre, typique des cartes 1v1.
Rotate 90° (4 players)4Symétrie de rotation pour les cartes à quatre joueurs. Nécessite une carte carrée. Sur une carte non carrée, l’entrée est grisée.
Mirror Diagonal2Reflète par rapport à la diagonale. Nécessite une carte carrée. Sur une carte non carrée, l’entrée est grisée.

Reset Centre replace le centre de symétrie au milieu de la carte. La section Symmetry du panneau d’outil comporte les curseurs Centre X et Centre Z pour déplacer le centre. Des lignes de guidage violettes sur le terrain matérialisent les axes de symétrie.

Menu de superposition de cheminement

La superposition colore le terrain selon ce que les unités peuvent y faire. Choisissez Off, Walkability (vert = praticable, rouge = bloqué), Buildability, Flyability, Water (eau peu profonde et profonde) ou Combined (cellules praticables, constructibles, d’eau et bloquées dans une même vue). Les entrées Opacity règlent l’opacité de la superposition sur 30 %, 55 % (par défaut) ou 80 %.

Barre d’outils (à gauche)

La colonne supérieure comporte un bouton par catégorie d’outils. Le petit chiffre affiché sur chaque bouton indique la touche correspondante. La colonne inférieure liste les outils de la catégorie sélectionnée, avec leur icône et leur nom. Survolez un outil pour afficher sa description et son indication d’utilisation.

ToucheCatégorieDescriptionOutils
1HeightÉlever, abaisser, lisser et modeler le sol.Raise / Lower, Smooth, Flatten, Set Height, Noise, Terrace, Erode
2CliffsNiveaux de falaise, rampes et matériaux de falaise dans le style des RTS classiques.Raise / Lower Level, Set Level, Ramp, Cliff Type, Clean Cliffs
3PaintPeindre les textures de sol.Paint Layer, Tile Paint, Fill / Replace, Smooth Paint, Auto Paint
4VegetationHerbe, fleurs et arbres.Paint Details, Erase Details, Place Trees, Erase Trees
5DecorPlacer, effacer et sélectionner des objets (doodads).Place Decor, Erase Decor, Select Decor
6WaterLacs, rivières et mers.Paint Water, Erase Water, Flood Fill
7PathingDéfinir où les unités peuvent se déplacer, construire et voler.Paint Pathing, Clear Pathing
8MarkersPositions de départ, régions et marqueurs nommés.Start Locations, Regions, Markers

L’éditeur mémorise le dernier outil utilisé dans chaque catégorie. Lorsque vous choisissez une catégorie avec son bouton ou sa touche numérique, cet outil est réactivé. Si vous appuyez sur la touche numérique de la catégorie dans laquelle vous vous trouvez déjà, l’éditeur passe à l’outil suivant de cette catégorie. Les outils personnalisés que vous enregistrez apparaissent ici automatiquement, avec une interface de paramètres construite à partir de leurs champs [ToolSetting].

Panneau d’outil (à droite)

L’en-tête affiche l’icône et le nom de l’outil actif. Survolez le nom pour lire la description de l’outil. Le bouton fléché replie le panneau. Sous l’en-tête, le panneau comporte des sections repliables. Les sections que vous repliez le restent lorsque vous changez d’outil.

SectionAffichée pourContenu
(à propos)tous les outilsLa description et l’indication d’utilisation de l’outil, par exemple Click: place / move · Shift+click: remove the nearest.
Brushoutils pinceauxShape (Circle, Square, Diamond et Stamp lorsqu’un tampon personnalisé est défini), Size (un curseur logarithmique et un champ en mètres), Strength, Hardness, Rotation, Random Rotation, Spacing, Jitter, ainsi qu’un bouton Reset dans l’en-tête de la section. Tous les outils partagent le même pinceau.
Symmetrytous les outilsMode de symétrie, Centre X et Centre Z, et un avertissement lorsque le mode nécessite une carte carrée.
Settingsoutils dotés d’optionsLes options de l’outil actif, comme la hauteur cible, les palettes de textures, les miniatures d’arbres et de décors, le niveau de falaise ou le joueur.
Actionscertains outilsCommandes supplémentaires : Apply to Whole Map (Auto Paint), New Random Layout (Place Trees, Place Decor) et autres commandes similaires.
SelectionSelect DecorDelete, Duplicate, rotation (−15°, +15°, +90°), décalage d’une demi-cellule (−X, +X, −Z, +Z), Smaller / Larger (10 %), alignement sur le sol, Lock / Unlock, Select All, Clear.

Le panneau et la barre d’état affichent tous deux There is no map to edit. lorsque le terrain n’a pas de carte.

Barre d’état (en bas)

ÉlémentExempleSignification
CellCell 42, 17La cellule sous le curseur (x, z).
HeightHeight 3.5 mHauteur du sol sous le curseur, en mètres.
LevelLevel 2Le niveau de falaise sous le curseur (0 à 15).
PathingWalkable, BuildableCe que les unités peuvent faire à cet endroit, par exemple Shallow water, Cliff, Too steep, Blocked ou No flying.
WaterWater 1.2 m ou DryProfondeur d’eau sous le curseur.
État de l’outilInformations fournies par l’outil actif, ou son indication d’utilisation.
BrushBrush 8.0 m 50 %Rayon et intensité du pinceau.
UndoUndo 12 4.2 MBLe nombre d’étapes d’annulation et la mémoire qu’elles occupent.
Nom de la carte● SandboxLe nom de la carte. Un point signale des modifications non enregistrées, que vous pouvez enregistrer avec Ctrl+S.

Notifications, info-bulles et messages d’information

  • Les notifications sont de courts messages qui apparaissent au-dessus de la barre d’état et s’estompent d’elles-mêmes, par exemple Saved "Sandbox" ou Undo: Raise / Lower. Il en existe quatre types. Les types Info et Success restent affichés environ 3 secondes, Warning 5 secondes et Error 6.5 secondes. Cliquez sur une notification pour la fermer. Quatre notifications au maximum sont affichées simultanément. Elles restent visibles même lorsque l’éditeur est masqué, afin que le message Editor closed. Press F2 to open it again. puisse être lu.
  • Open Map Editor : dans les navigateurs web ainsi que sur les téléphones et les tablettes, un bouton situé en bas à gauche, qui apparaît après l’utilisation du bouton de fermeture et rouvre l’éditeur. Si un clavier est disponible, il indique la touche d’affichage, par exemple Open Map Editor (F2).
  • Les info-bulles apparaissent après environ une demi-seconde au survol de n’importe quelle commande, y compris des commandes désactivées, et même pendant un test en jeu. Un clic masque l’info-bulle jusqu’à ce que le pointeur quitte la commande.
  • Astuce de bienvenue : un petit panneau qui présente les quatre commandes les plus importantes, avec les boutons All Shortcuts (F1) et Got it. Vous pouvez la réafficher avec Open Welcome Hint dans la fenêtre d’aide.
  • Messages d’information : No RTS Terrain found ou No camera found apparaissent au milieu de l’écran lorsque l’éditeur ne peut pas fonctionner, avec une courte explication de ce qu’il faut corriger.
  • Barre de test en jeu : pendant un test en jeu, une petite barre en haut au centre affiche Play test running et propose un bouton Back to Editor (Esc or F5).

Boîtes de dialogue

Les boîtes de dialogue sont modales : tant que l’une d’elles est ouverte, la carte ne peut pas être éditée et les raccourcis sont désactivés. Enter déclenche le bouton mis en évidence (principal) et Esc ferme la boîte de dialogue.

Boîte de dialogueOuverte parContenu
New MapFile ▸ New Map...Name ; préréglages de Size : Tiny (64 × 64), Small (96), Medium (128), Large (192), Huge (256), Epic (384), Giant (512) ; Width et Depth (16 à 1024 cellules, arrondies à des multiples de 16 ; dans les navigateurs web, la limite est plus basse, voir Limites) ; Cell Size 1, 2 ou 4 m (2 m correspond aux cartes des RTS classiques) ; Base Level (niveau de falaise 0 à 15 ; 2 laisse de la marge pour creuser des lacs et des rivières) ; Base Layer (la texture de sol). Une ligne en dessous indique la taille obtenue en mètres. La création d’une nouvelle carte ne peut pas être annulée, enregistrez donc d’abord votre travail.
Generate MapMap ▸ Generate...Style (réinitialise les options de forme), Seed avec un bouton Random, Symmetry ; section Terrain : Cliffs, Plateaus, Ramps, Ramp Count, Water, Lake Coverage, Island, Border ; section Content : Textures, Vegetation, Forests, Decor, Decor Count, Start Locations, Players. Remplace le contenu de la carte actuelle en une seule étape d’annulation. Les paramètres sont conservés pour la prochaine ouverture de la boîte de dialogue.
Map InfoMap ▸ Map Info...Name, Author, Description (affichée dans l’explorateur de cartes), Players (1 à 16), ainsi que des statistiques : taille, positions de départ, arbres, objets, régions. L’application des modifications constitue une seule étape d’annulation.
Resize MapMap ▸ Resize...Width et Depth (multiples de 16 ; dans les navigateurs web, même limite que pour New Map), Anchor (une grille 3 × 3 qui indique quelle partie de la carte reste en place), Fill Level et Fill Layer pour les nouvelles zones. Le redimensionnement efface l’historique d’annulation. Lorsque la carte rétrécit, le contenu situé hors de la nouvelle zone est supprimé.
Open Map / Save Map AsFile ▸ Open... / Save As...L’explorateur de cartes.
Unsaved ChangesNew, Open, Quit en présence de modifications non enregistréesSave (enregistre d’abord, et demande un nom si la carte n’en a pas), Don't Save, Cancel.
Shortcuts & HelpF1 ou le bouton ?Toutes les commandes de la souris et du clavier (voir Commandes), Open Welcome Hint, Open Manual (si un manuel est disponible) et Close.

L’explorateur de cartes

File ▸ Open... (Ctrl+O) et File ▸ Save As... (Ctrl+Shift+S) ouvrent le même explorateur, intitulé Open Map ou Save Map As. Il répertorie tous les fichiers .rtsmap du dossier des cartes.

PartieDescription
Ligne du dossierLe chemin complet du dossier des cartes. Le bouton Refresh relit le dossier, par exemple après que vous y avez copié des cartes. Dans les builds web, la ligne indique Saved in this browser. Use Download to keep a copy on your computer. et, dans l’explorateur en mode Open, propose un bouton Import... (voir Les cartes dans le navigateur).
Liste des cartesUne ligne par carte, avec son nom, sa taille, son nombre de joueurs et sa date de dernière modification, de la plus récente à la plus ancienne. Les fichiers illisibles portent la mention Unreadable or damaged file et ne peuvent pas être ouverts. Survolez une ligne pour afficher le chemin de son fichier (seulement le nom du fichier dans les builds web).
DétailsL’aperçu de la mini-carte, le nom, la taille en cellules et en mètres, l’auteur, les joueurs, la date de modification et la description de la carte sélectionnée. L’aperçu n’existe que si l’option Write Preview Images était activée lors de l’enregistrement de la carte.
Map NameUniquement dans Save As. Le nom du fichier est dérivé de ce nom. Cliquer sur une carte de la liste copie son nom dans le champ, ce qui vous permet d’écraser cette carte.
DeleteSupprime le fichier de la carte sélectionnée et son image d’aperçu, après confirmation. Cette opération ne peut pas être annulée.
DownloadBuilds web uniquement, dans l’explorateur en mode Open. Enregistre une copie de la carte sélectionnée sous forme de fichier .rtsmap sur l’ordinateur du joueur.
Cancel / Open / SaveOpen charge la carte sélectionnée. Double-cliquer sur une ligne ou appuyer sur Enter a le même effet. Save enregistre la carte sous le nom saisi.

L’explorateur ne lit que le petit en-tête de chaque fichier : il s’ouvre donc rapidement, même lorsque le dossier contient de nombreuses cartes volumineuses.

Enregistrer sous un nouveau nom

  1. Appuyez sur Ctrl+Shift+S. Le champ du nom contient déjà le nom de la carte actuelle.
  2. Saisissez un nouveau nom, par exemple Glacier Pass (2v2), puis appuyez sur Enter.
  3. Si un autre fichier porte déjà ce nom, l’éditeur affiche la question Replace Map?. Comme Enter déclenche Cancel par défaut, vous devez cliquer sur Replace pour écraser le fichier.
  4. La carte est enregistrée, une image d’aperçu est écrite et une notification confirme Saved "Glacier Pass (2v2)". Par la suite, Ctrl+S enregistre dans ce fichier sans rien demander.

Si vous enregistrez sous un autre nom, le nom de la carte elle-même (affiché dans Map Info) change aussi. Ce renommage constitue une étape d’annulation ordinaire, nommée Rename Map.

Commandes et raccourcis

La même liste est disponible dans l’éditeur avec F1. Sous macOS, Cmd fonctionne partout où Ctrl figure dans la liste. Les touches numériques désignent la rangée de chiffres du clavier principal. Les raccourcis avec une lettre suivent la lettre imprimée sur la touche : Ctrl+Z utilise donc la touche marquée Z, y compris sur les claviers allemands (QWERTZ) et français (AZERTY). Les touches du pinceau suivent le caractère saisi : [ et ] fonctionnent donc quel que soit leur emplacement sur votre clavier, par exemple avec AltGr. Dans les navigateurs web, quelques touches se comportent différemment ; voir L’éditeur en jeu dans le navigateur.

Souris

SaisieAction
Bouton gauche de la sourisPeindre ou utiliser l’outil actif. Maintenez le bouton enfoncé et faites glisser pour tracer un trait. Un trait complet constitue une seule étape d’annulation.
Shift + bouton gauche de la sourisL’action inverse : abaisser au lieu d’élever, effacer au lieu de peindre, retirer au lieu de placer.
Ctrl + clic gauchePrélever une valeur sur le terrain (hauteur, calque de sol, niveau de falaise…) pour les outils qui le permettent.
Glisser avec le bouton droit ou le bouton du milieuDéplacer la caméra (« attraper le sol »).
Alt + glisser avec le bouton gauche ou droitFaire pivoter la caméra. Tant que la touche Alt est enfoncée, le bouton gauche ne peint pas.
Molette de la sourisZoomer et dézoomer en direction du point situé sous le curseur.

Caméra (caméra intégrée de l’éditeur)

ToucheAction
W A S D ou touches fléchéesDéplacer la caméra. Maintenez Shift enfoncée pour aller plus vite.
Q / EPivoter vers la gauche / la droite.
FCentrer la caméra sur le point situé sous le curseur.

Pinceau et outils

ToucheAction
[ / ]Pinceau plus petit / plus grand (environ 15 % par appui).
- / = (ou +)Intensité plus faible / plus forte (5 % par appui). Les touches - et + du pavé numérique fonctionnent aussi.
1 à 8Sélectionner une catégorie d’outils (Height, Cliffs, Paint, Vegetation, Decor, Water, Pathing, Markers). Appuyez de nouveau pour passer à l’outil suivant de la catégorie.
EscAnnuler le trait en cours. Le terrain revient à l’état dans lequel il était quand vous avez appuyé sur le bouton.

Fichier et historique

ToucheAction
Ctrl+N ou Alt+NNouvelle carte. Dans les navigateurs web, seul Alt+N fonctionne, car le navigateur réserve Ctrl+N à l’ouverture d’une nouvelle fenêtre.
Ctrl+OOuvrir une carte (explorateur de cartes).
Ctrl+SEnregistrer. Demande un nom la première fois.
Ctrl+Shift+SEnregistrer sous.
Ctrl+ZAnnuler.
Ctrl+Y ou Ctrl+Shift+ZRétablir.

Affichage et éditeur

ToucheAction
GAfficher ou masquer la grille des cellules.
PActiver la superposition de cheminement (dernier mode utilisé, Combined au départ) ou la désactiver.
MAfficher ou masquer les positions de départ, les régions et les marqueurs.
HMasquer ou afficher les panneaux de l’éditeur.
F1Ouvrir Shortcuts & Help.
F5Lancer un test en jeu, ou terminer celui qui est en cours.
Esc (pendant un test en jeu)Terminer le test en jeu et revenir à l’éditeur.
F2 (le paramètre Toggle Key)Afficher ou masquer l’éditeur entier. Cette touche est sans effet pendant un test en jeu.

Sélection de décors (outil Select Decor uniquement)

SaisieAction
Cliquer / tracer un rectangle de sélectionSélectionner des objets.
Shift + clic / rectangleAjouter des objets à la sélection ou les en retirer.
Faire glisser un objet sélectionnéDéplacer la sélection. Le glissement complet constitue une seule étape d’annulation. Appuyer sur Esc pendant le glissement remet les objets à leur place. Les objets verrouillés ne peuvent pas être déplacés.
Cliquer sur un objet qui fait partie d’une sélection multipleSélectionner uniquement cet objet.
Delete / BackspaceSupprimer les objets sélectionnés.
Ctrl+DDupliquer la sélection, décalée d’une cellule en diagonale (+X et +Z).
Ctrl+ASélectionner tous les objets non verrouillés.
EscVider la sélection.

Ce que fait la touche Esc

Esc exécute la première des actions suivantes qui s’applique :

  1. Ferme un menu déroulant ouvert.
  2. Retire le focus clavier d’un champ de texte ou d’un curseur.
  3. Ferme la boîte de dialogue au premier plan.
  4. Annule le glissement de décors (les objets reviennent à leur place).
  5. Annule le trait en cours (notification Stroke cancelled).
  6. Vide la sélection de décors (outil Select Decor).
  7. Réaffiche les panneaux s’ils ont été masqués avec H.

Les raccourcis ne font rien ? Tant qu’un champ de texte a le focus clavier, les touches de lettres écrivent dans ce champ. Tant qu’une boîte de dialogue est ouverte, seules les touches Enter et Esc fonctionnent. Cliquez sur la carte ou appuyez sur Esc, puis réessayez. La peinture et le zoom à la molette sont également bloqués tant que le pointeur survole un panneau.

La caméra intégrée de l’éditeur

Lorsque l’option Use Built In Camera est activée, l’éditeur ajoute un composant RTSRuntimeEditorCamera à la caméra cible. Cette caméra orbitale tourne autour d’un point focal situé au sol. Elle reste dans les limites du terrain, élargies d’une marge, ne descend jamais sous le sol et s’incline d’autant plus vers le bas que vous dézoomez. Elle utilise le temps non mis à l’échelle : elle continue donc de fonctionner lorsque votre jeu est en pause (Time.timeScale = 0). L’éditeur active la caméra tant qu’il est visible, et la désactive lorsqu’il est masqué ainsi que pendant les tests en jeu. Après un test en jeu, la caméra reprend la position qu’elle avait auparavant.

Pour modifier son comportement, ajoutez vous-même le composant RTSRuntimeEditorCamera à votre caméra (Add Component ▸ RTS Terrain Studio ▸ In-Game Editor Camera) et réglez ses champs. L’éditeur utilise alors ce composant existant au lieu d’en ajouter un nouveau.

ParamètrePar défautDescription
Movement
Pan Speed18Vitesse de déplacement au clavier, en mètres par seconde, à la hauteur minimale. Elle augmente avec la hauteur.
Fast Multiplier2.5Multiplicateur de la vitesse de déplacement tant que Shift est maintenue enfoncée.
Edge PandésactivéDéplace la caméra lorsque la souris touche le bord de l’écran.
Edge Pan Margin12Largeur de la bordure d’écran utilisée pour le défilement par les bords, en pixels.
Rotate Speed100Vitesse de rotation de Q / E, en degrés par seconde.
Mouse Rotate Speed0.25Rotation appliquée par Alt + glissement de la souris, en degrés par pixel.
Zoom
Min Height8Hauteur minimale de la caméra au-dessus du point focal, en mètres.
Max Height120Hauteur maximale de la caméra au-dessus du point focal, en mètres.
Zoom Step0.14Variation de hauteur par cran de molette, exprimée en fraction de la hauteur actuelle.
Zoom Towards CursoractivéZoome vers le point situé sous le curseur plutôt que vers le centre de l’écran.
Min Pitch40Inclinaison en degrés sous l’horizon, à la hauteur minimale.
Max Pitch70Inclinaison à la hauteur maximale.
Pitch Curvecourbe ease-in-outInterpolation entre Min Pitch (0) et Max Pitch (1) selon la hauteur normalisée.
Limits & Smoothing
Ground Clearance3Distance minimale autorisée entre la caméra et le sol situé en dessous, en mètres.
Bounds Padding8Espace supplémentaire autour du terrain dans lequel le point focal peut se déplacer, en mètres.
Smooth Time0.1Temps de lissage en secondes (0 = aucun lissage).

Par le code, RTSRuntimeEditor.EditorCamera renvoie le composant, ou null si la caméra intégrée est désactivée :

MembreDescription
void Focus(Vector3 worldPosition, bool instant = false)Déplace le point focal vers une position dans l’espace monde, en douceur sauf si instant vaut true.
void FrameTerrain(bool instant = false)Centre la caméra au-dessus du terrain et dézoome pour en montrer la plus grande partie. Les nouvelles cartes et les cartes redimensionnées sont cadrées automatiquement.
void SnapToTargets()Passe directement à la position, à la rotation et à la hauteur cibles, sans lissage.
Vector3 FocusPoint, float Yaw, float HeightL’orbite actuelle (lecture seule).
bool IsDragging, bool WantsAltDragVaut true tant que la caméra est déplacée par glissement, ou tant que la touche Alt est enfoncée.
bool PointerBlocked, bool KeyboardBlockedDéfinies par l’éditeur à chaque frame tant que le pointeur survole l’interface, qu’un champ de texte a le focus ou qu’une boîte de dialogue est ouverte.
RTSTerrain TerrainLe terrain utilisé pour les limites et la hauteur du sol.

Utiliser votre propre script de caméra pendant l’édition : désactivez Use Built In Camera. L’éditeur se contente alors de lire la caméra cible pour la sélection sous le curseur et les gizmos. Veillez à ce que votre caméra ignore les entrées tant que RTSRuntimeEditor.IsPointerOverUI vaut true, afin que le défilement d’un panneau ne fasse pas zoomer la caméra en même temps.

Play Test : tester la carte dans votre jeu

Play Test (F5) transforme momentanément l’éditeur en votre jeu : l’interface de l’éditeur s’efface, votre code de gameplay fait apparaître des unités et active sa caméra, et le joueur peut essayer la carte. Esc, F5 ou Back to Editor termine le test, et la carte retrouve exactement son état antérieur. Unités, bâtiments, arbres récoltés, modifications du cheminement : tout disparaît.

Un test en jeu dans l’éditeur en jeu, avec des unités, la mini-carte, le HUD et le panneau des commandes
Un test en jeu lancé depuis l’éditeur en jeu : le jeu de démo fait apparaître des unités, la mini-carte affiche le brouillard de guerre et Esc ramène à l’éditeur.

L’éditeur ne sait rien de votre jeu. Il signale le début et la fin d’un test en jeu via la classe statique RTSRuntimeEditorEvents, et c’est votre jeu qui décide de la marche à suivre. Le composant d’exemple RTSDemoGame (GameObject ▸ RTS Terrain Studio ▸ Demo Game) écoute déjà ces événements. Ajoutez-le à votre scène d’édition pour obtenir des unités, le brouillard de guerre, une mini-carte et un HUD pendant les tests en jeu, sans écrire de code.

Ce qui se passe, étape par étape

QuandL’éditeur…
Vous appuyez sur Play Test
  1. termine le trait en cours,
  2. prend une copie complète (instantané) de la carte et mémorise le chemin du fichier ainsi que l’état des modifications non enregistrées,
  3. ferme les boîtes de dialogue et les menus, masque l’aperçu du pinceau, les gizmos, la grille et la superposition de cheminement,
  4. désactive sa caméra intégrée et remplace les panneaux par la petite barre de test en jeu,
  5. déclenche RTSRuntimeEditorEvents.PlaytestChanged(true). Votre jeu démarre.
Pendant le test en jeuIgnore toutes les saisies d’édition, les commandes d’annulation et de fichier (elles affichent Stop the play test first.) ainsi que la touche de bascule. Le gameplay peut modifier librement la carte.
Esc, F5 ou Back to Editor
  1. déclenche d’abord RTSRuntimeEditorEvents.PlaytestChanged(false), pour que votre jeu puisse faire son nettoyage tant que la carte du test en jeu est encore chargée,
  2. recopie l’instantané dans la carte, ce qui reconstruit le terrain,
  3. restaure le chemin du fichier et l’état des modifications non enregistrées, les panneaux, la vue de l’éditeur et la caméra intégrée,
  4. affiche la notification Play test ended: the map was restored.

Historique d’annulation : l’éditeur recopie l’instantané dans la même instance de carte, si bien que votre historique d’annulation est conservé après les tests en jeu. Si le gameplay a remplacé, rechargé ou redimensionné la carte pendant le test, l’instantané est chargé à la place comme une nouvelle carte. La notification indique alors (undo history was reset).

Référence de RTSRuntimeEditorEvents

RTSRuntimeEditorEvents se trouve dans le code d’exécution principal (Runtime/Core). Votre code de gameplay compile et fonctionne même si vous retirez l’éditeur en jeu d’un projet.

MembreDescription
static bool IsPlaytestingVaut true tant qu’un test en jeu est en cours.
static event Action<bool> PlaytestChangedDéclenché au début (true) ou à la fin (false) d’un test en jeu.
static event Action<RTSTerrain> MapOpenedDéclenché après que l’éditeur en jeu a ouvert une carte depuis un fichier ou créé une nouvelle carte.
static void ConsumeEscape()Appelez cette méthode lors d’une frame où votre code de gameplay a lui-même utilisé Esc, par exemple pour annuler le placement d’un bâtiment. L’éditeur ne met alors pas fin au test en jeu pendant cette frame.
static bool EscapeConsumedThisFrameVaut true lorsque ConsumeEscape a été appelée pendant la frame en cours.
static void SetPlaytesting(bool playtesting)Définit IsPlaytesting et déclenche PlaytestChanged. C’est l’éditeur qui l’appelle. Pour lancer un test depuis votre propre code, appelez plutôt RTSRuntimeEditor.StartPlaytest(), car seul l’éditeur prend l’instantané de la carte.
static void RaiseMapOpened(RTSTerrain terrain)Déclenche MapOpened. C’est l’éditeur qui l’appelle.

Les abonnements aux événements sont supprimés au démarrage du Play Mode. Abonnez-vous dans OnEnable (ou Awake / Start) d’un objet de scène, et non dans un constructeur statique ou un script d’éditeur, puis désabonnez-vous dans OnDisable.

Exemple : faire apparaître des unités pour un test en jeu

Ce composant fait apparaître une unité par position de départ au début d’un test en jeu et active vos systèmes de gameplay (caméra RTS, brouillard de guerre, HUD). À la fin du test, il supprime les unités et désactive de nouveau ces systèmes. Ajoutez-le à n’importe quel objet de la scène de l’éditeur, puis assignez-lui un prefab d’unité.

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

/// <summary>Starts a tiny "game" whenever the in-game editor runs a play test.</summary>
public class MyPlaytestGame : MonoBehaviour
{
    [Tooltip("Spawned once at every start location of the map.")]
    [SerializeField] GameObject unitPrefab;

    [Tooltip("Gameplay components that should only run during a play test, " +
             "for example your RTS camera script, the fog of war manager or your HUD.")]
    [SerializeField] Behaviour[] gameplaySystems = new Behaviour[0];

    readonly List<GameObject> spawned = new List<GameObject>();

    void OnEnable()
    {
        // Static event: always pair += in OnEnable with -= in OnDisable.
        RTSRuntimeEditorEvents.PlaytestChanged += HandlePlaytestChanged;
        SetSystemsEnabled(RTSRuntimeEditorEvents.IsPlaytesting);
    }

    void OnDisable()
    {
        RTSRuntimeEditorEvents.PlaytestChanged -= HandlePlaytestChanged;
        DespawnAll();
    }

    void HandlePlaytestChanged(bool playtesting)
    {
        if (playtesting) StartGame();
        else StopGame();
    }

    void StartGame()
    {
        var terrain = RTSTerrain.Main;          // the first RTS Terrain in the scene
        if (terrain == null || terrain.Map == null) return;

        foreach (var start in terrain.Map.StartLocations)
        {
            // Start locations are stored in map-local space: convert to world space
            // and put the unit on the ground.
            Vector3 position = terrain.LocalToWorld(start.position);
            position.y = terrain.GetHeight(position);
            Quaternion rotation = Quaternion.Euler(0f, terrain.transform.eulerAngles.y + start.yaw, 0f);

            var unit = Instantiate(unitPrefab, position, rotation);
            unit.name = "Player " + (start.player + 1) + " Unit";
            spawned.Add(unit);
        }
        SetSystemsEnabled(true);
    }

    void StopGame()
    {
        // Called BEFORE the editor restores the map, so everything is still in place.
        DespawnAll();
        SetSystemsEnabled(false);
    }

    void DespawnAll()
    {
        foreach (var unit in spawned)
            if (unit != null) Destroy(unit);
        spawned.Clear();
    }

    void SetSystemsEnabled(bool enabled)
    {
        foreach (var system in gameplaySystems)
            if (system != null) system.enabled = enabled;
    }
}

StartLocation.position est un Unity.Mathematics.float3, qui se convertit automatiquement en Vector3. Si votre script se trouve dans sa propre assembly definition, ajoutez-y des références à RTSTerrainStudio.Runtime et à Unity.Mathematics.

Exemple : partager la touche Esc avec votre jeu

De nombreux RTS utilisent Esc pour annuler un ordre ou le placement d’un bâtiment. Appelez ConsumeEscape() dans la frame où vous utilisez la touche, et l’éditeur ne mettra pas fin au test en jeu. L’éditeur effectue cette vérification dans LateUpdate : l’ordre d’exécution de vos scripts n’a donc aucune importance.

using UnityEngine;
using RTSTerrainStudio;

public class MyBuildingPlacement : MonoBehaviour
{
    bool placing;   // true while a building ghost follows the cursor

    void Update()
    {
        if (placing && RTSInput.GetKeyDown(RTSKey.Escape))
        {
            placing = false;                          // cancel the placement ...
            RTSRuntimeEditorEvents.ConsumeEscape();   // ... and keep the play test running
        }
    }
}

Les scripts d’exemple RTSBuildingPlacementDemo, RTSCommandController et RTSSelectionManager le font déjà. Dans la démo, un premier appui sur Esc vide la sélection et le suivant ramène à l’éditeur.

Liste de vérification du test en jeu pour votre propre jeu

  • Gardez votre script de caméra RTS, votre gestionnaire de brouillard de guerre et votre HUD désactivés dans la scène et activez-les dans PlaytestChanged(true). La scène de démo fait de même avec RTSCameraController et RTSFogOfWarManager.
  • La caméra intégrée de l’éditeur est désactivée pendant le test : votre script de caméra pilote donc entièrement la caméra.
  • Dans PlaytestChanged(false), supprimez tout ce que vous avez fait apparaître. Vous n’avez pas besoin d’annuler les modifications de la carte, car l’éditeur la restaure.
  • En multijoueur (intégration Mirror), les modifications de la carte effectuées pendant une partie ne sont pas transmises en direct. Appelez RTSNetworkMapSync.SendMapToAll() pour renvoyer la carte.

Enregistrer et charger des cartes dans les builds

Où sont enregistrées les cartes

Les cartes sont enregistrées dans RTSRuntimeEditor.MapsFolder. Par défaut, il s’agit du dossier Maps situé dans RTSMapSerializer.StorageRoot ; ce dossier est également accessible via RTSMapSerializer.DefaultMapsFolder. StorageRoot correspond à Application.persistentDataPath sur toutes les plateformes, sauf sur le web. Le dossier est créé lors du premier enregistrement. Unity détermine persistentDataPath en fonction de la plateforme. Sous Windows, il se trouve dans %USERPROFILE%\AppData\LocalLow\<Company>\<Product>, d’après les noms de société et de produit définis dans les Player Settings. Sur les plateformes de bureau, la commande File ▸ Show Maps Folder ouvre ce dossier, et l’explorateur de cartes affiche le chemin complet.

Dans les builds web, les cartes sont conservées dans le stockage du navigateur, et les commandes File ▸ Download Map et File ▸ Import Map... permettent de les transférer entre le navigateur et l’ordinateur du joueur. Voir Les cartes dans le navigateur.

Chaque carte comprend jusqu’à deux fichiers :

FichierExempleDescription
CarteGlacier Pass (2v2).rtsmapLa carte complète : hauteurs, falaises, textures, eau, végétation, décors, cheminement, positions de départ, régions, marqueurs, informations de la carte et environnement. Elle utilise le même format que les cartes dans l’éditeur Unity.
AperçuGlacier Pass (2v2).preview.pngUne image de mini-carte de 192 × 192 pour l’explorateur de cartes. Elle n’est enregistrée que si l’option Write Preview Images est activée, et elle est supprimée en même temps que la carte.

Le nom du fichier est dérivé du nom de la carte. Les caractères interdits dans les noms de fichiers sont remplacés par _, les points en fin de nom sont supprimés et un nom vide devient New Map.

Modifications non enregistrées

  • Tant qu’il reste des modifications non enregistrées, la barre d’état affiche un point devant le nom de la carte.
  • Les commandes New Map, Open et Quit demandent d’abord confirmation : Save, Don't Save ou Cancel.
  • Si le joueur ferme la fenêtre du jeu alors que la carte contient des modifications non enregistrées, l’éditeur annule la fermeture et demande lui aussi confirmation, sauf si l’option Confirm Quit With Unsaved Changes est désactivée. Dans un navigateur web, c’est le navigateur lui-même qui affiche à la place la question Leave site? avant la fermeture ou le rechargement de l’onglet ; ce comportement dépend de la même option.
  • Un test en jeu ne change rien à l’état d’enregistrement. L’éditeur le restaure en même temps que la carte.
  • La carte avec laquelle la scène démarre (l’asset de carte assigné au terrain) n’a pas encore de fichier dans le dossier des cartes : le premier Ctrl+S demande donc un nom.

Tester dans l’éditeur Unity : si vous modifiez une carte avec l’éditeur en jeu en Play Mode, puis quittez le Play Mode, Unity demande Save map changes made in Play Mode?. Le bouton Save enregistre les modifications dans l’asset de carte du terrain, au sein de votre projet. Les cartes enregistrées avec Ctrl+S vont en revanche dans le dossier des cartes. Vous pouvez copier un tel fichier .rtsmap dans votre dossier Assets pour l’utiliser comme asset de carte.

Livrer des cartes avec votre jeu

L’explorateur de cartes n’affiche que le contenu du dossier des cartes. Pour fournir aux joueurs vos propres cartes comme point de départ, copiez-les dans ce dossier au premier lancement. Cet exemple copie tous les fichiers de StreamingAssets/Maps (cartes et images d’aperçu) sans jamais écraser une version modifiée par un joueur :

using System.IO;
using UnityEngine;
using RTSTerrainStudio;

/// <summary>Copies bundled maps into the in-game editor's maps folder (desktop platforms).</summary>
public class InstallBundledMaps : MonoBehaviour
{
    [SerializeField] RTSRuntimeEditor editor;

    void Awake()
    {
        // Put your .rtsmap files (and optional .preview.png files) into Assets/StreamingAssets/Maps.
        string source = Path.Combine(Application.streamingAssetsPath, "Maps");

        // On Android and WebGL, StreamingAssets is not a normal folder: use UnityWebRequest there instead.
        if (!Directory.Exists(source)) return;

        string target = editor.MapsFolder;   // StorageRoot/Maps unless you changed it
        Directory.CreateDirectory(target);

        foreach (string file in Directory.GetFiles(source))
        {
            if (file.EndsWith(".meta")) continue;   // only matters when running in the Unity editor
            string destination = Path.Combine(target, Path.GetFileName(file));
            if (!File.Exists(destination)) File.Copy(file, destination);
        }
    }
}

Jouer sur des cartes créées par les joueurs dans votre jeu

Votre jeu peut charger des cartes depuis le dossier des cartes sans passer par l’éditeur, par exemple dans un salon de parties personnalisées. RTSMapSerializer.TryReadHeaderFromFile lit le nom, la taille, l’auteur et le nombre de joueurs sans charger toute la carte. Pour la charger, utilisez RTSTerrain.LoadFromFile.

using System;
using System.IO;
using UnityEngine;
using RTSTerrainStudio;

public static class MapLobby
{
    /// <summary>Logs every map in the default maps folder.</summary>
    public static void ListMaps()
    {
        string folder = RTSMapSerializer.DefaultMapsFolder;
        if (!Directory.Exists(folder)) return;

        foreach (string path in Directory.GetFiles(folder, "*" + RTSMapSerializer.FileExtension))
        {
            // Reads only the small header: fast, even for large maps.
            if (RTSMapSerializer.TryReadHeaderFromFile(path, out RTSMapHeader header))
                Debug.Log(header.name + " by " + header.author + ": " + header.width + " x " + header.height +
                          " cells, " + header.maxPlayers + " players, modified " + header.Modified);
        }
    }

    /// <summary>Loads a map file into the main terrain. Returns false when the file cannot be read.</summary>
    public static bool Play(string path)
    {
        var terrain = RTSTerrain.Main;
        if (terrain == null) return false;
        try
        {
            terrain.LoadFromFile(path);   // throws when the file is missing or damaged
            return true;
        }
        catch (Exception e)
        {
            Debug.LogError("Could not load " + path + ": " + e.Message);
            return false;
        }
    }
}

Une carte enregistre son contenu sous forme d’identifiants (calques de sol, prototypes de végétation et de décor). Les cartes créées par les joueurs ne s’affichent correctement qu’avec le même tileset, la même bibliothèque de végétation et la même bibliothèque de décors que le terrain de la scène de l’éditeur. Assignez donc les mêmes assets au terrain dans les scènes de votre jeu.

Piloter l’éditeur par le code

Tout ce que propose l’interface peut aussi se faire par le code, via RTSRuntimeEditor (espace de noms RTSTerrainStudio). Les membres les plus utiles :

MembreDescription
État
bool EditorVisible { get; set; }Affiche ou masque l’éditeur entier (comme la touche d’affichage). Le masquer termine le trait en cours, ferme les boîtes de dialogue et rend au jeu le contrôle de la vue du terrain.
bool PanelsVisible { get; set; }Masque uniquement les panneaux (H). L’édition reste possible.
bool IsPlaytesting { get; }Vaut true tant qu’un test en jeu lancé par cet éditeur est en cours.
RTSKey ToggleKey { get; set; }La touche qui affiche et masque l’éditeur. RTSKey.None la désactive et masque le bouton de fermeture (sauf dans les navigateurs web et sur les téléphones et tablettes, voir HasReliableFunctionKeys).
RTSTerrain Terrain { get; set; }Le terrain édité. Lui assigner un terrain fait basculer l’éditeur sur celui-ci et vide l’historique d’annulation.
Camera TargetCamera { get; set; }La caméra utilisée pour déterminer ce qui se trouve sous le pointeur et pour afficher les gizmos.
RTSRuntimeEditorCamera EditorCamera { get; }La caméra intégrée, ou null.
RTSEditSession Session { get; }La session d’édition : outils, pinceau, symétrie, sélection, annulation.
ToolCategory ActiveCategory { get; }La catégorie de l’outil actif.
bool HasHover, Vector3 HoverWorldPositionIndique si le pointeur survole le terrain et donne la position, dans l’espace monde, du point situé sous lui.
bool IsPointerOverUI { get; }Vaut true tant que le pointeur se trouve au-dessus d’un panneau de l’éditeur.
bool ShowGrid, bool ShowMarkersLes options activées ou désactivées par G et M.
PathingOverlayMode? PathingOverlay, float OverlayOpacityLa superposition de cheminement (null = désactivée) et son opacité (de 0 à 1).
string MapsFolder { get; set; }Le dossier des cartes. Une valeur vide désigne RTSMapSerializer.DefaultMapsFolder ; un chemin relatif est interprété par rapport à RTSMapSerializer.StorageRoot.
bool ShowQuitCommand, string ManualUrlL’entrée de menu File ▸ Quit et le lien vers le manuel (voir l’Inspector).
bool HasManual { get; }Vaut true si la commande Open Manual a une page à ouvrir.
static bool CanShowFolders, static bool CanQuitApplicationVérifications liées à la plateforme : un explorateur de fichiers de bureau est disponible, et il est possible de quitter l’application (pas sur WebGL, iOS ni Android).
static bool RunsInBrowser, static bool StoresMapsInBrowserRunsInBrowser vaut true dans les builds web, où les limites du navigateur s’appliquent et où le raccourci de la commande New Map est Alt+N. StoresMapsInBrowser vaut true quand les cartes sont conservées dans le stockage du navigateur (builds de joueur WebGL). Voir Builds Web (WebGL).
static bool HasReliableFunctionKeysVaut false dans les navigateurs web et sur les plateformes mobiles. Dans ce cas, le bouton de fermeture fait apparaître le bouton Open Map Editor.
VisualElement RootElement, UIDocument Document, RuntimeToolGizmos GizmosLa racine de l’interface de l’éditeur, son document d’interface et le moteur de rendu des gizmos. Tous valent null tant que le composant n’est pas activé.
Commandes
bool SetActiveTool(string toolId)Active un outil d’après son id, par exemple "paint.layer". Renvoie false si l’id n’existe pas.
void SelectCategory(ToolCategory category)Comme les touches numériques : active le dernier outil utilisé dans la catégorie, ou l’outil suivant si la catégorie est déjà active.
RTSTool GetRememberedTool(ToolCategory category)Le dernier outil utilisé dans une catégorie, ou son premier outil.
void Undo(), void Redo()Annuler et rétablir. Ces méthodes sont sans effet pendant un test en jeu.
bool OpenMap(string path)Charge un fichier .rtsmap. Les modifications non enregistrées sont abandonnées sans confirmation.
bool SaveMap(string path)Enregistre la carte à l’emplacement indiqué, ajoute .rtsmap si nécessaire et écrit l’image d’aperçu.
bool SaveCurrent()Comme Ctrl+S. Renvoie true si la carte a été enregistrée immédiatement. Si la carte n’a pas encore de fichier, la méthode ouvre la boîte de dialogue Save As et renvoie false.
void NewMap(MapCreationSettings settings)Crée une nouvelle carte plate sans demander quoi faire des modifications non enregistrées.
bool DeleteMapFile(string path)Supprime un fichier de carte et son image d’aperçu.
ShowNewMapDialog(), ShowOpenDialog(), ShowSaveAsDialog(), ShowGenerateDialog(), ShowMapInfoDialog(), ShowResizeDialog(), ShowHelp()Ouvrent les boîtes de dialogue avec le même comportement que les menus. New et Open demandent d’abord quoi faire des modifications non enregistrées.
void StartPlaytest(), void StopPlaytest()Démarrent ou terminent un test en jeu.
void TogglePathingOverlay()Comme P.
void DeleteSelectedDecor(), void DuplicateSelectedDecor()Suppriment ou dupliquent la sélection de décors. Chaque appel constitue une seule étape d’annulation.
void ShowMapsFolder(), void OpenManual(), void Quit()Les commandes des menus File et Help. Quit demande quoi faire des modifications non enregistrées.
bool DownloadMap(), void ImportMap()Builds web uniquement : les commandes File ▸ Download Map et File ▸ Import Map.... Les navigateurs n’affichent le sélecteur de fichiers qu’en réponse à un clic ou à un appui sur une touche : appelez donc ImportMap depuis un gestionnaire de clic.
void ShowToast(string message, ToastType type = ToastType.Info)Affiche une notification. Les valeurs de ToastType sont Info, Success, Warning ou Error.
void ShowToast(string message, ToastType type, string key)Si une notification portant la même clé est encore visible, elle est mise à jour et aucune nouvelle notification n’est ajoutée.
Événements
event Action<string> MapSavedAprès l’enregistrement d’une carte (chemin complet du fichier).
event Action<string> MapLoadedAprès l’ouverture d’une carte depuis un fichier (chemin complet) ou sa création (null).
event Action<bool> VisibilityChangedQuand EditorVisible change.

MapLoaded et RTSRuntimeEditorEvents.MapOpened sont déclenchés pour File ▸ New et Open. Pour réagir à chaque changement de carte, y compris Resize et les cartes chargées par votre propre code, abonnez-vous à RTSTerrain.MapLoaded sur le terrain.

Exemple : ouvrir l’éditeur depuis votre propre menu

Beaucoup de jeux ouvrent l’éditeur de cartes depuis le menu principal plutôt qu’avec une touche. Désactivez la touche d’affichage, ouvrez l’éditeur depuis un bouton et ajoutez un bouton « Back to Menu » à la couche supérieure de l’éditeur :

using UnityEngine;
using UnityEngine.UIElements;
using RTSTerrainStudio;

public class MapEditorLauncher : MonoBehaviour
{
    [SerializeField] RTSRuntimeEditor editor;   // with "Start Visible" turned off
    [SerializeField] GameObject mainMenu;       // your own menu UI

    void Start()
    {
        // No F2 key: the game decides when the editor is shown (on desktop this also hides the close button).
        editor.ToggleKey = RTSKey.None;

        // RootElement exists once the editor component is enabled (it is created in its OnEnable).
        // If you disable and enable the editor component later, its UI is rebuilt: add the button again.
        var back = new Button(BackToMenu) { text = "Back to Menu" };
        back.AddToClassList("rts-button");             // use the editor's button style
        back.style.position = Position.Absolute;
        back.style.right = 16;
        back.style.bottom = 56;                        // just above the status bar
        editor.RootElement.Add(back);                  // hidden together with the editor

        editor.VisibilityChanged += visible => mainMenu.SetActive(!visible);
    }

    /// <summary>Hook this up to a "Map Editor" button in your main menu.</summary>
    public void OpenEditor() => editor.EditorVisible = true;

    void BackToMenu()
    {
        if (editor.IsPlaytesting) editor.StopPlaytest();
        editor.EditorVisible = false;
        editor.ShowToast("Map editor closed", ToastType.Info);
    }
}

Exemple : masquer le HUD de votre jeu pendant l’édition

using UnityEngine;
using RTSTerrainStudio;

public class HudVisibility : MonoBehaviour
{
    [SerializeField] RTSRuntimeEditor editor;
    [SerializeField] GameObject hud;

    void OnEnable()
    {
        editor.VisibilityChanged += HandleVisibilityChanged;
        RTSRuntimeEditorEvents.PlaytestChanged += HandlePlaytestChanged;
        Refresh();
    }

    void OnDisable()
    {
        editor.VisibilityChanged -= HandleVisibilityChanged;
        RTSRuntimeEditorEvents.PlaytestChanged -= HandlePlaytestChanged;
    }

    void HandleVisibilityChanged(bool visible) => Refresh();
    void HandlePlaytestChanged(bool playtesting) => Refresh();

    // The editor stays "visible" during a play test (only its panels make room),
    // so both states are checked.
    void Refresh() => hud.SetActive(!editor.EditorVisible || RTSRuntimeEditorEvents.IsPlaytesting);
}

Personnaliser l’interface

Où se trouvent les styles

Fichier (dans Resources/RTSTerrainStudio/UI)Chargé en tant queUtilité
RTSRuntimeTheme.tssRTSRuntimeEditor.ThemeResourcePath = "RTSTerrainStudio/UI/RTSRuntimeTheme"La feuille de style du thème. Elle importe le thème d’exécution par défaut de Unity (curseurs, cases à cocher, champs de texte, vues à défilement) et RTSRuntimeEditor.uss.
RTSRuntimeEditor.ussRTSRuntimeEditor.StyleSheetResourcePath = "RTSTerrainStudio/UI/RTSRuntimeEditor"Tous les styles de l’éditeur. Chaque nom de classe commence par rts-, et les sélecteurs de type comme Label ne s’appliquent qu’aux descendants de .rts-root : l’éditeur ne modifie donc jamais l’apparence de l’interface de votre jeu, même si votre panneau utilise ce thème.

Si vos Panel Settings utilisent un autre thème, l’éditeur ajoute RTSRuntimeEditor.uss à sa propre racine, si bien que son apparence reste la même dans les deux cas.

Variables de couleur

Toutes les couleurs sont des variables définies sur .rts-root. Modifiez-les pour changer l’apparence de tout l’éditeur :

VariablePar défautSert à
--rts-panelrgba(20, 24, 30, 0.92)Fonds des panneaux (barre supérieure, barre d’outils, panneau d’outil, barre d’état).
--rts-panel-solidrgb(22, 26, 33)Fonds opaques (boîtes de dialogue, fenêtres contextuelles).
--rts-raised / --rts-hover / --rts-pressedblanc à 6 % / 11 % / 3 %États des boutons.
--rts-border / --rts-border-strongblanc à 8 % / 16 %Bordures et séparateurs.
--rts-inputrgba(0, 0, 0, 0.32)Fonds des champs de texte et des curseurs.
--rts-text / --rts-text-dim / --rts-text-faintrgb(226, 231, 238) / rgb(150, 160, 174) / rgb(104, 114, 128)Texte, texte secondaire, indications.
--rts-accent / --rts-accent-hover / --rts-accent-dim / --rts-accent-textdéclinaisons du bleu rgb(61, 169, 252)Outils sélectionnés, boutons principaux, Play Test.
--rts-danger / --rts-danger-dimrgb(239, 83, 80)Boutons de suppression et notifications d’erreur.
--rts-warning / --rts-successrgb(255, 183, 77) / rgb(102, 187, 106)Notifications d’avertissement et de réussite.
--rts-radius / --rts-radius-small6px / 4pxRayon d’arrondi des coins.

Changer l’apparence sans toucher aux fichiers du package

Ne modifiez pas directement les fichiers du dossier Resources du package : une mise à jour du package les écrase. Placez plutôt vos modifications dans votre propre feuille de style.

  1. Créez une feuille de style dans votre projet, par exemple Assets/UI/MyEditorSkin.uss, et redéfinissez les variables. Le sélecteur :root .rts-root est plus spécifique que le sélecteur .rts-root du package, donc vos valeurs l’emportent :
    /* MyEditorSkin.uss: an orange accent and warmer panels */
    :root .rts-root {
        --rts-accent: rgb(255, 160, 50);
        --rts-accent-hover: rgb(255, 190, 110);
        --rts-accent-dim: rgba(255, 160, 50, 0.22);
        --rts-accent-text: rgb(255, 210, 160);
        --rts-panel: rgba(30, 24, 20, 0.94);
    }
  2. Ajoutez la feuille au document d’interface de l’éditeur au démarrage :
    using UnityEngine;
    using UnityEngine.UIElements;
    using RTSTerrainStudio;
    
    public class EditorSkin : MonoBehaviour
    {
        [SerializeField] RTSRuntimeEditor editor;
        [SerializeField] StyleSheet skin;   // drag MyEditorSkin.uss here
    
        void Start()
        {
            // The document root holds the editor and its toast layer, so both get the new colours.
            editor.Document.rootVisualElement.styleSheets.Add(skin);
        }
    }

La même approche permet aussi de modifier le style de parties précises de l’interface. Les classes principales sont .rts-topbar, .rts-leftbar, .rts-toolpanel, .rts-statusbar, .rts-dialog, .rts-popup, .rts-toast (avec les variantes --success, --warning et --error), .rts-hint, .rts-playtest-bar, .rts-button et .rts-selected. Le UI Toolkit Debugger (Window ▸ UI Toolkit ▸ Debugger) affiche les classes de chaque élément pendant que le jeu tourne.

Panel Settings, mise à l’échelle et ordre d’affichage

  • Champ Panel Settings vide (par défaut) : l’éditeur crée ses propres Panel Settings avec le thème RTS. L’interface s’adapte à la hauteur de l’écran (référence 1920 × 1080), mais jamais en dessous de 85 %. Ui Scale multiplie le résultat, ce qui est utile pour les écrans 4K ou pour les joueurs qui veulent un texte plus grand.
  • Vos propres Panel Settings : assignez un asset pour gérer vous-même le thème et la mise à l’échelle. Tools ▸ RTS Terrain Studio ▸ Create Demo Content crée un asset prêt à l’emploi dans Resources/RTSTerrainStudio/UI/RTSRuntimePanelSettings.asset (thème RTS, mise à l’échelle selon la taille de l’écran, 1920 × 1080). La scène In-Game Editor Demo l’utilise.
  • Enforce Minimum UI Scale (option activée par défaut) : si votre asset s’adapte à la taille de l’écran et n’effectue pas son rendu dans une texture, l’éditeur travaille avec une copie de celui-ci créée à l’exécution. L’asset lui-même n’est jamais modifié. La copie se met à l’échelle exactement comme l’asset sur les grands écrans, ne descend jamais en dessous de 85 % dans les petites fenêtres, et Ui Scale multiplie son échelle. Son ordre d’affichage est supérieur d’une demi-unité à celui de l’asset, si bien que l’éditeur reste au-dessus d’un HUD de jeu qui utilise le même asset (le HUD dispose alors de son propre panneau). Désactivez l’option pour utiliser l’asset tel quel, par exemple pour partager un même panneau avec l’interface de votre jeu ; Ui Scale et le minimum de 85 % ne s’appliquent plus dans ce cas.
  • Builds web : le minimum de 85 % est mesuré en pixels CSS, si bien que l’interface garde la même taille sur les écrans haute résolution.
  • Sorting Order : 1000 par défaut, pour que l’éditeur passe au-dessus de votre HUD. Diminuez cette valeur si une partie de votre interface doit apparaître au-dessus de l’éditeur.
  • Ajouter vos propres contrôles : ajoutez des éléments à RootElement (voir l’exemple de lanceur ci-dessus). Ils sont masqués en même temps que l’éditeur, et un pointeur placé au-dessus d’eux bloque la peinture, comme au-dessus de n’importe quel autre panneau.

Livrer l’éditeur en jeu avec votre jeu

Parcourez cette liste avant de générer le build de votre jeu avec l’éditeur en jeu.

  1. Lancez Tools ▸ RTS Terrain Studio ▸ Validate Project et corrigez les problèmes signalés. La vérification Shader references est la plus importante pour les builds (voir l’étape suivante).
  2. Les shaders sont inclus via RTSShaderReferences. Unity exclut du build tout shader qu’aucun matériau du build n’utilise. Le package crée la plupart de ses matériaux à l’exécution (terrain, eau, brouillard de guerre, ainsi que les shaders de gizmos de l’éditeur Hidden/RTS Terrain Studio/GizmoLines et Hidden/RTS Terrain Studio/GizmoGhost) ; il conserve donc ces shaders dans l’asset Resources/RTSTerrainStudio/RTSShaderReferences. Cet asset est mis à jour automatiquement après la compilation des scripts, lors de l’import de shaders et avant chaque build de joueur. S’il est absent ou obsolète, utilisez la correction Update du validateur. Sans ces shaders, les contours de pinceau et les aperçus de décor n’apparaissent pas dans le build.
  3. Conservez le dossier Resources/RTSTerrainStudio avec UI/RTSRuntimeTheme.tss, UI/RTSRuntimeEditor.uss et RTSShaderReferences.asset. L’éditeur les charge par leur chemin Resources. Si le thème est absent, la fenêtre Console affiche Controls will be unstyled.
  4. Panel Settings : si vous avez assigné un asset Panel Settings, la scène le référence et il est inclus automatiquement dans le build. Si vous avez laissé le champ vide, les Panel Settings d’exécution chargent le thème depuis Resources (étape 3).
  5. Entrées : l’éditeur fonctionne avec le package Input System comme avec l’ancien Input Manager. Voir Gestion des entrées.
  6. Définissez les options destinées aux joueurs : Manual Url (lien vers votre guide de modding, ou laissez-le vide pour masquer le bouton), Show Quit Command (désactivez-la si votre jeu a son propre menu), Toggle Key et Start Visible.
  7. Dossier des cartes : le dossier Maps par défaut, situé dans RTSMapSerializer.StorageRoot (persistentDataPath), est accessible en écriture sur toutes les plateformes de bureau. Pour fournir des cartes d’exemple aux joueurs, copiez-les à cet endroit au premier lancement (voir Livrer des cartes avec votre jeu).
  8. Builds web : installez le modèle pleine fenêtre et consultez Builds Web (WebGL), qui traite du stockage dans le navigateur, des téléchargements, des touches et de l’hébergement.
  9. Outils personnalisés et élagage du code : si le paramètre Managed Stripping Level est réglé au-dessus de Minimal, marquez vos propres outils avec [Preserve] (voir Élagage du code et outils personnalisés).
  10. Contenu : les joueurs ne peuvent utiliser que le tileset, la bibliothèque de végétation et la bibliothèque de décors assignés au terrain dans la scène de l’éditeur. Ils sont inclus dans le build, car la scène les référence.
  11. Testez un build de développement : peignez, enregistrez, ouvrez, lancez un test en jeu et quittez une fois avec des modifications non enregistrées.

Vous ne livrez pas l’éditeur en jeu ? Son code se trouve dans Runtime/RuntimeEditor, et la prise en charge des menus dans Editor/RuntimeEditorSupport. Un projet qui n’en a pas besoin peut supprimer le dossier Runtime/RuntimeEditor. RTSRuntimeEditorEvents reste dans Runtime/Core ; le code de gameplay qui écoute les tests en jeu compile donc toujours.

Dépannage

ProblèmeCause et solution
Le message No RTS Terrain found s’affiche.La scène ne contient aucun RTS Terrain activé, ou le terrain assigné est désactivé. Ajoutez-en un avec GameObject ▸ RTS Terrain Studio ▸ RTS Terrain ou activez-le.
Le message No camera found s’affiche.Aucune caméra n’a le tag MainCamera et le champ Target Camera est vide. Attribuez ce tag à votre caméra ou assignez-la.
Cliquer sur la carte ne fait rien.Le pointeur se trouve au-dessus d’un panneau, la touche Alt est maintenue enfoncée (rotation de la caméra), une boîte de dialogue est ouverte ou aucun outil n’est actif. Quand aucun outil n’est actif, la barre d’état affiche Pick a tool on the left.
Les raccourcis ne font rien.Un champ de texte a le focus clavier ou une boîte de dialogue est ouverte. Appuyez sur Esc ou cliquez sur la carte.
F5 ou F2 ne fait rien.F5 ne fonctionne que si l’éditeur est visible et qu’aucune boîte de dialogue n’est ouverte. La touche d’affichage est ignorée pendant un test en jeu (terminez-le d’abord avec Esc ou F5) et pendant la saisie dans un champ. Sur Mac et sur de nombreux ordinateurs portables, les touches de fonction servent de touches multimédias : maintenez la touche Fn enfoncée, ou utilisez le bouton Play Test et, dans les builds web, le bouton Open Map Editor.
Esc termine le test en jeu alors que mon jeu a déjà utilisé cette touche.Appelez RTSRuntimeEditorEvents.ConsumeEscape() dans la même frame (voir l’exemple).
Rien ne se passe pendant un test en jeu.Aucun script n’écoute RTSRuntimeEditorEvents.PlaytestChanged. Ajoutez RTSDemoGame ou votre propre composant (voir Play Test).
Après un test en jeu, la notification indique undo history was reset.Votre code de gameplay a remplacé, rechargé ou redimensionné la carte pendant le test. La carte elle-même est correctement restaurée.
L’interface est trop petite ou trop grande.Modifiez Ui Scale. Si vous avez assigné vos propres Panel Settings et qu’ils ne s’adaptent pas à la taille de l’écran, ou si vous avez désactivé Enforce Minimum UI Scale, modifiez plutôt la mise à l’échelle dans cet asset. Dans un build web qui utilise un modèle de taille fixe, installez le modèle pleine fenêtre (voir Le modèle pleine fenêtre).
Mon HUD recouvre l’éditeur, ou l’éditeur recouvre un menu.Ajustez Sorting Order (1000 par défaut).
Les contrôles semblent dépourvus de style (aspect blanc par défaut de Unity).Le thème est introuvable dans un dossier Resources. Restaurez Resources/RTSTerrainStudio/UI.
Les contours de pinceau et les aperçus manquent dans le build.Les shaders de gizmos ont été exclus du build. Lancez Tools ▸ RTS Terrain Studio ▸ Validate Project et mettez à jour les références de shaders.
L’astuce de bienvenue ne réapparaît plus jamais.Le joueur l’a fermée. Utilisez Open Welcome Hint dans la fenêtre F1, ou supprimez la clé PlayerPrefs RTSTerrainStudio.InGameEditor.HintDismissed.
Mes cartes n’apparaissent pas dans l’explorateur de cartes.L’explorateur ne liste que les fichiers .rtsmap placés directement dans le dossier des cartes affiché en haut de celui-ci. Copiez-y les fichiers et cliquez sur Refresh.
Une carte affiche Unreadable or damaged file.Le fichier n’est pas un fichier .rtsmap valide, ou il est tronqué (par exemple à la suite d’une copie interrompue).
Les cartes enregistrées dans un build web ont disparu.Le navigateur les conserve séparément pour chaque site web : à une autre adresse ou après la suppression des données de navigation, le jeu démarre donc sans carte, et Safari peut supprimer les données des sites web qui n’ont pas été utilisés depuis sept jours. Utilisez File ▸ Download Map pour en conserver des copies (voir Les cartes dans le navigateur).
L’éditeur n’a aucun outil dans un build.L’élagage du code les a supprimés. Conservez le fichier Runtime/link.xml du package et marquez vos propres outils avec [Preserve] (voir Élagage du code et outils personnalisés).

Rendu et systèmes du monde

Ce chapitre explique comment une carte devient des pixels : comment le mesh du terrain est construit puis ombré, et comment la végétation, l’eau, les décors et l’éclairage de la scène sont dessinés. Chaque section commence par ce que vous voyez et par les paramètres que vous pouvez modifier. Plus bas, elle aborde l’API de programmation, le contrat du shader et les chiffres de performances dont les programmeurs ont besoin.

Les composants de rendu

Chaque système lit le même objet MapData d’un RTSTerrain et ne reconstruit que ce qu’une modification a changé. Les systèmes sont des composants distincts placés sur le GameObject du terrain. GameObject ▸ RTS Terrain Studio ▸ RTS Terrain les ajoute tous pour vous.

ComposantCe qu’il dessineObjets générésSection
RTSTerrainSol, falaises, rampes (meshes de chunks, un seul matériau partagé), grille des cellules, superpositions et curseur du pinceauRacine « RTS Chunks » avec un enfant par chunkRendu du terrain, Shader de terrain
RTSVegetationRendererHerbe et plantes peintes (détails), arbresObjet masqué « RTS Vegetation Objects » (proxys de collider, arbres en GameObjects)Végétation
RTSWaterRendererSurface d’eau transparente avec couleur selon la profondeur, vagues, réfraction et écumeRacine masquée « RTS Water » avec un enfant par chunk contenant de l’eauEau
RTSDecorManagerAccessoires et doodads, sous forme de GameObjects ou en instanciation GPUConteneur « RTS Decor » pour les objets qu’il fait apparaîtreDécor
RTSEnvironment (facultatif)Rien par lui-même. Il applique à la scène le soleil, la lumière ambiante et le brouillard atmosphérique de la carteAucunEnvironnement

Les objets générés sont marqués DontSave. Ils ne sont jamais écrits dans votre fichier de scène : le fichier .rtsmap est l’unique source de vérité, et tout est reconstruit à partir de lui à l’ouverture de la scène. Si vous cliquez sur un chunk, un arbre ou une surface d’eau générés dans la Scene View, c’est le terrain auquel ils appartiennent qui est sélectionné.

S’il manque l’un des composants de rendu, l’Inspector du RTSTerrain affiche un avertissement (par exemple « No Water Renderer: painted water is not shown. ») avec un bouton Add.

Rendu du terrain

Chunks

La carte est découpée en chunks carrés de 16, 32 (par défaut) ou 64 cellules de côté. Chaque chunk est un GameObject doté d’un MeshFilter, d’un MeshRenderer, d’un MeshCollider facultatif et d’un composant RTSTerrainChunk. Tous les chunks partagent une seule instance de matériau (RTSTerrain.TerrainMaterial), ce qui maintient la compatibilité du terrain avec le SRP Batcher.

  • Les chunks sont stockés ligne par ligne : index = z * ChunkCount.x + x. La dernière ligne et la dernière colonne peuvent être plus petites quand la taille de la carte n’est pas un multiple de la taille de chunk.
  • Une modification ne reconstruit que les chunks qu’elle touche. Chaque rectangle modifié est agrandi d’une cellule, car un changement de vertex affecte aussi les normales et la forme des falaises des cellules voisines. Peindre près de la bordure d’un chunk reconstruit donc aussi le chunk voisin.
  • Peindre les textures de sol ne reconstruit pas les meshes : seules les textures de splat sont mises à jour (voir Résolution de splat).
  • Peindre de l’eau ne reconstruit pas non plus les chunks du terrain. Seul le moteur de rendu de l’eau y réagit.

Le mesh d’un chunk est exprimé dans l’espace local de la carte : les objets chunk ont une transformation locale identité sous la racine masquée RTS Chunks du terrain, laquelle compense l’échelle du terrain ; l’espace objet coïncide donc avec l’espace local de la carte (X/Z de 0 à la taille réelle de la carte, Y vers le haut). Vous pouvez déplacer le transform du terrain et le faire pivoter autour de Y. L’échelle est ignorée.

Génération des meshes

RTSChunkMeshBuilder génère les meshes des chunks avec des jobs Burst et les écrit via Mesh.MeshDataArray :

  1. Les chunks demandés sont regroupés en lots de RTSChunkMeshBuilder.MaxChunksPerBatch (256) chunks au maximum, ce qui limite le pic de consommation mémoire sur les très grandes cartes.
  2. Si seuls quelques chunks doivent être reconstruits (cas typique pendant la peinture), chaque chunk est découpé en bandes de lignes. Les bandes sont générées sur différents threads de travail, puis fusionnées : même la modification d’un seul chunk exploite ainsi tous les cœurs du CPU.
  3. BuildChunkGeometryJob (Burst, parallèle) crée les triangles. Les cellules lisses et les cellules de rampe deviennent une grille régulière de S × S quads (S = Surface Subdivisions). Les cellules de falaise sont tracées sur une sous-grille plus fine (Cliff Subdivisions) avec l’algorithme marching squares. On obtient ainsi des contours arrondis, un sol plat à chaque niveau et des parois verticales entre les niveaux.
  4. Les données de collision sont précalculées en parallèle avec Physics.BakeMesh et assignées aux composants MeshCollider des chunks.
  5. Build termine tout le travail avant de rendre la main, si bien qu’une modification est visible dans la même frame.

Les cellules et les chunks voisins produisent toujours des vertices de bordure identiques au bit près, car la position de chaque vertex ne dépend que de sa position sur la carte. C’est pourquoi il n’y a aucune fissure entre les chunks. Le générateur suit la surface de référence MapGeometryView, également utilisée par les requêtes de hauteur, le cheminement et le moteur de rendu de l’eau. Le sol affiché est donc exactement celui que voit le gameplay.

Le format de vertex est RTSTerrainVertex (28 octets : position, normale et une couleur compactée). La couleur transporte des données pour le shader : r = masque de paroi de falaise, g = type de falaise, b = occlusion ambiante précalculée. Il n’y a ni UV ni tangentes : le shader projette les textures à partir de la position du vertex.

Mise en forme des parois de falaise

Les falaises sont générées de manière procédurale : elles ne nécessitent donc aucune pièce de falaise modélisée par un artiste. Quatre paramètres déterminent l’aspect des parois :

ParamètrePar défautPlageDescription
Cliff Noise0.180–0.5Déplacement horizontal aléatoire des vertices des parois de falaise, en fraction de cellule. Donne aux parois un aspect de roche naturelle. 0 = parois parfaitement lisses.
Cliff Noise Scale1.6≥ 0.1Taille des motifs du bruit de falaise, en unités monde. De petites valeurs donnent une roche fine et déchiquetée ; de grandes valeurs donnent de larges renflements.
Cliff Slant0.120–0.4Recul du bord supérieur d’une falaise, en fraction de cellule. Rend les parois légèrement inclinées au lieu d’être parfaitement verticales.
Cliff Wall Segments31–8Segments verticaux par niveau de falaise. Davantage de segments offrent plus de vertices au bruit (plus de relief), mais coûtent plus de vertices.

Le bruit et l’inclinaison cumulés ne peuvent jamais déplacer un vertex de plus de 45 % d’une cellule (RTSChunkMeshParams.MaxDisplacementFraction). Si la somme des deux paramètres dépasse cette limite, les deux sont réduits ensemble, de sorte que les triangles du sol voisins d’une paroi ne se replient jamais les uns sur les autres. Près des rampes et de la bordure de la carte, le déplacement s’estompe progressivement, si bien que ces bords restent droits.

Le pied des parois est également assombri par l’occlusion ambiante précalculée (couleur de vertex b). Là où deux parois se rejoignent sur un bord de cellule, elles utilisent la même luminosité : les falaises empilées et fusionnées paraissent ainsi sans raccord.

Colliders et requêtes

Avec Collider Mode = MeshCollider (par défaut), chaque chunk reçoit un MeshCollider sur le layer défini par Chunk Layer. Il est reconstruit en même temps que le mesh après chaque modification. Choisissez ce mode si votre jeu s’appuie sur la physique Unity (raycasts physiques, rigidbodies, précalcul du NavMesh).

Avec ColliderMode.None, aucun collider n’est créé. Le terrain reste interrogeable sans physique : RTSTerrain.Raycast, GetHeight, GetNormal, GetCliffLevel, IsWater et GetPathing s’appuient sur la surface de référence analytique, en Edit Mode comme à l’exécution. Vous économisez ainsi la mémoire et le temps de génération (cooking) des colliders.

using RTSTerrainStudio;
using UnityEngine;

/// Finds the terrain point under the mouse, with or without chunk colliders.
public class TerrainPointer : MonoBehaviour
{
    [SerializeField] Camera viewCamera;

    void Update()
    {
        if (viewCamera == null) return;
        Ray ray = viewCamera.ScreenPointToRay(RTSInput.PointerPosition);

        // 1. Physics-free: works even when Collider Mode is None.
        //    RaycastAll tests every RTSTerrain in the scene and returns the nearest hit.
        if (RTSTerrain.RaycastAll(ray, out RTSTerrainHit hit))
        {
            Debug.Log($"Cell {hit.cell} at {hit.point}, cliff level {hit.terrain.GetCliffLevel(hit.point)}");
        }

        // 2. Unity physics: needs Collider Mode = MeshCollider.
        //    RTSTerrainChunk.GetTerrain maps the collider of a chunk back to its terrain.
        if (Physics.Raycast(ray, out RaycastHit physicsHit, 1000f))
        {
            RTSTerrain terrain = RTSTerrainChunk.GetTerrain(physicsHit.collider);
            if (terrain != null) Debug.Log($"Physics hit on terrain '{terrain.name}'");
        }
    }
}

Paramètres de rendu du terrain

Ces paramètres se trouvent dans l’Inspector de RTSTerrain, regroupés dans les sections Chunks & Geometry, Cliff Shape, Physics et Rendering. Toute modification dans l’Inspector reconstruit automatiquement le terrain. Par le code, modifiez terrain.Settings, puis appelez terrain.RebuildAll().

ParamètrePar défautDescription
Chunk Size32Nombre de cellules par côté de chunk (16, 32 ou 64). Des chunks plus petits se reconstruisent plus vite pendant l’édition ; des chunks plus grands réduisent le nombre de draw calls. Voir Choisir la taille de chunk.
Surface Subdivisions2Nombre de quads par côté de cellule sur le sol lisse et les rampes (1–4). 1 = aspect RTS classique, 2–4 = collines plus douces.
Cliff Subdivisions4Résolution de la sous-grille qui sert à tracer les contours arrondis des falaises à l’intérieur d’une cellule de falaise (2–8). Elle est arrondie vers le haut à un nombre pair qui est aussi un multiple de Surface Subdivisions (voir Subdivisions).
Cliff Noise, Cliff Noise Scale, Cliff Slant, Cliff Wall Segmentsvoir Mise en forme des parois de falaiseAspect des parois de falaise.
Collider ModeMeshColliderNone ou MeshCollider (un par chunk, reconstruit après les modifications).
Chunk Layer0 (Default)Layer de GameObject des chunks. Il sert aux colliders et aux culling masks des caméras. Les détails peints sont eux aussi dessinés sur ce layer.
Cast ShadowsOnMode de projection des ombres des renderers des chunks.
Receive ShadowsactivéIndique si les chunks reçoivent des ombres.
Material OverridevideMatériau facultatif utilisé à la place du matériau par défaut (voir Matériaux).
Show GriddésactivéAffiche la grille des cellules en permanence (surtout utile pendant l’édition).
Grid Opacity0.35Opacité de la grille quand Show Grid est activé.

Le bouton Rebuild Terrain, en bas de l’Inspector (RTSTerrain.RebuildAll()), détruit puis recrée tous les chunks, les textures et la carte de cheminement. La végétation, l’eau et les décors sont reconstruits en même temps.

Matériaux, superpositions et grille

Par défaut, le terrain crée son propre matériau à partir du shader RTS Terrain Studio/Terrain (RTSTerrain.TerrainShaderName). Le terrain choisit la source du matériau dans cet ordre :

  1. Material Override dans les paramètres du terrain (RTSTerrainSettings.materialOverride).
  2. Material Override du tileset (RTSTileset.materialOverride), pour que tous les terrains qui utilisent ce tileset partagent le même aspect.
  3. Un nouveau matériau qui utilise RTS Terrain Studio/Terrain.

Le terrain travaille toujours sur une copie du matériau source et la remplit avec les splat maps, les tableaux de textures et les paramètres de la carte. Un matériau de remplacement doit utiliser le shader de terrain ou un shader qui déclare les mêmes propriétés (voir Contrat des propriétés du shader).

Comme le terrain affiche une copie, les modifications apportées ensuite à l’asset du matériau de remplacement ne sont pas prises en compte automatiquement. Après l’avoir modifié, cliquez sur Rebuild Terrain (ou appelez RebuildAll()). Pour changer une valeur à l’exécution sans reconstruction, définissez-la directement sur terrain.TerrainMaterial.

Si le shader de terrain est introuvable, par exemple dans un build de joueur qui ne l’inclut pas, le terrain est dessiné avec un simple matériau URP Lit gris. Un avertissement est consigné : « Shader 'RTS Terrain Studio/Terrain' was not found. » Lancez Tools ▸ RTS Terrain Studio ▸ Validate Project. Sa vérification « Shaders included in builds » crée l’asset RTSShaderReferences, qui conserve tous les shaders du package dans les builds (voir Générer le build de votre jeu).

Superposition. SetOverlayTexture(texture, opacity) superpose n’importe quelle texture à toute la carte, du premier vertex jusqu’à MapData.WorldSize. La couleur du terrain est mélangée avec la couleur RGB de la texture, selon un facteur égal à l’alpha de la texture × l’opacité. L’éditeur s’en sert pour la vue de cheminement. Vous pouvez vous en servir pour afficher des cartes de chaleur, des territoires ou des aperçus de placement de bâtiments. La superposition fait partie de la couleur de la surface, elle est donc éclairée et ombrée comme le terrain.

Grille. SetGridVisible(visible, opacity) force l’affichage de la grille de cellules anticrénelée par le code. Une ligne sur 4 est dessinée plus épaisse. Dans la Scene View, l’éditeur l’affiche ou la masque avec G pendant l’édition. IsGridVisible vaut true quand la grille est affichée par le code ou par Show Grid.

using RTSTerrainStudio;
using Unity.Mathematics;
using UnityEngine;

/// Shows unwalkable cells in red on top of the terrain (one overlay pixel per cell).
public class WalkabilityOverlay : MonoBehaviour
{
    [SerializeField] RTSTerrain terrain;
    Texture2D overlay;

    public void Show()
    {
        MapData map = terrain != null ? terrain.Map : null;
        if (map == null) return;

        // One texel per cell. Point filtering keeps hard cell borders.
        overlay = new Texture2D(map.Width, map.Height, TextureFormat.RGBA32, false)
        {
            filterMode = FilterMode.Point,
            wrapMode = TextureWrapMode.Clamp
        };

        var pixels = new Color32[map.Width * map.Height];
        for (int z = 0; z < map.Height; z++)
        {
            for (int x = 0; x < map.Width; x++)
            {
                // Texture row 0 is the map edge at z = 0, like the map itself.
                Vector3 world = terrain.CellCenterToWorld(new int2(x, z));
                bool walkable = terrain.IsWalkable(world);
                // Alpha 0 leaves the terrain untouched, alpha 160 tints it red.
                pixels[z * map.Width + x] = walkable ? new Color32(0, 0, 0, 0) : new Color32(255, 40, 40, 160);
            }
        }
        overlay.SetPixels32(pixels);
        overlay.Apply(false, false);

        terrain.SetOverlayTexture(overlay, 0.8f);
    }

    public void Hide()
    {
        if (terrain != null) terrain.SetOverlayTexture(null, 0f);   // null hides the overlay
        if (overlay != null) Destroy(overlay);
        overlay = null;
    }

    void OnDisable() => Hide();
}

L’API de rendu de RTSTerrain en un coup d’œil :

MembreDescription
Material TerrainMaterialL’instance de matériau partagée par tous les chunks (null tant que le terrain n’est pas activé).
Transform ChunkRootL’objet « RTS Chunks » qui contient les GameObjects des chunks.
IReadOnlyList<RTSTerrainChunk> Chunks, int2 ChunkCount, int ChunkSizeInCellsLa grille des chunks.
RTSTerrainChunk GetChunk(int2 chunkCoord), GetChunkAtCell(int2 cell)Recherche un chunk. Renvoie null en dehors de la carte.
bool IsRenderingReadyVaut true dès que les chunks, les textures et le matériau existent.
Texture GetSplatTexture(int index)Texture de splat 0–3 (le calque i se trouve dans la splat map i / 4, canal i % 4).
void SetOverlayTexture(Texture tex, float opacity), OverlayTexture, OverlayOpacitySuperposition sur toute la carte. Passez null ou 0 pour la masquer.
void SetGridVisible(bool visible, float opacity), IsGridVisibleGrille des cellules pilotée par le code.
void RebuildChunkMeshes(RectInt cellRect)Reconstruit immédiatement les meshes et les colliders des chunks touchés. Normalement inutile : NotifyChanged s’en charge.
void RefreshMaterial()Réapplique immédiatement au matériau le tileset, les tableaux de textures et les paramètres de la carte.
RTSTerrainChunk : Terrain, ChunkCoord, CellRect, Mesh, MeshRenderer, MeshCollider, LocalBounds, static GetTerrain(Collider)Données par chunk. GetTerrain renvoie le terrain auquel appartient un impact physique.

Le shader de terrain

RTS Terrain Studio/Terrain (Shaders/RTSTerrain.shader) est un shader URP 17.3 éclairé (lit), écrit à la main. Il prend en charge le rendu Forward, Forward+ et Deferred, le SRP Batcher, les ombres, le SSAO, les decals, les light layers, les light cookies et les lightmaps. Vous ne modifiez jamais son matériau à la main : le terrain renseigne toutes les propriétés à partir de la carte et de son tileset.

Fonctionnalités

FonctionnalitéRôlePiloté par
16 calques de solJusqu’à 16 calques mélangés par splat, échantillonnés avec une projection planaire XZ. Seuls les calques dont le poids est visible sur un pixel sont échantillonnés (branches dynamiques), si bien que peindre davantage de calques sur la carte ne rend pas chaque pixel plus coûteux.Calques de sol du tileset ; Tile Size, Tint, Normal Strength, Smoothness, Metallic
Fondu par hauteurDans une transition, le calque dont la texture de hauteur est la plus élevée l’emporte, si bien que l’herbe pousse entre les pierres au lieu de s’estomper par-dessus. Contraste = Height Blend² × 16 ; 0 donne un simple fondu linéaire.Height Blend par calque (0–1), plus une source de hauteur : une texture de hauteur (canal R) ou l’alpha de l’albédo (Height From Albedo Alpha)
Anti-tilingDans des régions choisies par un bruit basse fréquence, la texture se fond progressivement dans un second échantillon, aux UV tournées et mises à l’échelle, ce qui casse la répétition visible. À pleine intensité, environ la moitié du sol utilise le second échantillon. Cela coûte un échantillonnage de texture supplémentaire dans ces régions.Anti Tiling par calque (0–1)
Macro-variationUne variation de luminosité à grande échelle et une légère variation de teinte chaude/froide sur toute la carte. Elle masque la répétition vue de loin. Les falaises n’en reçoivent que la moitié de l’intensité.Macro Variation du tileset (0–1, 0.25 par défaut)
Falaises triplanairesJusqu’à 4 types de falaise sont projetés selon les trois axes, si bien que les parois verticales n’ont jamais l’air étirées. Les normales sont combinées par un mélange de type whiteout. Là où deux types de falaise se rencontrent, ils passent de l’un à l’autre en fondu sur une bande étroite.Calques de falaise du tileset ; Triplanar Sharpness (1–16, 6 par défaut)
Roche sur les pentesAu-delà d’environ 50° de pente, le sol prend progressivement le matériau de falaise (entièrement rocheux au-delà d’environ 63°), si bien que les collines escarpées n’affichent jamais d’herbe étirée. La roche perce à travers le sol là où sa texture de hauteur est élevée.Automatique
OcclusionAO par vertex précalculée au pied des falaises, multipliée par un terme de cavité issu de la texture de hauteur des falaises.Automatique
Grille des cellulesLignes anticrénelées (plus épaisses toutes les 4 cellules). Elles s’estompent au loin avant de pouvoir provoquer des motifs de moiré.Show Grid / SetGridVisible / G dans la Scene View
SuperpositionSuperposition RGBA sur toute la carte (vue de cheminement, cartes de chaleur).SetOverlayTexture ; dans la Scene View, P fait défiler les modes de la superposition de cheminement
Curseur du pinceauLe contour et l’atténuation du pinceau sont projetés dans le shader à la position exacte de la surface, si bien que vous peignez exactement là où vous le voyez (quelle que soit la mise à l’échelle de l’affichage). Jusqu’à 4 positions pour la peinture symétrique. Il est dessiné en dernier et reste donc visible dans le brouillard de guerre.RTSBrushPreview (défini par les outils de l’éditeur)
Brouillard de guerre (solution de repli)Quand la renderer feature du brouillard de guerre n’est pas installée, le shader assombrit lui-même les zones inexplorées et non visibles.RTSFogOfWarManager (voir Brouillard de guerre)
Repli sans tilesetSans tileset, le terrain affiche un sol gris neutre et des falaises d’un gris plus foncé au lieu d’échouer.Automatique
Options d’éclairageDésactivez les reflets spéculaires et les réflexions de l’environnement pour un ombrage moins coûteux.Options du matériau Specular Highlights / Environment Reflections (sur un matériau de remplacement)

La plupart de ces valeurs sont des paramètres du tileset : pour savoir comment créer les calques, voir Tilesets.

Passes : ForwardLit (UniversalForward), GBuffer (UniversalGBuffer, absent sur GLES/GLCore), ShadowCaster, DepthOnly, DepthNormals et Meta. Toutes les passes sauf GBuffer ciblent le Shader Model 3.5 : le terrain s’affiche donc aussi sous WebGL 2.0 et OpenGL ES 3.0. La passe GBuffer, elle, requiert le Shader Model 4.5. La file de rendu est Geometry-100, si bien que le grand terrain remplit le tampon de profondeur avant que les autres objets opaques ne soient dessinés. Le cross-fade de LOD n’est pas utilisé.

Désactiver les reflets spéculaires et les réflexions

Pour les appareils d’entrée de gamme, ou pour un rendu peint plus plat, utilisez un matériau de remplacement dont les options d’éclairage sont désactivées :

  1. Dans la fenêtre Project, choisissez Create ▸ Material et nommez-le, par exemple Terrain Low End.
  2. Dans l’Inspector du matériau, réglez le shader sur RTS Terrain Studio ▸ Terrain.
  3. Décochez Specular Highlights et/ou Environment Reflections en bas de l’Inspector du matériau. Ne touchez pas aux autres propriétés : le terrain les écrase.
  4. Assignez le matériau au champ Material Override du tileset (tous les terrains qui l’utilisent) ou d’un seul terrain (section Rendering de l’Inspector de RTSTerrain).
  5. Si le terrain ne change pas immédiatement, cliquez sur Rebuild Terrain.

Utilisez pour cela un asset de matériau, et non un matériau créé par le code. Unity ne conserve que les variantes de shader correspondant aux mots-clés de matériau utilisés par un asset de matériau présent dans le build. Un mot-clé défini uniquement par le code risque donc d’être éliminé des builds de joueur.

Contrat des propriétés du shader

Le code de rendu de RTSTerrain définit toutes les propriétés, à l’aide des identifiants de RTSShaderIDs. Un shader personnalisé doit déclarer les propriétés qu’il utilise sous les mêmes noms. Les scalaires et les vecteurs se trouvent dans le constant buffer UnityPerMaterial (SRP Batcher).

PropriétéTypeContenu
_RTS_SplatMap0 … _RTS_SplatMap3Texture2D, RGBA linéairePoids de splat. Le calque i se trouve dans la splat map i / 4, canal i % 4. La somme de tous les poids vaut 1. UV = positionOS.xz * _RTS_MapSize.zw. Échantillonnage bilinéaire, avec clamp.
_RTS_AlbedoArrayTexture2DArray, sRGBRGB = albédo, A = hauteur (0.5 si un calque n’a pas de hauteur). Tranches 0–15 = calques de sol, 16–19 = calques de falaise (RTSTileset.CliffSliceOffset).
_RTS_NormalArrayTexture2DArray, linéaireRGB = normale en espace tangent × 0.5 + 0.5 (déjà décompressée depuis DXT5nm/BC5 lors de la construction du tableau).
_RTS_LayerDataTexture2D 20 × 4, float, lue avec LoadUne colonne par tranche du tableau de textures, voir le tableau ci-dessous.
_RTS_LayerCountfloatNombre de calques de sol du tileset, au moins 1 (borné à 1–16). Sans tileset, RTSTerrain envoie 1, une configuration neutre des données de calque et des tableaux de textures de substitution (RTSTextureArrayBuilder.FallbackResolution = 128), si bien que le terrain affiche un sol gris et des falaises d’un gris plus foncé. Le shader traite aussi 0 comme « pas de données » et dessine alors RTS_FALLBACK_GROUND_ALBEDO / RTS_FALLBACK_CLIFF_ALBEDO sans lire _RTS_LayerData ; cela n’arrive qu’avec un matériau personnalisé utilisé en dehors de RTSTerrain.
_RTS_MapSizefloat4(taille réelle X, taille réelle Z, 1 / X, 1 / Z).
_RTS_MapParamsfloat4(taille de cellule, hauteur de niveau de falaise, macro-variation, netteté triplanaire). Le shader standard n’utilise pas la hauteur de niveau de falaise ; elle est fournie pour des personnalisations, comme une teinte qui dépend de la hauteur.
_RTS_OverlayTex, _RTS_OverlayOpacityTexture2D RGBA, floatSuperposition sur toute la carte. Opacité 0 = désactivée.
_RTS_GridParamsfloat4(activée 0/1, opacité, inutilisé, inutilisé).
_SpecularHighlights, _EnvironmentReflectionsbascules floatMots-clés _SPECULARHIGHLIGHTS_OFF, _ENVIRONMENTREFLECTIONS_OFF.
_RTS_LayerParams[20], _RTS_LayerTints[20], _RTS_LayerParams2[20]tableaux float4Les mêmes valeurs par calque sous forme de tableaux float4, pour les shaders personnalisés conçus autour de tableaux. Le shader standard ne lit que _RTS_LayerData.

RTSShaderIDs.WorldToMap (_RTS_WorldToMap) est réservé et n’est pas défini par RTSTerrain. Utilisez l’espace objet (positionOS), qui correspond à l’espace local de la carte pour les meshes des chunks.

Structure de _RTS_LayerData (colonne = tranche du tableau) :

Lignexyzw
01 / taille de tuileintensité de la normalelissagefondu par hauteur
1teinte RGB en couleur linéaire (Color.linear)métallicité
2anti-tilinga une hauteur (0/1)calque utilisé (0/1)0
3couleur de mini-carte (non lue par le shader)

Un emplacement de falaise (16–19) dont « calque utilisé » = 0 est rendu comme l’emplacement de falaise 16. Les types de falaise peints au-delà du nombre de types de falaise du tileset affichent quand même de la roche.

Entrée du mesh : POSITION (locale à la carte), NORMAL (lissée, espace objet), COLOR (r = masque de paroi de falaise, g = type de falaise × 85 / 255, de sorte que les types 0–3 correspondent à 0, 1/3, 2/3 et 1, b = occlusion ambiante, a = inutilisé). Pas d’UV, pas de tangentes.

Variables globales (issues de Shaders/Include/RTSCommon.hlsl, partagé par tous les shaders du package) :

Variable globaleDéfinie parContenu
_RTS_FogOfWarTex, _RTS_FogOfWarParams, _RTS_FogOfWarUnexplored, _RTS_FogOfWarExplored, _RTS_FogOfWarEnabledRTSFogOfWarManagerTexture de visibilité (R = visible, G = exploré), paramètres de projection et teintes. HLSL : RTS_SampleFogOfWar(positionWS), RTS_ApplyFogOfWar(color, positionWS).
_RTS_BrushPositions[4], _RTS_BrushRotations[4], _RTS_BrushCount, _RTS_BrushParams, _RTS_BrushColor, _RTS_BrushMaskRTSBrushPreviewCurseur du pinceau. HLSL : RTS_BrushCursor(positionWS) renvoie la couleur (rgb) et la couverture (a).
_RTS_WindRTSVegetationRendererxy = direction, z = intensité, w = vitesse.

Écrire un shader de terrain personnalisé

Toute la logique de surface du terrain se trouve dans un seul fichier include, Shaders/Include/RTSTerrainInput.hlsl. Les fichiers de passe se contentent de calculer l’éclairage à partir de la surface obtenue. Pour changer l’aspect, partez d’une copie du shader du package :

  1. Copiez Shaders/RTSTerrain.shader et tout le dossier Shaders/Include dans un dossier de votre propre projet (par exemple Assets/MyGame/Shaders), en conservant l’arborescence relative. Le shader inclut ses fichiers de passe sous la forme Include/…, et les includes se référencent entre eux par chemin relatif.
  2. Renommez le shader à la première ligne de votre copie, par exemple Shader "MyGame/Terrain", pour éviter tout conflit avec l’original.
  3. Faites vos modifications, en général dans RTS_EvaluateTerrainSurface de votre copie de RTSTerrainInput.hlsl.
  4. Créez un matériau avec votre shader et assignez-le comme Material Override (tileset ou terrain). L’asset de matériau garantit aussi que le shader sera inclus dans les builds de joueur.
  5. Cliquez sur Rebuild Terrain.

Comme vous travaillez sur des copies, une mise à jour du package n’écrase jamais vos modifications. Après une mise à jour, comparez votre copie avec les nouveaux fichiers du package si vous voulez profiter des derniers correctifs.

Exemple : de la neige sur les plateaux élevés. Ajoutez ceci à la fin de RTS_EvaluateTerrainSurface dans votre copie, juste avant return surface; :

// Snow on everything above cliff level 6. positionOS.y is the map-local ground height, and
// _RTS_MapParams.y the height of one cliff level, so their ratio is the (fractional) cliff level.
half level = (half)(positionOS.y / max(_RTS_MapParams.y, 1e-3));
// Soft border between level 5.5 and 6.5; cliff walls (cliffBlend = 1) stay rocky.
half snow = smoothstep(5.5h, 6.5h, level) * (1.0h - surface.cliffBlend);
surface.albedo = lerp(surface.albedo, half3(0.92h, 0.94h, 0.97h), snow);
surface.smoothness = lerp(surface.smoothness, 0.35h, snow);

Les principaux éléments de RTSTerrainInput.hlsl :

Fonction / typeUtilité
struct RTSTerrainSurfaceRésultat de l’évaluation de la surface : albédo, métallicité, lissage, occlusion, normale par pixel et normale géométrique (espace objet), repère tangent, cliffBlend (0 = sol, 1 = falaise).
RTS_EvaluateTerrainSurface(positionOS, normalOS, vertexColor, dPdx, dPdy)La surface complète : couverture de falaise, sol, falaises, transition basée sur la hauteur, macro-variation, occlusion.
RTS_EvaluateGround(positionXZ, dPdx, dPdy, detileNoise), RTS_AccumulateGroundLayer(…)Calques de sol mélangés par splat, avec fondu par hauteur et anti-tiling (accumulateur float RTSGroundAccumulator).
RTS_EvaluateCliff(cliffTypeValue, positionOS, dPdx, dPdy, normalOS), RTS_SampleCliffLayer(…), RTS_TriplanarWeights(normalOS, sharpness)Matériau de falaise triplanaire et fondu enchaîné entre les types de falaise.
RTS_LoadLayerData(slice) → RTSLayerDataLit une colonne de _RTS_LayerData.
RTS_DecodeArrayNormal(encoded, strength)Décode un texel du tableau de normales.
RTS_EvaluateNoise(positionXZ), RTS_ValueNoise, RTS_Hash21Bruit procédural (sans texture), stable sur les GPU mobiles.
RTS_GridMask(…), RTS_ApplyEditorOverlays(…)Lignes de la grille et texture de superposition.
RTS_CreateSurfaceData(surface)Convertit la surface en SurfaceData d’URP.
ConstantesRTS_MAX_GROUND_LAYERS (16), RTS_CLIFF_SLICE_OFFSET (16), RTS_MAX_CLIFF_TYPES (4), RTS_MIN_LAYER_WEIGHT (1/255), RTS_FALLBACK_GROUND_ALBEDO, RTS_FALLBACK_CLIFF_ALBEDO

L’échantillonnage des textures utilise des gradients explicites (SampleGrad). Les gradients dPdx/dPdy sont calculés une seule fois au début du fragment shader, en dehors de toute branche. Conservez ce principe si vous ajoutez vos propres échantillonnages dans des branches, sinon des coutures de mip-map apparaissent aux limites des branches.

La passe forward applique, dans cet ordre : évaluation de la surface, superpositions de l’éditeur, éclairage URP (UniversalFragmentPBR), brouillard atmosphérique d’Unity, brouillard de guerre et curseur du pinceau.

Végétation

RTSVegetationRenderer dessine deux types de végétation à partir de la carte :

  • Détails : herbe, fleurs et petites plantes peintes sous forme de densité. Ils sont générés patch par patch par des jobs Burst et dessinés avec l’instanciation GPU procédurale. Ils n’existent jamais sous forme de GameObjects.
  • Arbres : instances placées individuellement, soit instanciées sur le GPU (le plus rapide), soit créées comme GameObjects à partir de prefabs (pour les besoins du gameplay, comme la récolte).

Les deux sont organisés en patchs de RTSVegetationRenderer.PatchCells (16) × 16 cellules. Les patchs sont l’unité de culling et de reconstruction incrémentale : une modification ne régénère que les patchs qu’elle a touchés. Le renderer fonctionne en Edit Mode et en Play Mode, pour les caméras de la Game View et de la Scene View.

Mise en place

  1. Sélectionnez le GameObject du terrain. S’il n’a pas de Vegetation Renderer, cliquez sur Add à côté de l’avertissement dans l’Inspector de RTSTerrain (ou utilisez Add Component ▸ RTS Terrain Studio ▸ Vegetation Renderer).
  2. Assignez une Vegetation Library dans la section Assets de l’Inspector de RTSTerrain. Sans bibliothèque, l’Inspector du Vegetation Renderer affiche cet avertissement : « The terrain has no vegetation library, so nothing can be drawn. »
  3. Peignez des détails et placez des arbres avec les outils Vegetation (touche 4 dans la Scene View pendant l’édition).
  4. Pour les arbres dessinés en mode instancié, cochez Enable GPU Instancing sur leurs matériaux. Tools ▸ RTS Terrain Studio ▸ Validate Project liste les matériaux où l’option est désactivée et peut les corriger en un clic.

La bibliothèque définit les prototypes (meshes, textures, couleurs, tailles, distances). Pour le détail de chaque champ de prototype, consultez Bibliothèque de végétation.

L’Inspector du Vegetation Renderer affiche des statistiques en direct (Visible Details, Total Details, Visible Trees, Tree Objects, Colliders) et propose un bouton Rebuild (RebuildAll()) et un bouton Select Library.

Paramètres du renderer

ParamètrePar défautDescription
Quality
Detail Density Multiplier1Multiplie le nombre d’instances de détails par texel (0–2, 0 = aucun détail). Le modifier régénère tous les détails.
Detail Distance Multiplier1Multiplie la distance de rendu de chaque prototype de détail (0.1–3).
Tree Distance Multiplier1Multiplie la distance de rendu de chaque prototype d’arbre instancié (0.1–3).
Wind
Wind Direction(1, 0.35)Direction horizontale du vent en espace monde (x = X monde, y = Z monde).
Wind Strength0.6Intensité globale du vent (0–3). Chaque prototype et chaque matériau l’ajustent ensuite.
Wind Speed1.6Vitesse de l’animation du vent (0–10).
Rendering
Draw DetailsactivéDessine les détails peints par densité.
Draw TreesactivéDessine les arbres instanciés sur le GPU.
Draw In Scene ViewactivéDessine aussi la végétation dans les caméras de la Scene View.
Crossed Quad Count3Nombre de quads du mesh d’herbe généré pour les détails Crossed Quads (2–3). Le modifier reconstruit la végétation.
Collider Layer0Layer des proxys de collider créés pour les arbres instanciés.

Détails

Pour chaque calque de détails peint et chaque patch, DetailScatterJob (Burst) disperse des instances à partir de la carte de densité. Une densité de 255 donne Max Density instances du prototype par texel de détail, multiplié par Detail Density Multiplier. Les instances évitent les pentes plus escarpées que Max Slope et, avec Avoid Water, le sol inondé. Elles peuvent s’incliner avec le sol (Align To Ground) et reçoivent, selon un bruit, une couleur comprise entre Healthy Color et Dry Color.

Les instances d’un patch sont envoyées dans un GraphicsBuffer structuré et dessinées avec Graphics.RenderMeshPrimitives via le shader interne Hidden/RTS Terrain Studio/Detail. WebGL 2.0 ne dispose pas de structured buffers, et OpenGL ES 3 ne les garantit pas dans les vertex shaders ; sur ces appareils, les instances sont donc stockées dans une texture à virgule flottante (deux texels par instance). Le renderer choisit la méthode à l’exécution, et l’herbe a le même aspect dans les deux cas. Le shader lit chaque instance dans le buffer ou la texture et gère le vent, une réduction progressive de taille sur les derniers 25 % de la distance de rendu, l’assombrissement à la base, la translucidité et la solution de repli du brouillard de guerre. Chaque patch subit un culling par frustum et par distance pour chaque caméra.

Mode de renduMeshMatériau
CrossedQuadsMesh d’herbe généré avec 2 ou 3 quads croisés (Crossed Quad Count)Créé à partir de la Texture du prototype (découpe alpha à 0.5)
MeshLe Mesh du prototype (tous les sous-meshes)Si le matériau utilise déjà Hidden/RTS Terrain Studio/Detail, il est utilisé tel quel. Sinon, un matériau de détail est créé à partir de sa texture principale et de sa couleur. Son seuil alpha (alpha cutoff) n’est conservé que si le matériau source utilise la découpe alpha.

Les autres shaders ne peuvent pas lire les données d’instance, si bien que les détails en mode Mesh sont toujours rendus avec le shader de détails. Les fonctionnalités de shader personnalisées du matériau source (animation de vertex, éclairage spécial) ne sont pas utilisées pour les détails. Si vous en avez besoin, utilisez plutôt un prototype d’arbre.

Les détails ne projettent d’ombres que si l’option Cast Shadows du prototype est activée (désactivée par défaut). Ils sont dessinés sur le Chunk Layer du terrain, sans light probes ni reflection probes.

Arbres : instanciés ou GameObject

Chaque prototype d’arbre définit un Spawn Mode :

Instanced (par défaut)GameObject
RenduGraphics.RenderMeshInstanced, jusqu’à 1023 instances par draw call, culling par patch selon le frustum et Render Distance × Tree Distance MultiplierUne instance de prefab par arbre, rendue par Unity comme n’importe quel GameObject
LODLOD0 et LOD1 d’un LODGroup, choisis par groupe de patchs selon la règle LODGroup d’Unity (respecte QualitySettings.lodBias). Les prefabs sans LODGroup utilisent tous leurs MeshRenderer actifs.Le LODGroup propre au prefab
Teinte par instanceOui, pour les matériaux qui utilisent RTS Terrain Studio/Vegetation (valeur aléatoire entre Tint A et Tint B)Non
CollidersProxys capsules mis en pool (voir ci-dessous)Les colliders du prefab
Scripts sur le prefabNon exécutés (rien n’est instancié)Exécutés normalement
Idéal pourForêts, paysages, grandes quantités d’arbresArbres liés au gameplay : récolte, animation, scripts personnalisés

Dans les deux modes, les arbres sont placés à la hauteur du sol + position.y, orientés selon leur lacet et mis à l’échelle uniformément. Ils se recalent automatiquement sur le sol quand le terrain est modifié. Les arbres créés et les proxys de collider se trouvent sous un enfant masqué « RTS Vegetation Objects » du terrain et suivent son transform.

Les arbres instanciés nécessitent l’option Enable GPU Instancing sur leurs matériaux. Si elle est désactivée, le renderer dessine via une copie masquée du matériau avec l’instanciation activée (l’asset du projet n’est jamais modifié). En Edit Mode, la copie se resynchronise avec la source environ 4 fois par seconde. Dans les builds de joueur, les variantes d’instanciation de ces matériaux peuvent être éliminées. Cochez donc la case (le Project Validator peut le faire pour vous).

Le renderer conserve le mode de projection des ombres et le rendering layer mask de chaque partie. Les parties réglées sur Shadows Only (proxys d’ombre) fonctionnent comme prévu. Un prototype dont l’option Cast Shadows est désactivée désactive les ombres de toutes ses parties.

Colliders des arbres

Quand l’option Colliders d’un prototype d’arbre est activée :

  • Mode Instanced : chaque arbre reçoit un GameObject invisible « Tree Collider » avec un CapsuleCollider (Collider Radius, Collider Height, mis à l’échelle avec l’arbre) et un composant RTSTreeInstance (IsColliderProxy = true). Les proxys sont mis en pool et réutilisés, et ils utilisent le Collider Layer du renderer.
  • Mode GameObject : les colliders du prefab sont utilisés. Le renderer ajoute un RTSTreeInstance à chaque arbre créé.

Dans les deux cas, hit.collider.GetComponentInParent<RTSTreeInstance>() vous indique quel arbre une requête physique a touché. Le cheminement et le brouillard de guerre n’ont pas besoin de colliders : ils utilisent les paramètres Footprint Radius et Blocks Vision du prototype.

Vent

À chaque image, le renderer transmet le vecteur global _RTS_Wind (direction, intensité, vitesse) à tous les shaders. Le balancement total d’une plante se calcule ainsi :

  • Détails : Wind Strength global × Wind Strength du prototype (0–1).
  • Arbres et plantes utilisant RTS Terrain Studio/Vegetation : Wind Strength global × Wind Strength du matériau, pondéré selon le mode choisi dans Wind Mode. Avec le mode Object Height, la flexion augmente vers le sommet de la plante, par rapport à Wind Reference Height. Le mode Vertex Color R utilise la composante rouge de la couleur de vertex comme poids par vertex (peignez 0 sur le tronc et 1 à l’extrémité des branches). Leaf Flutter ajoute par-dessus un mouvement rapide de faible amplitude.

Réglez le paramètre Wind Strength du renderer sur 0 pour couper complètement le vent, par exemple pour une scène nocturne calme.

Le shader Vegetation

RTS Terrain Studio/Vegetation est un shader de feuillage éclairé, destiné aux matériaux des prefabs d’arbres et de plantes. Il prend en charge le SRP Batcher, l’instanciation GPU avec teinte par instance (_RTS_InstanceTint), Forward+, les decals DBuffer, le Rendering Debugger, l’APV et les lightmaps, ainsi que le rendu de repli du brouillard de guerre. D’autres matériaux compatibles avec l’instanciation (comme URP Lit) fonctionnent aussi, mais sans teinte par instance, ni translucidité, ni vent.

PropriétéPar défautDescription
Albedo, ColorblancTexture de base (son alpha sert au découpage) et couleur.
Alpha Clipping, Alpha Cutoffactivé, 0.5Test alpha pour les feuilles. Le découpage est actif sans aucun mot-clé ; c’est le mot-clé inversé _ALPHATEST_OFF qui le désactive.
Use Normal Map, Normal Map, Normal Strengthdésactivé, –, 1Normal map facultative (_NORMALMAP).
Smoothness, Specular Color0.2, gris foncéRéponse spéculaire.
Wrap Lighting0.35Adoucit l’atténuation de la lumière sur les feuilles (0–1).
Translucency, Translucency Color0.6, vert clairLumière qui traverse les feuilles lorsqu’on regarde en direction du soleil.
Wind ModeObject HeightOff, Vertex Color R ou Object Height.
Wind Strength, Wind Reference Height, Leaf Flutter1, 6, 0.5Échelle du vent côté matériau (multipliée par le vent global du renderer).
CullOffCulling des faces. Avec Off, les deux faces des quads de feuillage sont rendues.
Receive ShadowsactivéMot-clé _RECEIVE_SHADOWS_OFF lorsque l’option est désactivée.

Pour le code qui crée des matériaux de végétation : le découpage alpha est activé par défaut. N’activez le mot-clé _ALPHATEST_OFF (RTSVegetationShaderIDs.VegetationAlphaTestOffKeyword) que si vous voulez désactiver le découpage.

Multiplicateurs de qualité

Les trois champs de qualité pondèrent les valeurs de la bibliothèque sans modifier celle-ci. Ils sont parfaits pour les options graphiques du menu de votre jeu :

using RTSTerrainStudio;
using UnityEngine;

/// Applies a vegetation quality level (0 = low, 1 = medium, 2 = high) to every terrain in the scene.
public static class VegetationQuality
{
    public static void Apply(int level)
    {
        foreach (RTSTerrain terrain in RTSTerrain.All)
        {
            if (!terrain.TryGetComponent(out RTSVegetationRenderer vegetation)) continue;

            switch (level)
            {
                case 0:
                    vegetation.detailDensityMultiplier = 0.4f;   // fewer grass blades (regenerates details)
                    vegetation.detailDistanceMultiplier = 0.6f;  // grass disappears earlier
                    vegetation.treeDistanceMultiplier = 0.7f;    // instanced trees culled earlier
                    vegetation.crossedQuadCount = 2;             // 2 quads per grass tuft instead of 3
                    break;
                case 1:
                    vegetation.detailDensityMultiplier = 0.75f;
                    vegetation.detailDistanceMultiplier = 0.8f;
                    vegetation.treeDistanceMultiplier = 1f;
                    vegetation.crossedQuadCount = 3;
                    break;
                default:
                    vegetation.detailDensityMultiplier = 1f;
                    vegetation.detailDistanceMultiplier = 1f;
                    vegetation.treeDistanceMultiplier = 1.2f;
                    vegetation.crossedQuadCount = 3;
                    break;
            }
            // The renderer notices the changed values on its next update and rebuilds what is needed.
        }
    }
}

API des arbres et récolte

MembreDescription
bool RemoveTree(uint id)Retire l’arbre de la carte, désactive immédiatement son GameObject ou son proxy de collider, notifie le terrain (MapLayers.Trees, de sorte que le cheminement libère à nouveau l’emprise et que le brouillard de guerre supprime l’obstacle à la vision) et déclenche TreeRemoved. Aucune étape d’annulation n’est enregistrée. Renvoie false si aucun arbre ne porte cet id.
event Action<RTSVegetationRenderer, TreeInstanceData> TreeRemovedDéclenché par RemoveTree avec les données de l’arbre supprimé.
bool TryFindNearestTree(Vector3 worldPosition, float maxDistance, out TreeInstanceData tree)Arbre le plus proche, la distance étant mesurée sur le plan du sol (XZ). Avec Mathf.Infinity, la recherche porte sur toute la carte.
GameObject GetTreeObject(uint id)L’instance de prefab créée dans la scène (mode GameObject) ou le proxy de collider (mode instancié avec colliders). Sinon, null.
Vector3 GetTreeWorldPosition(in TreeInstanceData tree)Position en espace monde du pied de l’arbre (hauteur du sol + décalage).
void RebuildAll(), void ProcessChanges()Reconstruction complète ; application immédiate des modifications de carte en attente (normalement automatique à chaque image).
VisibleDetailInstances, VisibleTrees, TotalDetailInstances, SpawnedTreeObjects, TreeColliderCountStatistiques. Les valeurs « visibles » portent sur la dernière caméra (Game ou Scene) ayant effectué un rendu.
RTSTreeInstance : TreeId, Owner, IsColliderProxy, TryGetData(out TreeInstanceData), Remove()Composant présent sur les arbres créés dans la scène et sur les proxys de collider. Remove() équivaut à Owner.RemoveTree(TreeId).
using RTSTerrainStudio;
using UnityEngine;

/// A minimal lumberjack: chops the nearest tree in reach, or the tree under the mouse.
public class Lumberjack : MonoBehaviour
{
    [SerializeField] RTSVegetationRenderer vegetation;
    [SerializeField] Camera viewCamera;
    [SerializeField] float reach = 2f;
    public int wood;

    void OnEnable()
    {
        if (vegetation != null) vegetation.TreeRemoved += HandleTreeRemoved;
    }

    void OnDisable()
    {
        if (vegetation != null) vegetation.TreeRemoved -= HandleTreeRemoved;
    }

    /// Physics-free: finds the nearest tree around this unit on the ground plane.
    public bool ChopNearestTree()
    {
        if (vegetation == null) return false;
        if (!vegetation.TryFindNearestTree(transform.position, reach, out TreeInstanceData tree)) return false;
        return vegetation.RemoveTree(tree.id);
    }

    /// Physics based: needs "Colliders" on the tree prototype.
    public bool ChopTreeUnderMouse()
    {
        if (viewCamera == null) return false;
        Ray ray = viewCamera.ScreenPointToRay(RTSInput.PointerPosition);
        if (!Physics.Raycast(ray, out RaycastHit hit, 500f)) return false;

        // Works for collider proxies (instanced trees) and for colliders inside spawned tree prefabs.
        var tree = hit.collider.GetComponentInParent<RTSTreeInstance>();
        return tree != null && tree.Remove();
    }

    void HandleTreeRemoved(RTSVegetationRenderer renderer, TreeInstanceData tree)
    {
        wood += 10;
        Vector3 position = renderer.GetTreeWorldPosition(tree);
        Debug.Log($"Tree {tree.id} felled at {position}. Wood: {wood}");
    }
}

Les scripts d’exemple contiennent une démo de récolte complète (RTSTreeHarvestDemo : des ouvriers se rendent auprès d’un arbre, l’abattent et déclenchent une animation de chute avec RTSFallingTreeEffect). Consultez-la : c’est un exemple de gameplay complet, qui montre notamment comment les arbres récoltés sont restaurés à la fin d’un test en jeu.

Supprimer un arbre modifie la carte. Dans l’éditeur en jeu ou dans l’éditeur Unity, la carte est alors signalée comme comportant des modifications non enregistrées. Le code du jeu travaille généralement sur une carte chargée pour la partie et ne la réenregistre jamais.

Eau

RTSWaterRenderer affiche l’eau peinte sous forme de meshes transparents découpés en chunks. Chaque vertex marqué comme eau possède sa propre hauteur de surface, ce qui permet d’avoir des lacs sur différents niveaux de falaise. Les meshes suivent MapGeometryView.SampleWater, c’est-à-dire exactement ce qu’utilisent les requêtes de gameplay et le cheminement. Les chunks d’eau reprennent la taille de chunk du terrain, sont générés par des jobs Burst (WaterChunkMeshJob) et n’existent que là où il y a de l’eau. Seuls les chunks touchés par une modification sont reconstruits.

Mise en place

  1. Vérifiez que le GameObject du terrain possède un composant Water Renderer (Add Component ▸ RTS Terrain Studio ▸ Water Renderer, ou le bouton Add dans l’Inspector de RTSTerrain).
  2. Ouvrez l’asset URP actif, activez Depth Texture et Opaque Texture, puis réglez Opaque Downsampling sur None (voir ci-dessous). Le menu Tools ▸ RTS Terrain Studio ▸ Validate Project vérifie et corrige ces paramètres. Une caméra peut aussi activer les deux textures pour elle-même.
  3. Peignez l’eau avec les outils Water (touche 6 dans la Scene View pendant l’édition).
  4. Modifiez l’apparence dans la section Water de l’Inspector du tileset (le profil d’eau du tileset).

Configuration URP requise

Paramètre (asset URP ou caméra)Nécessaire pourSans cela
Depth Texture : activéLa couleur selon la profondeur, l’écume du rivage et le rivage adouci autour des objets qui se trouvent dans l’eau, ainsi qu’une réfraction qui exclut les objets situés devant l’eau (_CameraDepthTexture)L’eau utilise la profondeur stockée dans son mesh. La couleur selon la profondeur, l’écume et le rivage adouci sont conservés, mais ne tiennent pas compte des objets qui se trouvent dans l’eau.
Opaque Texture : activéLa réfraction (_CameraOpaqueTexture)Simple mélange alpha, sans réfraction.
Opaque Downsampling : None (asset URP)Un fond de lac net et des objets immergés netsLa scène sous l’eau paraît floue (la valeur par défaut d’URP est 2x Bilinear).

URP décide caméra par caméra : les paramètres Depth Texture et Opaque Texture propres à une caméra (dans la section Rendering de son Inspector) remplacent ceux de l’asset URP, tandis que la Scene View utilise toujours l’asset. L’eau adapte son matériau à chaque caméra juste avant le rendu de celle-ci, si bien que chaque vue bénéficie du meilleur rendu d’eau possible. Les caméras qui n’affichent pas le layer de l’eau sont ignorées, et les caméras de type Overlay ne reçoivent jamais la texture opaque.

L’Inspector du Water Renderer affiche un message pour chaque paramètre manquant, avec un bouton Select URP Asset. En Play Mode, il tient aussi compte des paramètres propres à la caméra principale. L’absence d’une texture n’empêche jamais l’eau de s’afficher : les vues qui n’en disposent pas utilisent le rendu de repli décrit plus haut. L’eau est simplement bien plus belle avec les deux textures activées.

Par le code : RTSWaterMaterialUtility.CheckPipelineSupport(Camera camera, out bool depthTexture, out bool opaqueTexture) indique ce qu’URP génère pour une caméra donnée, en résolvant les paramètres de la même manière qu’URP (passez null pour vérifier uniquement l’asset URP). CheckPipelineSupport(out bool depthTexture, out bool opaqueTexture) vérifie les vues qui affichent l’eau : dans les builds, la caméra principale (ou l’asset URP en l’absence de caméra principale) ; dans l’éditeur, également l’asset URP, car la Scene View l’utilise. Les deux méthodes renvoient false si URP n’est pas actif. RTSWaterMaterialUtility.IsOpaqueTextureDownsampled() vérifie le sous-échantillonnage.

Paramètres du renderer

ParamètrePar défautDescription
Material TemplatevideMatériau facultatif. Son shader et ses propriétés sont copiés, puis le profil d’eau du tileset est appliqué par-dessus. Servez-vous-en pour ajuster les valeurs que le profil ne couvre pas : Reflection Strength, Specular Strength, Foam Tile Size, Foam Lines, Shore Fade.
Cast ShadowsdésactivéEn général, les surfaces d’eau ne font que recevoir des ombres.
Receive ShadowsactivéOmbres de la lumière principale sur l’eau. Cela fonctionne aussi pour le matériau créé à l’exécution dans les builds de joueur.
Render Layer4 (Water)Layer de GameObject des chunks d’eau (RTSWaterRenderer.DefaultLayer correspond au layer Water intégré à Unity).
Wave Amplitude Multiplier1Multiplie la valeur Wave Height du profil (0–4, 0 = eau immobile).
Cell Subdivisions2Quads par côté de cellule (1–4). Des valeurs plus élevées donnent des rivages et des vagues plus lisses, mais coûtent davantage de vertices.
Light Probe UsageOffAvec Off, tous les chunks sont éclairés par la probe ambiante. Mélanger les probes donnerait à chaque chunk une couleur ambiante légèrement différente et ferait apparaître des ruptures visibles le long des bordures de chunks.
Reflection Probe UsageBlend ProbesEn Forward+, les probes sont évaluées par pixel. En Forward, chaque chunk choisit les probes correspondant à ses propres limites (bounds), si bien qu’avec plusieurs probes, des chunks voisins peuvent refléter des probes différentes.

Boutons de l’Inspector : Rebuild (RebuildAll()) et Refresh Material (RefreshMaterial(), réapplique le modèle et le profil). L’Inspector affiche aussi la grille de chunks, les chunks contenant de l’eau, le nombre total de vertices et l’origine du profil.

Profil d’eau (tileset)

L’apparence et les règles de cheminement proviennent de RTSTileset.water (un WaterProfile). Sans tileset, un profil par défaut partagé est utilisé. Considérez-le comme en lecture seule et utilisez WaterMath.CreateDefaultProfile() ou WaterProfile.Clone() lorsque vous avez besoin d’une copie modifiable.

ChampPar défautDescription
Shallow Colorbleu canard, alpha 0.55Couleur de l’eau peu profonde (alpha = opacité).
Deep Colorbleu foncé, alpha 0.95Couleur atteinte à la profondeur Color Depth (alpha = opacité).
Color Depth3 mProfondeur à laquelle la couleur de l’eau profonde est entièrement atteinte.
Shallow Depth Limit0.9 mAu-delà de cette profondeur, l’eau est profonde (non praticable). Une eau moins profonde est praticable, comme dans les RTS classiques.
Normal Map, Normal Strength, Normal Tile Sizeaucune, 0.6, 8 mOndulations de surface. Sans normal map, la surface n’utilise que les vagues de vertex.
Flow Speed(0.03, 0.02)Défilement de la normal map.
Wave Height0.05 mAmplitude des vagues de vertex (pondérée par le multiplicateur du renderer).
Smoothness0.92Lissé de la surface.
Refraction0.03Intensité du décalage de réfraction (0–0.2).
Foam Color, Foam Distance, Foam Textureblanc 0.8, 0.6 m, aucuneÉcume du rivage. Foam Distance atténue aussi les vagues en eau peu profonde.
Minimap ColorbleuCouleur de l’eau sur la mini-carte.

Le shader Water

RTS Terrain Studio/Water (RTSWaterMaterialUtility.ShaderName) est un shader URP transparent. Les meshes des chunks fournissent des positions dans l’espace local de la carte, ainsi que des données d’eau par vertex (profondeur, couverture et distance au rivage, jusqu’à ShoreSearchRadius = 4 cellules). Fonctionnalités :

  • Couleur variant avec la profondeur, de l’eau peu profonde à l’eau profonde, avec des rivages adoucis qui s’estompent là où l’eau rencontre le sol.
  • Quatre vagues de vertex directionnelles, atténuées en eau peu profonde pour que la surface ne s’élève jamais au-dessus de la plage.
  • Ondulations défilantes par normal map, réfraction de la scène immergée, reflet spéculaire du soleil et reflection probes.
  • Écume du rivage (lignes procédurales ou texture d’écume).
  • Lumière principale et lumières additionnelles (y compris les lumières additionnelles par vertex), light cookies, light layers, réception des ombres et rendu de repli du brouillard de guerre. Compatible avec le SRP Batcher.

Le matériau est créé à l’exécution (WaterMaterial, partagé par tous les chunks) et paramétré par RTSWaterMaterialUtility.ApplyProfile. Le shader est référencé par un champ sérialisé du composant, ce qui garantit son inclusion dans les builds.

En mode par vertex, les lumières additionnelles n’ajoutent que de la lumière diffuse (ni spéculaire, ni ombres), comme l’éclairage par vertex natif d’URP.

API du renderer d’eau

MembreDescription
Material WaterMaterialMatériau d’exécution partagé par tous les chunks (null tant que le composant est désactivé).
Material MaterialTemplate { get; set; }Modèle facultatif. L’assigner rafraîchit le matériau.
WaterProfile ProfileProfil du tileset ou profil par défaut partagé.
Transform ChunkRoot, ChunkCountX, ChunkCountZ, ActiveChunkCount, VertexCount, bool HasWaterGrille de chunks et statistiques.
MeshRenderer GetChunkRenderer(Vector2Int chunkCoord)Renderer d’un chunk, ou null si le chunk ne contient pas d’eau.
void RebuildAll(), void RebuildCells(RectInt cellRect), void RefreshMaterial()Reconstruction complète, reconstruction partielle, rafraîchissement du matériau.
event Action<RTSWaterRenderer> MeshesRebuiltDéclenché après une reconstruction complète ou partielle.
RTSWaterChunk : Owner, Terrain, ChunkCoord, CellRectMarqueur présent sur les objets de chunk masqués.

WaterMath : l’eau pour le gameplay

WaterMath répond aux questions liées à l’eau sans passer par la physique. Toutes les positions sont exprimées en espace monde.

MéthodeValeur renvoyée
GetWaterHeight(RTSTerrain, Vector3, out float height), GetWaterHeight(Vector3, out float height)Coordonnée Y monde de la surface de l’eau au repos. False si le sol est sec ou si la position est hors du terrain. La seconde surcharge trouve le terrain avec RTSTerrain.FindAt.
GetWaterDepth(RTSTerrain, Vector3, out float depth)Hauteur de la surface de l’eau moins celle du sol, en mètres. False si le sol est sec.
Classify(RTSTerrain, Vector3, out float depth)WaterDepthClass.Dry, Shallow ou Deep (d’après Shallow Depth Limit).
IsShallowWater(…), IsDeepWater(…), GetShallowDepthLimit(RTSTerrain)Raccourcis pour la classification.
GetWaterSurface(RTSTerrain, Vector3, float time, out float height, out Vector3 normal)La surface animée, exactement telle qu’elle est rendue : hauteur au repos + vagues, atténuées près du rivage, en tenant compte du Wave Amplitude Multiplier du renderer.
float ShaderTimeL’horloge avec laquelle le shader anime l’eau (Time.time en Play Mode et dans les builds de joueur, Time.realtimeSinceStartup en Edit Mode). Passez-la comme argument time pour que les vagues calculées sur le CPU et sur le GPU concordent.
SampleWaveOffset(Vector3, float waveHeight, float time)Décalage des vagues sans atténuation près du rivage.
EvaluateWaves(float2, float time), EvaluateWaveSurface(float2, float time, float amplitude, out float offset, out float3 normal), WaveAttenuation(float depth, float foamDistance)Briques de base compatibles Burst pour les systèmes de jobs (par exemple pour des milliers d’unités flottantes).
GetProfile(RTSTerrain), CreateDefaultProfile()Le profil utilisé ; un nouveau profil par défaut que vous pouvez modifier sans risque.
using RTSTerrainStudio;
using UnityEngine;

/// Makes a boat float on the animated water surface and keeps it out of shallow water.
public class FloatingBoat : MonoBehaviour
{
    [SerializeField] float draft = 0.15f;        // how deep the hull sits in the water
    [SerializeField] float heading;              // yaw in degrees, set by your movement code
    [SerializeField] float tiltSmoothing = 4f;

    void LateUpdate()
    {
        Vector3 p = transform.position;
        RTSTerrain terrain = RTSTerrain.FindAt(p);
        if (terrain == null) return;

        // ShaderTime is the clock the water shader uses, so the boat bobs in sync with the rendered waves.
        if (!WaterMath.GetWaterSurface(terrain, p, WaterMath.ShaderTime, out float height, out Vector3 normal))
            return; // dry ground: leave the boat alone

        transform.position = new Vector3(p.x, height - draft, p.z);

        // Tilt with the wave normal, keep our own heading.
        Quaternion target = Quaternion.FromToRotation(Vector3.up, normal) * Quaternion.Euler(0f, heading, 0f);
        transform.rotation = Quaternion.Slerp(transform.rotation, target, 1f - Mathf.Exp(-tiltSmoothing * Time.deltaTime));
    }

    /// Boats need deep water: use this before accepting a move order.
    public static bool CanSailTo(Vector3 world)
    {
        RTSTerrain terrain = RTSTerrain.FindAt(world);
        return terrain != null && WaterMath.Classify(terrain, world, out _) == WaterDepthClass.Deep;
    }
}

Décor

RTSDecorManager synchronise la scène avec les décors de la carte (doodads : rochers, caisses, ruines, clôtures, n’importe quel prefab). Il écoute les événements de modification du terrain et travaille de manière incrémentale. Une modification ne touche que les instances ajoutées, supprimées ou modifiées. Les objets sont réutilisés lorsque seul leur transform change, et placés dans un pool lorsqu’ils sont supprimés. Les modifications de hauteur du terrain replacent au sol les instances de la zone modifiée. Charger une carte ou changer la bibliothèque de décors reconstruit tout.

Modes d’apparition

Chaque prototype de la bibliothèque de décors définit un Spawn Mode :

GameObject (par défaut)Instanced
ReprésentationUne copie du prefab (ou de la variante) placée sous l’objet enfant « RTS Decor », avec un composant RTSDecorInstanceDessiné avec Graphics.RenderMeshInstanced (premier niveau de LOD du prefab), jusqu’à 1023 instances par draw call
CullingCelle d’UnityPar patch (frustum + Max Draw Distance)
Scripts, colliders, animationsOuiNon (aucun objet n’est créé)
TeinteVia un MaterialPropertyBlock (_BaseColor et _Color)Uniquement avec les shaders qui la prennent en charge (voir Teinte par instance)
Idéal pourLes accessoires interactifs ou destructibles, de quelques centaines à quelques milliers d’objetsLes éléments de décor statiques en grand nombre

Règle de placement : position = LocalToWorld(x, ground + y + prototype yOffset, z), ou la hauteur absolue enregistrée avec l’indicateur KeepHeight. Rotation = rotation du terrain × rotation de l’instance, échelle = échelle de l’instance. Pour les prefabs créés dans la scène, la rotation et l’échelle définies sur leur racine s’y ajoutent.

Le décor instancié nécessite l’option Enable GPU Instancing sur ses matériaux. Si elle est désactivée, une copie d’exécution avec instanciation activée est utilisée et un avertissement vous demande de cocher la case. Utilisez le Project Validator pour corriger tous les matériaux d’un coup.

Les champs du prototype (variantes, rotation et échelle aléatoires, teinte, emprise, blocage de la vision, ombres) sont décrits dans la section Bibliothèque de décors.

Paramètres du gestionnaire de décors

ParamètrePar défautDescription
Show In Scene ViewactivéDessine le décor instancié dans les caméras de la Scene View. Les GameObjects créés dans la scène sont toujours visibles.
Max Draw Distance0Le décor instancié situé au-delà de cette distance de la caméra n’est pas dessiné (0 = aucune limite).
Shadow Culling Margin12 mMarge supplémentaire autour des patches pour le culling par frustum, afin que les accessoires situés juste hors du champ continuent d’y projeter leurs ombres.
Instanced TintactivéTransmet les teintes par instance au décor instancié dont le shader les prend en charge.
Patch Size16Longueur du côté d’un patch de culling et de requête, en cellules (4–64). Modifier cette valeur reconstruit le décor.
Pool Capacity Per Prefab64Les décors GameObject supprimés sont conservés inactifs pour être réutilisés, dans la limite de ce nombre d’objets par prefab.
Log Missing PrototypesactivéAffiche dans la fenêtre Console un seul avertissement par id de prototype manquant, par bibliothèque manquante ou par prefab détruit.

L’Inspector du Decor Manager affiche les valeurs Instances, GameObjects, Instanced et Sync (qui indique si des modifications sont en attente), ainsi que les boutons Rebuild (RebuildAll() : détruit et recrée tout, vide les pools, relit les prefabs), Sync Now (SyncNow()) et Select Library.

Substituts

Si une carte référence un id de prototype absent de la bibliothèque, si le terrain n’a aucune bibliothèque de décors ou si un prefab a été supprimé, l’instance s’affiche sous la forme d’un petit cube magenta. Rien n’est perdu : l’instance reste dans la carte et réapparaît normalement dès que le prototype est de retour. IsPlaceholder(id) indique si une instance est un substitut. Les substituts sont comptabilisés comme décor instancié.

Si des cubes magenta apparaissent après l’ouverture d’une carte provenant de quelqu’un d’autre, c’est généralement que le terrain utilise une autre bibliothèque de décors que celle avec laquelle la carte a été créée. Assignez la bonne bibliothèque dans l’Inspector de RTSTerrain.

Teinte par instance avec vos propres shaders

Le décor instancié n’est teinté par instance que si le shader peut lire la teinte dans le buffer d’instanciation. URP Lit, Simple Lit et Unlit conservent la couleur de leur matériau. Un shader active cette prise en charge au moyen d’un tag de SubShader :

TagConstanteLe shader doit
"RTSInstanceTint" = "True"RTSDecorManager.InstanceTintShaderTagMultiplier son albédo par la valeur instanciée _RTS_InstanceTint (rgb = teinte, a = 1). Le shader RTS Terrain Studio/Vegetation du package est détecté automatiquement.
"RTSInstancedColor" = "True"RTSDecorManager.InstancedColorShaderTagLire _BaseColor et _Color avec UNITY_ACCESS_INSTANCED_PROP depuis un UNITY_INSTANCING_BUFFER. Les valeurs écrites valent couleur du matériau × teinte.

API de décor : sélection, requêtes et événements

La sélection par rayon et les requêtes n’ont besoin d’aucun collider. Chaque instance est testée sous la forme d’une boîte orientée, construite à partir de la boîte englobante du mesh du prefab. Sélection et requêtes fonctionnent donc avec les deux modes d’apparition, y compris pour les décors instanciés, qui n’ont pas de GameObject.

MembreDescription
bool TryPick(Ray worldRay, float maxDistance, out uint instanceId) (+ surcharge avec out float hitDistance)Instance la plus proche touchée par un rayon en espace monde.
int QueryRadius(Vector3 world, float radius, List<uint> results)Ajoute les ids situés dans un rayon donné sur le plan du sol. La liste n’est pas vidée au préalable. Sans allocation. Une surcharge IEnumerable<uint> alloue une nouvelle liste.
int QueryLocalRect(Rect localRect, List<uint> results)Ajoute les ids dont le pivot se trouve dans un rectangle XZ en espace local de la carte (sélection par rectangle).
GameObject GetInstanceObject(uint id)L’objet créé, ou null (décor instancié ou id inconnu).
ContainsInstance, TryGetInstance(uint, out DecorInstanceData), IsInstanced, IsPlaceholderConsultation des instances (données à l’état de la dernière synchronisation).
TryGetWorldBounds(uint, out Bounds), TryGetObjectMatrix(uint, out Matrix4x4)Boîte englobante en espace monde ; matrice de la racine de l’objet, y compris la rotation et l’échelle de la racine définies dans le prefab.
Matrix4x4 GetWorldMatrix(in DecorInstanceData), GetWorldMatrix(in DecorInstanceData, string prototypeId)Matrice monde du pivot, y compris pour des données qui ne sont pas encore dans la carte (aperçus de placement).
SpawnedCount, InstancedCount, InstanceCount, Container, PatchSize, HasPendingChangesÉtat et statistiques.
InstancesRebuilt, InstancesChangedAprès une reconstruction complète ; après une mise à jour incrémentale.
InstanceSpawned, InstanceDespawningUn objet a été créé ou sorti du pool ; un objet est sur le point d’être remis dans le pool ou détruit. Les objets conservés lors d’une reconstruction légère ne déclenchent pas de nouveau InstanceSpawned.
RTSDecorInstance : InstanceId (0 tant que l’objet est dans le pool), PrototypeId, Variant, Owner, Prototype, IsLive, TryGetData, static FromCollider(Collider)Composant présent sur la racine de chaque objet créé. Ses champs sont remplis avant l’exécution des méthodes Awake/OnEnable du prefab lui-même : les scripts de votre prefab peuvent donc les y lire.
using System.Collections.Generic;
using RTSTerrainStudio;
using Unity.Mathematics;
using UnityEngine;

/// Click a decor object to destroy it; Shift+click destroys everything within 5 m of the click.
public class DecorDemolisher : MonoBehaviour
{
    [SerializeField] RTSDecorManager decor;
    [SerializeField] Camera viewCamera;

    // Reused every click: QueryRadius appends to it and never allocates.
    readonly List<uint> nearby = new List<uint>();

    void Update()
    {
        if (decor == null || viewCamera == null || !RTSInput.GetMouseButtonDown(0)) return;

        Ray ray = viewCamera.ScreenPointToRay(RTSInput.PointerPosition);
        // Works for GameObject and instanced decor alike, without colliders.
        if (!decor.TryPick(ray, 500f, out uint id, out float distance)) return;

        if (RTSInput.Shift)
        {
            nearby.Clear();
            decor.QueryRadius(ray.GetPoint(distance), 5f, nearby);
            foreach (uint other in nearby) Remove(other);
        }
        else
        {
            Remove(id);
        }
    }

    void Remove(uint id)
    {
        RTSTerrain terrain = decor.Terrain;
        MapData map = terrain.Map;
        int index = map.FindDecorIndex(id);
        if (index < 0) return;

        DecorInstanceData data = map.Decor[index];
        map.Decor.RemoveAt(index);

        // Tell the terrain what changed. The decor manager removes (pools) the object,
        // and the pathing map reopens the footprint automatically.
        int2 cell = map.LocalToCell(data.position.xz);
        terrain.NotifyChanged(MapLayers.Decor, new RectInt(cell.x, cell.y, 1, 1));
    }
}
using RTSTerrainStudio;
using UnityEngine;

/// Gives every spawned decor object of the category "Destructible" some hit points.
public class DestructibleDecorSetup : MonoBehaviour
{
    [SerializeField] RTSDecorManager decor;

    void OnEnable()
    {
        if (decor != null) decor.InstanceSpawned += HandleSpawned;
    }

    void OnDisable()
    {
        if (decor != null) decor.InstanceSpawned -= HandleSpawned;
    }

    void HandleSpawned(RTSDecorManager manager, RTSDecorInstance instance)
    {
        // Prototype looks up the library entry, e.g. its category or footprint.
        DecorPrototype prototype = instance.Prototype;
        if (prototype == null || prototype.category != "Destructible") return;

        // Pooled objects come back here when they are reused, so add the component only once.
        if (!instance.TryGetComponent(out Health health)) health = instance.gameObject.AddComponent<Health>();
        health.hitPoints = 100;
    }
}

/// Example gameplay component.
public class Health : MonoBehaviour
{
    public int hitPoints;
}

Seuls les prototypes en mode GameObject déclenchent InstanceSpawned, car les décors instanciés ne créent aucun objet.

Environnement

Chaque carte stocke son propre éclairage dans MapData.Environment : couleur, intensité et rotation du soleil, couleur ambiante et brouillard atmosphérique. Une carte enneigée peut ainsi être livrée avec une lumière froide, et une carte désertique avec une lumière chaude. Le composant RTSEnvironment applique ces valeurs à la scène au chargement d’une carte et chaque fois que l’environnement change.

Mise en place

  1. Choisissez GameObject ▸ RTS Terrain Studio ▸ Environment. Cette commande crée un GameObject « Environment » doté du composant RTSEnvironment, ainsi qu’une lumière directionnelle « Sun » si la scène n’en contient pas. Si les scènes ouvertes contiennent déjà un environnement, vous pouvez le sélectionner à la place. Plusieurs environnements se disputeraient les mêmes paramètres d’éclairage.
  2. Vous pouvez aussi ajouter Add Component ▸ RTS Terrain Studio ▸ Environment au GameObject du terrain (l’Inspector de RTSTerrain propose un bouton Add).
  3. Modifiez les valeurs dans l’onglet Map de la fenêtre de l’éditeur (Tools ▸ RTS Terrain Studio ▸ Editor Window), dans le panneau Environment : Sun Colour, Sun Intensity, Sun Rotation (x = inclinaison au-dessus de l’horizon, y = lacet), Ambient Colour, Fog, Fog Colour, Fog Density. Ces modifications peuvent être annulées et sont enregistrées avec la carte.
  4. Ou bien éclairez la scène à la main, puis cliquez sur Capture From Scene (fenêtre de l’éditeur) ou sur Use Current Lighting (Inspector du composant) pour stocker dans la carte le soleil, la lumière ambiante et le brouillard atmosphérique actuels, en une seule étape d’annulation.

L’éclairage appliqué n’est qu’un aperçu. Il n’est pas enregistré dans l’historique d’annulation et ne marque pas la scène comme modifiée. Juste avant l’enregistrement de la scène, l’éclairage d’origine de la scène est restauré, puis, une fois l’enregistrement terminé, l’éclairage de la carte est appliqué de nouveau. L’éclairage de la carte n’est donc jamais écrit dans votre fichier de scène. Le bouton Restore Scene Lighting de l’Inspector rétablit l’éclairage d’avant la première application.

Paramètres du composant

ParamètrePar défautDescription
TerrainvideTerrain dont l’éclairage de carte est appliqué. Vide = le RTSTerrain de ce GameObject, sinon le terrain principal (RTSTerrain.Main). Un terrain activé plus tard est pris en compte automatiquement.
SunvideLumière directionnelle utilisée comme soleil. Vide = RenderSettings.sun, ou la lumière directionnelle active la plus intense.
Apply In Edit ModeactivéApplique l’éclairage de la carte pendant l’édition. Si l’option est désactivée, il n’est appliqué qu’en Play Mode.
Apply SunactivéApplique la couleur, l’intensité et la rotation du soleil (espace monde).
Apply AmbientactivéApplique la lumière ambiante.
Ambient ModeTrilightFlat = une seule couleur ambiante. Trilight = dégradé ciel / équateur / sol dérivé de la couleur ambiante de la carte.
Sky Factor1.2Trilight : couleur du ciel = couleur ambiante × ce facteur (0–3).
Ground Factor0.55Trilight : couleur du sol = couleur ambiante × ce facteur (0–3).
Apply FogactivéApplique l’état activé/désactivé du brouillard atmosphérique, sa couleur et sa densité.
Fog ModeExponential SquaredMode d’atténuation utilisé quand le brouillard atmosphérique est appliqué (la carte ne stocke que sa couleur et sa densité).
Restore On DisableactivéRestaure l’éclairage de la scène d’avant la première application lorsque le composant est désactivé.

Valeurs par défaut d’une nouvelle carte : couleur du soleil d’un blanc chaud (1, 0.956, 0.84), intensité 1.2, rotation (50, −30), lumière ambiante (0.45, 0.5, 0.58), brouillard atmosphérique désactivé, couleur du brouillard (0.6, 0.68, 0.75), densité 0.004.

Pour un cycle jour/nuit dans votre jeu, pilotez la lumière du soleil directement depuis votre propre script. RTSEnvironment ne réapplique les valeurs de la carte qu’au chargement d’une carte ou quand son environnement change. Vous pouvez aussi décocher Apply Sun et ne conserver de la carte que la lumière ambiante et le brouillard atmosphérique.

API de l’environnement

MembreDescription
void Apply()Applique immédiatement l’environnement de la carte à la scène (respecte Apply In Edit Mode).
void CaptureFromScene(RTSEditSession session)Écrit l’éclairage de la scène dans la carte, en une seule étape d’annulation de la session.
void CaptureFromScene(RTSToolContext ctx = null)Écrit l’éclairage de la scène dans la carte. L’annulation n’est enregistrée qu’à l’intérieur de RTSEditSession.RunOperation.
void RestoreSceneState()Restaure l’éclairage sauvegardé avant la première application.
RTSTerrain Terrain { get; set; }, Light Sun { get; set; }, bool CanApplyTerrain associé, lumière du soleil, et indication que l’application est actuellement autorisée ou non.
static Light FindSun()RenderSettings.sun s’il s’agit d’une lumière directionnelle, sinon la lumière directionnelle active la plus intense.
using RTSTerrainStudio;
using UnityEngine;

/// Switches the current map to a stormy mood. RTSEnvironment applies it immediately.
public static class StormLighting
{
    public static void Apply(RTSTerrain terrain)
    {
        MapData map = terrain != null ? terrain.Map : null;
        if (map == null) return;

        // Work on a copy, then assign it: this is how the editor tools change the environment too.
        EnvironmentSettings env = map.Environment.Clone();
        env.sunColor = new Color(0.7f, 0.75f, 0.85f);
        env.sunIntensity = 0.45f;
        env.ambientColor = new Color(0.3f, 0.33f, 0.4f);
        env.fog = true;
        env.fogColor = new Color(0.45f, 0.48f, 0.52f);
        env.fogDensity = 0.012f;
        map.Environment = env;

        // MapLayers.Environment tells RTSEnvironment (and the in-game editor) that the lighting changed.
        terrain.NotifyChanged(MapLayers.Environment, map.CellBounds);
    }
}

Guide des performances

Les valeurs par défaut fonctionnent bien sur ordinateur de bureau pour des cartes de RTS typiques (128–256 cellules par côté). Cette section explique ce que coûte chaque paramètre, afin que vous puissiez optimiser en connaissance de cause les grandes cartes et les builds mobiles.

Liste de vérification rapide

  • Gardez le package Burst installé et la compilation Burst activée (Jobs ▸ Burst ▸ Enable Compilation).
  • Générez les tableaux de textures du tileset dans l’éditeur avec Compress Arrays activé, pour la plateforme sur laquelle vous publiez (l’Inspector du tileset affiche le format et une estimation de la taille).
  • Cochez Enable GPU Instancing sur chaque matériau des arbres, détails et décors instanciés (le Project Validator s’en charge en un clic).
  • Utilisez le mode d’apparition Instanced pour les arbres et accessoires purement décoratifs. Réservez le mode GameObject aux objets qui jouent un rôle dans le gameplay.
  • Choisissez la résolution de splat et la résolution des tableaux en fonction de la plateforme (voir ci-dessous). Toutes deux coûtent surtout de la mémoire.
  • Lancez Validate Map (onglet Map ▸ Validation). Cette vérification signale un nombre excessif d’arbres (20 000), d’arbres GameObject (1 500), d’objets de décor (6 000), d’objets de décor GameObject (2 000) et de calques de détails (8), ainsi que les grandes cartes (plus de 512 cellules).

Choisir la taille de chunk

Chunk SizeDraw calls (carte de 256 × 256)Coût de reconstruction par modificationÀ utiliser pour
16256 chunksLe plus faible : retour visuel du pinceau le plus rapidePetites cartes, édition intensive (éditeur en jeu sur des machines plus lentes)
32 (par défaut)64 chunksÉquilibréLa plupart des cartes
6416 chunksLe plus élevé : chaque modification reconstruit jusqu’à 64 × 64 cellules, plus les chunks voisins aux borduresGrandes cartes rarement modifiées (cartes livrées avec le jeu, que les joueurs ne font que regarder)

Chaque chunk représente un draw call par vue rendue (la caméra principale et chaque cascade d’ombres), et le SRP Batcher les regroupe à moindre coût, car ils partagent un même matériau. Les chunks sont aussi l’unité de culling : des chunks plus petits permettent donc un culling plus précis quand la caméra est proche du sol.

Subdivisions

Le nombre de vertices d’un sol lisse croît avec le carré de Surface Subdivisions :

Surface SubdivisionsVertices d’un chunk plat de 32 × 32Valeur effective de Cliff Subdivisions avec la valeur par défaut 4 (avec 8)
11 0894 (8)
2 (par défaut)4 2254 (8)
39 4096 (12)
416 6414 (8)

Cliff Subdivisions est arrondi vers le haut à un nombre pair qui est aussi un multiple de Surface Subdivisions, afin que les cellules de falaise et les cellules lisses partagent tous les vertices de leurs bordures. Avec 3 subdivisions de surface, la sous-grille des falaises devient un multiple de 6, ce qui est coûteux. Préférez 1, 2 ou 4. Chaque cellule de falaise coûte environ (subdivisions de falaise)² × 2 triangles, plus ses parois (autant de rangées par niveau que la valeur de Cliff Wall Segments) : ce sont donc les cartes riches en falaises qui profitent le plus de paramètres de falaise modérés.

Un vertex de chunk occupe 28 octets. Les indices sont codés sur 16 bits tant qu’un chunk reste sous les 65 536 vertices. Une carte plate de 256 × 256 avec 2 subdivisions compte environ 260 000 vertices, soit à peu près 10 Mo de données de vertices et d’indices. Les falaises s’y ajoutent, et les colliders des chunks ont besoin de leurs propres données de collision précalculées.

Résolution de splat

La résolution de splat (texels par cellule : 1, 2, 4 ou 8, 4 par défaut) se choisit à la création de la carte (dans le New Map Wizard). Elle détermine la finesse avec laquelle les textures de sol peuvent être peintes. Les données de splat se composent toujours de 4 splat maps RGBA32 (16 octets par texel) et existent en trois exemplaires : dans les données de la carte, dans la copie CPU des textures et sur le GPU (les deux derniers avec mip maps, +33 %).

Taille de la carte (cellules)Résolution 2Résolution 4 (par défaut)Résolution 8
128 × 1281 Mio de données + 1.3 Mio sur le GPU4 Mio + 5.3 Mio16 Mio + 21 Mio
256 × 2564 Mio + 5.3 Mio16 Mio + 21 Mio64 Mio + 85 Mio
512 × 51216 Mio + 21 Mio64 Mio + 85 Mio256 Mio + 341 Mio
1024 × 102464 Mio + 85 Mio256 Mio + 341 Mio1 Gio + 1.3 Gio

(Pour la copie CPU des textures, ajoutez encore une fois la valeur GPU.) Le coût de la peinture est faible : seules les lignes modifiées sont copiées. Sur les textures de plus de 1 million de texels, si la zone modifiée ne dépasse pas 512 × 512 texels, seule cette zone est envoyée au GPU. Sa chaîne de mips est reconstruite sur le CPU par un job Burst (SplatMipDownsampleJob), puis copiée à sa place sur le GPU.

La résolution 2 suffit pour l’aspect en tuiles aux bords nets des RTS classiques (Tile Paint). La résolution 4 donne des transitions douces et détaillées. La résolution 8 est réservée aux très petites tailles de cellule ou aux caméras très rapprochées.

Résolution des tableaux de textures

Chaque tileset regroupe ses textures de sol et de falaise dans deux Texture2DArray (albedo/hauteur et normales) de 20 tranches chacun, à la résolution définie par le paramètre Array Resolution du tileset (256, 512, 1024 par défaut, 2048). Mémoire occupée par les deux tableaux ensemble, mip maps compris :

Array ResolutionRGBA32 non compresséBC7 / DXT5 (ordinateurs de bureau, consoles)ASTC 6×6 (Android, iOS)
25613 Mio3.3 Mio1.5 Mio
51253 Mio13 Mio5.9 Mio
1024 (par défaut)213 Mio53 Mio24 Mio
2048853 Mio213 Mio95 Mio

Lorsque Compress Arrays est activé, l’Inspector du tileset précalcule des tableaux compressés pour la plateforme de build active : BC7 pour Windows, macOS, Linux et les consoles, ASTC 6×6 pour Android, iOS, tvOS et visionOS, la compression de texture du build pour Web (DXT5, ASTC 6×6 ou ETC2 RGBA8), DXT5 dans les autres cas. Si les tableaux générés sont absents, ou obsolètes dans l’éditeur, le moteur de rendu construit à la place des tableaux RGBA32 non compressés sur le GPU. Cela convient pour itérer rapidement, mais consomme quatre fois plus de mémoire que le BC7. Lors de la génération d’un build de joueur, les tableaux obsolètes sont d’abord reconstruits (voir Tableaux de textures dans les builds de joueur). Les tableaux sont partagés par tous les terrains qui utilisent le même tileset.

Si un GPU ou un navigateur ne peut pas échantillonner le format précalculé, Unity décompresse les tableaux à leur chargement, ce qui consomme environ quatre fois plus de mémoire. Dans un build de joueur, la copie CPU des tableaux générés est libérée dès leur première utilisation : ils n’occupent alors que la mémoire GPU indiquée dans le tableau ci-dessus.

Pour vérifier quels tableaux utilise un jeu en cours d’exécution, effectuez une capture dans le Memory Profiler et cherchez les render textures nommées « RTS Albedo Array (…) » et « RTS Normal Array (…) ». Si vous les trouvez, ce sont les tableaux non compressés construits à l’exécution qui sont utilisés.

Distance d’affichage des détails et végétation

  • Les détails sont le goulot d’étranglement le plus probable sur le GPU, car l’herbe se compose de nombreux petits triangles avec alpha clipping. Le nombre d’éléments visibles est proportionnel à Render Distance² × densité. Diviser par deux la distance d’affichage des détails réduit l’herbe dessinée à environ un quart.
  • Mémoire des détails : chaque patch peint conserve ses instances sur le GPU, quelle que soit la caméra : 32 octets par instance. Exemple : un calque de détails à pleine densité (Max Density 6, résolution de détails 2 = 4 texels par cellule) sur toute une carte de 256 × 256 donne environ 1.6 million d’instances, soit à peu près 50 Mo. Peignez l’herbe là où elle compte, ou baissez Max Density.
  • Les ombres des détails sont désactivées par défaut. Les activer entraîne un nouveau rendu de toute l’herbe pour chaque cascade d’ombres.
  • Arbres : les arbres instanciés coûtent un draw call par tranche de 1 023 instances, par partie et par groupe de patchs. Utilisez un LODGroup avec un LOD1 peu coûteux. Les arbres GameObject coûtent chacun un GameObject (n’en dépassez pas 1 500 environ).
  • Décor : réglez Max Draw Distance pour les décors instanciés sur les grandes cartes. Les décors GameObject sont soumis au culling de Unity, mais coûtent tout de même un GameObject chacun (n’en dépassez pas 2 000 environ).
  • Eau : avec Cell Subdivisions réglé sur 1, le nombre de vertices de l’eau est divisé par quatre par rapport à la valeur par défaut 2.

Burst et jobs

Toutes les boucles lourdes s’exécutent dans des jobs compilés avec Burst : meshes des chunks (BuildChunkGeometryJob, CopyChunkPartsJob), mips de splat (SplatMipDownsampleJob), meshes de l’eau (WaterChunkMeshJob), dispersion des détails (DetailScatterJob), matrices des arbres (TreeMatrixJob) et placement des décors (DecorPlacementJob, DecorPartMatricesJob). Les pinceaux, le cheminement, le brouillard de guerre, le module de recherche de chemin et le précalcul de la mini-carte utilisent également Burst. Les colliders des chunks sont précalculés en parallèle sur des threads de travail.

  • Les jobs de mesh sont compilés de manière synchrone : la première construction après un rechargement du domaine n’est donc pas confiée à une solution de repli managée et lente.
  • Mesurez les performances dans un build de joueur ou avec les vérifications de sécurité de Burst désactivées (Jobs ▸ Burst ▸ Safety Checks). Les vérifications de sécurité de l’éditeur et le Jobs Debugger ralentissent sensiblement les jobs.
  • Lorsque la compilation Burst est désactivée, tout fonctionne encore, mais les reconstructions de meshes et les traits de pinceau deviennent plusieurs fois plus lents.
  • Les builds Web n’ont pas de threads de travail : tous les jobs s’exécutent donc les uns après les autres sur le thread principal. Les opérations portant sur l’ensemble de la carte y prennent sensiblement plus de temps (voir Rendu et performances des builds Web).

Profilage

Ouvrez Window ▸ Analysis ▸ Profiler et recherchez ces marqueurs sur le thread principal :

MarqueurCe qui est mesuré
RTSVegetation.UpdateApplication des modifications de la carte à la végétation (inclut les deux marqueurs de construction ci-dessous).
RTSVegetation.BuildDetailsRégénération des patchs de détails modifiés.
RTSVegetation.BuildTreesReconstruction des groupes d’arbres instanciés.
RTSVegetation.DrawCulling et émission des draw calls de la végétation pour une caméra.

Passez le module CPU en vue Timeline pour voir les noms des jobs cités plus haut sur les threads de travail. Côté GPU, utilisez le Frame Debugger (Window ▸ Analysis ▸ Frame Debugger) pour compter les draw calls des chunks de terrain, des détails et des objets instanciés. Les Inspectors des composants Vegetation Renderer, Water Renderer et Decor Manager affichent en direct le nombre d’instances et de vertices. L’Inspector de RTSTerrain affiche le nombre de chunks et la mémoire occupée par la carte.

Consommation mémoire en chiffres

Les données de la carte elles-mêmes (la valeur Map Memory dans l’Inspector de RTSTerrain, MapData.GetMemoryUsage()) représentent :

  • 11 octets par vertex (hauteur, niveau de falaise, indicateurs, type de falaise, hauteur de l’eau),
  • 16 octets par texel de splat,
  • 1 octet par texel de cheminement,
  • 1 octet par texel de détails et par calque de détails.
Taille de la carte (valeurs par défaut : splat 4, détails 2, cheminement 2, 1 calque de détails)Données de la carteTextures de splat (GPU)Tableaux de textures (1024, BC7)
128 × 128 (256 m avec des cellules de 2 m)≈ 4.3 Mio≈ 5.3 Mio53 Mio par tileset
256 × 256≈ 17 Mio≈ 21 Mio53 Mio par tileset
512 × 512≈ 69 Mio≈ 85 Mio53 Mio par tileset
1024 × 1024≈ 275 Mio≈ 341 Mio53 Mio par tileset

À cela s’ajoutent les meshes et colliders des chunks (voir Subdivisions), les instances de détails (32 octets chacune), la carte de cheminement et les textures du brouillard de guerre. L’historique d’annulation de l’éditeur dispose de son propre budget mémoire (voir les paramètres de la fenêtre de l’éditeur).

Tailles de carte recommandées

Les cartes peuvent mesurer de 16 à 1024 cellules par côté, par pas de 16. La valeur par défaut est de 128 × 128 cellules de 2 m.

Taille (cellules)Usage typiqueRemarques
64–128Cartes 1v1 et petites cartes d’escarmouche, mobileTout se reconstruit instantanément. Une bonne taille pour l’éditeur en jeu sur n’importe quel appareil.
128–2562–4 joueursLe compromis idéal. Toutes les valeurs par défaut sont optimisées pour cette taille.
256–512Grandes cartes, 4–8 joueursOrdinateur de bureau. Envisagez une résolution de splat de 2–4 et un Chunk Size de 32–64.
plus de 512Très grandes cartesLa validation de la carte affiche une information : l’édition et les reconstructions du cheminement prennent plus de temps. Surveillez la mémoire de splat (tableau ci-dessus) et envisagez de répartir le monde sur plusieurs RTSTerrain.

Plusieurs terrains peuvent être placés côte à côte, chacun avec son propre Transform. RTSTerrain.FindAt et RTSTerrain.RaycastAll trouvent le bon terrain pour une position en espace monde.

Remarques pour les mobiles

  • Tableaux de textures : générez-les avec la plateforme Android/iOS active, afin qu’ils soient précalculés en ASTC 6×6 (une fois générés, ils sont tenus à jour pour la plateforme active à chaque build de joueur). Une Array Resolution de 512 suffit généralement sur les téléphones.
  • Résolution de splat : 2 texels par cellule divisent par quatre la mémoire de splat par rapport à la valeur par défaut 4.
  • Calques : chaque calque de sol visible sur un pixel coûte des échantillonnages de texture. Utilisez moins de calques par zone et réglez Anti Tiling sur 0 pour les calques dont la répétition n’est pas visible (cela économise le second échantillonnage).
  • Éclairage : utilisez un matériau de remplacement avec Specular Highlights et Environment Reflections désactivés (voir plus haut).
  • OpenGL ES et WebGL 2.0 : les shaders ciblent le Shader Model 3.5 et fonctionnent donc sur les appareils OpenGL ES 3.0 et dans les navigateurs. Ces API ne garantissent que 16 textures de fragment par draw call, et la passe forward du terrain en utilise déjà 10 à elle seule. L’asset URP Mobile des modèles de projet URP de Unity (ombres de la lumière principale, fondu des reflection probes) en ajoute déjà 4, et avec les light cookies, la limite est atteinte. Une variante de shader qui nécessite davantage de textures ne se charge pas : le terrain disparaît alors ou s’affiche en rose. Dans l’asset URP utilisé pour les appareils GLES et les builds Web, désactivez le fondu des reflection probes si vos scènes n’utilisent pas le fondu entre probes, et laissez désactivés les light cookies, les decals, le SSAO, les ombres des lumières additionnelles et les adaptive probe volumes, sauf si vous en avez besoin. Le commentaire Texture slot budget de Shaders/Include/RTSTerrainInput.hlsl indique le coût de chaque fonctionnalité URP.
  • Eau : si vous désactivez Depth Texture ou Opaque Texture dans l’asset URP mobile pour économiser de la bande passante, l’eau passe à son rendu de repli : sans la texture opaque, pas de réfraction ; sans la texture de profondeur, les rivages ignorent les objets présents dans l’eau. Une caméra qui active ces textures pour elle-même bénéficie tout de même du rendu complet de l’eau. Réglez Cell Subdivisions sur 1.
  • Végétation : baissez les multiplicateurs Detail Density et Detail Distance, réglez Crossed Quad Count sur 2 et désactivez les ombres des détails.
  • Physique : si votre jeu n’utilise pas la physique Unity sur le terrain, réglez Collider Mode sur None et utilisez RTSTerrain.Raycast / RaycastAll pour la sélection par rayon.
  • Géométrie : Surface Subdivisions à 1 (l’aspect RTS classique) et Cliff Wall Segments à 2 réduisent considérablement le nombre de vertices.

Un préréglage pour configurations modestes, appliqué par le code

using RTSTerrainStudio;
using UnityEngine;

/// Applies cheap settings to a terrain and its systems, e.g. from a "Low" graphics option.
public static class LowEndPreset
{
    public static void Apply(RTSTerrain terrain)
    {
        if (terrain == null) return;

        // Terrain mesh: fewer vertices, larger chunks, no colliders (picking uses RTSTerrain.Raycast).
        RTSTerrainSettings s = terrain.Settings;
        s.surfaceSubdivisions = 1;
        s.cliffSubdivisions = 4;
        s.cliffWallSegments = 2;
        s.chunkSize = ChunkSize._64;
        s.colliderMode = ColliderMode.None;
        // Settings changed from code are applied by a rebuild (the inspector does this automatically).
        terrain.RebuildAll();

        if (terrain.TryGetComponent(out RTSVegetationRenderer vegetation))
        {
            vegetation.detailDensityMultiplier = 0.4f;
            vegetation.detailDistanceMultiplier = 0.5f;
            vegetation.treeDistanceMultiplier = 0.7f;
            vegetation.crossedQuadCount = 2;
        }

        if (terrain.TryGetComponent(out RTSWaterRenderer water))
        {
            water.cellSubdivisions = 1;   // rebuilt automatically when the value changes
        }

        if (terrain.TryGetComponent(out RTSDecorManager decor))
        {
            decor.maxDrawDistance = 120f; // instanced props beyond 120 m are skipped
        }
    }
}

ColliderMode.None supprime les colliders des chunks. Dans votre jeu, tout ce qui lance des Physics.Raycast sur le terrain cesse alors de fonctionner, tout comme les rigidbodies posés dessus et le précalcul du NavMesh à partir des colliders des chunks. Ne choisissez ce mode que si vous utilisez les requêtes sans physique.

Systèmes de gameplay

RTS Terrain Studio n’est pas qu’un éditeur de cartes. Les cartes que vous créez s’accompagnent des systèmes dont a besoin un RTS classique : un brouillard de guerre qui tient compte des niveaux de falaise et des arbres, une carte de cheminement avec recherche de chemin intégrée, des scripts de gameplay d’exemple prêts à l’emploi (caméra, unités, sélection, ordres, mini-carte, HUD) et un générateur de contenu de démo qui crée des textures, des modèles, des cartes et des scènes de démo jouables.

Ce chapitre présente les systèmes un par un. Chaque section commence par ce que vous pouvez faire sans code, détaille ensuite les composants et leurs paramètres, puis se termine par l’API de script destinée aux programmeurs.

Vous voulez juste jouer ? Lancez Tools ▸ RTS Terrain Studio ▸ Create Demo Content, double-cliquez sur la scène RTS Terrain Studio - Gameplay Demo qui est alors sélectionnée dans la fenêtre Project, puis appuyez sur Play. Voir Scènes de démo.

Brouillard de guerre dans la scène Gameplay Demo : des unités et un bâtiment de départ, la zone située derrière une falaise plus haute est noire
Brouillard de guerre dans la scène Gameplay Demo : les unités révèlent leurs alentours ; le plateau situé derrière la falaise plus haute reste noir, car un terrain plus élevé bloque la ligne de vue (règles classiques des RTS).

Brouillard de guerre

Le brouillard de guerre masque ce qu’un joueur ne peut pas voir. Il suit les règles classiques des RTS :

  • Par équipe. La visibilité est suivie pour 32 équipes au maximum (indices d’équipe 0 à 31). Chaque unité ou bâtiment donne la vision à sa propre équipe.
  • Trois états. Le sol qu’une équipe n’a jamais vu est noir (inexploré). Le sol qu’elle a déjà vu, mais qu’elle ne voit pas en ce moment, est assombri (exploré). Le sol qu’elle voit en ce moment s’affiche normalement (visible).
  • Mémoire de l’exploration. Chaque équipe se souvient de ce qu’elle a exploré, jusqu’à ce que vous réinitialisiez cette mémoire.
  • Ligne de vue selon les niveaux de falaise. Une unité voit son propre niveau de falaise et tout ce qui se trouve en dessous. Un terrain plus élevé n’est jamais visible d’en bas, et il bloque la vue sur les cellules situées derrière lui.
  • Obstacles à la vision. Les arbres (et les objets de décor que vous marquez comme bloquant la vision) masquent les cellules situées derrière eux.
  • Alliances et vision partagée. Les équipes peuvent partager leur vision dans un sens ou dans les deux.
  • Ennemis masqués. Les unités ennemies disparaissent tant que vous ne pouvez pas les voir. Les bâtiments restent visibles sous forme de « fantômes » une fois que vous les avez découverts.

La visibilité est calculée quelques fois par seconde par des jobs Burst, puis stockée dans une texture. Cette texture est lissée dans le temps et floutée sur le GPU : les bords du brouillard de guerre se déplacent ainsi en douceur au lieu de sauter d’une cellule à l’autre.

Démarrage rapide : ajouter un brouillard de guerre à votre scène

  1. Ouvrez une scène qui contient un RTS Terrain.
  2. Choisissez GameObject ▸ RTS Terrain Studio ▸ Fog of War Manager. Cette commande crée un GameObject Fog of War doté d’un composant RTSFogOfWarManager et le sélectionne.
  3. Si votre renderer URP ne possède pas encore la renderer feature du brouillard de guerre, une boîte de dialogue propose de l’ajouter. Cliquez sur Add Feature. (Vous pouvez aussi le faire plus tard avec Tools ▸ RTS Terrain Studio ▸ Validate Project, ou à la main, voir Rendu.)
  4. Ajoutez un composant RTSFogOfWarRevealer (Add Component ▸ RTS Terrain Studio ▸ Fog of War Revealer) à chaque unité et à chaque bâtiment qui doit pouvoir voir. Réglez ses paramètres Team et Radius.
  5. Ajoutez un composant RTSFogOfWarHideable (Add Component ▸ RTS Terrain Studio ▸ Fog of War Hideable) à chaque objet que les ennemis ne doivent pas voir. Réglez son paramètre Team. Utilisez Hide When Not Visible pour les unités et Ghost When Explored pour les bâtiments.
  6. Appuyez sur Play. La carte est noire, sauf autour des révélateurs de l’équipe locale (Local Team, l’équipe 0 par défaut).

Le brouillard de guerre ne fonctionne qu’en Play Mode. Pour le voir pendant l’édition, activez Preview In Edit Mode sur le gestionnaire (ou cliquez sur Enable Preview dans son Inspector). Les composants masquables ne cachent les objets qu’en Play Mode ; en Edit Mode, tout reste visible.

L’unité d’exemple RTSUnit nécessite et configure déjà un révélateur et un composant masquable. Si vous utilisez les exemples (ou RTSDemoGame), vous n’avez pas besoin d’ajouter ces composants à la main. RTSDemoGame crée même le gestionnaire pour vous lorsque la scène n’en contient aucun.

Comment la visibilité est calculée

La carte est divisée en cellules de brouillard. Avec la valeur par défaut de 2 pour Resolution Per Cell et la taille de cellule de carte par défaut de 2 m, une cellule de brouillard mesure 1 m de large. Pour chaque révélateur, le gestionnaire :

  1. Détermine le niveau d’observation : le niveau de falaise à la position exacte du révélateur, plus son Height Bonus.
  2. Parcourt chaque cellule de brouillard comprise dans le rayon de vision (Radius).
  3. Selon le paramètre Line Of Sight, trace une ligne du révélateur jusqu’à la cellule. La cellule est visible si son propre niveau de falaise ne dépasse pas le niveau d’observation et si aucune cellule sur le trajet n’est plus haute que le niveau d’observation ni (avec les obstacles à la vision) ne contient un arbre ou un objet de décor bloquant. La cellule bloquante elle-même est visible : vous voyez donc la lisière d’une forêt, mais pas ce qui se trouve derrière.
  4. Marque la cellule comme visible et explorée pour l’équipe du révélateur, ainsi que pour chaque équipe qui reçoit la vision de cette équipe.
Mode Line Of SightComportementÀ utiliser pour
NoneLes révélateurs voient un cercle complet. Ni les falaises ni les arbres ne bloquent la vue. C’est le mode le moins coûteux.Jeux sans ligne de vue, nombre d’unités très élevé.
CliffLevelsRègle classique des RTS : un révélateur voit son propre niveau de falaise et tout ce qui se trouve en dessous. Un terrain plus élevé bloque la vue.Cartes dégagées, ou lorsque les arbres ne doivent pas bloquer la vision.
CliffLevelsAndBlockers (par défaut)Comme CliffLevels, et en plus, les arbres et les objets de décor qui bloquent la vision masquent les cellules situées derrière eux.L’expérience RTS classique au complet.

Les objets qui bloquent la vision se définissent dans les bibliothèques :

  • Arbres : l’option Blocks Vision d’un prototype d’arbre dans la bibliothèque de végétation (activée par défaut). La zone bloquée correspond au Footprint Radius de l’arbre multiplié par l’échelle de l’instance.
  • Décors : l’option Blocks Vision d’un prototype de décor dans la bibliothèque de décors (désactivée par défaut). La zone bloquée correspond à l’emprise du prototype (cercle ou boîte orientée), mise à l’échelle avec l’instance.

Tours de guet, collines et éclaireurs volants : donnez à leur révélateur un Height Bonus d’un niveau ou plus pour qu’ils voient par-dessus les falaises plus hautes, ou activez Ignore Line Of Sight pour les unités aériennes afin que rien ne bloque leur vue.

Les modifications de la carte sont suivies automatiquement (dans l’éditeur, dans l’éditeur en jeu et depuis le code de gameplay qui appelle RTSTerrain.NotifyChanged). Les modifications des niveaux de falaise (MapLayers.CliffLevels / VertexFlags) ne rééchantillonnent que les cellules modifiées, plus une marge d’une cellule. Les modifications d’arbres et de décors reconstruisent la couche raster des obstacles à la vision pour toute la carte lors de la mise à jour suivante. Un appel à NotifyChangedAll reconstruit entièrement la couche raster des falaises.

RTSFogOfWarManager

Un seul gestionnaire par scène calcule et affiche le brouillard de guerre d’un terrain. Créez-le avec GameObject ▸ RTS Terrain Studio ▸ Fog of War Manager ou Add Component ▸ RTS Terrain Studio ▸ Fog of War Manager. Si plusieurs gestionnaires sont activés, seul le premier (RTSFogOfWarManager.Active) est utilisé, et l’Inspector vous en avertit.

ParamètrePar défautDescription
Map
TerrainvideTerrain couvert par le brouillard de guerre. Si le champ est vide, RTSTerrain.Main est utilisé (le premier terrain activé).
Resolution Per Cell2Nombre de cellules de brouillard par cellule de carte et par axe : 1, 2 ou 4. Des valeurs plus élevées donnent des bords plus lisses, mais coûtent plus cher. La valeur est réduite automatiquement pour que la grille de brouillard ne dépasse pas 2048 cellules par axe. La modifier reconstruit la grille et efface l’exploration.
Simulation
Update Interval0.1Secondes entre deux mises à jour de la visibilité. Avec 0, la mise à jour a lieu à chaque image.
Local Team0Équipe dont la vue est affichée et utilisée par les objets masquables (0 à 31). Changez-la dans l’Inspector pour vérifier ce que voient les autres joueurs.
Shared Visiontout à 0Pour chaque équipe réceptrice, un masque de bits des équipes qui partagent leur vision avec elle (bit t = équipe t). Généralement défini par le code, voir Alliances.
Line Of SightCliffLevelsAndBlockersManière dont les falaises et les objets bloquent la vue. Voir Comment la visibilité est calculée.
Compute All TeamsdésactivéCalcule la visibilité pour toutes les équipes, et pas seulement pour l’équipe locale. Nécessaire pour les serveurs (gestion d’intérêt) et pour le code d’IA qui demande ce qu’une autre équipe peut voir.
Start ExploreddésactivéToute la carte est explorée dès le départ : aucune zone noire, seulement le brouillard de guerre assombri. Appliqué à la création de la grille de brouillard.
Reveal AlldésactivéDébogage : tout est visible et exploré pour toutes les équipes.
Look
Unexplored Colornoir, alpha 1Couleur des zones jamais explorées. L’alpha détermine l’intensité.
Explored Color(0.3, 0.32, 0.38), alpha 0.6Teinte appliquée par multiplication aux zones explorées qui ne sont pas visibles en ce moment. L’alpha détermine l’intensité.
Fade Speed4Vitesse d’apparition et de disparition du brouillard de guerre (fondus complets par seconde). 0 = instantané.
Blur Iterations1Nombre de passes de flou GPU appliquées à la texture du brouillard de guerre (0 à 4, 0 = désactivé).
Blur Upscale2Multiplicateur de résolution de la texture floutée (1 à 4). Des valeurs plus élevées donnent des bords plus arrondis. Réduit automatiquement pour que la texture floutée ne dépasse pas 2048 pixels.
Editor
Preview In Edit ModedésactivéExécute le brouillard de guerre en Edit Mode, à titre d’aperçu.
Shaders
Blur Shader, Minimap Shaderassignés automatiquementRéférencés ici pour que les shaders cachés soient inclus dans les builds de joueur. Laissez-les tels quels.

L’Inspector affiche aussi des statistiques en direct (état, taille de la grille de brouillard, mémoire, révélateurs actifs, nombre de mises à jour), un aperçu en direct de la texture du brouillard de guerre (rouge = visible en ce moment, vert = exploré, noir = jamais vu) et les boutons suivants :

BoutonRôle
Explore AllMarque toute la carte comme explorée pour l’équipe locale.
Reset ExplorationOublie tout ce que chaque équipe a exploré.
Update NowRecalcule immédiatement la visibilité.
Rebuild Terrain DataRelit les niveaux de falaise et les obstacles à la vision depuis le terrain.

RTSFogOfWarRevealer

Donne à son équipe la vision autour du GameObject. Placez-le sur les unités, les bâtiments, les balises de vision et tout autre objet doté d’une vision. Le révélateur s’enregistre auprès du gestionnaire lorsqu’il est activé ; le gestionnaire lit sa position à chaque mise à jour, si bien que le composant n’a aucun coût par image. Sélectionnez-le pour voir son rayon de vision sous forme de cercle jaune dans la Scene View.

ParamètrePar défautDescription
Team0Équipe qui reçoit la vision (0 à 31).
Radius12Rayon de vision en mètres.
Height Bonus0Niveaux de falaise supplémentaires par-dessus lesquels le révélateur peut voir (tours de guet, collines, éclaireurs volants).
Ignore Line Of SightdésactivéVoit par-dessus les falaises et les obstacles à la vision (unités aériennes).
Reveal When DisableddésactivéContinue de révéler même lorsque ce composant ou son GameObject est désactivé, jusqu’à sa destruction.

Les révélateurs dont l’option Reveal When Disabled est activée et qui se trouvent sur des GameObjects déjà inactifs au chargement de la scène sont collectés une seule fois, lorsque le gestionnaire est activé. Les objets que vous instanciez plus tard à l’état inactif (pools d’objets, scènes additives) n’exécutent jamais Awake : enregistrez-les donc vous-même avec RTSFogOfWarManager.RegisterRevealer(revealer), ou définissez RevealWhenDisabled = true par le code.

RTSFogOfWarHideable

Masque les renderers (et, en option, les canvas et les colliders) d’un objet ennemi tant que l’équipe locale ne peut pas le voir. Les objets de l’équipe locale, et ceux des équipes qui partagent leur vision avec elle, ne sont jamais masqués. Seuls les composants qui étaient activés au moment où l’objet a été masqué sont réactivés lorsqu’il redevient visible : votre propre logique d’activation et de désactivation continue donc de fonctionner.

ParamètrePar défautDescription
Team0Équipe propriétaire de l’objet (0 à 31).
ModeHideWhenNotVisibleHideWhenNotVisible : l’objet n’est affiché que tant que sa position est visible en ce moment (unités). GhostWhenExplored : l’objet reste affiché une fois découvert, même lorsque la zone est de nouveau recouverte par le brouillard de guerre (bâtiments et accessoires neutres, comme dans les RTS classiques).
Require SightingactivéMode fantôme uniquement : l’objet doit avoir été vu au moins une fois. Si l’option est désactivée, il suffit que la zone soit explorée pour l’afficher.
Hide CanvasesactivéDésactive aussi les composants Canvas (barres de vie, étiquettes de nom).
Hide CollidersdésactivéDésactive aussi les colliders pendant que l’objet est masqué, pour qu’on ne puisse pas cliquer sur les ennemis masqués. Laissez cette option désactivée sur les serveurs qui font autorité et sur les hôtes : leurs requêtes physiques doivent continuer à toucher les unités que le joueur local ne voit pas.
PivotvideTransform facultatif dont la position est testée. Si le champ est vide, c’est le transform de cet objet qui est utilisé.

Ce composant déclenche l’événement VisibilityChanged(bool) lorsque l’objet est affiché ou masqué. Appelez RefreshComponents() après avoir ajouté ou supprimé des renderers enfants à l’exécution.

Rendu : renderer feature et shader de repli

Le brouillard de guerre peut être dessiné de deux manières. Le choix se fait par caméra, si bien qu’il n’est jamais appliqué deux fois.

MéthodeQuand elle est utiliséeCe qui est assombri
Renderer feature RTS Fog Of War (recommandée)La caméra effectue son rendu avec un Universal Renderer qui contient la renderer feature.Tout ce qui est à l’écran : terrain, végétation, eau, décors, unités et tout matériau personnalisé. Le ciel n’est pas modifié.
Shader de repliLe renderer de la caméra ne contient pas la renderer feature.Uniquement les shaders de terrain, d’eau et de végétation propres au package. Les unités et les accessoires qui utilisent d’autres matériaux ne sont pas assombris (les unités ennemies restent toutefois masquées par leur composant masquable).

Ajouter la renderer feature à la main :

  1. Sélectionnez votre asset Universal Renderer Data (le renderer utilisé par les caméras de votre jeu).
  2. Dans son Inspector, cliquez sur Add Renderer Feature et choisissez RTS Fog Of War.
  3. Répétez l’opération pour chaque renderer utilisé par les caméras du jeu, afin d’obtenir des résultats cohérents.

Vous pouvez aussi laisser Tools ▸ RTS Terrain Studio ▸ Validate Project corriger le problème : la commande ajoute la renderer feature au renderer par défaut de chaque asset URP utilisé.

Paramètre de la renderer featurePar défautDescription
Show In Scene ViewactivéDessine aussi le brouillard de guerre dans les caméras de la Scene View. Si l’option est désactivée, les caméras de la Scene View qui utilisent ce renderer affichent la carte sans brouillard de guerre.
Render Pass EventAfterRenderingTransparentsMoment où le brouillard de guerre est dessiné. Avec la valeur par défaut, il est dessiné avant le post-processing : le bloom et le tonemapping s’appliquent donc par-dessus le brouillard de guerre.

La renderer feature demande d’elle-même la texture de profondeur de la caméra et s’en sert pour reconstruire la position monde de chaque pixel. RTSFogOfWarRendererFeature.IsActive indique si une feature activée existe dans l’un des renderers de l’asset URP actif ; cette information est purement indicative.

Shaders personnalisés (avancé). Le gestionnaire publie le brouillard de guerre sous forme de variables globales de shader : _RTS_FogOfWarTex (R = visible, G = exploré), _RTS_FogOfWarParams (min X, min Z, 1/taille X, 1/taille Z en espace monde), _RTS_FogOfWarUnexplored, _RTS_FogOfWarExplored et _RTS_FogOfWarEnabled. Les shaders du package incluent Shaders/Include/RTSCommon.hlsl (après le Core.hlsl d’URP) et appellent sa fonction utilitaire sur la couleur éclairée. Un shader URP personnalisé peut faire de même pour la méthode de repli :

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
// Include RTSCommon.hlsl after Core.hlsl. Adjust the path if you moved the package folder.
#include "Assets/RTSTerrainStudio/Shaders/Include/RTSCommon.hlsl"

half4 frag(Varyings input) : SV_Target
{
    half3 color = /* your lit colour */ half3(1, 1, 1);
    // Darkens unexplored and fogged areas. Does nothing while the renderer feature handles this camera.
    color = RTS_ApplyFogOfWar(color, input.positionWS);
    return half4(color, 1);
}

Programmer le brouillard de guerre

Tous les types du brouillard de guerre se trouvent dans l’espace de noms RTSTerrainStudio. Récupérez le gestionnaire de la scène avec RTSFogOfWarManager.Active (abonnez-vous à l’événement statique ActiveChanged si des gestionnaires apparaissent et disparaissent).

MembreDescription
Requêtes
bool IsVisible(Vector3 world, int team)Renvoie true si l’équipe voit la position en ce moment (vision propre et partagée). Renvoie false pour les équipes qui ne sont pas calculées (voir IsTeamComputed).
bool IsExplored(Vector3 world, int team)Renvoie true si l’équipe a vu la position au moins une fois.
bool IsVisibleToLocalTeam(Vector3), bool IsExploredByLocalTeam(Vector3)Raccourcis pour l’équipe locale.
uint GetVisibilityMask(Vector3 world)Masque de bits des équipes calculées qui voient la position (bit t = équipe t). Idéal pour la gestion d’intérêt côté serveur.
uint GetExploredMask(Vector3 world)Masque de bits des équipes qui ont exploré la position.
bool IsTeamComputed(int team)Toujours true avec Compute All Teams, sinon uniquement pour l’équipe locale.
bool TryGetFogCell(Vector3, out int2), Vector3 FogCellToWorld(int2)Conversion entre positions monde et cellules de brouillard.
bool IsCellVisible(int2, int team), bool IsCellExplored(int2, int team)Versions des requêtes par cellule.
int GetCellLevel(int2), bool IsCellBlocked(int2)Niveau de falaise et état d’obstacle à la vision utilisés pour la ligne de vue.
Vector2 SampleDisplayedFog(Vector2 normalizedMapPosition)Valeurs lissées affichées à l’écran pour l’équipe locale (x = visible, y = exploré). Renvoie (1, 1) si aucun brouillard de guerre n’est actif.
Révélation et exploration
void RevealArea(Vector3 world, float radius, int team, float duration, bool ignoreLineOfSight = false)Révèle un cercle pour une équipe (fusées éclairantes, capacités du type « révéler une zone de la carte »). duration s’exprime en temps de jeu en Play Mode et en temps réel dans l’aperçu en Edit Mode. Une valeur inférieure ou égale à 0 ne révèle la zone que pendant une seule mise à jour.
void ClearTemporaryReveals()Supprime toutes les zones révélées avec RevealArea.
void ExploreAll(int team), void ExploreAllTeams()Marquent toute la carte comme explorée.
void ResetExploration(), void ResetExploration(int team)Effacent l’exploration (les zones visibles en ce moment sont de nouveau explorées lors de la mise à jour suivante).
Alliances et vision partagée
void SetAlliance(int teamA, int teamB, bool allied)Partage la vision dans les deux sens, ou supprime ce partage.
void SetSharedVision(int sourceTeam, int receiverTeam, bool shared)Permet à receiverTeam de voir ce que voit sourceTeam (dans un seul sens).
void SetSharedVisionMask(int receiverTeam, uint sourceTeams), uint GetSharedVision(int receiverTeam)Remplacent ou lisent le masque complet d’une équipe réceptrice.
bool HasSharedVision(int sourceTeam, int receiverTeam), uint GetViewMask(int team)Lisent l’état du partage ; le masque de vue inclut l’équipe elle-même.
bool IsFriendlyToLocalTeam(int team)Renvoie true pour l’équipe locale et pour les équipes qui partagent leur vision avec elle. Leurs objets ne sont jamais masqués.
Contrôle des mises à jour
void RequestUpdate(), void ForceUpdate()Recalculent lors de la mise à jour suivante, ou immédiatement.
void MarkTerrainDirty()Reconstruction complète de la couche raster des niveaux de falaise. Les modifications de la carte sont suivies automatiquement ; vous en aurez rarement besoin.
void MarkBlockersDirty()Reconstruit la couche raster des obstacles à la vision après que vous avez déplacé des arbres ou des décors par le code sans appeler RTSTerrain.NotifyChanged.
event Action UpdatedDéclenché après chaque mise à jour de la visibilité, une fois les objets masquables actualisés.
État
IsSimulating, IsRunning, IsRenderingFog, HasGrid, HasVisibilityDataIndiquent si le brouillard de guerre fonctionne, s’il dispose d’une grille et s’il a été calculé au moins une fois.
FogTexture, RawFogTexture, FogWidth, FogHeight, FogCellSize, Version, ActiveRevealerCount, MemoryUsageInformations sur la grille et la texture.
int EffectiveResolutionPerCellNombre de cellules de brouillard par cellule de carte réellement utilisé. Inférieur à ResolutionPerCell sur les très grandes cartes, où la grille est limitée à MaxFogGridSize (2048).
RTSTerrain Terrain, RTSTerrain BoundTerrainLe terrain à couvrir (null = RTSTerrain.Main) et le terrain pour lequel la grille est actuellement construite.
Paramètres (identiques à ceux de l’Inspector)
ResolutionPerCell, LocalTeam, LineOfSight, ComputeAllTeams, RevealAll, FadeSpeed, BlurIterations, BlurUpscalePropriétés modifiables. Modifier ResolutionPerCell reconstruit la grille et efface l’exploration.
const int MaxTeams (32), const int MaxFogGridSize (2048)Nombre maximal d’équipes et côté maximal de la grille de brouillard.
Registres
static IReadOnlyList<RTSFogOfWarRevealer> Revealers, static IReadOnlyList<RTSFogOfWarHideable> HideablesTous les révélateurs et objets masquables activés, tous gestionnaires confondus.
static RegisterRevealer / UnregisterRevealer, RegisterHideable / UnregisterHideableAppelées par les composants eux-mêmes ; vous n’en avez besoin que pour des composants personnalisés.
RTSFogOfWarHideable et RTSFogOfWarRevealer
bool IsVisible, bool HasBeenSighted (objet masquable)État actuel, et indique si l’objet a déjà été vu (mode fantôme).
Vector3 TestPosition (objet masquable)La position testée par rapport au brouillard de guerre (le Pivot, ou le transform).
void Reevaluate(), void ResetSighting() (objet masquable)Refait le test immédiatement ; oublie que l’objet a été repéré.
event Action<bool> VisibilityChanged (objet masquable)Déclenché quand l’objet apparaît ou disparaît pour l’équipe locale.
bool IsRevealing (révélateur)Vaut true tant que le révélateur est pris en compte (activé, ou avec l’option Reveal When Disabled activée).

Exemple : une capacité de fusée éclairante et un test de visibilité.

using RTSTerrainStudio;
using UnityEngine;

// Reveals an area for a few seconds and tells whether a target can be attacked.
public class ScoutAbilities : MonoBehaviour
{
    [SerializeField] int team = 0;          // the team that casts the flare
    [SerializeField] float flareRadius = 15f;
    [SerializeField] float flareSeconds = 5f;

    // Call this with the world position the player clicked.
    public void CastFlare(Vector3 worldPosition)
    {
        var fog = RTSFogOfWarManager.Active;
        if (fog == null) return; // no fog of war in this scene

        // ignoreLineOfSight: true lets the flare see over cliffs and trees, like an air unit.
        fog.RevealArea(worldPosition, flareRadius, team, flareSeconds, ignoreLineOfSight: true);
    }

    // True when our team may target something at this position.
    public bool CanTarget(Vector3 targetPosition)
    {
        var fog = RTSFogOfWarManager.Active;
        // Without a running fog, everything is visible.
        if (fog == null || !fog.IsRunning) return true;
        // For teams other than the local one, enable "Compute All Teams" on the manager,
        // otherwise IsVisible returns false for them.
        return fog.IsVisible(targetPosition, team);
    }
}

Exemple : alliances et apparition d’une unité par le code.

using RTSTerrainStudio;
using UnityEngine;

public class TeamSetup : MonoBehaviour
{
    [SerializeField] GameObject unitPrefab;

    void Start()
    {
        var fog = RTSFogOfWarManager.Active;
        if (fog != null)
        {
            fog.SetAlliance(0, 2, true);       // teams 0 and 2 see what the other sees
            fog.SetSharedVision(3, 0, true);   // team 0 also sees what team 3 sees (one way)
        }
        SpawnUnit(1, new Vector3(40f, 0f, 40f));
    }

    // Creates an enemy unit that sees and can be hidden by the fog of war.
    void SpawnUnit(int team, Vector3 position)
    {
        var go = Instantiate(unitPrefab, position, Quaternion.identity);

        // Reuse components the prefab may already have (RTSFogOfWarHideable allows only one per object).
        if (!go.TryGetComponent(out RTSFogOfWarRevealer revealer))
            revealer = go.AddComponent<RTSFogOfWarRevealer>();
        revealer.Team = team;
        revealer.Radius = 12f;               // metres

        if (!go.TryGetComponent(out RTSFogOfWarHideable hideable))
            hideable = go.AddComponent<RTSFogOfWarHideable>();
        // Subscribe BEFORE setting Team and Mode: in Play Mode both setters re-test the object immediately,
        // so a unit spawned in the fog is hidden (and the event raised) right away.
        // React when the unit appears or disappears for the local player (sounds, minimap pings ...).
        hideable.VisibilityChanged += visible => Debug.Log(go.name + (visible ? " spotted" : " lost"));
        hideable.Team = team;
        hideable.Mode = FogOfWarHideMode.HideWhenNotVisible;
        // The current state after configuring.
        Debug.Log(go.name + (hideable.IsVisible ? " starts visible" : " starts hidden"));
    }
}

Mini-carte avec brouillard de guerre

RTSFogOfWarMinimapUtility assombrit une image de mini-carte avec le brouillard de guerre de l’équipe locale, comme sur la mini-carte d’un RTS classique. La mini-carte doit couvrir exactement la zone de la carte, avec les UV (0, 0) au coin d’origine de la carte et les UV (1, 1) au coin opposé. Les images précalculées avec RTSMinimapBaker respectent cette disposition. L’exemple RTSMinimapUI utilise cet utilitaire.

MéthodeDescription
static bool Composite(Texture minimap, RenderTexture destination, RTSFogOfWarManager manager = null)Traitement sur le GPU, idéal pour une mini-carte mise à jour en direct. Appelez-la après l’événement Updated ou à quelques images d’intervalle. Sans brouillard de guerre actif, la mini-carte est copiée telle quelle. Renvoie false si le shader n’est pas disponible.
static bool CompositeCpu(Texture2D source, Texture2D destination, RTSFogOfWarManager manager = null)Traitement sur le CPU (job Burst), qui ne nécessite aucune render texture, par exemple pour des captures d’écran. source doit être lisible ; destination doit être une texture RGBA32 lisible de même taille (il peut s’agir de la même texture).
static bool CompositeCpu(NativeArray<Color32> source, NativeArray<Color32> destination, int width, int height, RTSFogOfWarManager manager = null)Traitement sur le CPU, directement sur des tampons de pixels bruts.
static void ReleaseResources()Détruit le matériau et le tampon de commandes mis en cache. Appelée automatiquement avant chaque rechargement du domaine ; appelez-la vous-même lorsque la mini-carte est fermée définitivement.
using RTSTerrainStudio;
using UnityEngine;

// Bakes the map once and keeps a fogged copy in a render texture.
// Show Output with a RawImage (uGUI) or a UI Toolkit Image.
public class FoggedMinimap : MonoBehaviour
{
    [SerializeField] int size = 256;      // longest side in pixels

    Texture2D baked;
    RenderTexture output;
    RTSFogOfWarManager fog;

    public RenderTexture Output => output;

    void OnEnable()
    {
        var terrain = RTSTerrain.Main;
        if (terrain == null) return;

        baked = RTSMinimapBaker.Bake(terrain, size);   // map image with cliffs, water, trees ...
        if (baked == null) return;
        output = new RenderTexture(baked.width, baked.height, 0, RenderTextureFormat.ARGB32);

        fog = RTSFogOfWarManager.Active;
        if (fog != null) fog.Updated += Refresh;          // refresh after each visibility update
        Refresh();
    }

    void OnDisable()
    {
        if (fog != null) fog.Updated -= Refresh;
        if (output != null) { output.Release(); Destroy(output); }
        if (baked != null) Destroy(baked);
    }

    void Refresh()
    {
        if (baked != null && output != null)
            RTSFogOfWarMinimapUtility.Composite(baked, output, fog);
    }
}

Conseils pour le multijoueur

  • Chaque client calcule son propre brouillard de guerre, pour l’équipe définie par son paramètre Local Team. Le brouillard de guerre ne transite jamais par le réseau.
  • Sur un serveur qui fait autorité, activez Compute All Teams et utilisez GetVisibilityMask(position) pour décider quels clients reçoivent quelles unités. Une seule consultation par unité est très peu coûteuse.
  • Laissez l’option Hide Colliders désactivée sur les objets masquables, côté serveur comme sur l’hôte d’un listen server, afin que les raycasts côté serveur touchent toujours les unités que le joueur hôte ne voit pas. Filtrez plutôt la sélection du joueur avec IsVisibleToLocalTeam.
  • Les alliances sont des paramètres locaux. Appelez SetAlliance sur le serveur et sur les clients si ceux-ci doivent afficher la vision des alliés.

L’intégration Mirror fait tout cela pour vous : RTSNetworkFogOfWar configure le gestionnaire (le serveur calcule toutes les équipes, un client uniquement la sienne), et RTSFogOfWarInterestManagement n’envoie jamais les unités ennemies masquées par le brouillard de guerre (protection anti-maphack). Consultez le chapitre sur l’intégration Mirror.

Performances et limites

  • La visibilité est calculée par des jobs Burst à chaque intervalle Update Interval (en secondes, 0.1 par défaut), et non à chaque image. Les révélateurs et les objets masquables sont conservés dans des listes internes, si bien qu’aucune recherche n’est effectuée dans la scène à chaque image.
  • La mémoire occupée est d’environ 18 octets par cellule de brouillard. Une carte de 128 × 128 avec le paramètre Resolution Per Cell réglé sur 2 utilise une grille de 256 × 256, soit environ 1.2 Mo.
  • Grandes cartes : la grille est limitée à 2048 cellules par axe, et la résolution par cellule est automatiquement abaissée pour respecter cette limite.
  • None est le mode de ligne de vue le moins coûteux ; CliffLevelsAndBlockers est le plus coûteux, mais les lignes ne sont tracées que pour les révélateurs qui ont à proximité une cellule plus haute ou un obstacle à la vision.
  • La texture du brouillard de guerre est alignée sur les axes de la carte. Si le terrain est pivoté, un avertissement est consigné.
  • Après une modification d’arbres ou de décors, la couche raster des obstacles à la vision est reconstruite pour toute la carte ; les modifications de falaises ne mettent à jour que la zone modifiée.

Rien n’est couvert par le brouillard ? Vérifiez que le gestionnaire est activé et que vous êtes en Play Mode (ou que Preview In Edit Mode est activé), que Reveal All est désactivé et que le terrain a une carte. Si seul le terrain est couvert par le brouillard de guerre, mais pas les unités ni les accessoires, ajoutez la renderer feature RTS Fog Of War. Si tout est noir, aucun révélateur de l’équipe locale (ou d’une équipe qui partage sa vision avec elle) n’est actif. Le message « No revealers exist » de l’Inspector n’apparaît que si la scène ne contient aucun révélateur : comparez donc aussi le paramètre Team de vos révélateurs au paramètre Local Team.

Cheminement et recherche de chemin

Chaque RTS Terrain conserve une carte de cheminement : une grille qui indique, pour chaque petit carré de la carte, si les unités terrestres peuvent y marcher, si l’on peut y placer des bâtiments, si les unités aériennes peuvent y voler et s’il y a de l’eau. Elle est dérivée automatiquement du terrain et mise à jour pendant que vous éditez. Sur cette base, le package fournit un module de recherche de chemin intégré (A* compilé avec Burst), rapide et utilisable sans aucun package tiers.

Si vous préférez l’A* Pathfinding Project ou le NavMesh de Unity, les intégrations construisent leurs graphes à partir de la même carte de cheminement ; consultez leurs chapitres respectifs.

La carte de cheminement

La carte de cheminement compte PathingResolution cellules de cheminement par cellule de carte et par axe (1, 2 ou 4, choisi à la création de la carte ; 2 par défaut). Avec les cellules de carte de 2 m par défaut, une cellule de cheminement mesure 1 m de large. Chaque cellule stocke un ensemble de PathingFlags :

IndicateurSignification
WalkableLes unités terrestres peuvent y marcher.
BuildableOn peut y placer des bâtiments.
FlyableLes unités aériennes peuvent y voler. Présent partout, sauf si un effet Unflyable le retire : une surcharge de cheminement peinte, la règle du calque de sol dans le tileset ou le paramètre Footprint Effect d’un prototype de décor.
ShallowWaterEau peu profonde : praticable, non constructible par défaut.
DeepWaterEau profonde : réservée aux unités navales.
CliffLa cellule touche une paroi de falaise.
BlockedLa cellule est bloquée par l’emprise d’un arbre ou d’un objet de décor.
SteepLa cellule est trop escarpée pour les unités terrestres.

Comment les indicateurs sont dérivés. Les règles sont appliquées dans cet ordre, sous forme de jobs Burst :

  1. Terrain. Les parois de falaise (élargies selon Cliff Margin) deviennent Cliff. Les pentes supérieures à Max Walkable Slope deviennent Steep. L’eau plus profonde que la limite de faible profondeur du tileset devient DeepWater, sinon ShallowWater. Flyable est défini partout. Buildable = praticable, moins pentu que Max Buildable Slope et au sec (ou en eau peu profonde avec Shallow Water Buildable). Ensuite, l’effet de cheminement du calque de sol dominant est appliqué (par exemple « Unbuildable » sur la roche rugueuse). Une rampe valide entre deux niveaux de falaise n’est testée que sur sa hauteur fine et reste donc praticable ; les rampes ne sont jamais constructibles.
  2. Emprises. Les arbres bloquent un cercle (Footprint Radius du prototype d’arbre × échelle de l’instance × Tree Footprint Scale) : ils définissent Blocked et retirent Walkable et Buildable. Les décors appliquent le Footprint Effect de leur prototype (par défaut Unwalkable et Unbuildable) dans un cercle ou une boîte pivotée. Les instances de décor dotées de l’indicateur IgnorePathing sont ignorées.
  3. Surcharges manuelles peintes avec les outils Pathing (voir ci-dessous). Un effet Unwalkable retire aussi Buildable, sauf si Force Buildable est défini.

La carte est reconstruite de façon incrémentielle : lorsque vous modifiez une région, seule cette région (plus une petite marge) est dérivée à nouveau.

Règles de cheminement (RTSPathingSettings)

Sélectionnez le RTS Terrain et ouvrez la section Pathing Rules de son Inspector. Toute modification d’une valeur reconstruit la carte de cheminement.

ParamètrePar défautDescription
Max Walkable Slope42Un sol plus pentu que cet angle (en degrés) n’est pas praticable.
Max Buildable Slope18Un sol plus pentu que cet angle (en degrés) n’est pas constructible.
Cliff Margin0.25Distance (en fraction de cellule de cheminement) sur laquelle la zone bloquée s’étend au-delà d’une paroi de falaise. Des valeurs plus élevées éloignent davantage les unités des bords de falaise.
Shallow Water BuildabledésactivéAutorise la construction de bâtiments en eau peu profonde.
Tree Footprint Scale1Multiplicateur du rayon d’emprise de cheminement de chaque arbre.
Use Ground Layer RulesactivéApplique l’effet de cheminement du calque de sol dominant (défini par calque dans le tileset, par exemple « Unbuildable » sur la roche rugueuse).

Par le code, assignez de nouveaux paramètres avec terrain.PathingSettings = settings (ce qui déclenche une reconstruction), ou modifiez les champs de l’instance actuelle et appelez terrain.RebuildPathing().

Peindre le cheminement à la main

Il arrive que les règles automatiques ne donnent pas ce que vous voulez : un mur invisible en bordure de carte, une zone non constructible pour garder une expansion libre, ou un pont praticable. Utilisez alors les outils Pathing (7 dans la Scene View sélectionne la catégorie Pathing) :

Outil / SurchargeEffet
Paint Pathing : BlockerNon praticable et non constructible : un mur invisible (bordures de carte, zones décoratives).
Paint Pathing : UnwalkableLes unités terrestres ne peuvent pas marcher ici.
Paint Pathing : UnbuildableImpossible de placer des bâtiments ici (pour garder libres les chemins et les expansions).
Paint Pathing : UnflyableLes unités aériennes ne peuvent pas voler ici.
Paint Pathing : Force WalkableLes unités terrestres peuvent marcher ici, même si la pente, l’eau ou des emprises les en empêcheraient.
Paint Pathing : Force BuildableOn peut placer des bâtiments ici, même si les règles dérivées l’interdisent.
Clear PathingSupprime toutes les surcharges peintes sous le pinceau, afin que le cheminement automatique s’applique de nouveau.

Avec Paint Pathing, maintenez Shift enfoncée pour supprimer la surcharge sélectionnée. Peindre un mode supprime la surcharge qui le contredit (peindre Force Walkable supprime Unwalkable), si bien qu’une cellule ne contient jamais de règles contradictoires.

Superpositions de cheminement

Une superposition colore le terrain selon son cheminement, comme la vue de cheminement des éditeurs de cartes des RTS classiques. Pour l’activer, utilisez :

  • la liste déroulante Pathing de l’overlay de la Scene View (Pathing: Off, Walkability, Buildability, Flyability, Water, Combined) ;
  • la liste déroulante Pathing Overlay et le curseur d’opacité de la fenêtre RTS Terrain Studio ;
  • P dans la Scene View, qui fait défiler Off → Walkability → Buildability → Combined → Off (raccourci RTS Terrain Studio/Cycle Pathing Overlay, réaffectable dans Edit ▸ Shortcuts..., sous macOS Unity ▸ Shortcuts...) ;
  • la vue de cheminement de l’éditeur en jeu.
ModeCouleurs
WalkabilityVert = praticable, rouge = bloqué, rouge foncé = falaise, orange = trop escarpé, bleu = eau profonde, cyan = eau peu profonde.
BuildabilityVert = constructible, jaune = praticable mais non constructible, rouge / rouge foncé = non praticable.
FlyabilityBleu clair = survolable, magenta = non survolable.
WaterCyan = eau peu profonde, bleu = eau profonde.
CombinedTout à la fois (vue de cheminement à la manière des RTS classiques).

Dans votre propre jeu, affichez une superposition avec un PathingOverlayController. Il maintient la texture à jour quand le cheminement change :

using RTSTerrainStudio;
using UnityEngine;

// Shows the buildability overlay on the terrain while this component is enabled (e.g. in build mode).
public class BuildModeOverlay : MonoBehaviour
{
    [SerializeField] RTSTerrain terrain;
    [SerializeField, Range(0f, 1f)] float opacity = 0.6f;

    PathingOverlayController overlay;

    void OnEnable()
    {
        if (terrain == null) terrain = RTSTerrain.Main;
        if (terrain == null) return;
        overlay = new PathingOverlayController(terrain, PathingOverlayMode.Buildability);
        // The texture can be replaced (for example after a map resize): re-assign it when that happens.
        overlay.TextureChanged += texture => terrain.SetOverlayTexture(texture, opacity);
        terrain.SetOverlayTexture(overlay.Texture, opacity);
    }

    void OnDisable()
    {
        if (terrain != null) terrain.SetOverlayTexture(null, 0f);
        overlay?.Dispose();   // destroys the overlay texture
        overlay = null;
    }
}

Changez l’information affichée avec overlay.Mode = PathingOverlayMode.Walkability (la texture est alors redessinée), ou forcez un rafraîchissement complet avec overlay.Refresh() ; inutile de créer un nouveau contrôleur.

Pour des textures à usage unique, utilisez PathingOverlay.CreateOrUpdate(map, mode, ref texture), PathingOverlay.UpdateRegion(...) et PathingOverlay.DestroyTexture(ref texture) ; PathingOverlay.GetColor(flags, mode) renvoie la couleur de légende d’une combinaison d’indicateurs.

Lire la carte de cheminement par le code

Membre (de RTSTerrain)Description
PathingFlags GetPathing(Vector3 world)Indicateurs à une position du monde (None hors de la carte ou tant que le cheminement n’est pas construit).
bool IsWalkable(Vector3 world), bool IsBuildable(Vector3 world)Raccourcis pour les deux indicateurs les plus utilisés.
PathingMap PathingLa grille de cheminement : Width, Height, CellSize, Flags (un octet par cellule, index = z × Width + x), Get(x, z), Version.
event Action<RTSTerrain, RectInt> PathingChangedDéclenché après une reconstruction complète ou partielle, avec le rectangle modifié en cellules de cheminement. Survit aux rechargements de carte. Les unités d’exemple s’en servent pour recalculer leur trajet.
RTSPathingSettings PathingSettings, void RebuildPathing()Règles et reconstruction complète.
ClearanceMap GetPathingClearance()La carte de dégagement, mise à jour au préalable (voir Taille des unités).
void RegisterPathingReader(JobHandle), void CompletePathingReaders()Pour vos propres jobs qui lisent Flags ou le dégagement : le terrain attend leur fin avant d’écrire des données de cheminement.

Trouver un chemin : RTSPathfinder

RTSPathfinder cherche un chemin sur la carte de cheminement avec un A* compilé par Burst : 8 directions sans couper les coins, prise en compte du dégagement pour les grandes unités, et string pulling pour lisser les chemins. Un départ ou une destination bloqués sont remplacés par la cellule libre la plus proche. Il s’exécute de manière synchrone sur le thread principal, ce qui convient pour quelques requêtes par image et en Edit Mode.

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

public class PathDebug : MonoBehaviour
{
    [SerializeField] Transform target;
    readonly List<Vector3> path = new List<Vector3>();

    void OnDrawGizmos()
    {
        var terrain = RTSTerrain.Main;
        if (terrain == null || target == null) return;

        // A unit with a radius of 0.6 m: the path keeps that distance from obstacles.
        var options = PathRequestOptions.ForUnit(0.6f);
        PathResult result = RTSPathfinder.FindPathDetailed(terrain, transform.position, target.position, options, path);

        // Success = reached the goal, Partial = closest reachable point.
        Gizmos.color = result.status == PathStatus.Success ? Color.green : Color.yellow;
        for (int i = 1; i < path.Count; i++) Gizmos.DrawLine(path[i - 1], path[i]);
    }
}
MéthodeDescription
static PathStatus FindPath(RTSTerrain, Vector3 startWorld, Vector3 endWorld, List<Vector3> resultWorld)Utilise PathRequestOptions.Default.
static PathStatus FindPath(RTSTerrain, Vector3, Vector3, PathRequestOptions, List<Vector3>)resultWorld est vidé, puis reçoit les points de passage, départ et arrivée compris.
static PathResult FindPathDetailed(RTSTerrain, Vector3, Vector3, PathRequestOptions, List<Vector3>)Renvoie en plus la longueur et des statistiques, et indique si le départ ou la destination ont été déplacés.
static void DisposeSharedBuffers()Libère les tampons de recherche (ce qui se fait aussi automatiquement lors du rechargement du domaine et à la fermeture de l’application).

PathRequestOptions (partez de PathRequestOptions.Default ou de PathRequestOptions.ForUnit(radius)) :

ChampPar défautDescription
unitRadius0Rayon de l’unité en unités monde. Les chemins restent à cette distance des obstacles. Le dégagement ne s’applique que si required contient Walkable : pour les requêtes navales (DeepWater) ou aériennes (Flyable), unitRadius n’a aucun effet. La carte de dégagement mesure les distances jusqu’aux cellules non praticables, et la bordure de la carte compte comme un obstacle. Il en va de même pour PathingQueries.FindNearest, LineOfSight et Raycast.
requiredWalkableIndicateurs que chaque cellule du chemin doit posséder (None est traité comme Walkable).
allowShallowWatertrueAutorise la traversée de l’eau peu profonde (gués).
maxSearchNodes500000Nombre maximal de nœuds développés avant que la recherche abandonne (0 = illimité).
smoothPathtrueSupprime les points de passage inutiles grâce à la ligne de vue sur la grille (string pulling).
snapToGroundtrueCale la coordonnée Y de chaque point de passage sur la hauteur du sol.
allowPartialtrueSi la destination est inaccessible, renvoie un chemin vers la cellule accessible la plus proche.
goalSearchRadius16Si la cellule de destination est bloquée, distance (en unités monde) jusqu’à laquelle chercher la cellule libre la plus proche.
PathStatusSignification
SuccessUn chemin vers la destination (ou vers la cellule libre la plus proche d’une destination bloquée) a été trouvé.
PartialLa destination est inaccessible ; le chemin mène à la cellule accessible la plus proche de celle-ci.
NoPathAucun chemin n’existe (ou la limite de recherche a été atteinte) et les chemins partiels n’étaient pas autorisés.
InvalidStartLe départ est hors de la carte, il n’y a pas de données de cheminement, ou aucune cellule franchissable ne se trouve près du départ.

Champs de PathResult : requestId, terrain, status, points (points de passage dans le monde), length (horizontale, en unités monde), searchedNodes, startAdjusted, goalAdjusted, userData, et HasPath (Success ou Partial avec au moins un point de passage).

Pour de nombreuses unités : RTSPathfindingService

Pour de nombreuses unités, utilisez RTSPathfindingService. Il regroupe les requêtes d’une image, les exécute sous forme de jobs Burst parallèles dans LateUpdate (après que le terrain a appliqué ses modifications) et transmet les résultats par des callbacks lors de l’Update de l’image suivante. Ajoutez-le avec Add Component ▸ RTS Terrain Studio ▸ Pathfinding Service, ou appelez RTSPathfindingService.GetOrCreate() en Play Mode (cela crée un objet de service qui survit aux chargements de scène). Le service ne fonctionne qu’en Play Mode ; en Edit Mode, utilisez RTSPathfinder.

ParamètrePar défautDescription
Max Requests Per Frame64Nombre de recherches de chemin lancées par image. Les requêtes en surplus attendent dans une file d’attente.
Max Parallel Jobs4Nombre de jobs exécutés en parallèle (1 à 16). Chaque job a besoin de ses propres tampons de recherche (environ 24 octets par cellule de cheminement).
Memory Budget MB256Plafond de mémoire pour les tampons de recherche. Sur les très grandes grilles, le nombre de jobs parallèles est réduit ; un avertissement est consigné si un seul jeu de tampons dépasse déjà ce plafond.
Complete In Same FramedésactivéTermine les jobs à la fin de l’image où ils ont été planifiés (latence plus faible, moins de parallélisme).
MembreDescription
int RequestPath(RTSTerrain, Vector3 startWorld, Vector3 endWorld, PathRequestOptions, Action<PathResult> callback, List<Vector3> resultBuffer = null, object userData = null)Met une requête en file d’attente et renvoie son identifiant. Avec resultBuffer, les points de passage sont écrits dans votre liste (vidée au préalable), ce qui évite une allocation par requête.
int RequestPath(RTSTerrain, Vector3, Vector3, Action<PathResult>)Identique, avec les options par défaut.
bool Cancel(int requestId)Annule une requête en file d’attente, en cours, ou terminée mais pas encore transmise. Son callback ne sera pas exécuté.
void CancelAll(), void CompleteAll()Annule tout, ou termine tout immédiatement (les callbacks s’exécutent avant le retour de la méthode).
PendingCount, InFlightCountStatistiques de la file d’attente et des jobs.
static Instance, static GetOrCreate()Le premier service activé, ou un nouveau service.
using RTSTerrainStudio;
using UnityEngine;

// Asks the service for a path and replaces the previous request when a new order arrives.
public class AsyncMover : MonoBehaviour
{
    [SerializeField] float radius = 0.5f;
    int requestId;   // 0 = no request pending

    public void OrderMove(Vector3 target)
    {
        var terrain = RTSTerrain.Main;
        var service = RTSPathfindingService.GetOrCreate(); // null outside Play Mode
        if (terrain == null || service == null) return;

        if (requestId != 0) service.Cancel(requestId);       // the old callback will not run
        requestId = service.RequestPath(terrain, transform.position, target,
            PathRequestOptions.ForUnit(radius), OnPathFound);
    }

    void OnPathFound(PathResult result)
    {
        requestId = 0;
        if (!result.HasPath) { Debug.Log("Can't reach that place."); return; }
        // result.points holds the waypoints. Copy them if you keep them.
        Debug.Log($"{result.points.Count} waypoints, {result.length:0.0} m, status {result.status}");
    }
}

Taille des unités : dégagement

Les grandes unités ne doivent pas se faufiler dans des passages prévus pour les petites. Le terrain conserve une carte de dégagement : pour chaque cellule praticable, la distance jusqu’à la cellule non praticable la plus proche (plafonnée à 64 cellules). Lorsqu’une requête spécifie un unitRadius, le module de recherche de chemin n’utilise que les cellules où l’unité tient. La carte de dégagement est mise à jour de façon incrémentielle après les modifications.

  • PathingQueries.GetClearance(terrain, world) renvoie le rayon libre à une position, en unités monde (négatif sur les cellules non praticables).
  • ClearanceMap (obtenue via terrain.GetPathingClearance()) propose GetClearanceCells(x, z), GetClearanceMetres(x, z) et ClearanceMap.RequiredValue(unitRadius, cellSize). Près des coins d’obstacles en diagonale, la valeur peut être trop généreuse d’environ 0.13 cellule au maximum ; cela permet aux unités d’un rayon de 0.3 à 0.5 cellule d’emprunter les couloirs d’une cellule de large dans lesquels elles tiennent physiquement.

Requêtes de gameplay : PathingQueries

PathingQueries répond aux questions que le gameplay d’un RTS pose en permanence. Toutes les positions sont exprimées en espace monde, les tailles et les rayons en unités monde.

MéthodeDescription
bool FindNearestWalkable(RTSTerrain, Vector3 world, float maxRadius, float unitRadius, out Vector3 result)Position praticable la plus proche de world où peut tenir une unité de rayon unitRadius (points d’apparition, points de ralliement).
bool FindNearest(RTSTerrain, Vector3 world, float maxRadius, float unitRadius, PathingFlags required, out Vector3 result)Idem pour n’importe quels indicateurs, par exemple DeepWater pour les navires.
Vector3 SnapToBuildGrid(RTSTerrain, Vector3 world, Vector2 sizeMetres)Aligne la position d’un bâtiment pour que son emprise couvre des cellules de cheminement entières (tailles paires sur un coin de cellule, tailles impaires sur un centre de cellule). Le résultat est posé au sol.
bool IsAreaBuildable(RTSTerrain, Vector3 worldCenter, Vector2 sizeMetres)Renvoie true si chaque cellule de cheminement de l’emprise est Buildable.
bool IsAreaClear(RTSTerrain, Vector3 worldCenter, Vector2 sizeMetres, PathingFlags required)Idem pour n’importe quels indicateurs. Renvoie false hors de la carte.
bool TryGetAreaCells(RTSTerrain, Vector3 worldCenter, Vector2 sizeMetres, out RectInt cells)Cellules de cheminement couvertes par une emprise. Renvoie false si l’emprise n’est pas entièrement dans la carte.
float GetClearance(RTSTerrain, Vector3 world)Rayon libre autour d’une position.
bool LineOfSight(RTSTerrain, Vector3 fromWorld, Vector3 toWorld, PathingFlags required = Walkable, float unitRadius = 0)Renvoie true si un déplacement en ligne droite est possible (ligne de vue sur la grille, sans couper les coins). Il s’agit ici de déplacement, et non de la vision du brouillard de guerre.
bool Raycast(RTSTerrain, Vector3 fromWorld, Vector3 toWorld, PathingFlags required, float unitRadius, out Vector3 lastFreeWorld)Parcourt le segment et indique la dernière position libre avant un obstacle (charges, repoussements).

Placement de bâtiments et modifications du cheminement à l’exécution

Dans un RTS classique, le placement d’un bâtiment se fait en trois étapes : aligner l’emprise sur la grille, la vérifier, puis la bloquer sur la carte de cheminement. Le blocage consiste à écrire des surcharges manuelles dans MapData.PathingOverrides, puis à en informer le terrain. Le terrain reconstruit la zone de façon incrémentale et déclenche PathingChanged, et les unités en mouvement recalculent leur chemin pour contourner le nouveau bâtiment.

using RTSTerrainStudio;
using UnityEngine;

public static class BuildingFootprint
{
    // Tries to place a footprint of sizeMetres (X/Z) at the cursor and blocks it for walking and building.
    // Returns the covered pathing cells and their previous override bytes, so Remove can restore them
    // (cells may already hold painted overrides, for example Force Walkable on a bridge).
    public static bool TryPlace(RTSTerrain terrain, Vector3 cursorWorld, Vector2 sizeMetres,
        out RectInt pathingCells, out byte[] previous)
    {
        pathingCells = default;
        previous = null;
        if (terrain == null || terrain.Map == null) return false;

        // 1. Align the footprint with the pathing grid.
        Vector3 center = PathingQueries.SnapToBuildGrid(terrain, cursorWorld, sizeMetres);

        // 2. Every cell must be buildable.
        if (!PathingQueries.IsAreaBuildable(terrain, center, sizeMetres)) return false;
        if (!PathingQueries.TryGetAreaCells(terrain, center, sizeMetres, out pathingCells)) return false;

        // 3. Keep the old bytes, then write Unwalkable | Unbuildable overrides (one byte per pathing cell).
        MapData map = terrain.Map;
        var overrides = map.PathingOverrides;
        previous = new byte[pathingCells.width * pathingCells.height];
        byte block = (byte)(PathingOverride.Unwalkable | PathingOverride.Unbuildable);
        int n = 0;
        for (int z = pathingCells.yMin; z < pathingCells.yMax; z++)
            for (int x = pathingCells.xMin; x < pathingCells.xMax; x++, n++)
            {
                int i = map.PathingIndex(x, z);
                previous[n] = overrides[i];
                overrides[i] = (byte)(overrides[i] | block);
            }

        Notify(terrain, pathingCells);
        return true;
    }

    // Restores the override bytes stored by TryPlace (call it when the building is destroyed).
    public static void Remove(RTSTerrain terrain, RectInt pathingCells, byte[] previous)
    {
        if (terrain == null || terrain.Map == null || previous == null) return;
        MapData map = terrain.Map;
        var overrides = map.PathingOverrides;
        int n = 0;
        for (int z = pathingCells.yMin; z < pathingCells.yMax; z++)
            for (int x = pathingCells.xMin; x < pathingCells.xMax; x++, n++)
                overrides[map.PathingIndex(x, z)] = previous[n];
        Notify(terrain, pathingCells);
    }

    // 4. NotifyChanged expects map cells, so convert the pathing rectangle.
    static void Notify(RTSTerrain terrain, RectInt pathingCells)
    {
        int res = Mathf.Max(1, terrain.Map.PathingResolution);
        int xMin = pathingCells.xMin / res, zMin = pathingCells.yMin / res;
        int xMax = Mathf.CeilToInt(pathingCells.xMax / (float)res);
        int zMax = Mathf.CeilToInt(pathingCells.yMax / (float)res);
        terrain.NotifyChanged(MapLayers.PathingOverrides, new RectInt(xMin, zMin, xMax - xMin, zMax - zMin));
    }
}

Pour supprimer un bâtiment, passez les cellules et les octets mémorisés à BuildingFootprint.Remove : la méthode réécrit les octets de surcharge précédents et appelle de nouveau NotifyChanged. L’exemple RTSDemoBuilding fait exactement cela (voir Démo de placement de bâtiments).

La suppression d’arbres fonctionne de la même façon, via le composant Vegetation Renderer : RTSVegetationRenderer.RemoveTree(id) informe le terrain, si bien que la carte de cheminement libère automatiquement l’emprise de l’arbre et que le brouillard de guerre retire l’obstacle à la vision. Voir Démo de récolte d’arbres.

Avancé : données de cheminement dans vos propres jobs

Pour vos propres jobs Burst (champs de flux, cartes d’influence), créez une vue en lecture seule avec new PathingGrid(terrain.Pathing, terrain.GetPathingClearance()). Elle propose les requêtes IsPassable, LineOfSight, Trace et FindNearestPassable, exprimées en cellules de cheminement et filtrées par un PathingFilter (PathingFilter.ForUnit(required, allowShallowWater, unitRadius, cellSize)). Enregistrez le handle de votre job avec terrain.RegisterPathingReader(handle) afin que le terrain attende la fin de ce job avant de modifier les données de cheminement.

PathingMapBuilder construit les cartes de cheminement d’objets MapData qui ne sont affichés par aucun terrain (par exemple sur un serveur qui charge des cartes sans effectuer de rendu) : PathingMapBuilder.Build(map, pathing, settings, tileset, vegetation, decor).

Scripts de gameplay d’exemple

Le dossier Samples/Scripts contient une couche de jeu RTS réduite mais complète : une caméra RTS, des unités qui suivent le relief du terrain, une sélection avec groupes de contrôle, des ordres de déplacement en formation, une mini-carte, un HUD et deux démos qui modifient la carte à l’exécution. Ces scripts se trouvent dans l’assembly RTSTerrainStudio.Samples et dans l’espace de noms RTSTerrainStudio.Samples.

Utilisez-les pour essayer vos cartes immédiatement, comme point de départ pour votre propre jeu ou comme référence pour l’utilisation de l’API d’exécution. Chaque script est commenté, et ses messages Unity sont protected virtual lorsque c’est pertinent, si bien que vous pouvez en dériver vos propres classes.

Tous les composants d’exemple se trouvent dans Add Component ▸ RTS Terrain Studio ▸ Samples. Les entrées sont lues via RTSInput, ce qui permet aux exemples de fonctionner aussi bien avec le package Input System qu’avec l’ancien Input Manager. L’interface est construite avec UI Toolkit.

Démarrage rapide : rendre n’importe quelle carte jouable

  1. Ouvrez une scène contenant un RTS Terrain dont la carte possède des positions de départ (placez-les avec les outils de marqueurs).
  2. Choisissez GameObject ▸ RTS Terrain Studio ▸ Demo Game. Cette commande crée un objet RTS Demo Game doté du composant RTSDemoGame.
  3. Cliquez sur Play. Le jeu de démo crée le brouillard de guerre, le contrôleur de caméra, la sélection, les ordres, la mini-carte et le HUD, fait apparaître des unités sur chaque position de départ (vous êtes le joueur 1, les autres errent au hasard) et place la caméra sur votre base.
  4. Appuyez sur F1 pour afficher ou masquer la liste des commandes.

Commandes par défaut

SaisieAction
W A S D / touches fléchéesFaire défiler la caméra. Lorsque des unités sont sélectionnées, S les arrête au lieu de faire défiler la caméra (les touches fléchées la font toujours défiler).
Bord de l’écran, glisser avec le bouton du milieuFaire défiler la caméra / saisir et faire glisser le sol.
Molette de la sourisZoomer (un zoom rapproché rend la vue plus rasante).
Q / E, Alt + glisser avec le bouton droitFaire pivoter la vue.
Clic gauche / glisserSélectionner une unité / tracer un rectangle de sélection.
Shift + clicAjouter ou retirer des unités.
Double-clic, Ctrl + clicSélectionner toutes les unités de ce type visibles à l’écran.
EscAnnuler le mode en cours, puis vider la sélection. Pendant un test en jeu lancé depuis l’éditeur en jeu, un nouvel appui sur Esc ramène à l’éditeur.
Ctrl+1…9, 0Enregistrer un groupe de contrôle (Shift+chiffre y ajoute les unités sélectionnées).
1…9, 0Rappeler un groupe (appuyez deux fois pour centrer la caméra dessus).
Clic droitSe déplacer en formation (Shift met l’ordre en file d’attente et enchaîne la formation).
S / H / PArrêter / tenir la position / patrouiller (cliquez ensuite avec le bouton gauche sur le second point de patrouille).
Mini-carteClic gauche ou glisser : déplacer la caméra. Clic droit : déplacer les unités sélectionnées.
BPlacer un bâtiment (modification du cheminement à l’exécution).
DeleteSupprimer le bâtiment situé sous le curseur.
TAbattre l’arbre situé sous le curseur.
Clic droit sur un arbreLes ouvriers sélectionnés s’y rendent et l’abattent.
F1Afficher ou masquer le panneau d’aide.

Toutes les touches sont des champs RTSKey des composants (caméra, sélection, ordres, démos, HUD) : vous pouvez donc les réaffecter dans l’Inspector.

RTSDemoGame : le composant d’amorçage

Ce composant transforme n’importe quelle scène contenant un RTS Terrain en un petit RTS jouable. Au démarrage de la partie, il :

  1. s’assure de la présence d’un RTSFogOfWarManager (équipe locale = Local Team, exploration réinitialisée) et du service de recherche de chemin ;
  2. recherche le contrôleur de caméra, la sélection, les ordres, la mini-carte, le HUD ainsi que les démos de bâtiments et d’arbres, et crée ceux qui manquent ;
  3. fait apparaître des unités sur chaque position de départ (équipe = indice du joueur ; le joueur 1 correspond à l’équipe 0) et attribue un RTSWanderAI aux unités ennemies, pour que vous puissiez les voir apparaître et disparaître dans le brouillard de guerre ;
  4. place la caméra sur la position de départ du joueur local.

Éditeur en jeu : le composant s’abonne à RTSRuntimeEditorEvents.PlaytestChanged. Lancer un test en jeu dans l’éditeur en jeu démarre la partie ; y mettre fin fait disparaître les unités, supprime les bâtiments de démo, restaure les arbres récoltés (facultatif), désactive les systèmes de gameplay et rend la caméra à l’éditeur. Si Auto Start est activé et que la scène ne contient aucun éditeur en jeu, la partie démarre immédiatement.

ParamètrePar défautDescription
Start
Auto StartactivéDémarre la partie quand la scène est lancée et qu’aucun éditeur en jeu n’est présent (sinon, la partie démarre avec le test en jeu de l’éditeur).
Local Team0Équipe du joueur local (0 = joueur 1). La modifier par le code met aussi à jour le brouillard de guerre et la sélection.
TerrainvideTerrain sur lequel jouer. Vide = RTSTerrain.Main.
Units
Unit PrefabsvidePrefabs d’unités, utilisés à tour de rôle. Vide = unités de substitution procédurales.
Units Per Player8Nombre d’unités créées pour chaque joueur (de 1 à 60).
Max Players8Nombre maximal de joueurs qui reçoivent des unités.
Enemy Wander AIactivéLes unités ennemies errent au hasard.
Wander Radius30Rayon d’errance de l’IA ennemie, en mètres.
Systems
Create Missing SystemsactivéCrée le contrôleur de caméra, la sélection, les ordres, la mini-carte, le HUD et les démos s’ils manquent. Le composant qui fait apparaître les unités est toujours créé.
Fog Of WaractivéActive le brouillard de guerre pendant la partie.
MinimapactivéAffiche la mini-carte.
HudactivéAffiche le HUD (panneau d’informations, barre d’actions, aide F1).
Show Help On StartactivéAffiche le panneau d’aide au démarrage de la partie.
Building DemoactivéActive la démo de placement de bâtiments (B).
Tree Harvest DemoactivéActive la démo de récolte d’arbres (T, ouvriers).
Restore Map On StopactivéRestaure les arbres récoltés à l’arrêt de la partie, pour que la carte éditée reste inchangée après un test en jeu.
References
Camera Controller, Selection Manager, Command Controller, Minimap UI, Demo HUD, Spawner, Building Placement, Tree Harvest, Fog Of War ManagervideSystèmes à utiliser. Vide = recherchés dans la scène ou créés.

API : StartGame(), StopGame(), IsRunning, AutoStart, LocalTeam, les événements GameStarted et GameStopped, ainsi que les propriétés Spawner, CameraController, SelectionManager, CommandController. Redéfinissez protected virtual bool DetectInGameEditor() si vous utilisez votre propre éditeur en jeu.

Vous développez votre propre jeu ? Servez-vous de RTSDemoGame comme d’une recette plutôt que comme d’une dépendance : reprenez l’ordre de ses étapes d’initialisation dans votre propre gestionnaire de jeu et laissez de côté ce dont vous n’avez pas besoin. En multijoueur avec Mirror, n’ajoutez pas RTSDemoGame : c’est le gestionnaire réseau qui fait apparaître les unités.

RTSCameraController

Une caméra RTS classique : défilement au clavier, par les bords et par glissement, zoom avec courbe d’inclinaison (un zoom rapproché rend la vue plus rasante), rotation, suivi fluide de la hauteur du sol et limites de la carte. Elle s’exécute dans LateUpdate. RTSCameraController.Main désigne le premier contrôleur activé.

ParamètrePar défautDescription
Target CameravideCaméra déplacée. Vide = le composant Camera de ce GameObject, sinon Camera.main.
TerrainvideTerrain utilisé pour la hauteur du sol et les limites. Vide = RTSTerrain.Main.
Keyboard Pan, Pan Forward/Back/Left/Right Key, Arrow Keysactivé, W/S/A/D, activéDéfilement au clavier.
Yield Keys To OrdersactivéLes touches de défilement qui sont aussi des touches d’ordre du contrôleur d’ordres (S = Stop) ne font pas défiler la caméra tant que des unités sont sélectionnées.
Pan Speed / Fast Pan Multiplier35 / 2Mètres par seconde au zoom par défaut (varie avec la distance de zoom) ; multiplicateur appliqué tant que Shift est maintenue enfoncée.
Edge Scrolling, Edge Size, Edge Speed Multiplieractivé, 12 px, 1Défilement lorsque la souris touche le bord de l’écran. Le défilement par les bords est suspendu tant que la fenêtre du jeu n’a pas le focus, tant que le pointeur se trouve en dehors de celle-ci (dans les builds Web, également lorsque la souris a quitté la page ou son iframe) et sur les écrans tactiles.
Middle Mouse DragactivéMaintenez le bouton du milieu enfoncé pour saisir et déplacer le sol.
Min / Max Distance12 / 75Distance par rapport au pivot en zoom avant / arrière maximal (en mètres).
Zoom Step, Start Zoom0.08, 0.6Variation du zoom par cran de molette ; zoom initial (0 = le plus proche, 1 = le plus éloigné).
Distance Curve, Pitch Curve-Associent le zoom (de 0 à 1) à la distance et à l’inclinaison en degrés (environ 55° au zoom par défaut).
Keyboard Rotate, Rotate Left/Right Key, Rotate Speedactivé, Q/E, 100Rotation au clavier, en degrés par seconde.
Alt Right Drag Rotate, Drag Rotate Sensitivityactivé, 0.3Rotation avec Alt + glisser avec le bouton droit.
Snap Back Rotation, Snap Back Delay, Default Yawdésactivé, 0.25, 0Revient à l’angle par défaut en l’absence de saisie de rotation (comportement classique des RTS). Avec un lacet de 0, la caméra regarde vers +Z (le nord).
Follow Ground Height, Height Smooth Timeactivé, 0.3Maintient le pivot à hauteur du sol, avec un lissage pour que les falaises ne fassent pas sauter la vue.
Clamp To Terrain, Bounds Marginactivé, 4Maintient le pivot à l’intérieur de la carte (une marge négative permet de regarder au-delà du bord).
Min Camera Clearance2Hauteur minimale de la caméra au-dessus du sol situé sous elle.
Pan / Zoom / Rotation Smooth Time0.08 / 0.12 / 0.08Lissage en secondes (0 = instantané).
Ignore Mouse Over UIactivéIgnore la molette, le défilement par les bords et le glissement tant que le pointeur survole l’interface.
Use Unscaled TimeactivéLa caméra se déplace aussi lorsque le jeu est en pause.

API : JumpTo(Vector3), FocusOn(Vector3), FocusOn(IReadOnlyList<RTSUnit>, bool instant = false), SetZoom(float, bool instant = false), SetYaw(float, bool instant = false), GetViewFootprint(Vector3[4]) (coins de l’écran projetés sur le sol, utilisés par la mini-carte), InitializeFromCamera(), InputEnabled et, en lecture seule, Pivot, Zoom, Yaw, Pitch, Distance, IsDragging.

RTSUnit et utilitaires d’unités

Une unité RTS simple : équipe, déplacement sur le terrain, suivi de chemin avec virages adoucis, évitement local et vision pour le brouillard de guerre. Elle demande un chemin à son fournisseur de chemins, le suit à l’aide d’un point d’anticipation, ralentit à l’arrivée, garde ses distances avec les autres unités, ne s’engage jamais sur une cellule non praticable et recalcule son chemin lorsqu’elle est bloquée ou que la carte de cheminement change le long de son trajet (bâtiments placés, arbres abattus, terrain modifié dans l’éditeur en jeu). Elle requiert et configure un RTSFogOfWarRevealer (équipe, rayon de vision) et un RTSFogOfWarHideable (équipe).

ParamètrePar défautDescription
Team0Indice d’équipe / de joueur (0 = joueur 1). Les unités de l’équipe locale peuvent être sélectionnées et recevoir des ordres.
Use Team Color, Player Coloractivé, rougeReprend la couleur dans la table classique des couleurs de joueur à chaque changement d’équipe ; elle sert aux cercles de sélection, aux points de la mini-carte et aux renderers de couleur d’équipe.
Unit Type« Unit »Nom de type utilisé par « un double-clic sélectionne toutes les unités du même type » (par exemple Footman, Worker). La démo d’arbres utilise « Worker ».
Move Speed, Turn Speed, Acceleration5, 540, 25Mètres par seconde, degrés par seconde, mètres par seconde².
Radius, Height0.5, 1.8Rayon de collision (dégagement pour la recherche de chemin, évitement, cercle de sélection) et hauteur (détection au clic, rectangle de sélection).
Align To Ground, Ground Align Speeddésactivé, 8Incline l’unité selon le sol (véhicules, animaux). Désactivé, il maintient l’infanterie à la verticale.
Look Ahead, Arrival Distance, Slow Down Distance1.5, 0.15, 1.5Suivi de chemin (en mètres).
Stuck Check Interval0.6Secondes entre deux vérifications de progression. Une unité qui ne progresse pas recalcule son chemin.
Path Request Timeout3Délai d’attente d’un chemin, en secondes, avant que la requête soit renvoyée une fois ; le déplacement échoue si la seconde requête expire aussi.
Avoidance, Separation Strength, Personal Spaceactivé, 8, 0.1Séparation simple. Les unités inactives s’écartent pour laisser passer celles qui se déplacent.
Sight Radius14Rayon de vision pour le brouillard de guerre, en mètres.
SelectableactivéLe joueur peut sélectionner cette unité.
TerrainvideTerrain sur lequel l’unité se déplace. Vide = le terrain situé sous l’unité (ou RTSTerrain.Main).
Path ProvidervideComposant facultatif qui implémente IRTSUnitPathProvider. Vide = le fournisseur global par défaut (voir Fournisseurs de chemins).
Team Color Renderers, Team Color Modeaucun, PropertyBlockRenderers qui affichent la couleur du joueur, via un MaterialPropertyBlock (n’importe quel matériau) ou via un matériau partagé par couleur (meilleur batching).
Draw Path GizmosactivéDessine le chemin actuel dans la Scene View.

Ordres : MoveTo(Vector3, bool queue = false), Stop(), HoldPosition(), Patrol(Vector3 a, Vector3 b), Warp(Vector3, float? yaw = null), FaceTowards(Vector3), Repath(). Événements : OnArrived, OnPathFailed (aucun chemin, abandon alors que l’unité était bloquée, ou arrêt au point accessible le plus proche), OnStateChanged. État : State (Idle, Moving, Patrolling, Holding), IsMoving, IsWaitingForPath, IsPathPartial, LastMoveReachedDestination, Destination, CurrentPath, QueuedDestinations, PlannedEndPosition, Velocity, Position, Yaw, IsSelected, IsVisibleToLocalTeam.

using RTSTerrainStudio;
using RTSTerrainStudio.Samples;
using UnityEngine;

// Spawns a knight for player 2 and listens to its movement events.
public class KnightSpawner : MonoBehaviour
{
    [SerializeField] Transform target;

    void Start()
    {
        var terrain = RTSTerrain.Main;
        // Nearest walkable spot where a unit of radius 0.75 m fits.
        Vector3 position = RTSUnitFactory.FindSpawnPosition(terrain, transform.position, 0.75f);
        RTSUnit knight = RTSUnitFactory.CreatePlaceholder(1, position, 180f, RTSUnitFactory.Knight);

        knight.OnArrived += unit => Debug.Log(unit.name + " arrived.");
        knight.OnPathFailed += unit => Debug.Log(unit.name + " can't reach that place.");
        if (target != null) knight.MoveTo(target.position);
    }
}

Utilitaires :

ClasseUtilité
RTSUnitFactoryUnités de substitution procédurales : styles Footman, Worker, Scout, Knight et DefaultMix ; CreatePlaceholder(team, position, yaw, style, parent), Spawn(prefab, team, position, yaw, parent) (ajoute RTSUnit au prefab s’il en est dépourvu), FindSpawnPosition(terrain, position, radius, searchRadius = 16).
RTSUnitSpawnerFait apparaître les unités de chaque joueur sur les positions de départ de la carte (ou sur les Custom Spawn Points, ou dans des coins opposés). Paramètres : Unit Prefabs, Units Per Player (6), Mix Placeholder Types, Terrain, Use Start Locations, Custom Spawn Points, Max Players, Spacing (2 m), Start Offset (5 m, pour laisser de la place à un hôtel de ville), Container, Spawn On Start. API : SpawnAll(), SpawnForPlayer(...), SpawnUnit(team, position, yaw, variant), DespawnAll(), TryGetStartLocation(player, out position, out yaw).
RTSWanderAIFait marcher une unité vers des points aléatoires autour de son point d’attache. Paramètres : Wander Radius (25 m), Min/Max Wait (2 / 7 s), Home Is Start Position, Home Position.
RTSUnitRegistryToutes les unités et un hachage spatial : All, GetTeam(team), QueryRadius(...), QueryScreenRect(...), PickAtScreen(...), les événements UnitRegistered, UnitUnregistered, UnitTeamChanged.

Fournisseurs de chemins : IRTSUnitPathProvider

Les unités ne dépendent d’aucune solution de recherche de chemin particulière. Elles interrogent un IRTSUnitPathProvider, choisi dans cet ordre : le Path Provider propre à l’unité (ou PathProviderOverride), sinon RTSUnitPathProviderRegistry.Default, sinon le fournisseur intégré RTSBuiltinPathProvider (l’A* Burst du package, via RTSPathfindingService en Play Mode). C’est ici que se branchent les intégrations A* Pathfinding Project et NavMesh.

Il existe deux types de fournisseurs :

  • Les fournisseurs de chemins (HandlesMovement = false) renvoient des points de passage via RequestPath ; l’unité les suit elle-même (pilotage, évitement, alignement sur le sol).
  • Les fournisseurs de mouvement (HandlesMovement = true) déplacent eux-mêmes l’unité (par exemple un NavMeshAgent). L’unité leur transmet ses ordres via OnUnitMoveCommand et OnUnitStop ; le fournisseur signale le résultat avec unit.NotifyArrived() ou unit.NotifyPathFailed(). Tant qu’un tel fournisseur a la charge d’une unité, celle-ci ne modifie jamais elle-même son transform.

Le contrat : appelez le callback onComplete exactement une fois, sur le thread principal, immédiatement ou plus tard, avec les points de passage (départ et arrivée inclus) et true en cas de succès ; en cas d’échec, passez une liste vide ou null et false. Renvoyer true avec un chemin qui mène au point accessible le plus proche est tout à fait correct ; l’unité détecte qu’il s’arrête avant la destination. Le fournisseur qui a reçu un déplacement le conserve jusqu’à la fin de celui-ci ; si le fournisseur change ou est détruit pendant un déplacement, l’ancien reçoit OnUnitStop et l’ordre passe au nouveau. Une requête restée sans réponse au-delà du délai Path Request Timeout est relancée une fois, puis échoue.

Dérivez de RTSUnitPathProviderComponent pour créer un composant de scène qui peut s’enregistrer comme fournisseur par défaut (Make Default, activé par défaut) ou être glissé dans le champ Path Provider d’une unité :

using System;
using System.Collections.Generic;
using RTSTerrainStudio;
using RTSTerrainStudio.Samples;
using UnityEngine;

// A path provider for heavy units that must never cross water (not even shallow fords).
// Turn off "Make Default" and drag it into the Path Provider field of the units that should use it.
public class NoWaterPathProvider : RTSUnitPathProviderComponent
{
    [SerializeField] int maxSearchNodes = 200000;
    readonly List<Vector3> path = new List<Vector3>(64);

    // The unit follows the waypoints itself.
    public override bool HandlesMovement => false;

    public override void RequestPath(RTSUnit unit, Vector3 from, Vector3 to, Action<List<Vector3>, bool> onComplete)
    {
        RTSTerrain terrain = unit != null ? unit.Terrain : RTSTerrain.Main;
        if (terrain == null) { onComplete(null, false); return; }

        var options = PathRequestOptions.ForUnit(unit != null ? unit.Radius : 0.5f);
        options.allowShallowWater = false;
        options.maxSearchNodes = maxSearchNodes;

        // Synchronous search; the list is reused for the next request, the unit copies what it keeps.
        PathStatus status = RTSPathfinder.FindPath(terrain, from, to, options, path);
        onComplete(path, status == PathStatus.Success || status == PathStatus.Partial);
    }
}

Par le code : RTSUnitPathProviderRegistry.Default = myProvider; fait basculer toutes les unités qui n’ont pas leur propre fournisseur ; Default = null rétablit le module de recherche de chemin intégré. RTSBuiltinPathProvider expose Options (son unitRadius est remplacé par le rayon de chaque unité) et UseAsyncService.

RTSSelectionManager

Sélection par clic, par rectangle, avec Shift et par double-clic, groupes de contrôle, anneaux de survol et de sélection. Seules les unités de l’équipe locale peuvent être sélectionnées. RTSSelectionManager.Main désigne le premier gestionnaire activé.

ParamètrePar défautDescription
Target CameravideCaméra utilisée pour la détection au clic. Vide = Camera.main.
Use Fog Of War Local TeamactivéUtilise l’équipe locale du gestionnaire de brouillard de guerre actif.
Local Team0Équipe dont les unités peuvent être sélectionnées (lorsqu’elle n’est pas reprise du brouillard de guerre).
Drag Threshold, Double Click Time6 px, 0.3 sDistance à partir de laquelle un clic devient un rectangle de sélection ; délai du double-clic.
Max Selection0Nombre maximal d’unités sélectionnées (0 = illimité ; 12 est une limite courante dans les RTS classiques).
Pick Tolerance6 pxRayon de détection supplémentaire, pour que l’on puisse cliquer facilement sur les petites unités.
Keep Selection On Empty ClickactivéCliquer sur un sol vide ou tracer un rectangle de sélection qui ne contient aucune de vos unités conserve la sélection, comme dans les RTS classiques.
Clear Selection KeyEscapeVide la sélection.
Control Groups, Group Double Tap Timeactivé, 0.35 sCtrl+chiffre enregistre, Shift+chiffre ajoute, le chiffre seul rappelle le groupe, deux appuis centrent la caméra. Il existe dix groupes (RTSSelectionManager.GroupCount = 10) sur les touches 1–9 et 0 ; l’indice de groupe i de StoreGroup, RecallGroup et GetGroup correspond à la touche numérique i (l’indice 0 est la touche 0).
Show Selection Circles, Show Hover, Use Team Color For Circles, Selection Color, Circle Scale, Circle Width, Box Color-Apparence des anneaux et du rectangle de sélection.

API : Selection, Count, Select(unit, additive), Deselect, ToggleSelection, SetSelection(units, additive), ClearSelection(), SelectAllOfTypeOnScreen(unit, additive), GetSelectionCenter(), StoreGroup(i), AddToGroup(i), RecallGroup(i), GetGroup(i), ClearGroups(), HoveredUnit, les événements SelectionChanged et GroupRecalled.

RTSCommandController et formations

Ce composant transforme les clics droits et les touches d’ordre en ordres pour les unités sélectionnées. RTSCommandController.Main désigne le premier contrôleur activé.

ParamètrePar défautDescription
Selection, Target CameravideVide = RTSSelectionManager.Main / Camera.main.
Stop Key, Hold Key, Patrol Key, Cancel KeyS, H, P, EscapeTouches d’ordre.
Use FormationactivéDéplace les groupes dans une formation en grille (désactivé = chaque unité se rend au point cliqué).
Spacing Multiplier, Extra Spacing, Width To Depth1.15, 0.3, 1.5Distance entre emplacements en multiple du plus grand diamètre d’unité, écart supplémentaire en mètres, rapport colonnes/rangées préféré.
Show Marker, Move Marker Color, Patrol Marker ColoractivéAnneau animé à l’emplacement cible de l’ordre.

API : IssueMove(Vector3 target, bool queue = false), IssueMove(IReadOnlyList<RTSUnit> units, Vector3 target, bool queue = false), IssuePatrol(Vector3), IssueStop(), IssueHold(), BeginPatrolTargeting(), CancelTargeting(), IsOrderKeyActive(RTSKey), les événements MoveIssued, CommandIssued, TargetingChanged.

RTSFormation.ComputeGrid(units, target, slots, spacingMultiplier, extraSpacing, widthToDepth, fromPlannedEnd) calcule un emplacement par unité et attribue à chaque unité l’emplacement le plus proche de sa place dans le groupe, si bien que les chemins se croisent rarement. La méthode renvoie la direction vers laquelle la formation est orientée. Avec fromPlannedEnd (utilisé pour les ordres mis en file d’attente avec Shift), la formation part de l’endroit où se trouveront les unités après leurs ordres en cours.

Coordination des entrées. RTSGameInput garantit qu’un clic est traité par un seul et unique système : un mode comme le placement de bâtiments s’approprie le pointeur (Acquire, Release, CanUsePointer), et un système qui a traité un clic ou une touche appelle Consume / ConsumeKey. Les exemples s’exécutent dans un ordre fixe (placement de bâtiments, récolte d’arbres, ordres, sélection, unités, caméra, interface), défini par les constantes RTSGameInput.Order…. Utilisez le même mécanisme dans vos propres modes pour qu’ils cohabitent avec les exemples.

RTSMinimapUI

Une mini-carte UI Toolkit pour le jeu en cours d’exécution. L’image de la carte est précalculée avec RTSMinimapBaker, puis à nouveau précalculée (à une fréquence limitée) quand la carte change ; le brouillard de guerre de l’équipe locale est superposé à l’image ; les unités sont dessinées sous forme de points dans leur couleur de joueur (les ennemis uniquement lorsqu’ils sont visibles) ; le champ de vision de la caméra est dessiné sous forme de contour. Un clic gauche ou un glissement déplace la caméra, un clic droit ordonne aux unités sélectionnées de s’y rendre.

ParamètrePar défautDescription
Terrain, Camera Controller, Command ControllervideVide = RTSTerrain.Main, RTSCameraController.Main, RTSCommandController.Main.
CornerBottomLeftCoin de l’écran (les RTS classiques utilisent le coin inférieur gauche).
Size, Margin248, 16Taille du cadre et distance aux bords de l’écran, en pixels d’interface (résolution de référence 1920 × 1080).
Resolution256Résolution de l’image précalculée de la carte (côté le plus long).
Rebake Delay, Min Rebake Interval0.35 s, 1 sPlusieurs modifications sont regroupées en un seul précalcul.
Bake Options-Apparence de l’image précalculée (mode du sol, ombrage du relief, falaises, eau, arbres, décors, positions de départ, couleurs de joueur).
Show Fog, Fog Refresh Intervalactivé, 0.1 sAssombrit les zones inexplorées et celles couvertes par le brouillard de guerre, comme dans la vue 3D.
Show Units, Unit Dot Size, Show Camera View, Camera View Color, Overlay Rateactivé, 4, activé, blanc, 20Points, contour de la caméra et fréquence à laquelle ils sont redessinés.
Left Click Moves Camera, Right Click Moves Unitsactivé, activéInteraction.

API : Visible, Terrain, MapTexture, BakeOptions, Rebake().

RTSDemoHUD et RTSRuntimeUI

RTSDemoHUD affiche un panneau d’informations sur la sélection, une barre d’actions (Stop, Hold, Patrol, Build), la fréquence d’images, de courts messages de retour (« Can't reach that place. », « Can't build there. », « Can't build in unexplored land. ») et le panneau d’aide F1. Paramètres : Help Key (F1), Show Help On Start, Show Fps, Show Feedback Messages, Message Duration (2.5 s) et des références à la sélection, aux commandes et aux démos. API : Visible, HelpVisible, SetMode(string), ShowMessage(string). Tant qu’il est actif, il active RTSInput.SetBrowserShortcutGuard : dans les builds Web, F1 ouvre ainsi l’aide du HUD au lieu de la page d’aide du navigateur. Cette protection empêche aussi le navigateur de réagir aux autres touches de fonction jusqu’à F10 (y compris F5, qui recharge la page) ainsi qu’à Ctrl+S/O/D/A (voir L’éditeur en jeu dans le navigateur). Sur les autres plateformes, elle n’a aucun effet.

RTSRuntimeUI est la petite boîte à outils UI Toolkit que partagent les exemples : CreateDocument, CreatePanel, CreateLabel, CreateButton(text, tooltip, action), AttachTooltip, IsScreenPointOverUI et la palette de couleurs des exemples. Servez-vous-en pour ajouter vos propres panneaux avec la même apparence.

Toutes les interfaces des exemples partagent un même panneau (RTSRuntimeUI.PanelSettings), dont l’échelle suit la taille de l’écran (résolution de référence 1920 × 1080). Comme pour l’éditeur en jeu, cette échelle ne descend jamais sous RTSRuntimeUI.MinimumScale (0.85 par défaut ; mesurée en pixels CSS dans les builds Web) : le HUD, la mini-carte et la sélection restent ainsi lisibles dans les petites fenêtres et les canvas des navigateurs. Les grands écrans ne sont pas concernés. Réglez cette valeur sur 0 pour désactiver le minimum.

RTSBuildingPlacementDemo

Montre comment le code du jeu modifie la carte de cheminement à l’exécution. Appuyez sur B : une emprise fantôme suit le curseur, alignée sur la grille de cheminement, et chaque cellule est dessinée en vert (constructible) ou en rouge (bloquée). Un clic gauche place un bâtiment simple dans la couleur de l’équipe (maintenez Shift enfoncée pour en placer plusieurs). L’emprise est écrite dans les surcharges de cheminement, le terrain reconstruit la zone et les unités en mouvement recalculent leur itinéraire pour contourner le bâtiment. Un clic sur un emplacement bloqué affiche un marqueur rouge et un message. Un clic droit ou Esc annule ; Delete supprime le bâtiment sous le curseur et rétablit le cheminement.

ParamètrePar défautDescription
Size In Cells2 × 2Taille de l’emprise en cellules de la carte (X × Z).
Building Height3Hauteur du bâtiment procédural, en mètres.
Building PrefabvidePrefab facultatif, utilisé à la place du bâtiment procédural. Son pivot est posé au sol, au centre de l’emprise.
Team-1Équipe propriétaire. -1 = l’équipe locale du gestionnaire de sélection (ou du brouillard de guerre).
Sight Radius10Rayon de vision des bâtiments (0 = aucune vision). Les bâtiments deviennent aussi des objets masquables, en mode fantôme.
Footprint FlagsUnwalkable, UnbuildableSurcharges de cheminement écrites pour l’emprise.
Push Units OutactivéLes unités qui se trouvent sur l’emprise s’écartent.
Require ExploredactivéN’autorise la construction que sur un sol déjà exploré par l’équipe locale (lorsqu’un brouillard de guerre est actif).
Place Key, Cancel Key, Demolish KeyB, Escape, DeleteTouches.
Valid Color, Invalid Colorvert, rougeCouleurs des cellules de l’emprise.
Terrain, Target CameravideVide = le terrain sous le curseur / Camera.main.

API : BeginPlacement(), CancelPlacement(), IsPlacing, GetFootprintSize(terrain), CanPlaceAt(terrain, worldCenter), GetPlacementError(terrain, worldCenter) (un message destiné au joueur, ou null), PlaceBuilding(terrain, worldCenter, owner), RemoveBuilding(building), RemoveAllBuildings(), Buildings, les événements BuildingPlaced, BuildingRemoved, PlacementModeChanged, PlacementFailed(Vector3, string). Chaque bâtiment placé possède un composant RTSDemoBuilding (Team, PathingCells, ContainsPoint, Remove()) qui mémorise les surcharges précédentes et les rétablit quand le bâtiment est supprimé ou détruit.

Pour en faire de vrais bâtiments, assignez votre prefab au champ Building Prefab, abonnez-vous à BuildingPlaced pour déduire le coût et lancer la construction, et appelez GetPlacementError pour indiquer au joueur pourquoi il ne peut pas construire.

RTSTreeHarvestDemo

Montre comment le gameplay supprime des arbres. Survolez un arbre (un anneau jaune l’entoure) et appuyez sur T pour l’abattre immédiatement. Vous pouvez aussi sélectionner des ouvriers (type d’unité « Worker ») et cliquer avec le bouton droit sur un arbre : ils marchent jusqu’à lui, se tournent vers lui, donnent des coups de hache pendant un moment (un anneau se resserre autour du tronc), puis l’abattent. L’arbre est supprimé avec RTSVegetationRenderer.RemoveTree : la zone devient praticable et le brouillard de guerre retire l’obstacle à la vision. Une animation de chute (RTSFallingTreeEffect) est jouée à l’ancienne position de l’arbre.

ParamètrePar défautDescription
Harvest KeyTAbat l’arbre sous le curseur.
Workers Harvest On Right ClickactivéUn clic droit sur un arbre alors que des ouvriers sont sélectionnés les envoie le couper.
Worker Type« Worker »Type d’unité capable de récolter des arbres.
Pick Radius1.5Distance maximale entre le rayon du curseur et un arbre pour pouvoir le sélectionner.
Chop Time, Work Distance1.5 s, 1.2 mDurée pendant laquelle un ouvrier coupe l’arbre, et distance à laquelle il se tient du tronc.
Fall Duration, Fade Duration1.1 s, 0.5 sAnimation de chute et rétrécissement final.
Highlight Color, Show Chop Progress, Chop Progress Color-Anneaux sous l’arbre survolé et sous l’arbre en cours d’abattage.
Target CameravideCaméra utilisée pour la sélection.

API : TryGetHoveredTree(out RTSVegetationRenderer, out TreeInstanceData), HarvestTree(vegetation, treeId, fallAwayFrom), OrderHarvest(workers, vegetation, tree), RestoreHarvestedTrees(), CancelAllJobs(), HarvestedCount, l’événement TreeHarvested.

using RTSTerrainStudio;
using UnityEngine;

// Cuts the tree nearest to a point, e.g. when a catapult hits a forest.
public static class TreeCutter
{
    public static bool CutNearest(RTSTerrain terrain, Vector3 worldPoint, float maxDistance)
    {
        var vegetation = terrain != null ? terrain.GetComponent<RTSVegetationRenderer>() : null;
        if (vegetation == null) return false;

        if (!vegetation.TryFindNearestTree(worldPoint, maxDistance, out TreeInstanceData tree)) return false;
        // Removes the tree from the map and notifies the terrain:
        // pathing and fog of war blockers update automatically.
        return vegetation.RemoveTree(tree.id);
    }
}

Petits utilitaires

ClasseUtilité
RTSMoveMarkerAnneau animé sur la cible d’un ordre : RTSMoveMarker.Spawn(position, color, radius, seconds).
RTSGroundRingAnneau qui épouse le terrain (cercles de sélection, portées) : RTSGroundRing.Create(name, color, radius, width, parent), puis Place(position).
RTSSampleMaterials, RTSSampleMeshesMatériaux URP mis en cache par couleur et meshes primitifs pour les substituts.
RTSSampleUtilityDétermination du terrain à utiliser, détection du point au sol visé, distances XZ et PathingRectToCellRect(map, pathingRect).

Générateur de contenu de démo

Le package est livré sans graphismes tiers. À la place, un générateur crée de manière procédurale tout le contenu de démo dans votre projet : textures répétables de sol, de falaise et d’eau, sprites d’herbe et de fleurs, arbres et accessoires low-poly, matériaux, prefabs, deux tilesets, des bibliothèques de végétation et de décors, un profil de peinture automatique, des formes de pinceau, trois cartes de démo et trois scènes de démo. Le résultat est déterministe (graines fixes) : chaque exécution produit le même contenu.

La carte de démo Four Kingdoms (4p) avec ses lacs, ses falaises, ses routes, ses forêts et son centre corrompu
La carte de démo Four Kingdoms (4p) dans la scène Editor Playground.

Créer le contenu de démo

  1. Vérifiez que vous êtes en Edit Mode et que votre scène est enregistrée (Unity n’autorise qu’une seule scène sans titre ; le générateur vous demande de l’enregistrer si nécessaire).
  2. Choisissez Tools ▸ RTS Terrain Studio ▸ Create Demo Content. Une barre de progression affiche les étapes. L’opération prend quelques instants.
  3. Quand le générateur vous demande s’il doit ajouter les scènes de démo aux paramètres de build, choisissez Not Now, sauf si vous voulez générer un build de joueur avec les démos (vous pourrez les ajouter plus tard dans File ▸ Build Profiles).
  4. Le générateur sélectionne la scène RTS Terrain Studio - Gameplay Demo dans la fenêtre Project. Double-cliquez dessus pour l’ouvrir.

Le générateur se lance aussi quand vous cliquez sur Create dans la section du contenu de démo de la fenêtre Welcome (Tools ▸ RTS Terrain Studio ▸ Welcome), ou quand vous acceptez la proposition qui s’affiche lorsque vous créez un RTS Terrain dans un projet qui ne contient encore aucun tileset. Il ne ferme ni ne remplace jamais les scènes que vous avez ouvertes : les scènes de démo sont créées à côté.

Le générateur exécute les étapes suivantes (vous pouvez appeler chacune d’elles par le code) :

ÉtapeMéthodeCe qui est créé
TexturesCreateTextures()Textures de sol, de falaise, d’eau, d’arbres et d’accessoires (512 px), sprites d’herbe et de fleurs et tampons de pinceau (256 px).
MatériauxCreateMaterials()Matériaux d’arbres et de plantes (shader RTS Terrain Studio/Vegetation, vent), matériaux d’accessoires (URP Lit), matériaux modèles utilisés par les exemples, matériau du ciel et profil de post-traitement.
Meshes et prefabsCreateModels()Arbres, buissons, rochers et accessoires low-poly, ainsi que leurs prefabs.
Tilesets, bibliothèques et pinceauxCreateDataAssets()Les tilesets Summer et Winter, les bibliothèques Demo Vegetation et Demo Decor (avec leurs icônes de palette), le profil Summer Auto Paint et les formes de pinceau.
Références de shaders et paramètres d’interfaceUpdateResources()Garantit que tous les shaders du package et les Panel Settings UI Toolkit utilisés à l’exécution sont conservés dans les builds de joueur.
Cartes de démoCreateMaps()Trois fichiers .rtsmap (voir ci-dessous).
Scènes de démoCreateScenes(bool interactive)Trois scènes (voir Scènes de démo). Ajoute aussi la renderer feature du brouillard de guerre à votre renderer URP.

Ce que vous obtenez

  • Tileset Summer (id rts-demo-summer) avec dix calques de sol : Grass, Lush Grass, Dirt, Rocky Dirt, Sand, Cobblestone, Dark Forest Floor, Rock, Snow et Blight. Rock et Blight sont réglés sur Unbuildable, un bon exemple de règles de cheminement des calques de sol.
  • Tileset Winter (id rts-demo-winter) : les mêmes textures avec des teintes froides et le même ordre de calques, si bien que chaque carte de démo peut passer de Summer à Winter et inversement.
  • Summer Auto Paint : des taches d’herbe luxuriante et de terre sur l’herbe, de la terre et de la terre rocailleuse le long des bords de falaise, du sable sur les rivages, de la roche sur les pentes escarpées et de la neige en altitude.
  • Bibliothèques Demo Vegetation et Demo Decor : herbe, hautes herbes, fleurs jaunes et violettes et fougères ; pins, feuillus, arbres morts et buissons ; rochers, un gros bloc de pierre, un pilier en ruine, des caisses, des tonneaux, des clôtures, des souches et des champignons.
  • Trois cartes :
    • Two Rivers (1v1) : 128 × 128 cellules, symétrie centrale. Deux rivières sinueuses se rejoignent dans un lac central ; des gués peu profonds permettent aux unités de traverser.
    • Four Kingdoms (4p) : 192 × 192 cellules, symétrie de rotation d’ordre 4, plateaux étagés et centre corrompu avec des ruines.
    • Sandbox : 96 × 96 cellules, en grande partie plate, avec un plateau et un étang, pour essayer les outils.
    Toutes les cartes comportent des places pavées aux positions de départ, des forêts avec un sol forestier et de petits groupes d’accessoires, le tout placé symétriquement pour que les cartes restent équitables.

Emplacement des fichiers

Le générateur écrit uniquement dans ses propres dossiers, sous le dossier du package (Assets/RTSTerrainStudio, sauf si vous l’avez déplacé ; le package fonctionne dans n’importe quel dossier) :

DossierContenu
Content/TexturesTextures générées, réparties dans les sous-dossiers Ground, Cliffs, Water, Details, Props et Brushes.
Content/Materials, Content/Meshes, Content/PrefabsMatériaux, meshes et prefabs des arbres et des accessoires.
Content/TilesetsSummer.asset, Winter.asset et Summer Auto Paint.asset.
Content/LibrariesDemo Vegetation.asset, Demo Decor.asset et leurs icônes.
Content/BrushesFormes de pinceau.
Content/MapsTwo Rivers (1v1).rtsmap, Four Kingdoms (4p).rtsmap, Sandbox.rtsmap.
Content/SettingsParamètres de rendu (profil de post-traitement).
Samples/ScenesLes trois scènes de démo.
Resources/RTSTerrainStudioRéférences de shaders et UI/RTSRuntimePanelSettings.asset.

Régénérer le contenu

Relancez Tools ▸ RTS Terrain Studio ▸ Create Demo Content et confirmez avec Regenerate. Les assets de démo existants sont écrasés sur place, si bien que les cartes, les scènes et les prefabs qui y font référence continuent de fonctionner. Vos propres assets ne sont jamais modifiés. Les fichiers de carte dont le contenu n’a pas changé ne sont pas réécrits, ce qui évite des modifications inutiles dans votre gestionnaire de versions.

La régénération écrase toutes les modifications que vous avez apportées aux assets générés eux-mêmes (par exemple un tileset de démo retouché ou une carte de démo modifiée). Pour personnaliser le contenu de démo, dupliquez d’abord l’asset (Ctrl+D) ou enregistrez la carte sous un nouveau nom, puis modifiez la copie.

Par le code (assembly d’éditeur, espace de noms RTSTerrainStudio.Editor) :

MembreDescription
RTSDemoContent.CreateAll(bool openScene)Exécute toutes les étapes avec une barre de progression. Renvoie false en cas d’annulation ou si une étape a échoué.
RTSDemoContent.CreateAllNonInteractive()N’affiche aucune boîte de dialogue et n’ouvre aucune scène ; destiné à l’automatisation et au mode batch. Renvoie un court résumé.
RTSDemoContent.IsCreatedVaut true si les principaux assets de démo existent.
RTSDemoContent.ContentFolder, ScenesFolder, SummerTilesetPath, TwoRiversMapPath, GameplayScenePath, …Chemins des dossiers et des assets générés.
RTSDemoContent.RenderPreview(scenePath, pngPath, width, height)Génère une image d’aperçu d’une scène.
// Editor script (place it in an Editor folder): create the demo content from a build pipeline or a CI job.
using RTSTerrainStudio.Editor;
using UnityEngine;

public static class BuildDemoContent
{
    // Run with: Unity -batchmode -executeMethod BuildDemoContent.Run -quit
    public static void Run()
    {
        if (RTSDemoContent.IsCreated) return;               // nothing to do
        Debug.Log(RTSDemoContent.CreateAllNonInteractive()); // logs where the content was written
    }
}

Scènes de démo

Le générateur crée trois scènes dans Samples/Scenes. Toutes contiennent un objet Sun, un volume Post Processing, un RTS Terrain (avec les composants de végétation, d’eau, de décor et d’environnement) et une caméra Main Camera qui active la texture de profondeur et la texture opaque dont elle a besoin pour l’eau.

ScèneCarteContenu
RTS Terrain Studio - Gameplay DemoTwo Rivers (1v1)Caméra RTS, brouillard de guerre et RTSDemoGame avec Auto Start. Appuyez sur Play et la partie démarre.
RTS Terrain Studio - In-Game Editor DemoSandboxL’éditeur en jeu. Le brouillard de guerre et la caméra RTS restent désactivés pendant l’édition ; les unités apparaissent quand vous lancez un test en jeu.
RTS Terrain Studio - Editor PlaygroundFour Kingdoms (4p)Pas de gameplay. Une grande carte pour essayer les outils de l’éditeur Unity.

Gameplay Demo : à essayer

  1. Appuyez sur Play. Vos unités (joueur 1) se tiennent sur la place de votre position de départ ; le reste de la carte est noir.
  2. Sélectionnez quelques unités avec un rectangle de sélection et cliquez avec le bouton droit de l’autre côté de la rivière. Observez-les trouver un gué dans l’eau peu profonde et traverser en formation.
  3. Approchez-vous d’une falaise. Remarquez que les unités en contrebas ne voient pas le plateau au-dessus, et qu’une forêt cache ce qui se trouve derrière elle. Montez ensuite une rampe et regardez en contrebas.
  4. Éloignez-vous d’une zone : elle reste assombrie (explorée) au lieu d’être noire. Les unités ennemies qui y errent disparaissent quand vous les perdez de vue.
  5. Appuyez sur B et placez un bâtiment sur le chemin d’unités en mouvement. Elles le contournent. Appuyez sur Delete en le survolant pour le supprimer.
  6. Survolez un arbre et appuyez sur T, ou sélectionnez des ouvriers et cliquez avec le bouton droit sur un arbre. La trouée dans la forêt devient praticable et vous pouvez voir à travers.
  7. Mémorisez un groupe avec Ctrl+1, faites défiler la vue ailleurs et appuyez deux fois sur 1 pour y revenir. Utilisez la mini-carte pour déplacer la caméra et envoyer des unités.
  8. Quittez le Play Mode, sélectionnez l’objet Fog of War et essayez d’autres modes Line Of Sight, ou modifiez le paramètre Local Team du composant RTS Demo Game pour incarner un autre joueur.

In-Game Editor Demo : à essayer

  1. Appuyez sur Play. L’éditeur en jeu s’ouvre sur la carte Sandbox ; toute la carte est visible.
  2. Modifiez la carte : surélevez un plateau, peignez le sol, plantez une forêt, placez des positions de départ avec les outils de marqueurs.
  3. Cliquez sur Play Test (F5). RTSDemoGame fait apparaître des unités aux positions de départ et active le brouillard de guerre et la caméra RTS. Vos modifications sont prises en compte immédiatement : les falaises bloquent la vue et les forêts barrent le passage.
  4. Appuyez sur Esc (après avoir annulé tout mode en cours et vidé la sélection) ou sur F5, ou cliquez sur Back to Editor (Esc or F5). Les unités disparaissent et la carte retrouve l’état qu’elle avait avant le test en jeu.

Editor Playground : à essayer

  1. Ouvrez la scène et la fenêtre RTS Terrain Studio (Tools ▸ RTS Terrain Studio ▸ Editor Window).
  2. Sélectionnez le RTS Terrain et essayez les outils sur la carte Four Kingdoms : falaises, rampes, peinture, végétation et décor.
  3. Appuyez sur P dans la Scene View pour faire défiler les superpositions de cheminement et voir comment les falaises, les pentes, l’eau, les arbres et le sol Blight influent sur la praticabilité et la constructibilité.
  4. Envie d’y jouer ? Ajoutez GameObject ▸ RTS Terrain Studio ▸ Demo Game et appuyez sur Play : des unités apparaissent aux positions de départ des quatre joueurs.

Les intégrations ont leurs propres scènes de démo, créées à la demande : Tools ▸ RTS Terrain Studio ▸ Integrations ▸ Mirror ▸ Create Demo Scene, Tools ▸ RTS Terrain Studio ▸ Integrations ▸ A* Pathfinding ▸ Create Demo Scene et Tools ▸ RTS Terrain Studio ▸ Integrations ▸ Unity NavMesh ▸ Create Demo Scene. Elles nécessitent le contenu de démo et le package tiers correspondant.

La démo s’affiche mal ou sans textures ? Lancez Tools ▸ RTS Terrain Studio ▸ Validate Project et appliquez les corrections proposées (URP Asset, renderer feature, textures de la caméra). S’il manque une scène de démo, relancez le générateur : il reconstruit les scènes manquantes et ne touche pas à vos propres scènes.

Génération de cartes et outils de carte

L’onglet Map de la fenêtre RTS Terrain Studio (Tools ▸ RTS Terrain Studio ▸ Editor Window, dernier onglet avant Settings) regroupe les panneaux qui agissent sur la carte entière : Map, New Map, Resize, Generator, Heightmap, Minimap, Validation et Environment. Ce chapitre présente le générateur procédural, l’import et l’export de heightmaps, le précalcul de la mini-carte et le validateur de cartes. Chacun d’eux peut aussi être utilisé depuis votre propre code ; les exemples compilent avec le package tel qu’il est livré.

Tous les panneaux agissent sur le terrain sélectionné dans l’en-tête de la fenêtre. Si un bouton vous demande « Select this terrain in the window header first », choisissez le terrain dans le champ de terrain de l’en-tête (sélectionner un terrain dans la scène le choisit également).

Générateur de cartes

Le générateur (RTSMapGenerator) crée un agencement complet de RTS classique à partir d’une graine : des plateaux séparés par des falaises nettes, des rampes entre eux, des lacs ou des îles, une bordure facultative, la peinture du sol, de l’herbe et des forêts, des décors et les positions de départ des joueurs. Il travaille sur la carte existante et conserve sa taille. La même graine, avec les mêmes paramètres et la même taille de carte, produit toujours la même carte : vous pouvez donc partager une graine au lieu d’un fichier.

La génération remplace toujours les hauteurs, les niveaux de falaise, les rampes, les types de falaise, l’eau et toutes les surcharges de cheminement (seule la bordure est repeinte ensuite : les surcharges peintes sont donc effacées même lorsque Border est réglé sur None). La peinture du sol, les couches de détails, les arbres, les décors et les positions de départ ne sont remplacés que si leur option est active : Paint Mode n’est pas réglé sur KeepExisting ; l’option Enabled de Vegetation ou de Decor est activée, le terrain possède une bibliothèque de végétation ou de décors, et Clear Existing est activé ; l’option Enabled de Start Locations est activée (Max Players est mis à jour si Update Max Players est activé). Sinon, le contenu existant est conservé et, si Clear Existing est désactivé, les nouveaux arbres et décors s’ajoutent à ceux qui existent déjà. Les régions, les marqueurs et les paramètres d’environnement ne sont jamais modifiés. L’exécution complète constitue une seule étape d’annulation : vous pouvez donc expérimenter sans risque.

Votre première carte générée (éditeur Unity)

  1. Si votre projet n’a pas encore de tileset ni de bibliothèques, lancez une fois Tools ▸ RTS Terrain Studio ▸ Create Demo Content. Le générateur peint avec le tileset et place les plantes et les décors issus des bibliothèques du terrain ; sans bibliothèques, il ignore la végétation et les décors.
  2. Sélectionnez votre RTS Terrain (ou créez-en un avec GameObject ▸ RTS Terrain Studio ▸ RTS Terrain) et ouvrez Tools ▸ RTS Terrain Studio ▸ Editor Window.
  3. Cliquez sur l’onglet Map et dépliez le panneau Generator.
  4. Choisissez un style dans Style (par exemple Highlands) et cliquez sur Apply Style Preset. Cela charge les valeurs de bruit, de falaises, de rampes et d’eau qui donnent au style son aspect.
  5. Choisissez une symétrie dans Symmetry : Rotate2 pour une carte 1v1 équitable, Rotate4 pour 4 joueurs sur une carte carrée.
  6. Ouvrez Start Locations et réglez Count sur le nombre de joueurs.
  7. Cliquez sur Randomize Seed, puis sur Generate, et confirmez la boîte de dialogue.
  8. Lisez le rapport sous les boutons : nombre de niveaux de plateau, de rampes, de positions de départ, d’arbres, de décors et durée de la génération. Les avertissements (par exemple only 3 of 4 start locations found) y sont listés, ainsi que dans la fenêtre Console.
  9. Le résultat ne vous plaît pas ? Appuyez sur Ctrl+Z, cliquez sur Randomize Seed et relancez la génération. Quand le résultat vous plaît, enregistrez la carte (Save dans l’en-tête de la fenêtre ou dans l’Inspector du RTS Terrain).
Les cartes générées sont un point de départ. Utilisez ensuite les outils habituels : déplacez une rampe, creusez un lac supplémentaire, peignez un chemin, placez quelques doodads choisis à la main. Grâce à la peinture symétrique du panneau Brush, vos retouches restent elles aussi équitables.

Les autres boutons du panneau :

BoutonRôle
Randomize SeedChoisit une nouvelle graine aléatoire. Tous les autres paramètres restent tels quels.
Apply Style PresetCharge les valeurs de bruit, de falaises, de rampes et d’eau du style sélectionné. Les paramètres de graine, de symétrie, de bordure, de peinture, de végétation, de décor et de positions de départ sont conservés.
ResetRéinitialise tous les paramètres du générateur aux valeurs par défaut du style sélectionné.
GenerateDemande une confirmation et génère la carte en une seule étape d’annulation nommée Generate Map.

Les paramètres du générateur dans la fenêtre sont enregistrés dans les préférences de l’éditeur : ils sont donc conservés après un redémarrage de Unity.

Générer une toute nouvelle carte (New Map Wizard)

Tools ▸ RTS Terrain Studio ▸ New Map Wizard... crée un nouveau fichier de carte. À l’étape Terrain, choisissez Generate au lieu de Flat, sélectionnez un préréglage dans Preset (les six styles, plus chaque asset RTSMapGeneratorPreset de votre projet, listé sous la forme Preset: name), une graine et une symétrie, puis cliquez sur Preview pour voir la mini-carte du résultat avant tout enregistrement. L’assistant reprend le nombre de joueurs de son propre paramètre de joueurs et le reporte dans les positions de départ.

Générer dans l’éditeur en jeu

Les joueurs peuvent aussi générer des cartes dans un jeu publié. Dans l’éditeur en jeu, ouvrez Map ▸ Generate... dans la barre d’outils. La boîte de dialogue propose un ensemble d’options simplifié :

OptionCorrespond à
StyleApplique le préréglage de style (réinitialise les options de forme situées en dessous).
Seed / Randomseed
Symmetrysymmetry
Terrain : Cliffs, Plateaus, Ramps, Ramp Count, Water, Lake Coverage, Island, Bordercliffs.enabled, cliffs.plateauCount, ramps.enabled, ramps.count, water.enabled, water.lakeCoverage, water.islandMode, border.mode
Content : Textures, Vegetation, Forests, Decor, Decor Count, Start Locations, Playerspaint.mode, vegetation.enabled, vegetation.forestCoverage, decor.enabled, decor.count, startLocations.enabled, startLocations.count

Appuyez sur Enter (ou cliquez sur Generate) pour générer, et sur Esc pour annuler. Le résultat constitue une seule étape d’annulation (Ctrl+Z), et la boîte de dialogue mémorise ses paramètres jusqu’à la fermeture du jeu.

Préréglages de style

Un style (TerrainStylePreset) modifie la forme du champ de hauteur de base et charge les valeurs par défaut correspondantes via MapGeneratorSettings.ApplyPreset.

StyleAspectNiveaux / plateauxRampesCouverture en lacs
PlainsTerrain en grande partie plat avec quelques plateaux bas. Une carte classique de mêlée ouverte.2–3 / 230.05
Hills (par défaut)Collines ondulées (hauteur fine prononcée) avec quelques plateaux et rampes. Un bon point de départ polyvalent.2–3 / 240.06
HighlandsDe nombreux plateaux et falaises étagés, reliés par des rampes.2–6 / 580.04
IslandsMasses de terre entourées d’eau (mode île, eau plus profonde, rivages plus larges).2–4 / 350.38
CanyonBruit à crêtes transformé en canyons sinueux entre de hauts plateaux.2–5 / 360.03
ArenaUne arène centrale basse entourée d’un anneau de hauteurs.2–4 / 360.03

Enregistrer vos propres préréglages

Vous avez trouvé des paramètres qui vous plaisent ? Enregistrez-les sous forme d’asset : Assets ▸ Create ▸ RTS Terrain Studio ▸ Map Generator Preset crée un RTSMapGeneratorPreset avec un champ Description et une section Settings complète (initialisée avec les valeurs du style Hills). Le New Map Wizard liste tous les assets de préréglage du projet, et votre code peut transmettre preset.settings au générateur (voir Générer par le code). Les préréglages sont des assets ordinaires : ils peuvent donc être livrés avec votre jeu, par exemple sous forme de choix « Canyon 2 joueurs » ou « Îles 4 joueurs » dans un menu d’escarmouche.

Symétrie : des cartes équitables pour le jeu compétitif

Avec la symétrie, le générateur crée un seul secteur de la carte et le copie : chaque joueur obtient ainsi le même terrain, les mêmes rampes, la même quantité d’arbres et de décors et une position de départ équivalente. Dans les copies en miroir, les décors inclinés penchent eux aussi en miroir.

SymétrieCopiesUsage typiqueCarte carrée requise
None1Cartes de campagne ou de forme libre.Non
MirrorX2Miroir gauche ↔ droite (2 joueurs face à face horizontalement).Non
MirrorZ2Miroir haut ↔ bas.Non
MirrorXZ4Miroir sur les deux axes (4 coins).Non
Rotate2 (par défaut)2Symétrie centrale à 180°, l’agencement classique en 1v1.Non
Rotate44Symétrie de rotation à 90°, l’agencement classique à 4 joueurs.Oui (sinon repli sur Rotate2)
MirrorDiagonal2Miroir selon la diagonale (x ↔ z).Oui (sinon repli sur MirrorX)
Utilisez un nombre de positions de départ multiple du nombre de copies (2, 4, 6… pour Rotate2). Sinon, le générateur signale que l’agencement ne peut pas être équitable. MapGenerationReport.symmetryUsed indique la symétrie réellement utilisée.

Référence des paramètres du générateur (MapGeneratorSettings)

Le panneau du générateur affiche tous les champs de MapGeneratorSettings, regroupés en sections repliables. La colonne Par défaut indique les valeurs de new MapGeneratorSettings(), qui correspondent au style Hills ; les groupes Noise, Cliffs, Ramps et Water changent selon le style sélectionné. Avant la génération, Validate() ramène dans la plage autorisée toutes les valeurs qui en sortent.

General

ParamètrePar défautDescription
Seed (seed)12345Graine aléatoire. Avec la même graine et les mêmes paramètres, vous obtenez toujours la même carte.
Style (style)HillsForme du terrain. Cliquez sur Apply Style Preset (ou appelez ApplyPreset) pour charger les valeurs par défaut correspondantes.
Symmetry (symmetry)Rotate2Génère un seul secteur et le copie pour que la carte soit équitable (voir Symétrie).

Noise (noise, GeneratorNoiseSettings)

ParamètrePar défautDescription
Scale85 mTaille des grandes formes du terrain, en mètres. Des valeurs plus élevées donnent des plateaux plus grands.
Octaves4Nombre de couches de bruit (1–8). Davantage d’octaves ajoutent des détails plus fins aux contours.
Persistence0.5Multiplicateur d’amplitude par octave (0.5 = chaque octave est deux fois moins forte que la précédente).
Lacunarity2Multiplicateur de fréquence par octave.
Ridged Amount0Mélange progressif vers un bruit à crêtes (crêtes vives et canyons). Le style Canyon utilise 1.
Warp0.4Intensité de la déformation de domaine (domain warp). Donne aux contours des formes plus naturelles et plus fluides.
Contrast1Des valeurs plus élevées repoussent une plus grande partie de la surface vers les plateaux les plus bas et les plus hauts.
Smoothing2Passes de flou appliquées avant la conversion du champ en niveaux de falaise (supprime les minuscules formes parasites dues au bruit).
Fine Height Amplitude1.6 mAmplitude du bruit de hauteur fine (collines au sommet des plateaux).
Fine Height Scale22 mTaille des formes du bruit de hauteur fine.
Fine Height Octaves3Nombre d’octaves du bruit de hauteur fine.
Cliff Edge Fade4 cellulesDistance sur laquelle la hauteur fine s’estompe à l’approche des bords de falaise, pour que le sommet des falaises reste net.

Cliffs (cliffs, GeneratorCliffSettings)

ParamètrePar défautDescription
EnabledActivéGénère des niveaux de falaise. Si ce paramètre est désactivé, toute la carte utilise Min Level et seules les hauteurs fines varient.
Min Level2Niveau de falaise du plateau le plus bas (0–15). Le niveau 2 laisse de la place pour creuser des lacs en dessous.
Max Level3Niveau de falaise du plateau le plus haut.
Plateau Count2Nombre de niveaux de plateau distincts entre Min Level et Max Level.
Hysteresis0.04Bande autour de chaque seuil de niveau (fraction de la plage de hauteurs). Les vertices situés dans cette bande prennent le niveau de leurs voisins, ce qui assure des lignes de falaise régulières.
Min Feature Width8 cellulesLargeur minimale de chaque plateau, terrasse, vallée et lac. Les parties plus étroites (fines terrasses entre deux falaises, crêtes, tranchées, plateaux minuscules) rejoignent le niveau voisin, et chaque plateau garde, jusqu’à la falaise située en dessous, une marge d’environ trois quarts de cette largeur. Les lacs peuvent être d’un quart plus étroits. Les préréglages utilisent 6–10.
Cleanup Passes2Passes qui suppriment les vertices isolés et les pics.
Cliff Type0Type de falaise (calque de falaise 0–3 du tileset) attribué à tous les vertices.

Ramps (ramps, GeneratorRampSettings)

ParamètrePar défautDescription
EnabledActivéPlace des rampes entre les plateaux adjacents.
Count4Nombre de rampes dans le secteur généré (les copies symétriques en ajoutent d’autres).
Width3 cellulesLargeur d’une rampe le long de la falaise.
Length2 cellulesLongueur d’une rampe par niveau de falaise, perpendiculairement à la falaise. Une valeur de 2 donne une pente douce.
Ensure ConnectivityActivéAjoute des rampes supplémentaires si nécessaire, pour que chaque plateau soit accessible depuis tous les autres.
Min Spacing12 cellulesDistance minimale entre deux rampes. Une rampe qui en chevaucherait une autre n’est pas placée.
Min Plateau Size40La passe de connectivité ignore les plateaux qui comptent moins de vertices.

Water (water, GeneratorWaterSettings)

ParamètrePar défautDescription
EnabledActivéGénère des lacs ou une mer, ainsi que leurs surfaces d’eau.
Sea Level Offset−0.25Surface de l’eau, en niveaux de falaise, par rapport au plateau le plus bas (−0.9 à 2). Les valeurs négatives gardent le plateau le plus bas au sec ; les valeurs positives l’inondent.
Lake Coverage0.06Fraction de la carte (les zones les plus basses) transformée en lacs ou en mer (0–0.7).
Max Depth2.5 mPoint le plus profond des lacs sous la surface de l’eau.
Shore Width4 cellulesLargeur du rivage en pente, de la ligne de rivage jusqu’à la profondeur maximale.
Island ModeDésactivéAbaisse le terrain vers les bords de la carte, pour qu’elle devienne une ou plusieurs îles. Les cartes insulaires comptent toujours au moins 15 % de mer (le rapport affiche un avertissement quand la couverture a été relevée).
Border Falloff0.25Mode île : largeur de l’atténuation vers le bord, en fraction de la taille de la carte.

Border (border, GeneratorBorderSettings)

ParamètrePar défautDescription
ModeNoneNone : aucune bordure particulière. Unwalkable : peint le long du bord des surcharges de cheminement non praticables et non constructibles. HighCliffs : élève un anneau de hautes falaises le long du bord (également non praticable).
Width2 cellulesLargeur de la bordure.
Cliff Level0Niveau de falaise de la bordure HighCliffs. 0 = automatique (deux niveaux au-dessus du plateau le plus haut).

Paint (paint, GeneratorPaintSettings)

ParamètrePar défautDescription
ModeAutoPaintKeepExisting : laisse la peinture du sol intacte. FillBaseLayer : remplit toute la carte avec le calque défini par Base Layer. AutoPaint : peint selon la hauteur, la pente, le niveau de falaise et l’eau à l’aide d’un profil Auto Paint.
ProfileaucunUn RTSAutoPaintProfile (Assets ▸ Create ▸ RTS Terrain Studio ▸ Auto Paint Profile). Vide = règles par défaut intégrées, associées d’après les noms des calques du tileset.
Base Layer0Calque de sol utilisé par FillBaseLayer.

Vegetation (vegetation, GeneratorVegetationSettings)

ParamètrePar défautDescription
EnabledActivéGénère des couches de détails et des forêts (nécessite une bibliothèque de végétation sur le terrain).
Use Whole Library When EmptyActivéSi les listes ci-dessous sont vides, tous les prototypes de la bibliothèque de végétation sont utilisés.
Clear ExistingActivéSupprime les couches de détails et les arbres existants avant la génération.
DetailsvideCouches de détails (herbe) à générer, voir le tableau suivant.
Tree Prototype IdsvideIds des prototypes d’arbres utilisés pour les forêts.
Forest Coverage0.22Fraction du sol propice couverte de forêts.
Forest Noise Scale55 mTaille des formes du bruit de forêt.
Tree Spacing2.6 mDistance entre les arbres.
Tree Density0.85Probabilité qu’un emplacement libre dans une forêt reçoive un arbre (des valeurs plus basses donnent des forêts clairsemées).
Max Tree Slope26°Aucun arbre sur les pentes plus raides.
Start Location Clearance14 mDistance autour des positions de départ à l’intérieur de laquelle aucun arbre ni détail n’est placé.

Chaque entrée de Details (GeneratorDetailEntry) :

ParamètrePar défautDescription
Prototype Id""Id du prototype de détail dans la bibliothèque de végétation.
Density0.6Densité dans les zones couvertes (1 = densité maximale du prototype).
Coverage0.55Fraction du sol propice qui est couverte.
Noise Scale28 mTaille des formes du bruit de couverture.
Max Slope32°Aucun détail sur les pentes plus raides.

Decor (decor, GeneratorDecorSettings)

ParamètrePar défautDescription
EnabledActivéDisperse des décors (nécessite une bibliothèque de décors sur le terrain).
Use Whole Library When EmptyActivéSi la liste ci-dessous est vide, tous les prototypes de la bibliothèque de décors sont utilisés.
Clear ExistingActivéSupprime les décors existants avant la génération.
Prototype IdsvideIds des prototypes de décor à disperser.
Count60Nombre d’objets de décor dans le secteur généré (les copies symétriques en ajoutent d’autres).
Min Spacing3 mDistance minimale entre les objets de décor (l’espacement propre au prototype s’applique s’il est plus grand).
Max Slope30°Aucun décor sur les pentes plus raides.
Start Location Clearance12 mDistance autour des positions de départ à l’intérieur de laquelle aucun décor n’est placé.

Les décors générés respectent les paramètres de chaque prototype de décor : lacet aléatoire et pas de lacet, plage d’échelle, teintes, variantes, alignement sur la normale et inclinaison aléatoire maximale.

Start Locations (startLocations, GeneratorStartLocationSettings)

ParamètrePar défautDescription
EnabledActivéPlace les positions de départ. Si ce paramètre est désactivé, les positions de départ existantes sont conservées.
Count2Nombre de positions de départ (1–16).
Flat Radius5 cellulesRayon qui doit rester plat autour d’une position de départ (un seul niveau, sans falaises, rampes ni eau).
Edge Margin8 cellulesDistance minimale au bord de la carte.
Update Max PlayersActivéÉcrit la valeur de Count dans le champ Max Players de la carte (MapInfo.maxPlayers).
Si la carte manque d’espace plat, le générateur place autant de positions de départ que possible et signale « Only N of M ». Réduisez Flat Radius ou Edge Margin, utilisez moins de plateaux ou agrandissez la carte.

Générer par le code

Trois points d’entrée couvrent toutes les situations :

MéthodeÀ utiliser pour
RTSMapGenerator.Generate(RTSTerrain, MapGeneratorSettings, RTSToolContext ctx = null)Code de jeu. Génère dans la carte du terrain, rafraîchit le terrain et écrit les avertissements dans le journal. L’opération n’est annulable que si vous passez le ctx d’un appel à RTSEditSession.RunOperation.
RTSMapGenerator.Generate(RTSEditSession, MapGeneratorSettings)Outils d’éditeur et extensions de l’éditeur en jeu : une seule étape d’annulation, nommée Generate Map.
RTSMapGenerator.GenerateInto(MapData, settings, tileset, vegetation, decor)Génération dans un MapData qui n’est pas affiché (aperçus, génération par lots, tests). Aucune notification et aucune annulation. Renvoie un MapGenerationReport.
using RTSTerrainStudio;
using UnityEngine;

// Generating maps from game code, e.g. for a "Random map" button in a skirmish menu.
public class GeneratorExample : MonoBehaviour
{
    [SerializeField] RTSTerrain terrain;
    [SerializeField] RTSMapGeneratorPreset preset;   // optional: settings saved as an asset

    // Generates a random 4-player layout into the current map (the map size is kept). No undo.
    public void GenerateRandomMap(int seed)
    {
        // Start from a saved preset or from a style preset, then change what you need.
        MapGeneratorSettings settings = preset != null
            ? preset.settings.Clone()                                  // never modify the asset itself
            : MapGeneratorSettings.CreatePreset(TerrainStylePreset.Highlands);
        settings.seed = seed;                       // same seed + settings + map size = same map
        settings.symmetry = SymmetryMode.Rotate4;   // needs a square map, otherwise Rotate2 is used
        settings.startLocations.count = 4;          // a multiple of the symmetry copies is fairest
        settings.water.lakeCoverage = 0.1f;
        settings.Validate();                        // clamps every value into its valid range

        RTSMapGenerator.Generate(terrain, settings);   // generates, refreshes the terrain, logs warnings
    }

    // Generates a map in memory without showing it (previews, batch generation, tests).
    public static MapData GenerateOffscreen(RTSTerrain template, int seed)
    {
        MapCreationSettings creation = MapCreationSettings.Default;   // 128 x 128 cells of 2 m
        creation.width = 192;
        creation.height = 192;
        MapData map = MapData.Create(creation);

        MapGeneratorSettings settings = MapGeneratorSettings.CreatePreset(TerrainStylePreset.Islands);
        settings.seed = seed;
        // Pass the tileset and libraries so painting, vegetation and decor can be generated.
        MapGenerationReport report = RTSMapGenerator.GenerateInto(map, settings,
            template.Tileset, template.VegetationLibrary, template.DecorLibrary);
        foreach (string warning in report.warnings) Debug.LogWarning(warning);
        Debug.Log(report);   // plateaus, ramps, start locations, trees, decor and time

        // You own the map: Dispose() it, or give it to a terrain with terrain.SetMap(map).
        return map;
    }
}

MapGenerationReport contient symmetryUsed, plateauLevels, ramps, startLocations, detailLayers, trees, decor, milliseconds et la liste warnings ; ToString() en donne un résumé sur une ligne. RTSMapGenerator.GeneratedLayers liste tous les indicateurs MapLayers que le générateur écrit : c’est ce que vous passez à RunOperation lorsque vous encapsulez vous-même GenerateInto.

Import et export de heightmaps

Le panneau Heightmap de l’onglet Map importe et exporte la hauteur du terrain au format PNG 16-bit ou RAW 16-bit. Servez-vous-en pour importer un terrain depuis World Machine, Gaea, Photoshop ou des données d’altitude réelles, ou pour envoyer la carte vers un tel outil puis la récupérer.

Correspondance entre heightmap et terrain

  • Une heightmap couvre la grille de vertices : une carte de 256 × 256 cellules compte 257 × 257 vertices, la heightmap idéale fait donc 257 × 257 pixels. Les images de toute autre taille sont rééchantillonnées de façon bilinéaire.
  • Les valeurs des pixels sont converties selon height = offset + value / 65535 × scale. Les images 8-bit sont acceptées aussi ; elles ont simplement moins de paliers.
  • La valeur par défaut de Height Scale couvre les 16 niveaux de falaise : 16 × Cliff Level Height (32 m pour les niveaux de 2 m par défaut). HeightmapIO.DefaultHeightScale(map) renvoie cette valeur.
  • La ligne 0 d’un fichier RAW et la ligne du bas d’un PNG correspondent à Z = 0 (la première rangée de vertices). Si votre carte apparaît en miroir, activez Flip Vertically.
  • Chaque import constitue une seule étape d’annulation, nommée Import Heightmap.

Importer

  1. Ouvrez l’onglet Map et dépliez le panneau Heightmap.
  2. Choisissez le Mode d’import (voir le tableau ci-dessous). Pour une heightmap externe classique, utilisez Cliff Levels And Fine Heights ; pour ajouter des collines sur des plateaux existants, utilisez Fine Heights Only.
  3. Laissez Height Scale sur 0 (automatique), sauf si vous savez combien de mètres votre image représente.
  4. Cliquez sur Import PNG… (PNG, JPG ou EXR ; niveaux de gris 8-bit ou 16-bit, seul le canal rouge est utilisé) ou sur Import RAW… (.raw / .r16, 16-bit).
  5. Vérifiez le résultat. Appuyez sur Ctrl+Z pour annuler et essayer un autre mode ou une autre échelle.
Mode d’importDonnées écritesDescription
Fine Heights OnlyHauteursUniquement la hauteur fine (hauteur fine = valeur × échelle + décalage). Les niveaux de falaise sont conservés et leur hauteur s’ajoute par-dessus : l’image ajoute donc des collines aux plateaux existants.
Cliff Levels And Fine HeightsHauteurs, niveaux de falaiseL’image représente la hauteur absolue du sol. Elle est répartie entre niveaux de falaise (arrondis au niveau le plus proche, vertices isolés nettoyés) et hauteurs fines, si bien que la hauteur du sol correspond exactement à l’image. Idéal pour les heightmaps en terrasses ; les pentes douces qui franchissent un niveau deviennent de petites falaises.
Absolute Heights Keep LevelsHauteursL’image représente la hauteur absolue du sol, mais les niveaux de falaise existants sont conservés (hauteur fine = hauteur − niveau × hauteur de niveau). Utilisez ce mode pour réimporter un export Ground Height que vous avez modifié dans un outil externe, sans changer les falaises.
Paramètre d’importPar défautDescription
Modevoir ci-dessusManière dont l’image est convertie en niveaux et en hauteurs.
Height Scale0 (automatique)Nombre de mètres représentés par toute la plage 16-bit. 0 = 16 × hauteur de niveau.
Height Offset0Mètres ajoutés à chaque hauteur importée.
Flip VerticallyDésactivéRetourne l’image selon l’axe Z (à utiliser quand la carte apparaît en miroir).
RAW Width / RAW Height0Nombre d’échantillons par ligne et nombre de lignes des fichiers RAW. 0 = déduit de la taille du fichier (fichiers carrés uniquement).
RAW Little EndianActivéOrdre des octets des fichiers RAW. Windows et la plupart des outils écrivent en little endian.
Pour un résultat aussi propre que possible, exportez votre heightmap depuis l’outil externe avec exactement cellules + 1 pixels par côté, et formez-y des terrasses espacées de la hauteur d’un niveau de falaise. Lissez les irrégularités restantes avec l’outil Smooth, et ajoutez des rampes là où les unités doivent pouvoir monter.

Exporter

Paramètre d’export / boutonPar défautDescription
SourceGround HeightGround Height : niveaux de falaise plus hauteur fine (valeur absolue). Fine Heights : uniquement la hauteur fine au-dessus des niveaux.
Height Scale0 (automatique)Nombre de mètres représentés par 65535.
Height Offset0Hauteur enregistrée avec la valeur 0.
RAW Little EndianActivéOrdre des octets des fichiers RAW exportés.
Export PNG…PNG 16-bit en niveaux de gris.
Export RAW…Fichier RAW 16-bit.
Export Splat PNG…Image de la peinture du sol (couleurs du calque dominant), pour la documentation ou des outils externes.

Aller-retour : exportez avec Ground Height, modifiez l’image dans un outil externe, puis réimportez-la avec Absolute Heights Keep Levels en gardant la même échelle et le même décalage.

Heightmaps par le code

HeightmapIO propose ImportPng, ImportRaw16 et ImportHeights (valeurs normalisées float[] ou NativeArray<float>, issues par exemple de votre propre bruit) pour les terrains, ApplyHeights pour un simple MapData, ExportPng16, ExportRaw16 et ExportSplatPng (modes DominantLayerColor et SplatWeights), ainsi que TryGuessRawSize et GetImportLayers(mode) pour enregistrer l’annulation. Chaque méthode d’export dispose d’une surcharge byte[] et d’une surcharge avec chemin de fichier.

using RTSTerrainStudio;
using UnityEngine;

// Heightmap import and export from code.
public static class HeightmapExample
{
    public static bool Import(RTSTerrain terrain, string pngPath)
    {
        // Imports need a height scale > 0. DefaultHeightScale = 16 cliff levels (all levels + headroom).
        float scale = HeightmapIO.DefaultHeightScale(terrain.Map);
        var options = new HeightmapImportOptions { heightOffset = 0f, flipZ = false };

        // The image is resampled to the vertex grid (cells + 1 per side) and the terrain is refreshed.
        // Pass an RTSToolContext (inside RTSEditSession.RunOperation) as the 5th argument to make it undoable.
        return HeightmapIO.ImportPng(terrain, pngPath, HeightmapImportMode.CliffLevelsAndFineHeights, scale,
            null, options);
    }

    public static bool Export(RTSTerrain terrain, string pngPath)
    {
        // 16-bit grayscale PNG of the absolute ground height. Scale 0 = DefaultHeightScale.
        return HeightmapIO.ExportPng16(terrain.Map, pngPath, 0f, 0f, HeightmapExportSource.GroundHeight);
    }
}
Contrairement à la fenêtre, les méthodes d’import utilisent telle quelle la valeur heightScale que vous leur passez. Passez toujours une valeur supérieure à 0, par exemple HeightmapIO.DefaultHeightScale(map). Pour les exports, 0 signifie automatique.

Précalcul de la mini-carte

RTSMinimapBaker produit une image de la carte vue de dessus : couleurs du sol, ombrage du relief, falaises, eau colorée selon la profondeur, arbres, décors, positions de départ et régions. Ce même outil de précalcul sert partout dans le package :

  • le panneau Minimap de l’onglet Map (aperçu et export PNG),
  • l’aperçu des assets .rtsmap dans la fenêtre Project et dans l’Inspector, ainsi que l’aperçu du New Map Wizard,
  • l’explorateur de cartes de l’éditeur en jeu (une petite image d’aperçu est enregistrée à côté de chaque carte, selon l’option Write Preview Images de RTSRuntimeEditor),
  • l’exemple RTSMinimapUI (mini-carte en jeu avec brouillard de guerre, points pour les unités, contour de la caméra, clic pour déplacer la caméra et clic droit pour déplacer les unités). Il relance automatiquement le précalcul quand la carte change, avec une fréquence limitée.

Précalcul dans l’éditeur

  1. Ouvrez l’onglet Map et dépliez le panneau Minimap.
  2. Choisissez une valeur pour Size (128, 256, 512 ou 1024 px pour le côté le plus long ; les cartes non carrées conservent leurs proportions).
  3. Ajustez les Bake Options si vous le souhaitez (voir le tableau ci-dessous).
  4. Cliquez sur Bake Preview pour afficher le résultat dans le panneau, ou sur Save PNG… pour l’enregistrer dans un fichier, par exemple pour un écran de chargement ou un menu de sélection de carte.

Options de précalcul (MinimapBakeOptions)

ParamètrePar défautDescription
Ground ModeBlendedLayersBlendedLayers mélange les couleurs de tous les calques peints ; DominantLayer utilise le calque le plus fort de chaque pixel (rendu plus net, dans le style des RTS classiques). Les couleurs des calques proviennent du tileset (sa couleur de mini-carte, ou la couleur moyenne de la texture du calque).
Level Brightness0.05Variation de luminosité par niveau de falaise, par rapport au niveau 2 (les plateaux plus hauts paraissent plus clairs).
Hill Shading / StrengthActivé / 1Assombrit les pentes orientées à l’opposé de la lumière.
Light Direction(−0.55, 0.75, 0.45)Direction vers la lumière dans l’espace local de la carte (x = est, y = haut, z = nord).
Use Map Sun DirectionDésactivéUtilise la direction du soleil définie dans l’environnement de la carte au lieu de Light Direction.
Draw Cliffs / Cliff Color / Cliff OpacityActivé / noir / 0.8Colore les cellules de falaise. Noir = utiliser la couleur de falaise du tileset.
Draw WaterActivéEau colorée selon la profondeur (profil d’eau du tileset).
Draw Trees / Tree Color / Tree Dot SizeActivé / vert foncé / 0.75 pxArbres représentés par des points (les valeurs inférieures à 1 dessinent des pixels isolés).
Draw Decor / Decor Color / Decor Dot SizeDésactivé / marron / 0.75 pxObjets de décor représentés par des points.
Draw Start Locations / Start Location SizeActivé / 4 pxMarqueurs aux couleurs des joueurs.
Scale MarkersActivéAdapte la taille des marqueurs à la taille de la texture (taille de référence 256).
Player Colors16 couleurs de joueur classiques des RTSCouleur par index de joueur. Les entrées manquantes utilisent MinimapBakeOptions.DefaultPlayerColors.
Draw RegionsDésactivéDessine le contour des régions dans leur couleur de région.

Mini-cartes par le code

RTSMinimapBaker.Bake(terrain, size, options) renvoie une nouvelle Texture2D sRGB lisible (c’est à vous de la détruire). Update(existing, terrain, size, options) refait le précalcul dans une texture existante et n’en crée une nouvelle que si l’ancienne ne peut pas être réutilisée. BakePng(terrain, size) renvoie directement les octets PNG, et les surcharges MapData précalculent des cartes qui ne sont pas affichées.

using RTSTerrainStudio;
using UnityEngine;
using UnityEngine.UIElements;

// Keeps a minimap image up to date in a UI Toolkit Image named "minimap".
public class MinimapExample : MonoBehaviour
{
    [SerializeField] RTSTerrain terrain;
    [SerializeField] UIDocument document;
    [SerializeField] int size = 256;      // longer side in pixels
    Texture2D minimap;

    void OnEnable()
    {
        if (terrain == null) return;
        terrain.MapLoaded += OnMapUpdated;
        terrain.ChangesProcessed += OnChangesProcessed;
        if (terrain.Map != null) Refresh();
    }

    void OnDisable()
    {
        if (terrain == null) return;
        terrain.MapLoaded -= OnMapUpdated;
        terrain.ChangesProcessed -= OnChangesProcessed;
    }

    void OnMapUpdated(RTSTerrain t) => Refresh();
    // Called after every processed edit. While someone paints, throttle this (the RTSMinimapUI sample
    // waits a moment after the last change and limits the bakes per second).
    void OnChangesProcessed(RTSTerrain t, System.Collections.Generic.IReadOnlyList<DirtyRegion> regions) => Refresh();

    void Refresh()
    {
        var options = new MinimapBakeOptions { drawDecor = true, hillShadingStrength = 1.2f };
        // Update reuses the texture when it can. When it returns a new texture, destroy the old one.
        Texture2D result = RTSMinimapBaker.Update(minimap, terrain, size, options);
        if (minimap != null && result != minimap) Destroy(minimap);
        minimap = result;
        Image target = document != null ? document.rootVisualElement?.Q<Image>("minimap") : null;
        if (target != null) target.image = minimap;
    }

    void OnDestroy()
    {
        if (minimap != null) Destroy(minimap);
    }
}

Validation des cartes

Le validateur de cartes (MapValidator) recherche dans une carte les problèmes qui passent facilement inaperçus : textures manquantes, positions de départ inaccessibles, références d’objets cassées et limites de performances. Exécutez-le avant de publier une carte ou de la mettre à disposition des joueurs.

  1. Ouvrez l’onglet Map et dépliez le panneau Validation.
  2. Cliquez sur Validate Map. Le résumé indique le nombre d’erreurs, d’avertissements et d’informations, ou No problems found.
  3. Cliquez sur un problème pour afficher sa position dans la Scene View (pour les problèmes liés à un emplacement, comme une position de départ).
  4. Corrigez les problèmes et relancez la validation.
Les vérifications basées sur le cheminement (positions de départ praticables, accessibilité, bord de carte praticable) nécessitent la carte de cheminement du terrain. Sans elle, le validateur ajoute une information indiquant que ces vérifications ont été ignorées.
Il s’agit ici du validateur de carte. Le validateur de projet (Tools ▸ RTS Terrain Studio ▸ Validate Project) vérifie URP, les shaders, la gestion des entrées et les packages ; voir Configuration du projet.

Ce qui est vérifié

ZoneVérificationGravité
TilesetAucun tileset assigné (le terrain s’affiche avec des couleurs neutres de repli)Warning
Le tileset n’a aucun calque de solWarning
La carte ne stocke aucun id de tileset (il est défini automatiquement quand la carte est enregistrée avec un tileset)Info
La carte a été créée pour un autre tileset que celui qui est assignéWarning
GéométrieVertices dont la hauteur est invalide (NaN ou infini)Error
Des cellules de falaise utilisent un type de falaise que le tileset ne définit pasWarning
La carte contient des falaises, mais le tileset n’a aucun calque de falaiseWarning
Peinture du solTexels de splat dont la somme des poids n’est pas égale à 255 (peinture corrompue)Warning
Un calque de sol est peint alors que le tileset ne le fournit pasWarning
Un calque de sol peint n’a pas de texture d’albédoInfo
Positions de départLa carte n’a aucune position de départError
Moins de positions de départ que la valeur de Max PlayersWarning
Un joueur a plus d’une position de départWarning
Une position de départ se trouve hors de la carteError
Une position de départ se trouve sur un bord de falaiseWarning
Une position de départ est recouverte d’eau profonde / se trouve dans de l’eau peu profondeError / Info
Deux positions de départ sont très proches (à une distance inférieure à Min Start Distance Cells)Warning
Une position de départ n’est pas praticableError
AccessibilitéUn joueur ne peut pas rejoindre un autre joueur à pied (remplissage par diffusion sur la carte de cheminement, à partir du niveau de falaise de la position de départ elle-même)Error
Une grande partie du bord de la carte est praticable (envisagez une bordure impraticable)Info
Arbres, décors, détailsIl existe des arbres, des décors ou des couches de détails, mais aucune bibliothèque de végétation / de décors n’est assignéeWarning
Des objets référencent un index de prototype absent de la palette de la carteError
Des objets ou des couches de détails utilisent un prototype absent de la bibliothèqueWarning
Un prototype n’a pas de prefab (ses objets sont invisibles)Warning
Objets hors de la carte, ids d’instance en double ou compteur d’ids d’instance inférieur aux ids existantsWarning
RégionsUne région n’a pas de surface ; plusieurs régions portent le même nom (le code de jeu qui recherche les régions par leur nom risque de choisir la mauvaise)Info
PerformancesTrop d’arbres, d’objets de décor ou de couches de détailsWarning
Trop d’arbres ou d’objets de décor en mode d’apparition GameObjectWarning
Grande carte (consommation de mémoire et temps de construction)Info

Seuils (MapValidationSettings)

ParamètrePar défautDescription
maxTrees20000Nombre d’arbres au-delà duquel un avertissement de performances s’affiche.
maxGameObjectTrees1500Nombre d’arbres en mode d’apparition GameObject au-delà duquel un avertissement s’affiche.
maxDecor6000Nombre d’objets de décor au-delà duquel un avertissement s’affiche.
maxGameObjectDecor2000Nombre d’objets de décor en mode d’apparition GameObject au-delà duquel un avertissement s’affiche.
maxDetailLayers8Nombre de couches de détails au-delà duquel un avertissement s’affiche.
largeMapSize512Les cartes plus grandes que cette valeur (en cellules par côté) reçoivent une information sur la mémoire et les temps de construction.
minStartDistanceCells12Des positions de départ plus proches que cette distance déclenchent un avertissement.
walkableEdgeFraction0.1Proportion de cellules praticables sur l’anneau extérieur au-delà de laquelle l’information sur le bord praticable s’affiche.
checkReachabilitytrueVérifie que toutes les positions de départ peuvent s’atteindre mutuellement.

Valider par le code

MapValidator.Validate(terrain) renvoie une List<MapIssue>. Chaque MapIssue possède une gravité Severity (Info, Warning, Error), un Message, une position facultative WorldPosition et les couches de données concernées (Layers). Des surcharges acceptent un MapValidationSettings ou un simple MapData accompagné d’un tileset, de bibliothèques et d’une carte de cheminement.

using RTSTerrainStudio;
using UnityEngine;

// Checks a map before it is published (for example in a "Publish map" button of your game).
public static class ValidationExample
{
    public static bool CanPublish(RTSTerrain terrain)
    {
        // Optional thresholds; null uses the defaults.
        var settings = new MapValidationSettings { maxTrees = 10000, checkReachability = true };
        var issues = MapValidator.Validate(terrain, settings);

        foreach (MapIssue issue in issues)
        {
            // WorldPosition is set for issues that belong to a place on the map (e.g. a start location).
            string where = issue.WorldPosition.HasValue ? " at " + issue.WorldPosition.Value : "";
            switch (issue.Severity)
            {
                case MapIssueSeverity.Error: Debug.LogError(issue.Message + where, terrain); break;
                case MapIssueSeverity.Warning: Debug.LogWarning(issue.Message + where, terrain); break;
                default: Debug.Log(issue.Message + where, terrain); break;
            }
        }
        return MapValidator.Count(issues, MapIssueSeverity.Error) == 0;
    }
}

Intégrations

RTS Terrain Studio fonctionne de manière autonome : il dispose d’un module de recherche de chemin Burst intégré, de son propre brouillard de guerre et d’un gameplay d’exemple. Trois intégrations optionnelles le relient à des packages populaires. Elles font partie du package (dossier Integrations) et s’activent d’elles-mêmes lorsque le package dont elles ont besoin est installé.

IntégrationPrérequisCe que vous obtenezMenu de la scène de démo
MirrorMirror 96 ou plus récentJeu en ligne sur n’importe quelle carte : streaming de carte vers les clients, unités à autorité serveur, brouillard de guerre par équipe, gestion d’intérêt anti-maphack.Tools ▸ RTS Terrain Studio ▸ Integrations ▸ Mirror ▸ Create Demo Scene
A* Pathfinding ProjectA* Pathfinding Project Pro 5.4.4 ou plus récent, antérieur à 6.0Graphes en grille générés à partir de la carte de cheminement avec mises à jour incrémentales, unités qui se déplacent avec AIPath et évitement local RVO.Tools ▸ RTS Terrain Studio ▸ Integrations ▸ A* Pathfinding ▸ Create Demo Scene
Unity NavMeshAI Navigation (com.unity.ai.navigation) 2.0 ou plus récentUn NavMesh construit à partir des chunks du terrain et de la carte de cheminement, tenu à jour pendant l’édition de la carte, et des unités qui suivent des chemins NavMesh ou utilisent des NavMeshAgent.Tools ▸ RTS Terrain Studio ▸ Integrations ▸ Unity NavMesh ▸ Create Demo Scene

La fenêtre Welcome (Tools ▸ RTS Terrain Studio ▸ Welcome) affiche l’état de chaque intégration : Active (compilée et prête), Installed (la dépendance a été trouvée mais l’intégration n’est pas compilée, généralement à cause d’une version incompatible) ou Not installed.

Toutes les scènes de démo ont besoin du contenu de démo. Exécutez Tools ▸ RTS Terrain Studio ▸ Create Demo Content une fois avant de créer une démo d’intégration.

Fonctionnement des assemblies optionnelles

Chaque intégration réside dans ses propres assembly definitions. Unity ne compile une assembly que si toutes ses define constraints sont satisfaites. Les symboles proviennent de deux sources :

  • Version defines (versionDefines dans le .asmdef) : l’assembly définit un symbole pour son propre usage lorsqu’un package dont la version correspond est installé. A* et NavMesh utilisent ce mécanisme ; ils réagissent donc automatiquement à l’installation ou à la suppression du package.
  • Scripting define symbols des Player Settings : Mirror est généralement importé sous forme de dossier de l’Asset Store, et non comme package ; son assembly utilise donc le symbole MIRROR que Mirror ajoute lui-même aux Player Settings.
AssemblyVersion defineDefine constraints
RTSTerrainStudio.Integrations.Mirror et .Mirror.EditoraucunMIRROR
RTSTerrainStudio.Integrations.Mirror.DefineCleanup.Editoraucunaucune (toujours compilée ; supprime les symboles Mirror obsolètes, voir Supprimer des intégrations)
RTSTerrainStudio.Integrations.AStar et .AStar.Editorcom.arongranberg.astar dans [5.4.4,6.0.0) → RTS_ASTARRTS_ASTAR, !RTS_ASTAR_DISABLED
RTSTerrainStudio.Integrations.NavMesh et .NavMesh.Editorcom.unity.ai.navigation 2.0.0 ou plus récent → RTS_AI_NAVIGATIONRTS_AI_NAVIGATION

Résultat : sans la dépendance, l’intégration est simplement ignorée, rien ne casse et les unités utilisent le module de recherche de chemin intégré. Pour A* et NavMesh, inutile de jongler manuellement avec les symboles de définition.

Fournisseurs de chemins. L’unité d’exemple (RTSUnit) demande ses chemins à un IRTSUnitPathProvider. Le fournisseur intégré est utilisé par défaut ; les fournisseurs A* et NavMesh s’enregistrent en tant que RTSUnitPathProviderRegistry.Default lorsque l’option Make Default est activée, ou bien vous assignez un fournisseur au champ Path Provider d’unités individuelles. Votre propre solution de recherche de chemin peut se brancher de la même façon en implémentant IRTSUnitPathProvider.
Les assemblies d’intégration référencent RTSTerrainStudio.Samples (pour RTSUnit et les contrôleurs de sélection et de commandes). Conservez le dossier Samples/Scripts tant que vous utilisez une intégration.

Multijoueur avec Mirror

Jouez en ligne sur des cartes RTS Terrain Studio avec Mirror (version 96 ou plus récente) :

  • Streaming de carte : le serveur envoie sa carte à chaque client qui se connecte ; les joueurs peuvent donc rejoindre des parties sur des cartes qu’ils ne possèdent pas, y compris des cartes créées avec l’éditeur en jeu. Les cartes téléchargées sont mises en cache, si bien que la partie suivante sur la même carte démarre immédiatement.
  • Unités à autorité serveur : la recherche de chemin et le déplacement s’exécutent uniquement sur le serveur. Les clients envoient des ordres, et le serveur vérifie que les unités appartiennent bien au joueur.
  • Brouillard de guerre par équipe sur chaque client.
  • Gestion d’intérêt anti-maphack : les unités masquées par le brouillard de guerre ne sont jamais envoyées aux clients ennemis.

Démarrage rapide : la scène de démo

  1. Importez Mirror (Asset Store ou GitHub). Mirror ajoute le symbole de définition MIRROR, et l’intégration se compile.
  2. Exécutez Tools ▸ RTS Terrain Studio ▸ Create Demo Content (une fois par projet).
  3. Exécutez Tools ▸ RTS Terrain Studio ▸ Integrations ▸ Mirror ▸ Create Demo Scene. La commande crée, dans Integrations/Mirror/Demo : la scène RTS Mirror Demo.unity, les prefabs Prefabs/RTS Network Unit.prefab (une capsule de substitution avec RTSUnit, RTSNetworkUnit, NetworkIdentity et NetworkTransformReliable) et Prefabs/RTS Network Player.prefab, les matériaux des unités et, si le projet ne contient aucune carte avec au moins deux positions de départ, une carte générée pour 4 joueurs, RTS Mirror Demo Map.rtsmap.
  4. Lorsque cela vous est demandé, laissez le générateur de scène de démo ajouter la renderer feature du brouillard de guerre et placer la scène en tête de la liste des scènes du build.
  5. Appuyez sur Play et cliquez sur Host (Server + Client) dans le HUD de Mirror. Vous contrôlez l’équipe 1 (rouge) et vos unités apparaissent à votre position de départ.
  6. Lancez une deuxième instance (voir ci-dessous), cliquez sur Client et conservez l’adresse localhost. Le client télécharge la carte (une barre de progression s’affiche), rejoint la partie en tant qu’équipe 2 (bleue) et reçoit ses propres unités. Les unités ennemies n’apparaissent que lorsque vos unités peuvent les voir.

Tester l’hôte et le client

MéthodeProcédure
Build de joueur (le plus fiable)Ouvrez File ▸ Build Profiles. Vérifiez que RTS Mirror Demo est la première scène, puis générez le build. Lancez le build deux fois, ou bien le build et l’éditeur. Cliquez sur Host dans l’une des instances et sur Client dans l’autre.
ParrelSync (gratuit, GitHub)Ouvrez ParrelSync ▸ Clones Manager, créez un clone et ouvrez-le dans un nouvel éditeur. Appuyez sur Play dans les deux : cliquez sur Host dans l’original et sur Client dans le clone. Le clone partage le dossier Assets ; n’exécutez donc le générateur de scène de démo que dans l’original.
Multiplayer Play Mode (com.unity.multiplayer.playmode)Ouvrez Window ▸ Multiplayer ▸ Multiplayer Play Mode. Activez un joueur virtuel et appuyez sur Play. Cliquez sur Host dans l’éditeur principal et sur Client dans le joueur virtuel.
Sur un réseauSaisissez l’adresse IP de l’hôte dans le champ d’adresse du client. KCP utilise le port UDP 7777 ; ouvrez-le dans le pare-feu de l’hôte.
Serveur dédiéGénérez le build avec un profil de build Dedicated Server. Le gestionnaire réseau utilise Headless Start Mode = Auto Start Server, si bien que le serveur démarre tout seul. Les clients se connectent avec Client.

Chaque machine conserve les cartes téléchargées dans Application.persistentDataPath/MapCache. Utilisez Tools ▸ RTS Terrain Studio ▸ Integrations ▸ Mirror ▸ Clear Map Cache ou … ▸ Open Map Cache Folder pour tester un nouveau téléchargement. L’éditeur et un build de joueur Windows du même projet partagent ce dossier.

Vous voulez voir le streaming de carte dans la démo ? L’hôte et le client démarrent tous deux avec la carte de démo, et le client constate qu’il affiche déjà exactement la carte du serveur : rien n’est donc téléchargé. Désactivez Reuse Loaded Map et Use Cache sur le RTSNetworkMapSync du client, ou modifiez la carte sur l’hôte avant de lancer l’hébergement (par exemple avec l’éditeur en jeu).

Ajouter le multijoueur à votre propre scène

ComposantÀ placer surUtilité
RTSNetworkManagerObjet gestionnaire réseauAttribue les équipes, attend que le client ait la carte, puis fait apparaître le joueur et ses unités de départ à sa position de départ. Fait disparaître les unités lorsqu’un joueur quitte la partie.
RTSNetworkMapSyncMême objet (ajouté automatiquement)Transmet la carte en streaming aux clients, par chunks, avec une somme de contrôle, un cache et des événements de progression.
RTSFogOfWarInterestManagementMême objetGestion d’intérêt de Mirror : chaque client ne reçoit que les unités que son équipe peut voir.
RTSNetworkFogOfWarMême objetConfigure le RTSFogOfWarManager : le serveur calcule toutes les équipes, un client uniquement la sienne.
RTSNetworkStatusUIMême objet (facultatif)Barre de progression du téléchargement et « You are Player N » (IMGUI).
RTSNetworkPlayerPrefab du joueurSyncVar d’équipe. Configure le joueur local (équipe du brouillard de guerre, sélection, caméra) et envoie les ordres sous forme de commandes.
RTSNetworkUnitPrefabs d’unitésSyncVar d’équipe. Le déplacement s’exécute uniquement sur le serveur ; les clients se contentent d’afficher l’unité.
RTSNetworkCommandRelayAjouté automatiquement sur les clientsEnvoie au serveur les ordres du RTSCommandController d’exemple.
  1. Construisez une scène RTS Terrain Studio normale : un RTSTerrain avec une carte qui contient des positions de départ, un RTSFogOfWarManager, un RTSCameraController, un RTSSelectionManager et un RTSCommandController. N’ajoutez pas RTSDemoGame : c’est le gestionnaire réseau qui fait apparaître les unités.
  2. Créez un objet vide et ajoutez-y KcpTransport, RTSNetworkManager (qui ajoute RTSNetworkMapSync), RTSFogOfWarInterestManagement, RTSNetworkFogOfWar et, si vous le souhaitez, NetworkManagerHUD. Assignez le transport au champ Transport du gestionnaire.
  3. Créez un prefab de joueur avec NetworkIdentity et RTSNetworkPlayer, puis assignez-le au champ Player Prefab.
  4. Créez un prefab d’unité avec NetworkIdentity, RTSUnit, RTSNetworkUnit et NetworkTransformReliable (Sync Direction sur Server To Client, Sync Scale désactivé). Assignez-le au champ Unit Prefab ; il est ajouté automatiquement aux prefabs qui peuvent apparaître. Tout autre prefab réseau que vous faites apparaître doit figurer dans Registered Spawnable Prefabs.
  5. Réglez Units Per Player (5 par défaut) et, si vous le souhaitez, Max Players Override (0 = autant de joueurs que la carte a de positions de départ).
  6. Placez les composants d’IA ou de logique des prefabs d’unités (par exemple RTSWanderAI ou vos propres scripts d’IA) dans la liste Server Only Behaviours de RTSNetworkUnit, afin que les clients ne les exécutent pas.
ParamètrePar défautDescription
RTSNetworkManager
TerrainvideTerrain sur lequel se joue la partie. Vide = RTSTerrain.Main.
Unit PrefabvideUnité de départ de chaque joueur (nécessite NetworkIdentity, RTSUnit et RTSNetworkUnit).
Units Per Player5Nombre d’unités de départ (0–64).
Max Players Override0Permet d’avoir moins de joueurs que d’emplacements sur la carte (0 = toutes les positions de départ).
Unit Spacing2 mDistance entre les unités de départ.
Spawn Offset4 mDistance entre la position de départ et la première rangée d’unités de départ, en direction du centre de la carte.
Despawn Units On DisconnectActivéDétruit les unités d’un joueur qui quitte la partie.
Reserve Team Of Kept UnitsActivéSi les unités restent : garde l’emplacement d’équipe réservé tant que l’une d’elles est en vie.
Reject Disconnect Delay0.5 sSecondes entre le message de refus et la déconnexion, pour que le message ait le temps d’arriver.
RTSNetworkUnit
Server Only BehavioursvideBehaviours que les clients désactivent, car c’est le serveur qui exécute la logique de l’unité.
RTSNetworkPlayer
Jump Camera To StartActivéDéplace la caméra RTS vers la position de départ au début de la partie.
Create Command RelayActivéClients purs : ajoute un RTSNetworkCommandRelay si la scène n’en a pas, pour que le contrôleur de commandes d’exemple envoie ses ordres au serveur.
Max Units Per Command, Max Commands Per Second256, 20Validation des ordres par le serveur (voir Unités à autorité serveur).
Formation (Server)-Paramètres de formation utilisés par le serveur ; gardez-les alignés sur ceux de RTSCommandController.

Rejoindre une partie et streaming de carte

client connects
  server: team = first free player slot of the map (rejected when the map is full)
  server -> client: map header (name, size, CRC-32)
  client: same map already loaded, or in the cache?  yes -> "no data needed"
                                                     no  -> download the chunks
  client: check the CRC-32 -> terrain.SetMap(RTSMapSerializer.Deserialize(bytes)) -> "map ready"
  client: NetworkClient.Ready() + AddPlayer()
  server: spawns the RTSNetworkPlayer and the starting units (owned by the connection)

Le serveur ignore les messages Ready et AddPlayer d’un client tant que celui-ci n’a pas signalé la bonne somme de contrôle de la carte ; un client ne reçoit donc jamais d’objets du monde pour une carte qu’il n’a pas. En mode hôte, le client local utilise le terrain du serveur et rejoint la partie immédiatement.

  • Les données transmises sont le fichier .rtsmap (déjà compressé avec deflate). Une carte de 128 × 128 avec de la végétation pèse généralement quelques centaines de Ko.
  • Si la carte du serveur n’a pas changé depuis son chargement à partir de son asset ou de son fichier, ce sont les octets du fichier d’origine qui sont envoyés. Ils sont identiques d’une session à l’autre, si bien que le cache du client fonctionne entre les sessions. Une carte modifiée ou générée est sérialisée au besoin.
  • Le serveur n’accepte que l’accusé de réception du plus ancien chunk non confirmé ; un client modifié ne peut donc pas récupérer toute la carte d’un coup.
  • Les changements de scène (ServerChangeScene ou la scène en ligne de Mirror) renvoient la carte de la nouvelle scène à chaque joueur ; les clients ne rejoignent la nouvelle scène qu’une fois qu’ils disposent de cette carte.
Paramètre de RTSNetworkMapSyncPar défautDescription
TerrainvideTerrain dont la carte est envoyée (serveur) et remplacée (client). Vide = RTSTerrain.Main.
Chunk Size16 KoTaille en octets de chaque message de chunk, réduite automatiquement pour respecter la taille maximale des messages du transport.
Chunks In Flight8Chunks non confirmés en route vers un client. Des valeurs plus élevées accélèrent le téléchargement en cas de ping élevé ; des valeurs plus faibles laissent plus de bande passante au jeu.
Transfer Timeout30 sSecondes sans progression au bout desquelles un transfert échoue.
Load Timeout120 sServeur : temps dont un client dispose après le téléchargement pour charger sa scène et appliquer la carte. Les clients envoient des messages keep-alive pendant l’attente.
Disconnect On FailureActivéServeur : déconnecte les clients dont le transfert a échoué (ils ne peuvent pas jouer sans la carte).
Max Map Size MB64Client : taille maximale de carte acceptée par le client (protège contre les serveurs défaillants ou malveillants).
Reuse Loaded MapActivéIgnore le téléchargement si le client affiche déjà exactement la carte du serveur.
Use Cache / Max Cached MapsActivé / 20Conserve les cartes téléchargées dans Application.persistentDataPath/MapCache (les cartes jouées le moins récemment sont supprimées en premier, 0 = illimité).
Log TransfersActivéJournalise le début et la fin de chaque transfert.

Événements pour les écrans de chargement : ClientHeaderReceived, ClientProgressChanged(float), ClientMapReady, ClientTransferFailed(string) ; sur le serveur, ServerClientReady et ServerClientFailed. SendMapToAll() renvoie une carte modifiée (par exemple après un vote de carte dans un salon) à tous les clients connectés.

Unités à autorité serveur

  • Sur le serveur, RTSUnit planifie ses chemins et se déplace comme en solo ; NetworkTransformReliable réplique la position et la rotation.
  • Sur les clients, RTSNetworkUnit devient le fournisseur de chemins de l’unité avec HandlesMovement = true, si bien que l’unité ne se déplace jamais d’elle-même ; elle se contente de reproduire ce qu’écrit le network transform.
  • Les ordres locaux sont envoyés au serveur : clic droit (déplacement en formation, Shift pour mettre en file d’attente), Stop, Hold et Patrol via RTSNetworkCommandRelay, et tout autre appel à RTSUnit.MoveTo sur une unité côté client via RTSNetworkUnit. Depuis votre propre code, appelez RTSNetworkPlayer.RequestMove, RequestMoveTo, RequestPatrol, RequestStop ou RequestHold, ou ajoutez des méthodes [Command] à une classe dérivée de RTSNetworkPlayer.
  • Les formations sont calculées sur le serveur avec les paramètres Formation (Server) de RTSNetworkPlayer. Donnez-leur les mêmes valeurs que dans le RTSCommandController de la scène si vous avez modifié les paramètres de formation du contrôleur.
  • Le serveur valide chaque ordre : les unités existent et appartiennent à l’équipe du joueur, la cible est une position finie sur un terrain, l’ordre porte sur Max Units Per Command unités au maximum (256 par défaut) et le joueur envoie au maximum Max Commands Per Second ordres par seconde (20 par défaut).
  • Joueurs qui quittent la partie : avec Despawn Units On Disconnect (activé par défaut), leurs unités sont détruites et l’emplacement est libéré. Sans cette option, les unités restent ; Reserve Team Of Kept Units (activé par défaut) garde l’emplacement réservé tant que l’une d’elles est en vie. Un client refusé (par exemple parce que la partie est complète) reçoit la raison du refus avant d’être déconnecté (RTSNetworkManager.ClientRejected, LastRejectReason).

Brouillard de guerre et anti-maphack

Le serveur calcule le brouillard de guerre de chaque équipe. Toutes les Rebuild Interval secondes, RTSFogOfWarInterestManagement vérifie chaque unité dotée de RTSNetworkUnit :

  • Les unités de l’équipe du client et des équipes alliées (équipes qui partagent leur vision via RTSFogOfWarManager.SetAlliance) sont toujours envoyées.
  • Les unités ennemies ne sont envoyées que tant que le brouillard de guerre les montre à l’équipe du client. Linger Time conserve une unité un peu plus longtemps après sa sortie du champ de vision, pour que les unités en limite de vision ne clignotent pas.
  • Les objets sans RTSNetworkUnit (joueurs, gestionnaires) sont toujours envoyés.

Un ennemi masqué est supprimé côté client et aucun de ses déplacements n’est envoyé ; un client modifié ne peut donc pas le révéler. Sur les clients, RTSFogOfWarHideable masque en outre les ennemis qui se trouvent dans la portée réseau mais ne sont pas encore visibles.

ParamètrePar défautDescription
Fog Of WarvideBrouillard de guerre côté serveur. Vide = RTSFogOfWarManager.Active.
Rebuild Interval0.2 sSecondes entre deux vérifications de visibilité. Gardez une valeur de 0.1–0.3 s : chaque fois qu’une unité devient visible, le client reçoit un message d’apparition complet.
Linger Time0.5 sSecondes pendant lesquelles une unité reste observée après être sortie du champ de vision d’une équipe.
Share With AlliesActivéLes équipes qui partagent leur vision voient toujours les unités les unes des autres.
Show All Without FogActivéTant qu’aucun brouillard de guerre n’est actif sur le serveur, chaque connexion voit toutes les unités. Désactivé : uniquement ses propres unités.
Spectators See AllDésactivéLes connexions sans équipe (spectateurs) voient toutes les unités.

RTSNetworkFogOfWar propose Compute All Teams On Server (activé, requis par la gestion d’intérêt), un intervalle de mise à jour côté serveur (0 = conserver la valeur du gestionnaire ; des valeurs plus faibles font apparaître les unités plus tôt) et Disable Reveal All Online (activé). Une vérification de visibilité se résume à une seule lecture par unité dans la grille du brouillard de guerre : des milliers d’unités coûtent donc bien moins d’une milliseconde. Sur le serveur, le coût du brouillard de guerre augmente avec le nombre d’équipes, et 2–8 équipes restent peu coûteuses.

Programmation avec Mirror

using RTSTerrainStudio.Integrations.Mirror;
using RTSTerrainStudio.Samples;
using UnityEngine;

// Needs Mirror (96 or newer). Sends orders of the local player to the server and shows the map download.
public class MirrorExample : MonoBehaviour
{
    [SerializeField] RTSNetworkMapSync mapSync;   // on the network manager object

    void OnEnable()
    {
        if (mapSync == null) return;
        mapSync.ClientProgressChanged += OnProgress;          // 0-1 while the map downloads
        mapSync.ClientMapReady += OnMapReady;                 // the map is applied to the terrain
        mapSync.ClientTransferFailed += OnTransferFailed;
    }

    void OnDisable()
    {
        if (mapSync == null) return;
        mapSync.ClientProgressChanged -= OnProgress;
        mapSync.ClientMapReady -= OnMapReady;
        mapSync.ClientTransferFailed -= OnTransferFailed;
    }

    void OnProgress(float progress) => Debug.Log($"Downloading map: {progress:P0}");
    void OnMapReady() => Debug.Log("Map ready");
    void OnTransferFailed(string reason) => Debug.LogWarning("Map download failed: " + reason);

    // For your own UI (e.g. a "Move here" button): the server validates the order (ownership,
    // target, unit count, rate limit) before the units move.
    public void SendSelectedTo(Vector3 target, bool queue)
    {
        RTSNetworkPlayer player = RTSNetworkPlayer.Local;
        RTSSelectionManager selection = RTSSelectionManager.Main;
        if (player == null || selection == null) return;
        player.RequestMove(selection.Selection, target, queue);
    }

    // Host only: after changing the map (map vote, in-game editor), send it to every client again.
    public void ResendMap()
    {
        if (mapSync != null) mapSync.SendMapToAll();
    }
}
MembreDescription
RTSNetworkManager (RTSNetworkManager.Instance)
ServerPlayerJoined(conn, team), ServerConnectionRejected(conn)Serveur : une connexion a reçu une équipe (avant le transfert de la carte), ou a été refusée parce que tous les emplacements sont occupés.
ServerPlayerSpawned(conn, player), ServerUnitSpawned(conn, unit)Serveur : l’objet joueur est apparu (une fois sa carte prête) ; une unité est apparue, y compris via SpawnUnit. Servez-vous-en pour donner aux joueurs leurs objets de départ.
ServerPlayerLeft(conn, team)Serveur : une connexion a quitté la partie ; l’événement est déclenché avant la destruction de ses objets.
ClientJoinedGame, ClientDisconnected, ClientRejected(reason)Client : a rejoint la partie après le chargement de la carte ; la connexion a pris fin ; le serveur a refusé ce client.
RTSNetworkUnit SpawnUnit(owner, team, position, yaw, prefab = null)Serveur : fait apparaître une unité (déplacée vers l’emplacement praticable le plus proche). owner à null = aucun propriétaire, par exemple pour des creeps neutres ou des bâtiments. Le prefab doit être enregistré parmi les prefabs spawnables et comporter RTSNetworkUnit.
GetUnits(conn), TryGetTeam(conn, out team), IsTeamReserved(team)Serveur : les unités d’une connexion, son équipe, et si les unités d’un joueur parti occupent encore un emplacement d’équipe.
RejectConnection(conn, reason)Serveur : envoie le motif au client et le déconnecte après le délai Reject Disconnect Delay.
RTSNetworkUnit et RTSNetworkPlayer
static RTSNetworkUnit.Spawned, Despawned, AllDéclenchés sur chaque machine quand une unité réseau est apparue (après l’application de son équipe) ou a disparu ; toutes les unités connues sur cette machine.
static RTSNetworkPlayer.LocalPlayerStarted, LocalPlayerStopped, LocalL’objet du joueur local est apparu ou a disparu ; le joueur local actuel.
using Mirror;
using RTSTerrainStudio.Integrations.Mirror;
using UnityEngine;

// Server: gives every player an extra starting object (for example a town hall) next to its start location.
// Put it on the network manager object.
public class StartingObjectsExample : MonoBehaviour
{
    [SerializeField] GameObject townHallPrefab;   // NetworkIdentity + RTSUnit + RTSNetworkUnit, in Registered Spawnable Prefabs

    RTSNetworkManager manager;

    void Awake() => manager = GetComponent<RTSNetworkManager>();

    void OnEnable()
    {
        if (manager != null) manager.ServerPlayerSpawned += OnPlayerSpawned;
    }

    void OnDisable()
    {
        if (manager != null) manager.ServerPlayerSpawned -= OnPlayerSpawned;
    }

    void OnPlayerSpawned(NetworkConnectionToClient conn, RTSNetworkPlayer player)
    {
        if (player == null || townHallPrefab == null) return;
        // Start location of the player's team (a fallback position when the map has none).
        RTSNetworkUtility.GetStartLocation(manager.Terrain, player.Team, manager.MaxPlayers, out Vector3 start, out float yaw);
        // Owned by the connection, so the player can select and order it.
        manager.SpawnUnit(conn, player.Team, start, yaw, townHallPrefab);
    }
}

Limitations et dépannage

  • Les modifications de la carte en cours de partie (éditeur en jeu sur l’hôte) ne sont pas transmises en direct. Appelez RTSNetworkMapSync.SendMapToAll() pour renvoyer la carte.
  • RTSBuildingPlacementDemo et RTSTreeHarvestDemo s’exécutent localement et ne sont pas synchronisés en réseau. RTSDemoGame est un script d’amorçage pour une partie solo et n’a pas sa place dans une scène réseau.
  • Sur les clients, RTSUnit.State reste à Idle. Utilisez RTSUnit.Velocity (par exemple pour les animations de marche) ou ajoutez votre propre SyncVar.
  • Les alliances sont définies dans le brouillard de guerre du serveur. Les clients ne les reçoivent pas ; appelez SetAlliance sur les clients également si la vision alliée doit s’y afficher.
  • Les chargements de scène additifs conservent la carte actuelle. Le serveur et les clients doivent utiliser le même tileset et les mêmes bibliothèques (le même contenu de projet).
ProblèmeSolution
« The server's fog of war computes only its local team »Ajoutez RTSNetworkFogOfWar au gestionnaire réseau, ou activez Compute All Teams sur le Fog of War Manager du serveur.
Le client reste bloqué sur « Connecting... »Le serveur est injoignable (adresse, pare-feu, port UDP 7777), ou la scène du serveur ne contient pas de RTSNetworkManager.
« Could not join the game: The game is full »La carte a moins d’emplacements libres que de joueurs. Ajoutez des positions de départ, augmentez la valeur Max Players de la carte ou vérifiez Max Players Override. Les emplacements des joueurs partis restent réservés tant que leurs unités sont en vie.
Erreurs de compilation signalant des types Mirror manquants après la suppression de MirrorLe symbole de définition MIRROR est toujours défini. Voir Supprimer des intégrations.
Les unités ne bougent pas sur le clientLe prefab d’unité a besoin de NetworkTransformReliable, et la scène d’un RTSCommandController.
Les unités ennemies sont toujours visiblesRTSFogOfWarInterestManagement doit se trouver sur un objet actif, et le Fog of War Manager doit s’exécuter sur le serveur.
La carte est téléchargée à chaque foisLe serveur envoie une carte modifiée ou générée après son chargement. Enregistrez-la dans son asset ou son fichier avant d’héberger la partie.

A* Pathfinding Project

Cette intégration convertit la carte de cheminement du terrain en graphes en grille A*, les tient à jour pendant que vous modifiez la carte (dans l’éditeur et en jeu) et permet aux unités d’exemple de se déplacer avec A* : soit le long de chemins A* avec leur propre logique de pilotage, soit avec le composant AIPath d’A* et l’évitement local RVO.

Prérequis : A* Pathfinding Project Pro 5.4.4 ou plus récent, mais antérieur à 6.0 (testé avec 5.4.7). L’intégration utilise TraversalConstraint (nouveauté de la 5.4) et l’évitement local RVO (RVOController, RVOSimulator), que seule la version Pro contient. La version gratuite porte le même nom de package, si bien que Unity ne peut pas les distinguer : avec la version gratuite, ajoutez RTS_ASTAR_DISABLED dans Project Settings ▸ Player ▸ Scripting Define Symbols (ou supprimez le dossier de l’intégration).

Démarrage rapide : la scène de démo

  1. Installez A* Pathfinding Project Pro 5.4 ou plus récent.
  2. Exécutez une fois Tools ▸ RTS Terrain Studio ▸ Create Demo Content.
  3. Exécutez Tools ▸ RTS Terrain Studio ▸ Integrations ▸ A* Pathfinding ▸ Create Demo Scene. La scène est enregistrée sous Integrations/AStarPathfinding/Demo/RTS AStar Demo.unity. Si le contenu de démo ne contient aucune carte, RTS AStar Demo Map.rtsmap (plateaux, rampes, lacs) est généré à côté.
  4. Appuyez sur Play. Sélectionnez des unités avec le bouton gauche de la souris, puis cliquez avec le bouton droit pour les déplacer. Les chevaliers utilisent le graphe RTS Large, toutes les autres unités le graphe RTS Ground.
  5. Sélectionnez l’objet A* Pathfinding et basculez le paramètre Mode du composant A* Path Provider entre Agent Movement et Path Only pour comparer les deux modes de déplacement.

Ajouter A* à votre propre scène

Sélectionnez votre RTS Terrain et exécutez Tools ▸ RTS Terrain Studio ▸ Integrations ▸ A* Pathfinding ▸ Add A* To Selected Terrain. La commande ajoute un GameObject A* Pathfinding comportant :

ComposantUtilité
AstarPathLe composant principal d’A*. L’option Scan on Startup est désactivée (c’est le Graph Builder qui lance le scan), et la journalisation des chemins est limitée aux erreurs.
RTSAstarGraphBuilder (A* Graph Builder)Crée les graphes en grille à partir de la carte de cheminement et les met à jour à chaque modification de la carte.
RVOSimulatorÉvitement local pour les agents dotés d’un RVOController.
RTSAstarPathProvider (A* Path Provider)Fait en sorte que toutes les unités utilisent A* (enregistré comme RTSUnitPathProviderRegistry.Default).

La configuration manuelle fonctionne de la même façon : ajoutez ces composants à n’importe quel GameObject (Add Component ▸ RTS Terrain Studio ▸ Integrations) et assignez le terrain au Graph Builder, ou placez le Graph Builder sur le GameObject du terrain, où il trouve le terrain de lui-même. Désactivez l’option Scan On Startup du composant AstarPath.

Plusieurs terrains : chaque terrain a besoin de son propre Graph Builder, avec ses propres noms de graphes. Si vous exécutez Add A* To Selected Terrain pour un second terrain, ses graphes prennent le nom du terrain, par exemple RTS Ground (Island). Un graphe déjà rempli par un autre Graph Builder n’est jamais partagé.

Comment les graphes sont construits

  • Agencement exact. Un nœud par cellule de cheminement ; le graphe est centré sur la carte et suit la rotation Y du terrain. Déplacer ou faire pivoter le terrain reconstruit les graphes (en Edit Mode, dès que le terrain est resté immobile pendant 0.2 seconde).
  • Aucune physique requise. Les tests de collision et de hauteur d’A* sont désactivés. La hauteur des nœuds provient de la surface du terrain (comme RTSTerrain.GetHeight) ; la praticabilité, les tags et les pénalités proviennent des indicateurs de cheminement. Les données sont calculées par des jobs Burst.
  • Tags (modifiables dans le Graph Builder) : 0 sol, 1 eau peu profonde, 2 eau profonde, 3 bord de falaise. Utilisez-les dans les paramètres Tags du Seeker pour interdire ou pénaliser certains types de sol selon l’unité.
  • Profils de graphe. Un graphe en grille A* par profil (par exemple un par taille d’unité). Chaque profil possède un nom de graphe, un paramètre Traversal (Land, Shallow Water, Deep Water), un Unit Radius (les nœuds trop proches d’un obstacle deviennent impraticables, si bien que les grandes unités n’empiètent jamais sur les obstacles), des pénalités par type de sol (1000 ≈ un mètre supplémentaire par nœud), l’option Use Water Surface Height pour les graphes navals et une hauteur de montée maximale. Les unités choisissent le plus petit graphe adapté à leur rayon.
  • Unités navales et amphibies. Réglez le paramètre Traversal du profil sur Deep Water (bateaux) ou Land | Shallow Water | Deep Water et activez Use Water Surface Height. Donnez aux bateaux un RTSAstarUnitSetup avec Required Traversal = Deep Water. Par le code, les méthodes de fabrique RTSAstarGraphProfile.Ground() (« RTS Ground », rayon 0.5 m, Land | Shallow Water), Naval() (« RTS Naval », rayon 1 m, Deep Water, hauteur de la surface de l’eau) et Amphibious() (« RTS Amphibious », rayon 0.75 m, tous les types de sol, hauteur de la surface de l’eau) créent des profils prêts à l’emploi. Par défaut, un nouveau profil utilise Land | Shallow Water, une pénalité d’eau peu profonde de 600 et une pénalité de bord de falaise de 200.
  • Mises à jour. Une nouvelle carte, un terrain déplacé ou des paramètres modifiés entraînent une reconstruction complète. Chaque modification de la carte (RTSTerrain.PathingChanged) ne réécrit que les nœuds concernés, leur marge de dégagement et leurs connexions, dans un appel à AstarPath.AddWorkItem.
  • Très grandes cartes. A* limite les graphes en grille à 1024 nœuds par axe (8192 avec le symbole de définition d’optimisation ASTAR_LARGER_GRIDS). Les cartes de cheminement plus grandes utilisent automatiquement plusieurs cellules de cheminement par nœud ; Cells Per Node permet de le faire délibérément, pour obtenir des graphes plus rapides.
  • L’option Build In Edit Mode affiche les graphes sous forme de gizmos A* pendant que vous modifiez la carte.
Membre de RTSAstarGraphBuilderDescription
Cells Per Node (paramètre, 1 par défaut)Nombre de cellules de cheminement par nœud du graphe, sur chaque axe. 1 = correspondance exacte avec la carte de cheminement ; augmenté automatiquement sur les très grandes cartes (EffectiveCellsPerNode).
Log Rebuilds (paramètre, désactivé par défaut)Écrit une ligne dans la fenêtre Console à chaque reconstruction complète.
Profiles, TagsLes profils de graphe et les numéros de tag. Appelez RequestRebuild() après les avoir modifiés par le code.
RequestRebuild()Planifie une reconstruction complète pour la prochaine mise à jour (appel peu coûteux, même répété).
bool RebuildNow()Reconstruit immédiatement tous les graphes. Renvoie false s’il n’y a pas d’AstarPath actif ou pas de carte.
UpdateRegion(RectInt pathingRect)Réécrit les nœuds d’un rectangle de cellules de cheminement. Appelée automatiquement depuis RTSTerrain.PathingChanged ; appelez-la vous-même après avoir modifié PathingMap.Flags sans cet événement.
ProcessPendingChanges()Applique immédiatement les mises à jour en attente (pour les chemins demandés dans la même frame qu’une modification de la carte).
GetGraph(index), GetGraph(name), GetProfileIndex(name)Le GridGraph A* d’un profil.
FindProfileFor(radius, traversal), FindGraphFor(radius, traversal)Le plus petit profil (ou graphe) adapté à une unité ; -1 / null si aucun profil n’autorise ce mode de traversée.
GetStats(index)RTSAstarGraphStats : taille, taille des nœuds, nœuds praticables, durées de reconstruction et de mise à jour, isBuilt.
IsBuilt, IsProfileBuilt(index), bool TryGetProblem(out string problem)Indique si les graphes contiennent la carte actuelle ; pourquoi ils ne peuvent pas être construits (pas d’AstarPath, pas de terrain, pas de carte).
GraphsRebuilt, GraphsUpdatedÉvénements déclenchés après une reconstruction complète et après une mise à jour incrémentielle (avec le rectangle de cheminement).
static FindFor(terrain), static AllLe Graph Builder d’un terrain ; tous les composants Graph Builder activés.

Modes du fournisseur et RVO

Mode (RTSAstarMovementMode)Comportement
Agent Movement (par défaut)HandlesMovement = true. Les ordres de déplacement définissent la destination de l’AIPath de l’unité et lancent une recherche ; Stop et Hold effacent le chemin, et les unités qui tiennent leur position verrouillent leur RVOController. L’arrivée et l’échec sont signalés à l’unité, si bien que les ordres en file d’attente (Shift), les patrouilles et les événements d’unité se comportent comme avec le module de recherche de chemin intégré. L’évitement local RVO maintient les unités en mouvement à distance les unes des autres.
Path OnlyHandlesMovement = false. A* se contente de calculer les points de passage (via le Seeker de l’unité, de sorte que les modificateurs comme le Funnel Modifier s’appliquent) ; l’unité les suit avec sa propre logique de pilotage et de séparation. Les chemins des unités sans Funnel Modifier sont redressés (Smooth Paths).
Paramètre du fournisseurPar défautDescription
ModeAgent MovementVoir ci-dessus.
Graph BuildervideGraph Builder dont les graphes sont utilisés. Vide = le Graph Builder du terrain de l’unité.
Auto Configure UnitsActivéAjoute et configure RTSAstarUnitSetup sur chaque unité : un Seeker, un FunnelModifier, un RTSAstarAIPath (un AIPath qui se tient sur la surface du terrain sans raycasts physiques) et un RVOController, avec la vitesse, la vitesse de rotation, l’accélération, le rayon et la hauteur copiés depuis le RTSUnit.
Fallback To BuiltinActivéUtilise le module de recherche de chemin intégré tant qu’aucun graphe A* n’est disponible (en Edit Mode et avant le premier scan).
Smooth PathsActivéPath Only : redresse les chemins des unités sans Funnel Modifier ; les raccourcis restent sur les tags autorisés et ne traversent jamais de nœuds plus coûteux.
Stuck Time1.5 sAgent Movement : nombre de secondes pendant lesquelles un agent peut rester immobile au cours d’un déplacement avant de recalculer son chemin une fois, puis d’abandonner.

Ajoutez vous-même RTSAstarUnitSetup à un prefab d’unité pour choisir un graphe par son nom, ou pour désactiver l’évitement local ou le lissage des chemins par type d’unité. L’Inspector de RTSAstarAIPath affiche les paramètres de déplacement habituels d’A*, plus une section RTS Terrain (Follow Terrain Height, Stay On Water Surface, Terrain).

using RTSTerrainStudio.Integrations.AStar;
using RTSTerrainStudio.Samples;
using UnityEngine;

// Needs the A* Pathfinding Project Pro 5.4+. Put it into an assembly that references
// RTSTerrainStudio.Integrations.AStar (or into Assembly-CSharp, which references it automatically).
public class AstarExample : MonoBehaviour
{
    [SerializeField] RTSUnit unit;

    void Start()
    {
        // Configure one unit by hand (Seeker, FunnelModifier, RTSAstarAIPath and RVOController).
        RTSAstarUnitSetup setup = RTSAstarUnitSetup.Configure(unit, agentMovement: true);
        setup.Agent.maxSpeed *= 1.5f;

        // The graph that fits this unit's radius.
        RTSAstarGraphBuilder builder = RTSAstarGraphBuilder.FindFor(unit.Terrain);
        if (builder != null)
            Debug.Log("Unit uses graph " + builder.FindGraphFor(unit.Radius)?.name);
    }

    // After changing the pathing map from code in the middle of a frame, push the change to A* now
    // instead of waiting for the next update.
    public static void FlushGraphs(RTSUnit anyUnit)
    {
        RTSAstarGraphBuilder.FindFor(anyUnit.Terrain)?.ProcessPendingChanges();
    }
}

Limitations

  • Les règles des graphes en grille d’A* (GridGraph.rules) n’ont aucun effet : le Graph Builder écrit lui-même la praticabilité, les tags, les pénalités et les positions après chaque scan. Utilisez plutôt les tags et les pénalités du Graph Builder.
  • Les terrains pivotés autour de X ou de Z ne sont pas pris en charge (les graphes en grille sont des plans horizontaux).
  • Une surcharge de cheminement Unwalkable peinte ne bloque que les unités terrestres. Les navires sont bloqués par les obstacles et les falaises ; délimitez les voies navigables avec des doodads ou des bordures d’eau profonde. Les unités navales nécessitent le mode Agent Movement.
  • Les profils de graphe retirés du Graph Builder laissent leur graphe dans le composant AstarPath ; supprimez-le dans ce composant si vous n’en avez plus besoin.
  • A* ne recherche des chemins qu’en Play Mode. En Edit Mode, les requêtes de chemin se rabattent sur le module de recherche de chemin intégré.

Unity NavMesh (AI Navigation)

Cette intégration construit un NavMesh Unity pour un RTSTerrain et permet aux unités d’exemple d’y trouver leur chemin. Choisissez-la si votre jeu s’appuie déjà sur le NavMesh de Unity (NavMeshAgents, requêtes NavMesh, NavMeshLinks) ou si vous voulez profiter de l’évitement de foule de Unity. Elle nécessite le package AI Navigation (com.unity.ai.navigation) 2.0 ou plus récent et fonctionne dans l’éditeur comme en jeu, y compris avec des cartes chargées ou modifiées à l’exécution.

Supprimer des intégrations

Vous n’êtes jamais obligé de supprimer une intégration : sans sa dépendance, elle n’est pas compilée. Supprimez-en une si vous désinstallez la dépendance ou si vous voulez un projet plus léger. Dans tous les cas, si vous avez créé une scène de démo, supprimez d’abord le dossier Demo de l’intégration : ses scènes et ses prefabs utilisent les composants de l’intégration et afficheraient des scripts manquants.

Supprimer A* Pathfinding Project ou AI Navigation

  1. Supprimez Integrations/AStarPathfinding/Demo (ou Integrations/UnityNavMesh/Demo) s’il existe.
  2. Retirez de vos propres scènes et prefabs les composants de l’intégration (Graph Builder, fournisseur de chemins, configuration des unités / NavMesh Builder, fournisseur de chemins NavMesh).
  3. Désinstallez le package (A* Pathfinding Project, ou AI Navigation dans le Package Manager). Le symbole défini par les Version Defines disparaît avec le package, et les assemblies d’intégration sont automatiquement exclues de la compilation.
  4. Si vous aviez ajouté RTS_ASTAR_DISABLED pour la version gratuite d’A*, vous pouvez maintenant le retirer des Scripting Define Symbols.

Supprimer Mirror

Mirror ajoute aux Player Settings les symboles de définition MIRROR, MIRROR_89_OR_NEWER, MIRROR_90_OR_NEWER, MIRROR_93_OR_NEWER et MIRROR_96_OR_NEWER, et supprimer Mirror ne les retire pas. Tant que MIRROR reste défini, Unity continue de compiler l’intégration en référençant des assemblies Mirror qui n’existent plus, et les erreurs de compilation bloquent tous les scripts du projet.

  1. Supprimez d’abord Integrations/Mirror/Demo.
  2. Supprimez le dossier Mirror dans l’éditeur Unity (fenêtre Project). La petite assembly d’éditeur RTSTerrainStudio.Integrations.Mirror.DefineCleanup.Editor détecte la suppression, retire les symboles de Mirror de toutes les cibles de build et journalise ce qu’elle a retiré. Elle s’exécute aussi chaque fois que l’éditeur démarre sans Mirror. La commande Tools ▸ RTS Terrain Studio ▸ Integrations ▸ Mirror ▸ Remove Stale Mirror Defines fait la même chose manuellement.
  3. Vérifiez les Project Settings ▸ Player ▸ Other Settings ▸ Scripting Define Symbols de chaque plateforme pour laquelle vous générez un build : aucune entrée MIRROR ou MIRROR_..._OR_NEWER ne doit subsister. Supprimez à la main les entrées restantes, par exemple quand Mirror a été supprimé alors que l’éditeur était fermé et que l’éditeur a ensuite démarré en Safe Mode. Le plugin Edgegap de Mirror ajoute aussi EDGEGAP_PLUGIN_SERVERS ; il est inoffensif, mais vous pouvez également le retirer.

Les scripts d’intégration peuvent rester dans le projet : ils ne sont pas compilés tant que Mirror n’est pas réinstallé.

Supprimer les dossiers d’intégration

Chaque intégration est autonome. Supprimer Integrations/Mirror, Integrations/AStarPathfinding ou Integrations/UnityNavMesh (dans la fenêtre Project) la retire entièrement ; rien d’autre dans le package ne fait référence à ces dossiers. Vous pouvez aussi supprimer tout le dossier Integrations.

Retirez les composants de l’intégration de vos scènes et prefabs avant de supprimer son dossier, sinon ils deviennent des scripts manquants. Si vous supprimez Integrations/Mirror alors que Mirror reste installé, puis que vous désinstallez Mirror plus tard, supprimez à la main les symboles de définition de Mirror (le nettoyage automatique se trouve dans ce dossier).

Guide de programmation

Tout ce que vous pouvez faire dans les fenêtres de l’éditeur, vous pouvez aussi le faire en C#. Ce chapitre montre comment interroger le terrain, modifier la carte par le code (avec et sans annulation), écrire vos propres outils, réagir aux événements, et enregistrer et charger des cartes à l’exécution. Tous les exemples ci-dessous compilent avec le package tel qu’il est livré ; copiez-le dans votre projet et adaptez-le.

Assemblies, espaces de noms et coordonnées

AssemblyEspace de nomsContenu
RTSTerrainStudio.RuntimeRTSTerrainStudioTerrain, données de carte, outils, pinceaux, végétation, eau, décors, brouillard de guerre, cheminement, générateur, sérialiseur, éditeur en jeu.
RTSTerrainStudio.SamplesRTSTerrainStudio.SamplesCaméra RTS, unités, sélection, commandes, interface de la mini-carte, jeu de démo.
RTSTerrainStudio.EditorRTSTerrainStudio.EditorFenêtre de l’éditeur, outils de la Scene View, inspecteurs, importeurs, fenêtres de configuration, RTSEditorContext.
RTSTerrainStudio.Integrations.*RTSTerrainStudio.Integrations.Mirror / .AStar / .NavMeshIntégrations optionnelles.

Les scripts qui n’ont pas d’assembly definition (Assembly-CSharp, et Assembly-CSharp-Editor pour les scripts placés dans des dossiers Editor) référencent automatiquement ces assemblies. Si votre code possède son propre .asmdef, ajoutez à ses références RTSTerrainStudio.Runtime (ainsi que RTSTerrainStudio.Samples ou RTSTerrainStudio.Editor si vous les utilisez), plus Unity.Mathematics et Unity.Collections si vous utilisez des types comme float3 ou NativeArray.

La carte en trois grilles

  • Cellules : la carte compte Width × Height cellules de CellSize mètres (2 m par défaut). Les rectangles passés à NotifyChanged sont exprimés en cellules.
  • Vertices : les coins des cellules, au nombre de (Width + 1) × (Height + 1) ; indice z * VertexCountX + x (MapData.VertexIndex(x, z)). Les hauteurs, les niveaux de falaise, les indicateurs, les types de falaise et l’eau sont stockés ici. Le vertex (x, z) se trouve en (x * CellSize, z * CellSize).
  • Texels : des couches raster à N texels par cellule, à savoir le splat (SplatResolution), les détails (DetailResolution) et le cheminement (PathingResolution). Le centre du texel (x, z) se trouve en (x + 0.5, z + 0.5) * CellSize / N.

L’espace local de la carte commence au premier vertex : X/Z en mètres de 0 à MapData.WorldSize, Y vers le haut. Seules la position et la rotation Y du terrain sont prises en compte (l’échelle est ignorée). Pour convertir, utilisez WorldToLocal, LocalToWorld, WorldToLocalDirection, LocalToWorldDirection, WorldToCell, CellCenterToWorld et VertexToWorld. La hauteur du sol d’un vertex vaut CliffLevels[i] × CliffLevelHeight + Heights[i]. Les rotations s’expriment en degrés, dans le sens horaire vu du dessus (0 = +Z, 90 = +X), comme la rotation Y de Unity.

Interroger le terrain

L’API de requête de RTSTerrain suit exactement la surface que vous voyez, y compris les contours arrondis des falaises, et ne nécessite aucun collider. Elle fonctionne en Edit Mode comme à l’exécution.

MembreValeur renvoyée
RTSTerrain.Main, RTSTerrain.AllLe premier terrain activé / tous les terrains activés.
RTSTerrain.FindAt(Vector3 world)Le terrain dont la zone contient la position, ou null.
RTSTerrain.RaycastAll(Ray, out RTSTerrainHit, maxDistance)L’impact le plus proche, tous terrains confondus.
Raycast(Ray, out RTSTerrainHit, maxDistance)Raycast analytique sur ce terrain. RTSTerrainHit contient point, normal, distance, localPoint, cell et terrain.
GetHeight(world), SnapToGround(world)La coordonnée Y du sol en espace monde / la position replacée sur le sol.
GetNormal(world)La normale de la surface en espace monde.
GetCliffLevel(world)Le niveau de falaise (0–15) à cette position.
IsWater(world, out depth), TryGetWaterHeight(world, out waterY)Indique si la position est sous l’eau, ainsi que sa profondeur et la coordonnée Y de la surface en espace monde.
GetPathing(world), IsWalkable(world), IsBuildable(world)PathingFlags (Walkable, Buildable, Flyable, ShallowWater, DeepWater, Cliff, Blocked, Steep). None en dehors de la carte ou tant que la carte de cheminement n’est pas construite.
Contains(world), WorldBoundsIndique si la position se trouve dans la zone de la carte / les limites de la carte en espace monde.
GetGeometry()Une vue MapGeometryView compatible Burst (SampleHeight, SampleNormal, SampleCliffLevel, SampleWater, Raycast… en espace local de la carte) pour vos propres jobs.
RTSPathfinder.FindPath(terrain, from, to, options, list)Un chemin calculé par le module de recherche de chemin Burst intégré (PathStatus : Success, Partial, NoPath, InvalidStart).
using System.Collections.Generic;
using RTSTerrainStudio;
using UnityEngine;

// Logs what is under the mouse cursor when you left-click: height, cliff level, water and pathing.
// Works with any number of RTS terrains in the scene and needs no colliders.
public class TerrainQueryExample : MonoBehaviour
{
    [SerializeField] Camera viewCamera;

    void Update()
    {
        // RTSInput works with the Input System and with the legacy Input Manager.
        if (!RTSInput.GetMouseButtonDown(0)) return;

        Camera cam = viewCamera != null ? viewCamera : Camera.main;
        if (cam == null) return;
        Ray ray = cam.ScreenPointToRay(RTSInput.PointerPosition);

        // Analytic ray cast against every enabled RTS terrain (closest hit wins).
        if (!RTSTerrain.RaycastAll(ray, out RTSTerrainHit hit)) return;

        RTSTerrain terrain = hit.terrain;
        Vector3 p = hit.point;

        float groundY = terrain.GetHeight(p);           // world Y of the ground
        Vector3 normal = terrain.GetNormal(p);          // world space surface normal
        int level = terrain.GetCliffLevel(p);           // 0-15
        bool walkable = terrain.IsWalkable(p);          // ground units can walk here
        bool buildable = terrain.IsBuildable(p);        // buildings can be placed here
        PathingFlags flags = terrain.GetPathing(p);     // all pathing flags of the cell

        string water = "dry";
        if (terrain.IsWater(p, out float depth) && terrain.TryGetWaterHeight(p, out float waterY))
            water = $"water, depth {depth:0.00} m, surface at y = {waterY:0.00}";

        Debug.Log($"Cell {hit.cell} on '{terrain.name}': ground y = {groundY:0.00}, level {level}, " +
                  $"slope {Vector3.Angle(normal, Vector3.up):0} deg, {water}, " +
                  $"walkable {walkable}, buildable {buildable}, flags {flags}");
    }

    // Keeps an object standing on the ground of whatever terrain is below it.
    public static void PlaceOnGround(Transform t)
    {
        RTSTerrain terrain = RTSTerrain.FindAt(t.position);
        if (terrain != null) t.position = terrain.SnapToGround(t.position);
    }

    // Asks the built-in Burst pathfinder for a path (main thread, no third-party package needed).
    public static bool TryFindPath(RTSTerrain terrain, Vector3 from, Vector3 to, List<Vector3> waypoints)
    {
        // ForUnit sets the clearance for a unit of this radius (large units avoid narrow gaps).
        PathRequestOptions options = PathRequestOptions.ForUnit(0.5f);
        PathStatus status = RTSPathfinder.FindPath(terrain, from, to, options, waypoints);
        // Partial: the goal is unreachable, the path ends at the closest reachable cell.
        return status == PathStatus.Success || status == PathStatus.Partial;
    }
}
Pour la sélection à la souris, préférez RTSTerrain.RaycastAll à Physics.Raycast : cette méthode est exacte, fonctionne sans colliders et aussi en Edit Mode. Les colliders (Collider Mode dans les paramètres du terrain) restent utiles pour les objets physiques et pour les raycasts qui doivent aussi toucher d’autres objets.

Modifier la carte par le code

Tout le contenu de la carte se trouve dans terrain.Map, un MapData. Pour le modifier, procédez toujours selon les trois mêmes étapes :

  1. Modifiez les données dans terrain.Map (sur le thread principal).
  2. Appelez terrain.NotifyChanged(layers, cellRect) avec les MapLayers modifiés et le rectangle modifié en cellules, ou NotifyChangedAll(layers) après une modification de toute la carte.
  3. C’est tout. Lors de son prochain LateUpdate (en Edit Mode : à la prochaine mise à jour de l’éditeur), le terrain ne reconstruit que ce qui a été marqué comme modifié : chunks, textures de splat, eau, végétation, décor et carte de cheminement. Appelez terrain.ProcessPendingChanges() si vous avez besoin des résultats dans la même frame (l’appeler souvent coûte peu).
Données (MapData)Grille / typeIndicateur MapLayers
Heightsvertices, float, hauteur fine en mètres, qui s’ajoute au niveauHeights
CliffLevelsvertices, byte 0–15CliffLevels
VertexFlagsvertices, VertexFlags (Ramp, Water, User0, User1)VertexFlags
CliffTypesvertices, byte 0–3CliffTypes
WaterHeightsvertices, hauteur de la surface de l’eau en mètres, en espace local de la carte (utilisée là où l’indicateur Water est activé)Water
SplatMaps[0..3]texels de splat, 4 × RGBA32 ; le calque i se trouve dans la splat map i/4, canal i%4 ; la somme des poids vaut 255Splat
DetailLayerstexels de détail, un octet de densité par couche (DetailLayer.prototypeId, density)Details
Trees, Decorlistes de TreeInstanceData / DecorInstanceData avec des indices de palette pointant vers TreePrototypeIds / DecorPrototypeIdsTrees, Decor
PathingOverridestexels de cheminement, surcharges peintesPathingOverrides
Regions, StartLocations, MarkerslistesRegions, StartLocations, Markers
Info, Environmentinformations de la carte et éclairageInfo, Environment
Règles pour que la carte reste valide : limitez les niveaux de falaise à 0–15 et les types de falaise à 0–3 ; maintenez les hauteurs fines dans la plage autorisée (TerrainToolUtility.ClampFineHeight) ; veillez à ce que chaque texel de splat totalise exactement 255 (utilisez SplatRaster et SplatMath) ; allouez les identifiants d’instance des nouveaux arbres et objets de décor avec map.AllocateInstanceId(), et les indices de prototype avec GetOrAddTreePrototype / GetOrAddDecorPrototype. Ne conservez jamais de références à MapData ou à ses tableaux au-delà d’un chargement ou d’un redimensionnement de carte : SetMap, LoadFromFile et ResizeMap remplacent l’objet entier et libèrent l’ancien.

Déformation et peinture à l’exécution : cratères et sol corrompu

Un usage typique en jeu : une explosion creuse un cratère, et un bâtiment mort-vivant répand un « sol corrompu » autour de lui. Le cheminement, ainsi que la hauteur de la végétation et des décors, s’adaptent automatiquement.

using RTSTerrainStudio;
using UnityEngine;

// Runtime terrain changes from gameplay code: explosion craters and spreading "blight".
// Both edit MapData directly and then call NotifyChanged. The terrain rebuilds only the
// touched chunks (and the pathing map) in its next LateUpdate.
public static class TerrainEffects
{
    // Digs a bowl-shaped crater into the fine height around a world position.
    public static void Crater(RTSTerrain terrain, Vector3 worldPosition, float radius, float depth)
    {
        MapData map = terrain != null ? terrain.Map : null;
        if (map == null || radius <= 0f) return;

        // Work in map-local space: X/Z in metres from the first vertex.
        Vector3 local = terrain.WorldToLocal(worldPosition);

        // Vertex rectangle covered by the crater (vertices sit at x * CellSize, z * CellSize).
        int x0 = Mathf.Max(0, Mathf.FloorToInt((local.x - radius) / map.CellSize));
        int z0 = Mathf.Max(0, Mathf.FloorToInt((local.z - radius) / map.CellSize));
        int x1 = Mathf.Min(map.Width, Mathf.CeilToInt((local.x + radius) / map.CellSize));
        int z1 = Mathf.Min(map.Height, Mathf.CeilToInt((local.z + radius) / map.CellSize));
        if (x1 < x0 || z1 < z0) return; // completely outside the map

        for (int z = z0; z <= z1; z++)
        for (int x = x0; x <= x1; x++)
        {
            float dx = x * map.CellSize - local.x;
            float dz = z * map.CellSize - local.z;
            float t = Mathf.Sqrt(dx * dx + dz * dz) / radius;
            if (t >= 1f) continue;

            // Smooth bowl: deepest in the centre, zero at the rim.
            float falloff = 1f - t * t;
            int i = map.VertexIndex(x, z);
            // Heights is the fine height on top of the cliff level. Clamp it to the allowed range.
            map.Heights[i] = TerrainToolUtility.ClampFineHeight(map, map.Heights[i] - depth * falloff * falloff);
        }

        // Tell the terrain which cells changed. Meshes, colliders, water, vegetation, decor and
        // pathing follow automatically.
        var vertexRect = new RectInt(x0, z0, x1 - x0 + 1, z1 - z0 + 1);
        terrain.NotifyChanged(MapLayers.Heights, BrushUtility.VertexRectToCellRect(map, vertexRect));
    }

    // Paints a ground layer (for example a "blight" texture) around a position with a soft edge.
    // amount is the coverage reached in the centre (0-1).
    public static void PaintLayer(RTSTerrain terrain, Vector3 worldPosition, float radius, int layer, float amount = 1f)
    {
        MapData map = terrain != null ? terrain.Map : null;
        if (map == null || radius <= 0f) return;
        layer = Mathf.Clamp(layer, 0, MapData.MaxGroundLayers - 1);

        Vector3 local = terrain.WorldToLocal(worldPosition);
        int res = map.SplatResolution;            // splat texels per cell
        float texel = map.CellSize / res;         // texel size in metres

        // Texel rectangle (texel centres sit at (x + 0.5) * texel).
        int x0 = Mathf.Max(0, Mathf.FloorToInt((local.x - radius) / texel));
        int z0 = Mathf.Max(0, Mathf.FloorToInt((local.z - radius) / texel));
        int x1 = Mathf.Min(map.SplatWidth - 1, Mathf.CeilToInt((local.x + radius) / texel));
        int z1 = Mathf.Min(map.SplatHeight - 1, Mathf.CeilToInt((local.z + radius) / texel));
        if (x1 < x0 || z1 < z0) return;

        // SplatRaster gives read/write access to all 16 layer weights of a texel.
        var splat = new SplatRaster(map);
        for (int z = z0; z <= z1; z++)
        for (int x = x0; x <= x1; x++)
        {
            float dx = (x + 0.5f) * texel - local.x;
            float dz = (z + 0.5f) * texel - local.z;
            float t = Mathf.Sqrt(dx * dx + dz * dz) / radius;
            if (t >= 1f) continue;

            int index = splat.Index(x, z);
            SplatTexel weights = splat.Read(index);
            int target = Mathf.RoundToInt(Mathf.Clamp01(amount * (1f - t)) * SplatMath.Total);
            if (weights[layer] >= target) continue; // never remove blight that is already there

            // Sets the layer weight and rescales the other layers, so the texel still sums to 255.
            SplatMath.SetLayerWeight(ref weights, layer, target, 0);
            splat.Write(index, weights);
        }

        var texelRect = new RectInt(x0, z0, x1 - x0 + 1, z1 - z0 + 1);
        terrain.NotifyChanged(MapLayers.Splat, BrushUtility.TexelRectToCellRect(map, texelRect, res));
    }
}
Voici comment les utiliser : TerrainEffects.Crater(RTSTerrain.FindAt(hitPoint), hitPoint, 4f, 1.5f); ou TerrainEffects.PaintLayer(terrain, building.position, 12f, blightLayer);. Pour les effets qui touchent des milliers de vertices à chaque frame, déplacez la boucle dans un job Burst, comme le font les outils intégrés.

Modifications annulables : RTSEditSession.RunOperation

Les modifications directes ne peuvent pas être annulées, ce qui convient au gameplay. Pour les outils d’éditeur et les fonctionnalités d’édition de cartes, utilisez une RTSEditSession : RunOperation(name, layers, action) mémorise l’état des couches indiquées sur toute la carte, exécute votre action et regroupe le tout en une seule étape d’annulation. Dans l’éditeur Unity, utilisez la session partagée RTSEditorContext.Session ; ses étapes font partie du système d’annulation de Unity, si bien que Ctrl+Z / Ctrl+Y fonctionnent comme d’habitude.

// Put this file into a folder named "Editor".
using RTSTerrainStudio;
using RTSTerrainStudio.Editor;
using UnityEditor;
using UnityEngine;

// Editor menu command that raises a plateau in the middle of the edited map.
// It runs through the shared edit session, so Ctrl+Z / Ctrl+Y undo and redo it in one step.
public static class PlateauMenu
{
    [MenuItem("Tools/My Game/Raise Centre Plateau")]
    static void RaiseCentrePlateau()
    {
        RTSTerrain terrain = RTSEditorContext.Terrain;   // the terrain selected in the RTS Terrain Studio window
        if (terrain == null || terrain.Map == null) return;

        // The shared session of the window and the Scene View. It always edits RTSEditorContext.Terrain.
        RTSEditSession session = RTSEditorContext.Session;

        // RunOperation records the listed layers of the whole map BEFORE the operation runs,
        // so inside it you only change data and notify the terrain.
        session.RunOperation("Raise Centre Plateau", MapLayers.CliffLevels | MapLayers.Heights, ctx =>
        {
            MapData map = ctx.Map;
            int size = Mathf.Min(map.Width, map.Height) / 4;          // plateau size in cells
            var vertexRect = new RectInt(map.Width / 2 - size / 2, map.Height / 2 - size / 2, size + 1, size + 1);

            for (int z = vertexRect.yMin; z < vertexRect.yMax; z++)
            for (int x = vertexRect.xMin; x < vertexRect.xMax; x++)
            {
                int i = map.VertexIndex(x, z);
                // Cliff levels are bytes 0-15. Ground height = level * CliffLevelHeight + fine height.
                map.CliffLevels[i] = (byte)Mathf.Min(MapData.MaxCliffLevel, map.CliffLevels[i] + 1);
                map.Heights[i] = 0f;                                   // flat top
            }

            ctx.MarkChanged(MapLayers.CliffLevels | MapLayers.Heights,
                BrushUtility.VertexRectToCellRect(map, vertexRect));
        });
    }
}

Dans un jeu en cours d’exécution, utilisez la session de l’éditeur en jeu (RTSRuntimeEditor.Session) pour que votre opération partage son historique d’annulation, ou créez votre propre session :

using RTSTerrainStudio;
using UnityEngine;

// Undoable edits in a running game: use the session of the in-game editor, or your own session.
public class RuntimeUndoExample : MonoBehaviour
{
    RTSEditSession ownSession;

    public void FloodLowGround(RTSTerrain terrain, float waterLocalY)
    {
        // Prefer the in-game editor's session, so the edit shares its undo history (Ctrl+Z in the editor UI).
        var ingameEditor = FindFirstObjectByType<RTSRuntimeEditor>();
        RTSEditSession session = ingameEditor != null ? ingameEditor.Session : null;
        if (session == null)
        {
            // Without the in-game editor: a plain session works as well (call Dispose when done).
            if (ownSession == null) ownSession = new RTSEditSession();
            ownSession.Terrain = terrain;
            session = ownSession;
        }

        session.RunOperation("Flood Low Ground", MapLayers.Water | MapLayers.VertexFlags, ctx =>
        {
            MapData map = ctx.Map;
            const byte waterFlag = (byte)VertexFlags.Water;
            for (int i = 0; i < map.VertexCount; i++)
            {
                // Ground height of a vertex = cliff level * level height + fine height.
                float ground = map.CliffLevels[i] * map.CliffLevelHeight + map.Heights[i];
                if (ground >= waterLocalY) continue;
                // A vertex is wet when it has the Water flag; WaterHeights holds its surface height.
                map.VertexFlags[i] = (byte)(map.VertexFlags[i] | waterFlag);
                map.WaterHeights[i] = waterLocalY;
            }
            // Water changes only need the Water layer: terrain meshes are not rebuilt.
            ctx.Terrain.NotifyChangedAll(MapLayers.Water);
        });
    }

    public void UndoLast()
    {
        ownSession?.Undo();
    }

    void OnDestroy()
    {
        ownSession?.Dispose();
    }
}
Dans un outil qui travaille par traits, vous n’appelez pas RunOperation ; vous appelez ctx.Record et ctx.MarkChanged pour chaque empreinte (voir la section suivante). RunOperation mémorise des couches entières : sur les grandes cartes, préférez donc des couches précises à MapLayers.All.

Écrire un outil personnalisé

Les outils sont de simples classes C# qui dérivent de RTSTool. Le package trouve par réflexion (RTSToolRegistry) chaque outil non abstrait doté d’un constructeur public sans paramètre. Votre outil apparaît donc automatiquement dans l’onglet de sa catégorie, dans la fenêtre RTS Terrain Studio et dans l’éditeur en jeu, avec une interface de paramètres construite à partir de ses champs [ToolSetting], le panneau du pinceau, la symétrie, l’annulation et le rétablissement, le curseur de pinceau projeté et la barre d’état. Dans l’éditeur, ses paramètres sont mémorisés d’une session à l’autre.

  1. Créez un fichier C# n’importe où dans votre projet (mais pas dans un dossier Editor, afin que l’outil existe aussi dans les builds pour l’éditeur en jeu).
  2. Faites dériver votre classe de RTSTool et redéfinissez Id (unique, par exemple "height.crater"), DisplayName et Category.
  3. Ajoutez des champs publics avec [ToolSetting("Label", ...)] pour les options que l’utilisateur peut modifier.
  4. Redéfinissez ApplyDab : calculez les poids du pinceau avec BrushUtility.ComputeWeights, appelez ctx.Record(layers, cells) avant de modifier les données, modifiez les données, puis appelez ctx.MarkChanged(layers, cells) après.
  5. Revenez dans Unity. Une fois le script compilé, l’outil apparaît dans son onglet.
  6. Si l’outil doit faire partie d’un build dont le paramètre Managed Stripping Level est supérieur à Minimal, marquez la classe avec [UnityEngine.Scripting.Preserve] afin que l’élagage du code la conserve (voir Élagage du code et outils personnalisés).
using RTSTerrainStudio;
using UnityEngine;

// A custom tool: every click digs a crater and paints scorched ground into it.
// No registration is needed. The class is found by reflection and appears in the Height tab
// of the RTS Terrain Studio window and of the in-game editor, with a UI for every [ToolSetting].
public sealed class CraterTool : RTSTool
{
    // Unique id. The part before the dot also picks a fallback icon ("height" = height tools).
    public override string Id => "height.crater";
    public override string DisplayName => "Crater";
    public override ToolCategory Category => ToolCategory.Height;
    public override string Description => "Digs a crater with a scorched floor at the click position.";
    public override string Hint => "Click: dig a crater | Shift+click: raise a mound";
    public override int Order => 100;                                   // after the built-in height tools
    public override ToolInputMode InputMode => ToolInputMode.Click;     // one dab per click
    public override bool UsesBrush => true;                             // keep the brush size / shape panel
    public override MapLayers ModifiedLayers => MapLayers.Heights | MapLayers.Splat;
    public override Color PreviewColor => new Color(1f, 0.45f, 0.1f, 1f);

    // Public fields with [ToolSetting] get a slider, toggle or palette automatically.
    [ToolSetting("Depth", Min = 0.1f, Max = 6f, Order = 0, Tooltip = "Depth of the crater centre in metres.")]
    public float depth = 1.5f;

    [ToolSetting("Paint Floor", Order = 1, Tooltip = "Paint a ground layer into the crater.")]
    public bool paintFloor = true;

    [ToolSetting("Floor Layer", Kind = ToolSettingKind.GroundLayer, Order = 2, Tooltip = "Ground layer of the crater floor.")]
    public int floorLayer = 0;

    public override void ApplyDab(RTSToolContext ctx, in BrushDab dab)
    {
        MapData map = ctx.Map;

        // 1. Brush weights (0-1) for every vertex under the brush. Shape, hardness, falloff and
        //    rotation are already applied; strength is not (use dab.strength). Dispose the result.
        using BrushWeights w = BrushUtility.ComputeWeights(map, dab, ctx.BrushMask, BrushGrid.Vertices, 1);
        if (w.IsEmpty) return;
        // Cells touched by the dab (covers both the vertex and the splat texel grid).
        RectInt cells = BrushUtility.GetCellRect(map, dab);

        // 2. Record for undo BEFORE changing anything. Record every layer you are going to write.
        MapLayers layers = paintFloor ? MapLayers.Heights | MapLayers.Splat : MapLayers.Heights;
        ctx.Record(layers, cells);

        // 3. Change the data. Shift (dab.invert) raises a mound instead.
        float delta = depth * dab.strength * (dab.invert ? 1f : -1f);
        for (int z = w.rect.yMin; z < w.rect.yMax; z++)
        for (int x = w.rect.xMin; x < w.rect.xMax; x++)
        {
            float weight = w[x, z];
            if (weight <= 0f) continue;
            int i = map.VertexIndex(x, z);
            map.Heights[i] = TerrainToolUtility.ClampFineHeight(map, map.Heights[i] + delta * weight);
        }

        if (paintFloor && !dab.invert)
        {
            // The splat maps use their own texel grid: compute weights for it as well.
            int res = map.SplatResolution;
            using BrushWeights sw = BrushUtility.ComputeWeights(map, dab, ctx.BrushMask, BrushGrid.Texels, res);
            var splat = new SplatRaster(map);
            int layer = Mathf.Clamp(floorLayer, 0, MapData.MaxGroundLayers - 1);
            for (int z = sw.rect.yMin; z < sw.rect.yMax; z++)
            for (int x = sw.rect.xMin; x < sw.rect.xMax; x++)
            {
                int target = Mathf.RoundToInt(sw[x, z] * SplatMath.Total);
                int index = splat.Index(x, z);
                SplatTexel t = splat.Read(index);
                if (t[layer] >= target) continue;
                SplatMath.SetLayerWeight(ref t, layer, target, 0);
                splat.Write(index, t);
            }
        }

        // 4. Notify the terrain AFTER the change (the same rectangle you recorded).
        ctx.MarkChanged(layers, cells);
    }
}

Ce que vous pouvez redéfinir

MembrePar défautDescription
Id, DisplayName, CategoryobligatoireId unique, nom affiché dans l’interface et onglet (Height, Cliffs, Paint, Vegetation, Decor, Water, Pathing, Markers).
Description, Hint""Info-bulle et texte d’aide ; indication d’utilisation dans la barre d’état.
IconNameIdNom de l’icône. Pour un nom inconnu, c’est l’icône du préfixe de groupe de l’id (height., paint.…) qui est utilisée, puis, à défaut, une clé à molette générique. Vous pouvez ajouter vos propres dessins d’icônes avec RTSIcons.RegisterIcon.
Order0Position dans la catégorie.
InputModeBrushBrush : empreintes le long du trajet du pointeur (selon l’espacement du pinceau). Click : une empreinte par appui. Drag : OnDragBegin / OnDragUpdate / OnDragEnd (rectangles, lignes).
UsesBrushtrue pour BrushAffiche le panneau du pinceau (taille, forme, intensité…).
RepeatRate0Empreintes par seconde tant que le bouton reste enfoncé sans que le pointeur bouge (pour élever ou abaisser en continu).
ModifiedLayersNoneÀ titre informatif : utilisé par les superpositions et la barre d’état.
PreviewColorbleu clairCouleur du curseur de pinceau projeté.
SnapNoneAligne le centre du pinceau sur les vertices (outils de falaise) ou sur les centres des cellules.
SupportsPick + OnPickfalseCtrl+clic prélève une valeur (une hauteur, un calque) au lieu de peindre.
OnActivated, OnDeactivated, OnSettingChangedCallbacks du cycle de vie.
OnStrokeBegin, OnStrokeEnd, OnStrokeCancelledAppelées au début et à la fin d’un trait ; les modifications d’un trait annulé (Esc) sont ensuite défaites.
DrawGizmos(ctx, gizmos, hasHover, hoverLocal)Aperçus supplémentaires via IToolGizmos ; cette interface est implémentée avec Handles dans l’éditeur et avec des lignes GL en jeu.
GetStatus(ctx, hoverLocal)nullTexte de la barre d’état, par exemple « Level 3 → 4 ».

[ToolSetting] accepte Min/Max (plage du curseur), Order, Tooltip et Kind. Avec Auto, le contrôle est choisi d’après le type du champ (curseur pour float/int, case à cocher pour bool, liste déroulante pour enum, Color, string). Types spéciaux : GroundLayer et CliffType (palettes du tileset avec miniatures), CliffLevel, DetailPrototype / DetailPrototypeList, TreePrototype / TreePrototypeList, DecorPrototype / DecorPrototypeList (palettes de bibliothèque), Player (0–15) et Hidden.

Les paramètres Hidden n’apparaissent pas dans les interfaces de paramètres génériques, à une exception près : dans la fenêtre de l’éditeur Unity, un champ Hidden dont le type est un UnityEngine.Object (une référence d’asset comme AutoPaintTool.profile) est tout de même affiché sous forme de champ d’objet, car les interfaces génériques n’ont pas d’autre moyen d’afficher des références d’assets. L’éditeur en jeu, lui, ne l’affiche pas. Un paramètre masqué est néanmoins enregistré avec les autres paramètres de l’outil.

Bon à savoir

  • La symétrie est automatique. ApplyDab est appelée une fois pour chaque copie symétrique ; dab.symmetry vous indique de quelle copie il s’agit (avec son décalage de lacet et l’indication d’une éventuelle mise en miroir). dab.rotation est déjà transformée.
  • L’empreinte (BrushDab) contient localPosition, worldPosition, radius, strength, rotation, invert (Shift enfoncée), isFirstDab et dabIndex.
  • Poids du pinceau : BrushGrid.Vertices avec une résolution de 1 pour les couches par vertex, BrushGrid.Texels avec map.SplatResolution, DetailResolution ou PathingResolution pour les couches raster. Convertissez les rectangles avec BrushUtility.VertexRectToCellRect, TexelRectToCellRect ou GetCellRect(map, dab). Libérez toujours les poids.
  • Les valeurs aléatoires doivent être identiques pour toutes les copies symétriques d’une empreinte. ctx.Random reçoit une nouvelle graine à chaque trait et avance à chaque appel : une copie qui l’appelle obtient donc une autre valeur que l’original. Tirez les valeurs aléatoires uniquement quand dab.symmetry.index == 0, mettez-les en cache pour ce dab.dabIndex et réutilisez-les pour les autres copies en les reflétant ou en les faisant pivoter avec SymmetricScatter.TransformOffset et SymmetryPoint.TransformYaw. La classe publique SymmetricScatter (GetCandidates, GetSingleSeed) s’en charge pour vous.
  • Sélection stricte : pour des modifications en tout-ou-rien dans le style des RTS classiques, faites dériver votre outil de CliffTool, WaterTargetTool ou PathingTool (ces classes fournissent la catégorie, la couleur du curseur et le texte d’état ; WaterTargetTool ajoute aussi les paramètres Water Height et le prélèvement par Ctrl+clic), ou appelez TerrainToolUtility.BeginHardVertexSelection(ctx, dab, layers, out weights, out forcedIndex, out cells). Les vertices dont le poids vaut au moins TerrainToolUtility.HardSelectionThreshold (0.5), ainsi que le vertex situé sous le centre du pinceau (forcedIndex), sont modifiés, et l’annulation n’est enregistrée que pour cette zone. Libérez weights même lorsque la méthode renvoie false.
  • Performances : les outils intégrés exécutent leurs boucles dans des jobs Burst (voir RaiseLowerTool et PaintLayerTool dans Runtime/Tools). De simples boucles suffisent pour les petits pinceaux.
  • Une classe marquée [HideTool] n’est pas enregistrée du tout : elle est absente des deux éditeurs et de session.Tools, si bien que SetActiveTool, RTSEditorContext.ActivateTool et FindTool ne la trouvent pas. Pour utiliser un tel outil (par exemple un outil de débogage) par le code, assignez directement une instance : session.ActiveTool = new MyDebugTool();. Dans l’éditeur Unity, réglez aussi RTSEditorContext.EditingEnabled = true.
  • Le registre ne parcourt que l’assembly d’exécution du package et les assemblies qui la référencent, directement ou par l’intermédiaire d’une autre assembly de ce type. Un outil dérive toujours de RTSTool : son assembly référence donc de toute façon l’assembly d’exécution (les scripts sans définition d’assembly se trouvent dans Assembly-CSharp, qui la référence automatiquement). Le registre ignore les assemblies dont le nom commence par System, Unity., UnityEngine, UnityEditor, Mono., mscorlib, netstandard ou nunit. Ne donnez pas un tel nom à votre propre assembly.
  • Élagage du code : les outils sont créés par réflexion ; un build dont le paramètre Managed Stripping Level est supérieur à Minimal ne peut donc pas détecter qu’ils sont utilisés. Le fichier Runtime/link.xml du package conserve les outils intégrés ; marquez les vôtres avec [UnityEngine.Scripting.Preserve] ou listez-les dans un fichier link.xml de votre projet (voir Élagage du code et outils personnalisés).
  • Activez un outil par le code avec session.SetActiveTool("height.crater") ou, dans l’éditeur, avec RTSEditorContext.ActivateTool("height.crater").

Piloter la session par le code

Le pinceau, la symétrie et les traits des deux éditeurs passent par une RTSEditSession. Vous pouvez utiliser la même API pour créer votre propre front-end, par exemple une interface de peinture personnalisée, un tutoriel qui peint à la place du joueur ou un script propre à une carte.

MembreDescription
BrushSettings BrushLe pinceau partagé : shape, customShape, radius, strength, hardness, useFalloffCurve, falloffCurve, rotation, randomRotation, spacing, jitter. Appelez Brush.MarkDirty() après avoir modifié par le code les clés de falloffCurve : le masque de pinceau précalculé détecte les changements de forme, de dureté, de useFalloffCurve et de customShape, mais pas ceux des clés de la courbe.
SymmetrySettings Symmetrymode (SymmetryMode) et center (normalisé, 0.5/0.5 = centre de la carte). GetPoints(localPos, mapWorldSize, mergeDistance, results) renvoie le point d’origine et ses copies.
ScaleRadius(factor), AddStrength(delta)Ce que font les raccourcis [ ] et - =, en restant dans les plages valides.
bool InvertModifierÉquivaut à maintenir Shift enfoncée : abaisser au lieu d’élever, effacer au lieu de peindre.
BeginStroke(worldPoint), UpdateStroke(worldPoint, deltaTime), EndStroke(), CancelStroke()Un trait, de l’appui au relâchement. Appelez UpdateStroke à chaque image tant que le bouton est enfoncé (même si le pointeur ne bouge pas, pour que les outils à répétition continuent de fonctionner). EndStroke ajoute une étape d’annulation ; CancelStroke défait le trait.
Pick(worldPoint)Le prélèvement par Ctrl+clic de l’outil actif.
FindTool(id), FindTool<T>(), GetTools(category), SetActiveTool(id), ActiveToolRecherche et activation des outils.
ActiveToolChanged, StrokeEnded, UndoRedoPerformed, SelectionChangedÉvénements pour votre interface : l’outil actif a changé, un trait est terminé (non déclenché pour les traits annulés), une annulation ou un rétablissement a eu lieu, la sélection de décors a changé.
using RTSTerrainStudio;
using UnityEngine;

// Paints with the built-in tools from your own code, for example from a custom UI.
// Call PressAt / DragTo / Release with world positions on the terrain (for example from terrain.Raycast).
public class SessionDriverExample : MonoBehaviour
{
    public RTSTerrain terrain;
    RTSEditSession session;

    void OnEnable()
    {
        // In a scene with the in-game editor you can use RTSRuntimeEditor.Session instead.
        session = new RTSEditSession();
        session.Terrain = terrain;

        // Brush and symmetry are shared by every tool of this session.
        session.Brush.radius = 8f;
        session.Brush.strength = 0.6f;
        session.Symmetry.mode = SymmetryMode.Rotate2;          // 1v1 point symmetry
        session.Symmetry.center = new Vector2(0.5f, 0.5f);     // map centre

        session.SetActiveTool("height.raise");
        session.StrokeEnded += () => Debug.Log("Stroke finished (one undo step)");
    }

    void OnDisable()
    {
        session?.Dispose();
        session = null;
    }

    public void PressAt(Vector3 worldPoint, bool lower)
    {
        session.InvertModifier = lower;      // like holding Shift
        session.BeginStroke(worldPoint);
    }

    // Call every frame while the button is held.
    public void DragTo(Vector3 worldPoint) => session.UpdateStroke(worldPoint, Time.deltaTime);

    public void Release() => session.EndStroke();

    public void Abort() => session.CancelStroke(); // reverts the running stroke

    public void UseLinearFalloff()
    {
        session.Brush.useFalloffCurve = true;
        session.Brush.falloffCurve = AnimationCurve.Linear(0f, 1f, 1f, 0f);
        // Curve keys are not detected automatically: rebuild the baked brush mask.
        session.Brush.MarkDirty();
    }
}

Événements

ÉvénementSignatureDéclenchement
MapLoadedAction<RTSTerrain>Après l’assignation d’une nouvelle carte (chargement, nouvelle carte, redimensionnement, reconstruction). Reconstruisez tout ce que vous calculez à partir de la carte.
MapUnloadingAction<RTSTerrain>Avant que la carte actuelle soit remplacée ou libérée. Supprimez ici vos références à cette carte.
MapChangedAction<RTSTerrain, MapChangeEventArgs>Immédiatement lors de l’appel à NotifyChanged / NotifyChangedAll, avant la reconstruction des meshes. MapChangeEventArgs contient Layers, CellRect et IsFullRefresh. Déclenché souvent pendant les traits : veillez à ce que vos gestionnaires restent légers.
ChangesProcessedAction<RTSTerrain, IReadOnlyList<DirtyRegion>>Après le traitement des modifications en attente : les meshes, les textures et le cheminement sont à jour. Chaque DirtyRegion contient layers et cellRect.
PathingChangedAction<RTSTerrain, RectInt>Après la reconstruction (partielle) de la carte de cheminement ; le rectangle est exprimé en cellules de cheminement. Survit aux rechargements de carte (contrairement à PathingMap.Changed).
TilesetChangedAction<RTSTerrain>La référence au tileset ou son contenu a changé.
LibrariesChangedAction<RTSTerrain>La référence à une bibliothèque de végétation ou de décors, ou son contenu, a changé.
RTSTerrain.TerrainEnabled / TerrainDisabledstatic Action<RTSTerrain>Un terrain a été activé ou désactivé (modifications du registre).
RTSRuntimeEditorEvents.PlaytestChangedstatic Action<bool>L’éditeur en jeu a démarré ou arrêté un test en jeu. Faites apparaître et supprimez ici vos objets de gameplay ; la carte est restaurée une fois le test terminé.
RTSRuntimeEditorEvents.MapOpenedstatic Action<RTSTerrain>L’éditeur en jeu a ouvert une carte.
RTSEditSession : ActiveToolChanged, TerrainChanged, StrokeEnded, UndoRedoPerformed, SelectionChangedÉtat d’édition d’une session (éditeur ou éditeur en jeu).
using System.Collections.Generic;
using RTSTerrainStudio;
using UnityEngine;

// Listens to all important terrain events. Put it on the RTS Terrain GameObject (or assign the terrain).
public class TerrainEventsExample : MonoBehaviour
{
    [SerializeField] RTSTerrain terrain;

    void OnEnable()
    {
        if (terrain == null) terrain = GetComponent<RTSTerrain>();
        if (terrain == null) return;
        terrain.MapLoaded += OnMapLoaded;               // new map assigned (load, new map, resize)
        terrain.MapChanged += OnMapChanged;             // immediately when NotifyChanged is called
        terrain.ChangesProcessed += OnChangesProcessed; // after meshes, textures and pathing are up to date
        terrain.PathingChanged += OnPathingChanged;     // after the pathing map was rebuilt
        terrain.TilesetChanged += OnTilesetChanged;     // tileset reference or content changed

        // The map may already be loaded before this component was enabled.
        if (terrain.Map != null) OnMapLoaded(terrain);
    }

    void OnDisable()
    {
        // Always unsubscribe: terrains survive scene changes in the editor and domain reloads.
        if (terrain == null) return;
        terrain.MapLoaded -= OnMapLoaded;
        terrain.MapChanged -= OnMapChanged;
        terrain.ChangesProcessed -= OnChangesProcessed;
        terrain.PathingChanged -= OnPathingChanged;
        terrain.TilesetChanged -= OnTilesetChanged;
    }

    void OnMapLoaded(RTSTerrain t)
    {
        // Rebuild everything your game derives from the map, e.g. spawn points from start locations.
        Debug.Log($"Map '{t.Map.Info.name}' loaded: {t.Map.Width} x {t.Map.Height} cells, " +
                  $"{t.Map.StartLocations.Count} start locations.");
    }

    void OnMapChanged(RTSTerrain t, MapChangeEventArgs e)
    {
        // Raised often during brush strokes: keep it cheap. Check which layers changed.
        if ((e.Layers & (MapLayers.Trees | MapLayers.Decor)) != 0)
            Debug.Log($"Objects changed in cells {e.CellRect} (full refresh: {e.IsFullRefresh})");
    }

    void OnChangesProcessed(RTSTerrain t, IReadOnlyList<DirtyRegion> regions)
    {
        // Meshes are rebuilt now, so GetHeight and Raycast return the new surface.
        foreach (DirtyRegion r in regions)
            if ((r.layers & MapLayers.Geometry) != 0)
                Debug.Log($"Ground changed in cells {r.cellRect}");
    }

    void OnPathingChanged(RTSTerrain t, RectInt pathingRect)
    {
        // The rectangle is in pathing cells (Map.PathingResolution per map cell). Re-plan paths here.
        Debug.Log($"Pathing changed in {pathingRect}");
    }

    void OnTilesetChanged(RTSTerrain t)
    {
        Debug.Log("Tileset is now " + (t.Tileset != null ? t.Tileset.name : "none"));
    }
}

Enregistrement et chargement à l’exécution, sections de fichier personnalisées

Les cartes sont des fichiers .rtsmap. Le même format est utilisé par l’éditeur Unity (qui les importe en tant que RTSMapAsset), par l’éditeur en jeu et par le streaming de carte de Mirror : une carte créée par un joueur s’ouvre donc telle quelle dans Unity, et inversement.

MembreDescription
terrain.SaveToFile(path) / terrain.LoadFromFile(path)Enregistrement et chargement à l’exécution. Les deux définissent CurrentFilePath ; l’enregistrement réinitialise HasUnsavedChanges.
terrain.MapAsset, terrain.LoadFromAsset()Utilise une carte importée dans le projet (cartes de campagne, cartes d’escarmouche intégrées).
terrain.SetMap(MapData)Affiche n’importe quel objet MapData. Le terrain en devient propriétaire et libère la carte précédente.
RTSMapSerializer.Serialize(map) / Deserialize(bytes)Cartes sous forme d’octets (réseau, sauvegardes dans le cloud, téléchargements de mods). Une carte désérialisée appartient à l’appelant.
RTSMapSerializer.SaveToFile, LoadFromFile, Write(map, stream), Read(stream)Accès aux fichiers et aux flux sans terrain.
RTSMapSerializer.TryReadHeaderFromFile(path, out header)Lit uniquement le petit en-tête (nom, auteur, description, taille, taille de cellule, nombre maximal de joueurs, id du tileset, date de modification), pour les explorateurs de cartes.
RTSMapSerializer.DefaultMapsFolder, FileExtensionLe dossier Maps situé dans StorageRoot (utilisé par l’éditeur en jeu, sauf si son paramètre Maps Folder est défini) et ".rtsmap".
RTSMapSerializer.StorageRootLe dossier des fichiers conservés d’une session à l’autre : Application.persistentDataPath. Dans les builds Web, il s’agit d’un dossier du stockage du navigateur, nommé d’après le nom de l’entreprise et le nom du produit, car persistentDataPath y change avec l’adresse de la page.
RTSWebFileSystem.Flush(), DownloadFile(...), IsSupportedBuilds Web : écrivent les fichiers modifiés dans le stockage du navigateur pour qu’ils soient conservés après un rechargement de la page, et font télécharger un fichier par le navigateur. RTSMapSerializer.SaveToFile et terrain.SaveToFile s’en chargent pour vous ; appelez Flush() après vos propres écritures et suppressions effectuées avec System.IO. Sur les autres plateformes, ces méthodes ne font rien. Voir API de script pour les builds Web.
using System.Collections.Generic;
using System.IO;
using RTSTerrainStudio;
using UnityEngine;

// Saving, listing and loading maps at runtime (for example for your own map browser or a save game).
public static class MapFilesExample
{
    // The folder the in-game editor uses too: Maps in RTSMapSerializer.StorageRoot.
    static string Folder => RTSMapSerializer.DefaultMapsFolder;

    public static void Save(RTSTerrain terrain, string fileName)
    {
        // SaveToFile creates the folder when needed and remembers the path in terrain.CurrentFilePath.
        terrain.SaveToFile(Path.Combine(Folder, fileName + RTSMapSerializer.FileExtension));
    }

    public static void Load(RTSTerrain terrain, string fileName)
    {
        string path = Path.Combine(Folder, fileName + RTSMapSerializer.FileExtension);
        if (File.Exists(path)) terrain.LoadFromFile(path); // raises MapLoaded
    }

    // Lists all maps with their header (name, size, players) without loading the whole file.
    public static List<RTSMapHeader> ListMaps()
    {
        var result = new List<RTSMapHeader>();
        if (!Directory.Exists(Folder)) return result;
        foreach (string path in Directory.GetFiles(Folder, "*" + RTSMapSerializer.FileExtension))
            if (RTSMapSerializer.TryReadHeaderFromFile(path, out RTSMapHeader header))
                result.Add(header);
        return result;
    }

    // Maps can also travel as bytes (network, cloud save, mod download).
    public static byte[] ToBytes(RTSTerrain terrain) => RTSMapSerializer.Serialize(terrain.Map);

    public static void FromBytes(RTSTerrain terrain, byte[] bytes)
    {
        // The terrain takes ownership of the new MapData and disposes the previous map.
        terrain.SetMap(RTSMapSerializer.Deserialize(bytes));
    }

    // Loads a .rtsmap that was imported into the project (an RTSMapAsset), e.g. for a campaign.
    public static void LoadAsset(RTSTerrain terrain, RTSMapAsset asset)
    {
        // Assigning a different asset loads it immediately (when the terrain is enabled).
        // Assigning the same asset again does nothing, so reload it explicitly.
        if (terrain.MapAsset == asset) terrain.LoadFromAsset();
        else terrain.MapAsset = asset;
    }
}

Structure du fichier et sections personnalisées

"RTSM"            4 bytes magic
int32             format version (RTSMapSerializer.CurrentVersion = 1)
int32 + bytes     uncompressed header (RTSMapHeader)
deflate stream    sections: [int32 tag][int32 length][payload] ...
                  (built-in sections first, then the CustomSectionWriter sections)
                  int32 0  end marker

À la lecture, les sections inconnues sont ignorées : vous pouvez donc stocker vos propres données dans un fichier de carte (déclencheurs, ressources de départ, données de quête), et les versions plus anciennes ou d’autres outils pourront toujours lire la carte. Abonnez-vous à RTSMapSerializer.CustomSectionWriter pour ajouter des sections lors de l’enregistrement, et à RTSMapSerializer.CustomSectionReader pour recevoir chaque section inconnue lors du chargement. Utilisez des étiquettes qui commencent par 'X', afin qu’elles n’entrent jamais en collision avec les sections intégrées. L’étiquette 0 est réservée : elle marque la fin des sections.

Chaque système doit utiliser une étiquette 'X…' unique qui lui est propre, car CustomSectionReader est appelé pour chaque section inconnue. Si deux gestionnaires d’écriture émettent la même étiquette avec des données différentes, un gestionnaire de lecture reçoit des données qu’il ne comprend pas, et le chargement de la carte échoue. Par exemple, StartingGoldSection dans Sections personnalisées utilise XGLD ; l’exemple ci-dessous utilise donc XGMD.

using System.IO;
using System.Runtime.CompilerServices;
using RTSTerrainStudio;
using UnityEngine;

// Stores your own game data (here: starting gold and a victory text) inside the .rtsmap file.
// Older versions of the package and other games simply skip the unknown section.
public static class MapGameData
{
    public sealed class Data
    {
        public int startingGold = 500;
        public string victoryText = "";
    }

    // Section tag "XGMD" as a little-endian FourCC. Start your tags with 'X' so they never
    // collide with the built-in sections, and use a tag no other script of your project uses.
    const int Tag = 'X' | ('G' << 8) | ('M' << 16) | ('D' << 24);
    // Bump this when you change the payload layout, and keep reading the old layouts.
    const int PayloadVersion = 1;

    // One Data object per MapData instance. The table does not keep maps alive.
    static readonly ConditionalWeakTable<MapData, Data> s_Data = new ConditionalWeakTable<MapData, Data>();

    // Returns the game data of a map (created with defaults on first access).
    public static Data Get(MapData map) => s_Data.GetValue(map, _ => new Data());

    // Registers the hooks before any scene loads (play mode and builds) and, in the editor,
    // after every script reload, so maps saved from the RTS Terrain Studio window keep the data too.
#if UNITY_EDITOR
    [UnityEditor.InitializeOnLoadMethod]
#endif
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
    static void Register()
    {
        // Remove first, so entering play mode without a domain reload never registers twice.
        RTSMapSerializer.CustomSectionWriter -= Write;
        RTSMapSerializer.CustomSectionWriter += Write;
        RTSMapSerializer.CustomSectionReader -= Read;
        RTSMapSerializer.CustomSectionReader += Read;
    }

    // Called while a map is saved: hand every section you want to write to addSection(tag, payload).
    static void Write(MapData map, System.Action<int, byte[]> addSection)
    {
        if (!s_Data.TryGetValue(map, out Data data)) return; // nothing set: write no section
        using var stream = new MemoryStream();
        using (var w = new BinaryWriter(stream))
        {
            w.Write(PayloadVersion);
            w.Write(data.startingGold);
            w.Write(data.victoryText ?? "");
        }
        addSection(Tag, stream.ToArray());
    }

    // Called for every section the serializer does not know. Ignore tags that are not yours,
    // other scripts may have registered readers too.
    static void Read(MapData map, int tag, byte[] payload)
    {
        if (tag != Tag) return;
        using var r = new BinaryReader(new MemoryStream(payload));
        int version = r.ReadInt32();
        var data = Get(map);
        data.startingGold = r.ReadInt32();
        if (version >= 1) data.victoryText = r.ReadString();
    }
}
Dans cet exemple, les données appartiennent à un seul objet MapData. Les opérations qui créent un nouvel objet de carte (chargement, redimensionnement, Clone) ne les transfèrent pas automatiquement : relisez-les depuis le fichier, ou copiez-les vous-même dans votre code lorsque vous clonez ou redimensionnez une carte.

Foire aux questions (FAQ)

Tout est rose (magenta). Que se passe-t-il ?

Le rose signifie qu’un shader n’a pas pu être utilisé. RTS Terrain Studio utilise des shaders écrits à la main, conçus uniquement pour l’Universal Render Pipeline.

  1. Ouvrez Tools ▸ RTS Terrain Studio ▸ Validate Project. La vérification Universal Render Pipeline is active doit être verte ; Fix All (ou le bouton de correction de cette vérification) assigne un asset URP.
  2. Regardez aussi la vérification Package shaders compile dans la même fenêtre. Si un shader contient des erreurs, la fenêtre Console indique lequel ; réimportez le dossier Shaders du package (clic droit ▸ Reimport).
  3. Si seuls vos propres prefabs sont roses (arbres, rochers, unités), leurs matériaux utilisent des shaders du pipeline Built-in. Convertissez-les avec le convertisseur de pipeline de rendu d’Unity, ou assignez-leur des matériaux URP.

J’ai ajouté un RTS Terrain, mais rien ne s’affiche.

  • Sélectionnez le terrain et consultez son Inspector. S’il indique qu’aucune carte n’est chargée, assignez un asset de carte, créez une nouvelle carte (fenêtre ▸ onglet Map ▸ New Map) ou utilisez le New Map Wizard.
  • Vérifiez que le composant RTSTerrain est activé. Un composant désactivé décharge sa carte.
  • Vérifiez la caméra : les chunks se trouvent sur le layer défini dans les paramètres du terrain (Chunk Layer), qui doit faire partie du culling mask de la caméra. Cadrez le terrain avec F dans la Scene View : une carte de 128 cellules de côté, avec des cellules de 2 m, mesure 256 m de large.
  • Un terrain sans tileset n’est pas invisible : il s’affiche avec des couleurs de repli neutres. Assignez un tileset, ou lancez Tools ▸ RTS Terrain Studio ▸ Create Demo Content et utilisez le tileset de démo.
  • Cliquez sur Rebuild Terrain dans l’Inspector du terrain pour recréer tous les chunks, les textures et la carte de cheminement.

Le pinceau peint ailleurs que sous mon curseur.

L’éditeur utilise le rayon de la Scene View d’Unity, qui tient compte du DPI, et le curseur du pinceau est dessiné par le shader de terrain : avec une configuration ordinaire, le curseur et la peinture coïncident donc toujours, y compris avec une mise à l’échelle de l’affichage de 150 % ou plus. Si ce n’est pas le cas :

  • Le terrain ou l’un de ses parents est mis à l’échelle, ou pivoté autour de X ou Z. Seules la position et la rotation Y sont prises en compte. L’Inspector du terrain signale ces deux cas ; remettez l’échelle à 1 et la rotation X/Z à 0, et modifiez la taille de cellule de la carte au lieu de mettre le terrain à l’échelle.
  • Le terrain utilise un Material Override dont le shader ne dessine pas le curseur du pinceau. Vous peignez alors au bon endroit, mais sans voir le curseur. Utilisez le shader de terrain du package ou intégrez son code de curseur de pinceau.

Le brouillard de guerre n’est pas visible.

  • La scène doit contenir exactement un RTSFogOfWarManager (GameObject ▸ RTS Terrain Studio ▸ Fog of War Manager).
  • Lancez Tools ▸ RTS Terrain Studio ▸ Validate Project et corrigez Fog of War renderer feature. La renderer feature assombrit tout ce qui s’affiche à l’écran. Sans elle, le brouillard de guerre ne s’applique qu’aux shaders du package (terrain, eau, végétation), et non à vos propres unités ni à vos accessoires.
  • En Edit Mode, activez Preview In Edit Mode sur le gestionnaire.
  • Reveal All doit être désactivé. Start Explored fait apparaître toute la carte comme explorée (assombrie au lieu de noire).
  • Vos unités ont besoin d’un RTSFogOfWarRevealer dont l’équipe correspond à la Local Team du gestionnaire. Les révélateurs des autres équipes ne révèlent rien pour l’équipe locale : sans révélateur de cette équipe, la carte reste donc couverte (en noir par défaut).

La végétation (ou l’eau, ou le terrain) manque dans les builds, alors que tout va bien dans l’éditeur.

  • Lancez Tools ▸ RTS Terrain Studio ▸ Validate Project et corrigez Shaders included in builds. Le package conserve ses shaders dans un asset de références de shaders situé sous Resources, qui est actualisé automatiquement avant chaque build de joueur. Si vous l’avez supprimé ou déplacé, la vérification le recrée.
  • Corrigez GPU instancing on instanced prototypes : les arbres, les détails et les objets de décor instanciés ont besoin de matériaux dont l’option Enable GPU Instancing est activée.
  • Vérifiez que la carte fait partie du build : les cartes assignées sous forme de RTSMapAsset à un terrain d’une scène du build sont incluses automatiquement ; les fichiers de carte chargés depuis le disque doivent exister sur la machine du joueur (par exemple dans RTSMapSerializer.DefaultMapsFolder).
  • Le stripping de shaders ou un asset URP différent pour la plateforme cible (paramètres Quality) peut supprimer des fonctionnalités. Vérifiez que l’asset URP utilisé par le build a les mêmes paramètres que celui de l’éditeur.
  • Dans un build Web sous WebGL 2.0, un asset URP qui active de nombreuses fonctionnalités peut dépasser la limite de 16 textures par draw call, et le terrain disparaît. Consultez la remarque sur OpenGL ES et WebGL 2.0 dans Remarques pour les mobiles.
  • Brouillard atmosphérique absent des builds : voir Brouillard atmosphérique dans les builds de joueur.

L’eau paraît noire ou grise, ou n’a pas de réfraction.

  • Le shader d’eau lit la profondeur et la couleur de la scène. Activez Depth Texture et Opaque Texture sur l’asset URP : Tools ▸ RTS Terrain Studio ▸ Validate Project ▸ Depth and Opaque Texture enabled ▸ corriger.
  • Réglez Opaque Downsampling de l’asset URP sur None ; le sous-échantillonnage rend la réfraction floue.
  • Vérifiez la caméra : ses surcharges Depth Texture et Opaque Texture ne doivent pas être réglées sur Off. L’eau respecte le réglage propre à chaque caméra, et la Scene View utilise toujours celui de l’asset URP.
  • Dans un build Web, vérifiez l’asset URP du niveau de qualité utilisé par les builds Web (la vérification Web quality levels have Depth and Opaque Texture, voir Vérifications Web dans le Project Validator).
  • Les couleurs de l’eau proviennent du Water Profile du tileset. Vérifiez-y les couleurs d’eau peu profonde et d’eau profonde.

Comment obtenir les meilleures performances ?

  • Burst doit être activé (Jobs ▸ Burst ▸ Enable Compilation). Les pinceaux, le cheminement, le brouillard de guerre, le générateur et la mini-carte s’exécutent dans des jobs Burst.
  • Chunk size (paramètres du terrain) : 16, 32 (par défaut) ou 64 cellules. Les petits chunks se reconstruisent plus vite pendant l’édition ; les grands chunks réduisent le nombre de draw calls en jeu.
  • Surface Subdivisions : 1 donne l’aspect RTS classique avec le moins de triangles possible, 2–4 des collines plus douces.
  • Collider Mode réglé sur None évite de créer les mesh colliders lorsque vous utilisez uniquement l’API de requête (Raycast, GetHeight).
  • Privilégiez le mode d’apparition Instanced pour les arbres et les décors ; n’utilisez le mode GameObject que pour les objets dont votre gameplay a besoin sous forme de GameObjects (arbres récoltables, objets de décor dotés de scripts).
  • Sur du matériel moins puissant, baissez Detail Density Multiplier et Detail Distance Multiplier sur le renderer de végétation.
  • Brouillard de guerre : une valeur de 1 pour Resolution Per Cell et un Update Interval plus grand sont moins coûteux.
  • Lancez le validateur de cartes : ses avertissements de performances signalent un trop grand nombre d’arbres, d’objets de décor, d’objets en mode GameObject ou de couches de détails.

Puis-je utiliser plusieurs terrains dans une même scène ?

Oui. Chaque RTSTerrain possède sa propre carte, son tileset, ses bibliothèques et son transform. RTSTerrain.All les liste, RTSTerrain.FindAt(position) renvoie celui qui se trouve sous une position donnée et RTSTerrain.RaycastAll lance un raycast sur tous les terrains. Dans la fenêtre de l’éditeur, choisissez le terrain édité dans l’en-tête (sélectionner un terrain dans la scène fonctionne aussi) ; dans l’éditeur en jeu, utilisez Map ▸ Edited terrain. Remarques :

  • L’historique d’annulation appartient au terrain édité : changer de terrain édité l’efface.
  • Le gestionnaire du brouillard de guerre couvre un seul terrain (celui de son champ Terrain, ou RTSTerrain.Main si ce champ est vide).
  • A* nécessite, pour chaque terrain, un graph builder avec ses propres noms de graphes ; l’intégration NavMesh, un builder par terrain.

Puis-je déplacer ou faire pivoter un terrain ?

Oui : la position et la rotation Y sont entièrement prises en charge, y compris à l’exécution. Toutes les requêtes, les pinceaux, la végétation, les décors, l’eau, le cheminement, le brouillard de guerre et les intégrations suivent le transform. La rotation autour de X ou Z et la mise à l’échelle ne sont pas prises en charge (l’Inspector affiche un avertissement) ; pour agrandir une carte, utilisez Resize dans l’onglet Map ou une taille de cellule plus grande.

Fonctionne-t-il avec l’Input System, l’ancien Input Manager, ou les deux ?

Les trois options de Project Settings ▸ Player ▸ Active Input Handling fonctionnent. Le code d’exécution lit les entrées via RTSInput, qui utilise le package Input System lorsqu’il est installé et actif, et l’ancien Input Manager dans le cas contraire. La vérification Input handling de Tools ▸ RTS Terrain Studio ▸ Validate Project indique ce qu’utilise votre projet. Dans votre propre code de gameplay, vous pouvez aussi utiliser RTSInput (PointerPosition, GetMouseButtonDown, GetKey(RTSKey)…) pour qu’il fonctionne quelle que soit l’option choisie. Pour que les raccourcis associés à une lettre suivent la disposition de clavier du joueur, utilisez GetKeyDownByLabel(RTSKey) ; pour les touches de symboles comme [ ou +, utilisez GetCharacterDown(char).

Puis-je publier mon jeu ou l’éditeur en jeu dans un navigateur web ?

Oui. Les builds Web (WebGL 2.0) font tourner le terrain, la végétation, l’eau, le brouillard de guerre, l’éditeur en jeu et les exemples dans les navigateurs des ordinateurs de bureau, à la souris et au clavier. Installez le modèle pleine fenêtre avec Tools ▸ RTS Terrain Studio ▸ Install WebGL Template, puis consultez Builds Web (WebGL) pour les paramètres, le stockage des cartes dans le navigateur et les remarques sur l’hébergement.

Puis-je déplacer le package dans un autre dossier ?

Oui. Rien ne dépend d’un chemin fixe : le package trouve ses fichiers par rapport à son propre emplacement.

Dépannage

Parcourez cette liste de vérification de haut en bas : la plupart des problèmes se règlent dès les trois premières étapes.

  1. Consultez la fenêtre Console. Les messages du package commencent par [RTS Terrain Studio] et sont liés à l’objet qu’ils concernent (cliquez sur le message pour le sélectionner). Corrigez d’abord les erreurs de compilation : tant qu’un script ne compile pas, rien d’autre n’est mis à jour.
  2. Validez le projet. Tools ▸ RTS Terrain Studio ▸ Validate Project vérifie l’URP, la Depth Texture et l’Opaque Texture, la renderer feature du brouillard de guerre, les modes de brouillard atmosphérique conservés dans les builds, l’espace colorimétrique, Burst/Collections/Mathematics, la gestion des entrées, la compilation des shaders, les shaders dans les builds, les tableaux de textures des tilesets, l’instanciation GPU, les terrains dotés d’un tileset et les terrains qui enregistrent dans des fichiers de carte, ainsi que, lorsque Web est la plateforme active, les niveaux de qualité Web et le modèle Web. Cliquez sur Fix All (une boîte de dialogue liste d’abord chaque modification), puis sur Run Again.
  3. Vérifiez l’Inspector du terrain. Une carte est-elle chargée, un tileset assigné, le composant activé ? Y a-t-il des avertissements concernant l’échelle ou la rotation ? Cliquez sur Rebuild Terrain.
  4. Validez la carte. Onglet Map ▸ Validation ▸ Validate Map détecte les prototypes manquants, la peinture défectueuse, les positions de départ inaccessibles et les problèmes de performances.
  5. Vérifiez le contenu. Des textures, des plantes ou des décors manquants signifient généralement qu’un tileset ou une bibliothèque n’est pas assigné, ou qu’un id de prototype de la carte n’existe pas dans la bibliothèque. Relancer Tools ▸ RTS Terrain Studio ▸ Create Demo Content restaure les assets de démo.
  6. Vérifiez les intégrations. Des erreurs de compilation dans Integrations après la suppression de Mirror signifient que le symbole MIRROR est toujours défini (Supprimer Mirror). Si une intégration est marquée Installed mais pas Active dans la fenêtre Welcome, sa version ne correspond pas à la version requise.
  7. Le Play Mode sans rechargement du domaine est pris en charge. Si quelque chose se comporte différemment après le deuxième Play, activez une fois le rechargement du domaine pour voir si votre propre état statique en est la cause.
  8. Toujours bloqué ? Reproduisez le problème dans une nouvelle scène, avec un terrain créé via GameObject ▸ RTS Terrain Studio ▸ RTS Terrain et le contenu de démo, puis indiquez la version d’Unity, la version de l’URP, la sortie de la fenêtre Console et les étapes de reproduction lorsque vous demandez de l’aide.
SymptômeCause probableVoir
Matériaux rosesURP inactif, erreurs de shader, matériaux Built-in sur vos prefabsFAQ
Terrain invisibleAucune carte chargée, composant désactivé, layer des chunks exclu par le cullingFAQ
Le pinceau agit à côté du curseurTerrain mis à l’échelle ou rotation X/ZFAQ
Pas de brouillard de guerreRenderer feature manquante, aucun révélateur de l’équipe locale, Reveal All activéFAQ
Eau noireDepth / Opaque Texture désactivéesFAQ
Végétation absente des buildsRéférences de shaders, instanciation GPUFAQ
Les unités ne bougent pasCarte de cheminement pas encore construite, départ ou destination non praticable, fournisseur sans graphe ni NavMeshValidation des cartes, Intégrations
Le générateur place moins de positions de départPas assez d’espace plat pour Flat Radius / Edge MarginParamètres du générateur
L’import de heightmap donne un terrain plat ou extrêmeÉchelle de hauteur à 0 dans le code, taille RAW ou ordre des octets incorrectsImport et export de heightmaps
Erreurs de compilation liées à Mirror après sa suppressionSymbole MIRROR obsolète encore définiSupprimer des intégrations
Boîte de dialogue RTS Terrain Studio requires URPURP 17.3 n’est pas installé, ou l’éditeur est antérieur à Unity 6.3Unity et pipeline de rendu
Build Web : interface minuscule, cartes perdues, touches qui ouvrent des fonctions du navigateurModèle de taille fixe, stockage du navigateur, raccourcis du navigateurBuilds Web (WebGL)

Historique des versions

Version 1.0.0 — Première version

Nécessite Unity 6.3 LTS (6000.3) et l’Universal Render Pipeline 17.3, avec Burst, Collections et Mathematics.

Modèle de carte

  • Grille de cellules et de vertices de coin dans le style des RTS classiques, de 16 à 1024 cellules par côté (multiples de 16), taille de cellule libre.
  • 16 niveaux de falaise avec des parois de falaise arrondies, générées de façon procédurale ; hauteur fine au-dessus de chaque niveau ; rampes ; 4 types de falaise par tileset.
  • 16 calques de sol par tileset dans des splat maps haute résolution, fondu par hauteur, projection triplanaire et anti-tiling optionnels ; textures de toute taille et de tout format.
  • Eau par vertex, avec eau peu profonde et eau profonde.
  • Carte de cheminement (praticable, constructible, survolable, eau peu profonde et profonde) déduite automatiquement, complétée par des surcharges peintes.
  • Régions, positions de départ, marqueurs, informations de la carte et éclairage d’environnement stockés dans la carte.

Édition

  • Un seul jeu d’outils pour l’éditeur Unity et l’éditeur en jeu : hauteur, falaises, peinture (douce, par tuile, remplissage, peinture automatique), végétation, décor, eau, cheminement et marqueurs.
  • Pinceaux en forme de cercle, de carré, de losange et de tampon de texture, avec courbe d’atténuation, rotation, espacement et décalage aléatoire ; peinture symétrique (miroir X/Z, 4 directions, rotation d’ordre 2 et 4).
  • Annulation et rétablissement avec budget mémoire, intégrés au système d’annulation d’Unity.
  • Fenêtre RTS Terrain Studio ancrable, intégration à la Scene View avec curseur de pinceau projeté et overlays, inspecteurs et importeurs personnalisés pour tous les assets, fenêtre Welcome, New Map Wizard et validateur de projet.
  • Éditeur en jeu construit avec UI Toolkit : barre d’outils, panneaux d’outils et de pinceaux, palettes, explorateur de cartes, raccourcis clavier et test en jeu.

Outils de carte

  • Générateur de cartes procédural basé sur une graine, avec six styles, agencements symétriques, rampes, lacs et îles, bordures, peinture automatique, végétation, décor et positions de départ ; préréglages enregistrables.
  • Import (trois modes) et export de heightmaps PNG et RAW 16 bits, export d’images de splat.
  • Précalcul de la mini-carte, validateur de cartes, redimensionnement avec ancre.
  • Format binaire .rtsmap commun à l’éditeur et au jeu, avec sections personnalisées.

Systèmes d’exécution

  • Meshes de terrain découpés en chunks et construits dans des jobs Burst, mesh colliders optionnels et API de requête sans physique.
  • Végétation à instanciation GPU, avec vent et culling ; arbres sous forme d’instances ou de GameObjects.
  • Rendu de l’eau avec couleur selon la profondeur et réfraction ; gestionnaire de décors pour n’importe quel prefab.
  • Brouillard de guerre des RTS classiques : visibilité par équipe, mémoire des zones explorées, ligne de vue bloquée par les falaises et les bloqueurs, vision partagée, prise en charge de la mini-carte.
  • Module de recherche de chemin A* intégré, compilé avec Burst, avec tailles d’unités tenant compte du dégagement et lissage des chemins.
  • Exemples : caméra RTS, sélection, ordres de déplacement avec formations, unités de test, interface de mini-carte, scènes de démo et contenu de démo généré.

Plateformes

  • Shaders ciblant le Shader Model 3.5 : le package fonctionne donc aussi sous OpenGL ES 3.0 et dans les builds Web (WebGL 2.0).
  • Builds Web : cartes conservées dans le stockage du navigateur, commandes Download Map et Import Map, glisser-déposer, avertissement avant de quitter la page en cas de modifications non enregistrées, raccourcis clavier adaptés au navigateur, modèle Web pleine fenêtre et vérifications Web dans le validateur de projet.
  • Les tableaux de textures des tilesets sont reconstruits automatiquement avant les builds de joueur, selon la compression de textures du build.
  • Sans URP 17.3, le package reste inactif et explique comment installer URP, au lieu d’afficher des erreurs de compilation.

Intégrations

  • Mirror : streaming de carte avec cache, unités à autorité serveur, brouillard de guerre par équipe, gestion d’intérêt basée sur le brouillard de guerre.
  • A* Pathfinding Project Pro : graphes en grille issus de la carte de cheminement avec mises à jour incrémentales, unités AIPath et RVO.
  • Unity AI Navigation : NavMesh construit à partir du terrain et de la carte de cheminement, mises à jour incrémentales, fournisseur de chemins et mode NavMeshAgent.