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.
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 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.
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.
| Notion | Définition |
|---|---|
| Niveau de falaise | Un 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 fine | Un 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. |
| Rampe | Les 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 falaise | Le matériau des parois de falaise (par exemple des falaises rocheuses ou herbeuses). Un tileset en compte jusqu’à 4. |
| Calque de sol | Une texture de sol peinte, parmi 16 au maximum (herbe, terre, roche…), stockée dans les splat maps. |
| Eau | Une 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 arbres | De l’herbe et des fleurs peintes (densité par texel), ainsi que des arbres placés individuellement. |
| Décor | Tout prefab que vous placez sur la carte : rochers, ruines, caisses, clôtures, bâtiments. |
| Cheminement | Pour 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. |
| Marqueurs | Des 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. |
| Tileset | Un 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èques | Une 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
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.
- Ouvrez 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.
- Lancez . 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.
- Double-cliquez sur cette scène pour l’ouvrir, puis appuyez sur Play.
- 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.
- Quittez le Play Mode et ouvrez la scène RTS Terrain Studio - Editor Playground. Ouvrez , 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.
- 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 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 projet | Configuration du projet et |
| Créer ma première carte pas à pas | Démarrage rapide et |
| Découvrir la fenêtre de l’éditeur et chaque outil | Fenê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 web | Builds Web (WebGL) |
| Masquer la carte jusqu’à ce que les unités l’explorent | Brouillard de guerre |
| Utiliser Mirror, A* Pathfinding Project ou Unity NavMesh | Intégrations |
| Interroger le terrain ou écrire mes propres outils en C# | Programmation |
| Corriger un problème d’affichage ou de fonctionnement | Dé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.

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
MeshColliderfacultatif 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,IsWalkableetIsBuildable. - 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)etRTSTerrain.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/Vegetationajoute 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/Waterpropose 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 duWaterProfiledu 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
(
LineOfSightModeet l’optionblocksVisiond’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
RTSFogOfWarRevealerrévèlent la carte, et les objets dotés deRTSFogOfWarHideablesont 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 . 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.persistentDataPathet, 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’APIUnityEditor: 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.
RTSDemoGamemet tout cela en place sur n’importe quel terrain doté de positions de départ. Ajoutez-le avec .
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égration | Ce 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 Project | Des 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 (sous macOS, ).
- 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.rtsmapaffiche 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.MeshDataArraydans 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 utilisentGraphics.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.
| Question | Ré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
| Exigence | Version | Remarques |
|---|---|---|
| Unity | 6.3 LTS (6000.3) ou plus récent | Développé et testé avec 6000.3.3f1. |
| Universal Render Pipeline | 17.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étrique | Linear | L’espace Gamma fonctionne, mais les couleurs, l’éclairage et l’eau paraissent alors délavés. |
| Matériel graphique | Shader Model 3.5 ou supérieur | Les 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 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 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 (). La fenêtre détecte les packages manquants et les installe en un clic (vérification Burst, Collections and Mathematics).
| Package | Nom | Version testée | Sert à |
|---|---|---|---|
| Burst | com.unity.burst | 1.8.27 | Compiler les jobs en code natif rapide. |
| Collections | com.unity.collections | 2.6.2 | Fournir des conteneurs natifs pour les données de carte et les jobs. |
| Mathematics | com.unity.mathematics | 1.3.3 | Effectuer les calculs vectoriels dans les jobs et le modèle de données. |
| Universal RP | com.unity.render-pipelines.universal | 17.3.0 | Assurer 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 . 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égration | Dépendance | Version | Détection |
|---|---|---|---|
| Mirror | Mirror (Asset Store ou GitHub) | 96 ou plus récent | Symbole de définition MIRROR, que Mirror ajoute lui-même. |
| A* Pathfinding Project | com.arongranberg.astar | Pro 5.4.4 jusqu’à 6.0 (exclue), testé avec 5.4.7 | Symbole 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 NavMesh | AI Navigation, com.unity.ai.navigation | 2.0 ou plus récent, testé avec 2.0.9 | Symbole 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ètre | Pourquoi |
|---|---|
| Asset URP actif | Les shaders du package ne s’affichent qu’avec URP. |
| Options Depth Texture et Opaque Texture activées sur l’asset URP | L’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 renderer | Assombrit 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 joueur | Unity 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 Linear | Pour obtenir des couleurs et un éclairage corrects. |
| Références de shaders et tableaux de textures des tilesets à jour | Les 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
| Dossier | Contenu | Puis-je le supprimer ? |
|---|---|---|
Runtime | Tout 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. |
Editor | Uniquement des fonctionnalités de l’éditeur Unity. Rien de ce dossier n’est inclus dans les builds de joueur. | Non. |
Shaders | RTS 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. |
Samples | Les 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. |
Integrations | Un 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. |
Content | Contenu 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/RTSTerrainStudio | UI/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. |
Documentation | Ce manuel. et chaque bouton ? l’ouvrent. | Oui, mais les boutons d’aide n’ont alors plus rien à ouvrir. |
Tests | Tests 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 . | Oui. |
Contenu du dossier Runtime
| Dossier | Contenu |
|---|---|
Core | RTSTerrain (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. |
Data | Types d’assets : RTSTileset, RTSVegetationLibrary, RTSDecorLibrary, RTSMapAsset. |
Serialization | RTSMapSerializer : le format binaire .rtsmap (sections, compression deflate) et les entrées/sorties de fichiers. |
Brushes | BrushSettings, RTSBrushShape, SymmetrySettings, BrushUtility. |
Tools | RTSTool (classe de base), RTSEditSession, MapUndo et un sous-dossier par catégorie : Height, Cliffs, Paint, Vegetation, Decor, Water, Pathing, Markers. |
Mesh | La génération de la géométrie des chunks et ses jobs Burst. |
Rendering | La partie rendu de RTSTerrain, RTSTerrainChunk, les textures de splat, les données de calques et RTSTextureArrayBuilder. |
Vegetation | RTSVegetationRenderer, RTSTreeInstance. |
Water | RTSWaterRenderer, RTSWaterChunk, les jobs de mesh de l’eau. |
Decor | RTSDecorManager, RTSDecorInstance. |
FogOfWar | RTSFogOfWarManager, RTSFogOfWarRevealer, RTSFogOfWarHideable, RTSFogOfWarRendererFeature. |
Pathing | La partie cheminement de RTSTerrain, RTSPathingSettings, PathingMapBuilder, ClearanceMap, RTSPathfinder, RTSPathfindingService, les superpositions de cheminement. |
Generation | RTSMapGenerator, MapGeneratorSettings, RTSMapGeneratorPreset, RTSAutoPaintProfile, RTSAutoPaint, HeightmapIO et l’outil Auto Paint. |
Minimap | RTSMinimapBaker. |
Environment | RTSEnvironment (applique le soleil, la lumière ambiante et le brouillard atmosphérique de la carte). |
Validation | MapValidator (recherche les problèmes d’une carte, comme des positions de départ inaccessibles). |
RuntimeEditor | L’éditeur en jeu : RTSRuntimeEditor, RTSRuntimeEditorCamera, RuntimeToolGizmos et son interface UI Toolkit. |
Input | RTSInput et RTSKey. |
UI | RTSIcons : des icônes procédurales partagées par l’éditeur et l’interface en jeu. |
Plugins/WebGL | Plugins 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.xml | Conserve les outils d’édition dans les builds avec élagage du code (voir Élagage du code et outils personnalisés). |
Contenu du dossier Editor
| Dossier | Contenu |
|---|---|
Core | RTSEditorContext (la session d’édition partagée et les options d’affichage), RTSEditorPaths, la persistance des paramètres des outils. |
Window | La fenêtre RTS Terrain Studio (RTSTerrainStudioWindow) et ses pages. |
SceneView | La 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. |
Inspectors | Les inspectors du tileset, des bibliothèques, des formes de pinceau, des profils de peinture automatique et des composants. |
Importers | L’importeur de fichiers .rtsmap, son aperçu et l’entrée de menu . |
Building | Le 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. |
Setup | La 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. |
Requirements | Le 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. |
RuntimeEditorSupport | Le menu . |
DemoContent | Le 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) | Dossier | Espace de noms | Plateformes | Compilée quand |
|---|---|---|---|---|
RTSTerrainStudio.Runtime | Runtime | RTSTerrainStudio | Toutes | URP 17.3 ou plus récent est installé (RTS_URP). Définit RTS_INPUT_SYSTEM lorsque le package Input System est installé. |
RTSTerrainStudio.Samples | Samples/Scripts | RTSTerrainStudio.Samples | Toutes | URP 17.3 ou plus récent est installé. |
RTSTerrainStudio.Editor | Editor | RTSTerrainStudio.Editor | Éditeur | URP 17.3 ou plus récent est installé. |
RTSTerrainStudio.Requirements.Editor | Editor/Requirements | RTSTerrainStudio.Requirements | Éditeur | Uniquement 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.Editor | Tests/Editor | RTSTerrainStudio.Tests | Éditeur | UNITY_INCLUDE_TESTS est défini (Unity Test Framework). |
RTSTerrainStudio.Integrations.MirrorRTSTerrainStudio.Integrations.Mirror.Editor | Integrations/Mirror | RTSTerrainStudio.Integrations.Mirror | Toutes / Éditeur | MIRROR est défini. |
RTSTerrainStudio.Integrations.Mirror.DefineCleanup.Editor | Integrations/Mirror/Editor/DefineCleanup | RTSTerrainStudio.Integrations.Mirror | Éditeur | Toujours. Elle ne dépend pas de Mirror et retire les symboles de définition Mirror obsolètes une fois Mirror supprimé. |
RTSTerrainStudio.Integrations.AStarRTSTerrainStudio.Integrations.AStar.Editor | Integrations/AStarPathfinding | RTSTerrainStudio.Integrations.AStar | Toutes / Éditeur | RTS_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.NavMeshRTSTerrainStudio.Integrations.NavMesh.Editor | Integrations/UnityNavMesh | RTSTerrainStudio.Integrations.NavMesh | Toutes / Éditeur | RTS_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 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/Sceneset deux assets dansResources/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 |
|---|---|---|
| Textures | Content/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, prefabs | Content/Materials, Content/Meshes, Content/Prefabs | Arbres, rochers, ruines et accessoires low-poly, avec leurs matériaux. |
| Tilesets | Content/Tilesets/Summer.asset, Winter.asset | Deux 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 automatique | Content/Tilesets/Summer Auto Paint.asset | Rè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étation | Content/Libraries/Demo Vegetation.asset | Détails : Grass, Tall Grass, Flowers Yellow, Flowers Purple, Fern. Arbres : Pine, Broadleaf, Dead Tree, Bush. |
| Bibliothèque de décors | Content/Libraries/Demo Decor.asset | Rock 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 pinceau | Content/Brushes | Tampons personnalisés : Noise Blob, Splatter, Star, Soft Square. |
| Cartes | Content/Maps | Trois fichiers .rtsmap (voir ci-dessous). |
| Paramètres de rendu | Content/Settings | Un profil de volume de post-traitement utilisé par les scènes de démo. |
| Scènes | Samples/Scenes | Trois scènes de démo (voir ci-dessous). |
| Ressources | Resources/RTSTerrainStudio | L’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.
| Carte | Taille | Symétrie | Description |
|---|---|---|---|
Two Rivers (1v1).rtsmap | 128 × 128 cellules | Rotate 2 | Deux 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).rtsmap | 192 × 192 cellules | Rotate 4 | Quatre 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.rtsmap | 96 × 96 cellules | None | Une petite carte, presque entièrement plate, pour essayer les outils. |
Scènes de démo
| Scène | Carte | Ce qui est affiché |
|---|---|---|
| RTS Terrain Studio - Gameplay Demo | Two 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 Demo | Sandbox | L’é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 Playground | Four 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 :
- crée
RTS Mirror Demo.unity. - crée
RTS AStar Demo.unity. - 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 :
| Domaine | Classes |
|---|---|
| Amorçage | RTSDemoGame, RTSUnitSpawner |
| Unités et déplacement | RTSUnit, RTSUnitFactory, RTSUnitRegistry, RTSFormation, RTSWanderAI |
| Fournisseurs de chemins | IRTSUnitPathProvider, RTSBuiltinPathProvider, RTSUnitPathProviderComponent, RTSUnitPathProviderRegistry |
| Caméra, entrées, sélection, ordres | RTSCameraController, RTSGameInput, RTSSelectionManager, RTSCommandController |
| Interface utilisateur | RTSMinimapUI, RTSDemoHUD, RTSRuntimeUI |
| Démos de gameplay | RTSBuildingPlacementDemo, RTSDemoBuilding, RTSTreeHarvestDemo, RTSFallingTreeEffect |
| Utilitaires | RTSMoveMarker, 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.
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.
| Partie | Ce que vous faites | Durée |
|---|---|---|
| Installation et configuration | Importez 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émo | Jouez sur une carte terminée, essayez l’éditeur en jeu, explorez la scène Editor Playground. | 5 min |
| Votre première carte | Cré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 jeu | Jouez 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 minutes | Construisez 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 (). Le manuel complet s’ouvre avec .
Installation et configuration
Configuration requise
| Élément | Version | Remarques |
|---|---|---|
| Unity | 6.3 LTS (6000.3) | Utilisez la version de l’éditeur pour laquelle le package a été conçu. |
| Universal Render Pipeline | 17.3 | Obligatoire. 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, Mathematics | depuis le Unity Registry | Obligatoires. Les traitements lourds (construction des meshes, pinceaux, cheminement, brouillard de guerre, recherche de chemin) s’exécutent dans des jobs Burst. |
| Input System | depuis le Unity Registry | Recommandé. 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 Navigation | facultatifs | Né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
- 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).
- Ouvrez , sélectionnez My Assets, recherchez RTS Terrain Studio, cliquez sur Download, puis sur Import.
- Dans la boîte de dialogue d’import, laissez tout coché et cliquez sur Import. Le package est installé dans
Assets/RTSTerrainStudio. - 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 . 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 . 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 :
| Étape | Bouton | Rôle |
|---|---|---|
| 1. Validate & fix the project | Validate | Ouvre 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 content | Create | Exécute . |
| 3. Open a demo scene | liste des scènes + Open | Liste 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 map | New Map | Ouvre le New Map Wizard. |
| 5. Start editing | Editor Window | Ouvre 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).
- Ouvrez , ou cliquez sur Validate dans la fenêtre Welcome.
- 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é.
- Cliquez sur Fix All. Avant toute modification, une boîte de dialogue liste chacun des changements prévus. Cliquez sur Apply Fixes.
- 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érification | Niveau de gravité | Bouton de correction | Effet de la correction et intérêt |
|---|---|---|---|
| Rendering | |||
| Universal Render Pipeline is active | Error | Use URP | Assigne 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 enabled | Warning | Enable Both | Active 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 feature | Warning | Add Feature | Ajoute 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 builds | Warning | Keep Fog Modes | Cette 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 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 space | Warning | Switch to Linear | Règle 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 Mathematics | Error | Install | Ajoute les packages manquants via le Package Manager. Sans eux, les scripts du package ne se compilent pas. |
| Input handling | Info | aucun | Indique 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 Texture | Warning | Enable Both | Active 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 builds | Error | Turn MSAA Off | Dé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 window | Warning | Install Template | Installe 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 compile | Error | Reimport | Ré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 builds | Error | Update | Cré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 built | Info | Build Arrays | Construit 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 prototypes | Warning | Enable Instancing | Coche 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 tileset | Warning | Assign '<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 file | Info | Create Map Files | Enregistre 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.
- Choisissez , ou cliquez sur Create dans la fenêtre Welcome.
- 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.
- À 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 ). Seul le bouton Add Scenes modifie les paramètres de build.
- 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/Textures | Textures de sol, de falaise, d’eau, de détails, d’accessoires et de pinceaux. |
Content/Materials, Content/Meshes, Content/Prefabs | Arbres, buissons, rochers et accessoires low-poly, avec leurs matériaux. |
Content/Tilesets | Les 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/Libraries | Demo 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/Brushes | Tampons de formes de pinceau. |
Content/Maps | Trois 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/Scenes | Les trois scènes de démo décrites ci-dessous. |
Resources/RTSTerrainStudio | Les 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.
| Scène | Carte | Contenu | Essayez 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 et essayez les outils sur une carte terminée. |
Commandes de la démo de gameplay
| Saisie | Action |
|---|---|
| W A S D / touches fléchées, bord de l’écran, glisser avec le bouton du milieu | Dé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 souris | Zoomer |
| Q / E, Alt + glisser avec le bouton droit | Faire pivoter la vue |
| Clic gauche / glisser avec le bouton gauche | Sélectionner une unité / tracer un rectangle de sélection |
| Shift + clic | Ajouter ou retirer des unités |
| Double-clic, Ctrl + clic | Sélectionner toutes les unités de ce type visibles à l’écran |
| Clic droit | Se déplacer en formation (Shift met l’ordre en file d’attente) |
| S / H / P | Arrêter / tenir la position / patrouiller |
| Ctrl + 0…9, Shift + 0…9, 0…9 | Enregistrer un groupe de contrôle / y ajouter la sélection / le rappeler (appuyez deux fois pour centrer la caméra) |
| Mini-carte | Le clic gauche déplace la caméra, le clic droit déplace les unités sélectionnées |
| B, Delete | Placer un bâtiment / supprimer le bâtiment sous le curseur |
| T, clic droit sur un arbre | Abattre l’arbre sous le curseur / le faire couper par les ouvriers sélectionnés |
| Esc | Annuler le mode en cours ou vider la sélection |
| F1 | Afficher 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 :
- Choisissez et sélectionnez un modèle de scène URP (par exemple Basic (URP)).
- 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éthode | Menu | À utiliser quand |
|---|---|---|
| En un clic | Vous 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ée | 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 :
| Étape | Paramètres |
|---|---|
| 1. Basics | Map 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. Size | Panneaux 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. Look | Tileset (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. Terrain | Flat (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. Create | New 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 (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.

| Zone | Ce qui est affiché |
|---|---|
| En-tête | Sé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’onglets | Huit 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 outils | Grands 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’état | Cellule sous le curseur, niveau de falaise, hauteur et cheminement sous la souris, et mémoire d’annulation. |
Les huit catégories et leurs outils :
| Touche | Catégorie | Outils |
|---|---|---|
| 1 | Height | Raise / Lower, Smooth, Flatten, Set Height, Noise, Terrace, Erode |
| 2 | Cliffs | Raise / Lower Level, Set Level, Ramp, Cliff Type, Clean Cliffs |
| 3 | Paint | Paint Layer, Tile Paint, Fill / Replace, Smooth Paint, Auto Paint |
| 4 | Vegetation | Paint Details, Erase Details, Place Trees, Erase Trees |
| 5 | Decor | Place Decor, Erase Decor, Select Decor |
| 6 | Water | Paint Water, Erase Water, Flood Fill |
| 7 | Pathing | Paint Pathing, Clear Pathing |
| 8 | Markers | Start 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
- 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.
- 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.
- Maintenez le bouton gauche de la souris enfoncé et faites glisser pour peindre.
| Saisie (Scene View) | Action |
|---|---|
| Bouton gauche | Peindre un trait (ou cliquer, pour les outils à clic comme Start Locations) |
| Shift + bouton gauche | Action inverse : abaisser, effacer, supprimer |
| Ctrl + clic | Pré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 … 8 | Passer à une catégorie d’outils (appuyez de nouveau pour parcourir ses outils) |
| G / P | Afficher ou masquer la grille / faire défiler les modes de la superposition de cheminement (Off, Walkability, Buildability, Combined) |
| R | Activer ou désactiver la rotation aléatoire du pinceau |
| Ctrl+Z / Ctrl+Y | Annuler / rétablir les modifications du terrain (le menu Edit affiche le nom des étapes) |
| Esc | Annuler 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 (sous macOS, ), 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
- Ouvrez l’onglet Height (1) et cliquez sur Raise / Lower.
- 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.
- Passez à Smooth et faites glisser sur les reliefs trop anguleux pour les adoucir.
- 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.
- Ouvrez l’onglet Cliffs (2) et cliquez sur Raise / Lower Level.
- 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é.
- Cliquez à l’intérieur du plateau et faites glisser de nouveau pour empiler un deuxième niveau par-dessus.
- 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.
- 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.
- 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
- Ouvrez l’onglet Paint (3) et cliquez sur Paint Layer.
- Cliquez sur un calque de sol dans la palette des calques, par exemple Dirt.
- 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.
- Pour des tuiles aux bords nets, dans le style des RTS classiques, utilisez Tile Paint. Pour les grandes zones, utilisez Fill / Replace.
- 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
- Ouvrez l’onglet Vegetation (4) et cliquez sur Place Trees.
- 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.
- 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).
- Réglez Mode sur Single pour placer un arbre par clic. Shift supprime des arbres.
- 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.
- 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).
- Ouvrez l’onglet Water (6) et cliquez sur Flood Fill.
- 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.
- Cliquez à l’intérieur du bassin. Il se remplit en un seul clic. Shift+clic vide l’étendue d’eau contiguë.
- 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 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.
- Ouvrez l’onglet Markers (8) et cliquez sur Start Locations.
- Dans la palette des joueurs, choisissez P1 (joueur 1, rouge).
- 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.
- 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
.rtsmapn’importe où dansAssetset 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
- 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).
- Choisissez . Un objet RTS Demo Game est créé et sélectionné.
- Appuyez sur Play. Enregistrez la carte quand on vous le demande.
- 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.
- Appuyez sur F1 pour afficher le panneau d’aide. Les commandes sont listées dans la section Commandes de la démo de gameplay.
- 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é.
- 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.
- Choisissez .
- 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.
- 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.
- 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.
- 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, (Ctrl+S) et (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é.
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)
- Choisissez , sélectionnez un modèle URP et enregistrez la scène sous
Assets/MyMaps/Duel.unity. - Ouvrez .
- Basics : Map Name
Duel, votre nom dans Author, Players 2. Cliquez sur Next. - Size : cliquez sur Small (96 × 96, 1v1 et 2v2). Conservez Cell Size à 2 m et Base Cliff Level à 2. Cliquez sur Next.
- Look : Tileset Summer, cliquez sur Grass comme calque de base, Vegetation Library Demo Vegetation, Decor Library Demo Decor. Cliquez sur Next.
- Terrain : choisissez Flat. Cliquez sur Next.
- Create : conservez New terrain object, cochez Add Environment et Open Editor Window, puis cliquez sur Create Map.
2. Activer la symétrie (10 secondes)
- Dans la fenêtre de l’éditeur, ouvrez l’onglet Cliffs. Repérez le panneau Symmetry sous le panneau Brush.
- Choisissez Rotate 180°. Laissez le centre de symétrie au centre de la carte (0.5, 0.5).
- 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) | Copies | Usage typique |
|---|---|---|
| Off | 1 | Cartes de campagne ou scénarisées |
| Mirror X | 2 | Miroir gauche-droite |
| Mirror Z | 2 | Miroir haut-bas |
| Mirror XZ | 4 | Miroir sur les deux axes (4 joueurs) |
| Rotate 180° | 2 | Symétrie centrale, l’agencement 1v1 classique (coin contre coin) |
| Rotate 90° | 4 | Rotation d’ordre 4 pour 4 joueurs ; carte carrée requise |
| Diagonal | 2 | Miroir 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)
- Cliquez sur Raise / Lower Level. Avec [ et ], choisissez un grand pinceau.
- 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.
- 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.
- 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)
- 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.
- Laissez un ou deux passages terrestres près du centre pour que les joueurs puissent se rejoindre.
- 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)
- 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.
- 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).
- Choisissez Dirt et peignez un chemin de la rampe de la base jusqu’au passage terrestre.
- 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)
- Ouvrez l’onglet Vegetation et cliquez sur Place Trees. Choisissez Pine et Broadleaf, et conservez le mode Scatter.
- 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.
- Cliquez sur Paint Details, choisissez Grass et Flowers Yellow, puis peignez quelques prairies.
- 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)
- Ouvrez l’onglet Markers et cliquez sur Start Locations.
- Choisissez le joueur P1 et vérifiez que la case Symmetry Assigns Next Players est cochée.
- 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)
- 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).
- Cliquez sur Save dans l’en-tête de la fenêtre. La carte est écrite dans
Assets/MyMaps/Duel.rtsmap. - Choisissez et appuyez sur Play.
- 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 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 , 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égorie | Ce qui est vérifié |
|---|---|
| Rendering | URP 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. |
| Project | Espace colorimétrique Linear ; Burst, Collections et Mathematics sont installés ; mode de gestion des entrées actif. |
| WebGL | Uniquement 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). |
| Content | Les 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. |
| Scene | Chaque 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 :
| État | Signification |
|---|---|
| OK | Tout est correctement configuré. |
| Info | Une indication ou une recommandation. Rien n’est cassé. |
| Warning | Une fonctionnalité n’est disponible qu’en mode dégradé, par exemple l’eau sans réfraction. Une correction est recommandée. |
| Error | Un 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 :
- Si le projet n’a pas encore d’asset URP, créez-en un dans la fenêtre Project avec .
- Assignez-le comme Default Render Pipeline dans .
- Ouvrez . 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 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
, 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 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 Handling | Input System installé | Résultat |
|---|---|---|
| Input System Package (new) | oui | OK. L’Input System est utilisé. |
| Both | oui | OK. L’Input System est utilisé. |
| Input Manager (old) | oui | Info. La solution de repli est utilisée. |
| toute valeur | non | Info. 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 . 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 :
- Exécutez et corrigez toutes les erreurs et tous les avertissements.
- 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.
- 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).
- 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).
- Validez vos cartes dans l’onglet Map (voir Validation des cartes).
- 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é.
- 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
MapsdeRTSMapSerializer.StorageRoot(Application.persistentDataPathou, dans les builds Web, le stockage du navigateur) ; voir Fichiers de carte à l’exécution. - 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.
- 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 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 :
- Ouvrez , sélectionnez Web et cliquez sur Switch Platform (ou faites de votre profil de build Web le profil actif).
- Exécutez 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.
- Si vos cartes utilisent le brouillard atmosphérique, vérifiez que Fog kept in player builds indique OK.
- 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
| Sujet | Prise en charge |
|---|---|
| API graphique | WebGL 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é. |
| Navigateurs | Les 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 tablettes | La 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. |
| Rendu | Le 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 jeu | Tous 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). |
| Threads | Les 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
maxDevicePixelRatiodans le fichierindex.htmldu 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 :
- Choisissez , ou cliquez sur Install Template dans le panneau Web template fills the browser window du Project Validator.
- Le modèle est copié dans
Assets/WebGLTemplates/RTSTerrainStudio(Unity ne trouve les modèles que dansAssets/WebGLTemplates) et sélectionné dans . - 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érification | Correction | Ce qui est vérifié |
|---|---|---|
| Web quality levels have Depth and Opaque Texture | Enable Both | Les niveaux de qualité cochés dans la colonne Web de (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 builds | Turn MSAA Off | Une 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 window | Install Template / Reinstall | Un 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 à 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ètre | Emplacement | Recommandation |
|---|---|---|
| Texture Compression | Votre profil de build Web | Use 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 Size | Conservez 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 Format | Brotli 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 Fallback | Activez-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 Caching | Activé. Le navigateur conserve les données du jeu téléchargées : la visite suivante démarre donc plus vite. | |
| Enable Exceptions | Explicitly 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 Level | Tous 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 URP | Dé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 Template | RTSTerrainStudio (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.htmlgénéré ne fonctionne pas. Les navigateurs n’exécutent pas les builds Web depuis des adressesfile://, 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,BuildetTemplateData. - Les builds compressés nécessitent deux en-têtes sur les fichiers de
Build:Content-Encoding: brpour Brotli ouContent-Encoding: gzippour Gzip, et le bonContent-Type, par exempleapplication/wasmpour le fichier.wasm. SansContent-Encoding, la page affiche un message d’erreur, et unContent-Typeincorrect 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 avecindex.htmlà la racine. Uneiframeen sandbox nécessiteallow-downloadspour Download Map etallow-modalspour 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 :
| Commande | Emplacement | Rôle |
|---|---|---|
| Download Map | Menu File | Demande 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 File | Ouvre 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. |
| Download | Explorateur de cartes (Open) | Télécharge le fichier de carte sélectionné. |
| Glisser-déposer | Canvas du jeu | Un 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 uneiframe, 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 :
| Limite | Navigateur | Autres plateformes |
|---|---|---|
| Plus grande carte dans New Map et Resize | 2048 ÷ 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’annulation | 192 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 Mo | Pas 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’
iframedu 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
| Membre | Description |
|---|---|
RTSWebFileSystem.IsSupported | Vaut 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.StorageRoot | Dossier 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.DefaultMapsFolder | Maps dans StorageRoot. |
RTSRuntimeEditor.RunsInBrowser | Vaut true dans les builds Web, où l’éditeur applique les limites du navigateur et utilise Alt+N pour New Map. |
RTSRuntimeEditor.StoresMapsInBrowser | Vaut true lorsque les cartes sont conservées dans le stockage du navigateur (builds de joueur WebGL). |
RTSRuntimeEditor.HasReliableFunctionKeys | Vaut 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.PointerInsideScreen | Vaut 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. Utilisezmap.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ètre | Par défaut | Valeurs autorisées | Description |
|---|---|---|---|
width, height | 128 | 16–1024, arrondi à un multiple de 16 | Nombre de cellules selon X et Z. Le New Map Wizard propose des préréglages allant de Tiny (64) à Epic XL (512). |
cellSize | 2 | ≥ 0.1 | Taille réelle d’une cellule, en mètres. |
cliffLevelHeight | 2 | ≥ 0.05 | Hauteur réelle d’un niveau de falaise, en mètres. |
baseCliffLevel | 2 | 0–15 | Niveau de falaise initial de chaque vertex. Le niveau 2 laisse de la place pour creuser des lacs et des rivières. |
baseGroundLayer | 0 | 0–15 | Calque de sol qui recouvre initialement toute la carte. |
splatResolution | 4 | 1, 2, 4, 8 | Nombre de texels de texture de sol (splat) par côté de cellule. |
detailResolution | 2 | 1, 2, 4 | Nombre de texels de densité de détails (herbe) par côté de cellule. |
pathingResolution | 2 | 1, 2, 4 | Nombre de cellules de cheminement par côté de cellule de carte. |
name | « New Map » | texte libre | Nom 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ées | Stocké par | Membre de MapData | Type | Indicateur MapLayers |
|---|---|---|---|---|
| Hauteur fine | vertex | Heights | NativeArray<float>, en mètres | Heights |
| Niveau de falaise | vertex | CliffLevels | NativeArray<byte>, 0–15 | CliffLevels |
| Indicateurs de vertex (rampe, eau) | vertex | VertexFlags | NativeArray<byte> de VertexFlags | VertexFlags |
| Type de falaise | vertex | CliffTypes | NativeArray<byte>, 0–3 | CliffTypes |
| Hauteur de la surface de l’eau | vertex | WaterHeights | NativeArray<float>, Y local à la carte | Water |
| Poids des calques de sol | texel de splat | SplatMaps[0..3] | NativeArray<Color32> × 4 | Splat |
| Densité d’herbe / de plantes | texel de détail | DetailLayers | un DetailLayer (un octet par texel) par prototype | Details |
| Arbres | instance | Trees, TreePrototypeIds | List<TreeInstanceData> | Trees |
| Décor (doodads) | instance | Decor, DecorPrototypeIds | List<DecorInstanceData> | Decor |
| Surcharges manuelles de cheminement | cellule de cheminement | PathingOverrides | NativeArray<byte> de PathingOverride | PathingOverrides |
| Régions | liste | Regions | List<MapRegion> | Regions |
| Positions de départ | liste | StartLocations | List<StartLocation> | StartLocations |
| Marqueurs | liste | Markers | List<MapMarker> | Markers |
| Informations de la carte | carte | Info | MapInfo | Info |
| Environnement (éclairage) | carte | Environment | EnvironmentSettings | Environment |
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
CliffLevelHeightmè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 cellule | Condition | Surface |
|---|---|---|
| Cellule lisse | Les quatre coins ont le même niveau de falaise. | Surface bilinéaire passant par les hauteurs des quatre coins. |
| Cellule de rampe | Les 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 falaise | Les 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ètre | Par défaut | Description |
|---|---|---|
| Surface Subdivisions | 2 | Nombre de quads par côté de cellule sur un sol lisse (1 = aspect RTS classique, 2–4 = collines plus douces). |
| Cliff Subdivisions | 4 | Résolution de la sous-grille qui sert à tracer le contour arrondi dans une cellule de falaise. |
| Cliff Noise | 0.18 | Déplacement horizontal aléatoire des vertices de la paroi (fraction de cellule) pour un aspect de roche naturel. |
| Cliff Noise Scale | 1.6 | Échelle du bruit de falaise, en unités du monde. |
| Cliff Slant | 0.12 | Recul du bord supérieur d’une paroi, qui rend les parois légèrement inclinées (fraction de cellule). |
| Cliff Wall Segments | 3 | Nombre 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 :
| Membre | Description |
|---|---|
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, WorldSize | Taille 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 (idcliff.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,
GetCliffLevelrenvoie le niveau interpolé, arrondi : le niveau inférieur sur la moitié basse, le niveau supérieur sur la moitié haute.
- Surélevez un plateau d’un niveau avec l’outil Raise / Lower Level.
- 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.
- 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 map | R | G | B | A |
|---|---|---|---|---|
SplatMaps[0] | calque 0 | calque 1 | calque 2 | calque 3 |
SplatMaps[1] | calque 4 | calque 5 | calque 6 | calque 7 |
SplatMaps[2] | calque 8 | calque 9 | calque 10 | calque 11 |
SplatMaps[3] | calque 12 | calque 13 | calque 14 | calque 15 |
- Le calque i est stocké dans la splat map
i / 4, canali % 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/SetChanneletmap.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 dansWaterHeights; 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)etterrain.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
DetailLayerdansmap.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 × maxDensityinstances ; 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
idunique et stable au sein de la carte. Obtenez de nouveaux identifiants avecmap.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.
| Objet | Hauteur de rendu (Y local de la carte) |
|---|---|
| Arbre | hauteur du sol + position.y |
| Décor | hauteur du sol + position.y + le Y Offset du prototype |
Décor avec DecorFlags.KeepHeight | position.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.
| Champ | TreeInstanceData | DecorInstanceData |
|---|---|---|
id | uint, unique dans la carte | uint, unique dans la carte |
prototype | ushort, index dans TreePrototypeIds | ushort, 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 |
position | float3, local à la carte, y = décalage | float3, local à la carte, y = décalage (ou absolu avec KeepHeight) |
| rotation | yaw en degrés | rotation, un quaternion local à la carte |
| échelle | scale, float uniforme | scale, float3 |
tint | Color32 multiplié par la couleur du matériau | Color32 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.
PathingFlags | Signification |
|---|---|
Walkable | Les unités terrestres peuvent marcher ici. |
Buildable | Des bâtiments peuvent être placés ici. |
Flyable | Les 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. |
ShallowWater | Eau peu profonde (praticable, non constructible par défaut). |
DeepWater | Eau profonde (unités navales uniquement). |
Cliff | La cellule touche une paroi de falaise. |
Blocked | Bloquée par l’emprise d’un arbre ou d’un décor. |
Steep | Trop escarpée pour les unités terrestres. |
Comment les indicateurs sont dérivés
- Terrain : les parois de falaise (ainsi que la marge Cliff Margin) activent
Cliff; les pentes supérieures à Max Walkable Slope (42° par défaut) activentSteep; l’eau activeShallowWaterouDeepWaterselon sa profondeur ;Flyableest 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). - 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. - 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).
PathingOverride | Effet |
|---|---|
Unwalkable | Retire Walkable (et Buildable), active Blocked. |
Unbuildable | Retire Buildable. |
Unflyable | Retire Flyable. |
ForceWalkable | Active Walkable, même si les règles dérivées disent le contraire. |
ForceBuildable | Active 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.
| Type | Champs | Usage 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, yaw | Points 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, properties | Camé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 MapInfo | Par défaut | Description |
|---|---|---|
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. |
maxPlayers | 2 | Nombre 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, modifiedUtcTicks | défini automatiquement | Date 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
() ; sans ce composant, les valeurs sont enregistrées mais pas utilisées.
Champ EnvironmentSettings | Par défaut | Description |
|---|---|---|
sunColor | blanc chaud (1, 0.956, 0.84) | Couleur de la lumière du soleil. |
sunIntensity | 1.2 | Intensité 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. |
fog | désactivé | Active le brouillard atmosphérique de distance. |
fogColor | (0.6, 0.68, 0.75) | Couleur du brouillard atmosphérique. |
fogDensity | 0.004 | Densité 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édiatementMapChangedet 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 avecterrain.ProcessPendingChanges(). Ensuite, l’événementChangesProcessedest 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 avecBrushUtility.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.WorldSizeen 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 / LocalToWorldDirection | Conversion 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. |
WorldBounds | Boî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, Raycast | Requê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 Transform | Pris en charge | Remarques |
|---|---|---|
| Position | Oui | Déplace toute la carte. Servez-vous-en pour placer plusieurs terrains côte à côte ou à des hauteurs différentes. |
| Rotation Y | Oui | Fait 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 / Z | Non | Seule 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. |
| Échelle | Ignorée | Les 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.Allliste tous les terrains activés ;RTSTerrain.Mainrenvoie 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.terrainindique le terrain touché).RTSTerrain.TerrainEnabled/TerrainDisabledsont 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
- : 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é.
- : 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
Assetsun fichier.rtsmapcréé 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).
| Commande | Description |
|---|---|
| Open In Scene | Assigne 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 Size | Côté le plus long de l’aperçu précalculé : 128, 256 (par défaut) ou 512 pixels. |
| Preview Tileset | Tileset utilisé pour les couleurs de l’aperçu. Vide = le tileset dont la carte stocke l’identifiant (trouvé automatiquement). |
| Re-bake Preview, Apply / Revert | Pré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
.rtsmapet 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.DefaultMapsFolderest le dossierMapssitué dansRTSMapSerializer.StorageRoot, qui vautApplication.persistentDataPath, si bien que sous Windows, ce dossier est en général%USERPROFILE%\AppData\LocalLow\<Company>\<Product>\Maps. Dans les builds Web,StorageRootest 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-carteName.preview.png, destinée à son explorateur de cartes. - Pour partager une carte, copiez le fichier
.rtsmapdans 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.
| API | Description |
|---|---|
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 = asset | Assigne 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.HasUnsavedChanges | Vaut 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.PendingLayers | Couches dont les modifications ont été notifiées mais pas encore traitées. |
RTSMapAsset.Header / Preview / Data | L’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.
- Créez un tileset avec .
- 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é. - Ajoutez de la même façon des calques de falaise dans Cliff Layers.
- Assignez le tileset au champ Tileset de votre
RTSTerrain. - Cliquez une fois sur Build Texture Arrays dans la section Texture Arrays (voir Tableaux de textures).
Champs du tileset
| Paramètre | Par défaut | Description |
|---|---|---|
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) | vide | Jusqu’à 16 entrées GroundLayer. Les entrées en trop sont supprimées. |
Cliff Layers (cliffLayers) | vide | Jusqu’à 4 entrées CliffLayer. |
Water (water) | bleu-vert | Le WaterProfile, voir ci-dessous. |
Resolution (arrayResolution) | 1024 | Taille 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) | aucun | Maté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.25 | Variation à grande échelle qui casse la répétition des textures sur de grandes surfaces. |
Triplanar Sharpness (triplanarSharpness) | 6 | Netteté du fondu triplanaire sur les parois de falaise (1–16). |
Champs des calques de sol
| Paramètre | Par défaut | Description |
|---|---|---|
| Name | « Layer » | Affiché dans les palettes. |
| Albedo | aucune | Couleur de base (RGB). Taille et format quelconques. |
| Normal | aucune | Normal map en espace tangent (importez-la en tant que Normal Map). |
| Height Map | aucune | Hauteur facultative (canal R) pour le fondu par hauteur. Prend le pas sur l’alpha de l’albédo. |
| Height From Albedo Alpha | désactivé | Utilise l’alpha de l’albédo comme hauteur lorsqu’aucune texture de hauteur n’est assignée. |
| Tint | blanc | Couleur multipliée par l’albédo. |
| Tile Size | 6 | Taille réelle d’une répétition de la texture, en mètres (≥ 0.1). |
| Normal Strength | 1 | 0–2. |
| Smoothness | 0.1 | 0–1. |
| Metallic | 0 | 0–1. |
| Height Blend | 0.5 | Intensité du fondu par hauteur avec les calques voisins (0 = fondu linéaire). Nécessite une source de hauteur. |
| Anti Tiling | 0.3 | Casse la répétition visible grâce à un second échantillonnage varié (0–1). |
| Pathing Effect | None | Rè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 Color | noir | Couleur 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ètre | Par défaut | Description |
|---|---|---|
| Name | « Cliff » | Affiché dans la palette Cliff Type. |
| Albedo | aucune | Couleur de la paroi. Sans elle, les falaises de ce type affichent un substitut gris foncé. |
| Normal | aucune | Normal map en espace tangent. |
| Tint | blanc | Couleur multipliée par l’albédo. |
| Tile Size | 4 | Taille réelle d’une répétition de la texture, en mètres. |
| Normal Strength | 1 | 0–2. |
| Smoothness | 0.15 | 0–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 Color | noir | Couleur 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ètre | Par défaut | Description |
|---|---|---|
| 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 Depth | 3 | Profondeur, en mètres, à laquelle la couleur de l’eau profonde est entièrement atteinte. |
| Shallow Depth Limit | 0.9 | Au-delà de cette profondeur, l’eau est profonde (non praticable). L’eau moins profonde est praticable, comme dans les RTS classiques. |
| Normal Map | aucune | Normal map des vagues. |
| Normal Strength | 0.6 | 0–2. |
| Normal Tile Size | 8 | Taille 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 Height | 0.05 | 0–1. |
| Smoothness | 0.92 | 0–1. |
| Refraction | 0.03 | 0–0.2. |
| Foam Color | blanc, alpha 0.8 | Couleur de l’écume le long du rivage. |
| Foam Distance | 0.6 | Distance de l’écume le long du rivage, en mètres. |
| Foam Texture | aucune | Motif 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
| Tableau | Tranches | Canaux | Espace colorimétrique |
|---|---|---|---|
_RTS_AlbedoArray | 0–15 : calques de sol, 16–19 : calques de falaise | RGB = albédo, A = hauteur pour le fondu par hauteur | sRGB |
_RTS_NormalArray | 0–15 : calques de sol, 16–19 : calques de falaise | RGB = 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 estRTSTileset.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 par | Le bouton Build Texture Arrays dans l’Inspector du tileset | Le renderer, automatiquement, lorsqu’il n’existe aucun tableau généré à jour |
| Stockage | Sous forme de sous-assets dans l’asset du tileset (inclus dans les builds de joueur) | Uniquement en mémoire GPU, reconstruits au chargement |
| Format | BC7 (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 px | environ 56 Mo en BC7 pour les deux tableaux | environ 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. 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
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ètre | Par défaut | Description |
|---|---|---|
| Id | généré | Identifiant stable stocké dans les fichiers de carte. |
| Name | « Grass » | Affiché dans la palette. |
| Render Mode | Crossed Quads | CrossedQuads : quads croisés texturés avec Texture (herbe classique). Mesh : utilise Mesh, texturé avec la texture principale et la couleur de Material. |
| Mesh | aucun | Mesh pour le mode Mesh. |
| Material | aucun | Maté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. |
| Texture | aucune | Texture avec alpha pour le mode Crossed Quads. |
| Healthy Color / Dry Color | vert clair / paille | Les instances mélangent ces deux couleurs selon un bruit. |
| Min / Max Width | 0.6 / 1.0 | Plage de largeur aléatoire, en mètres. |
| Min / Max Height | 0.4 / 0.8 | Plage de hauteur aléatoire, en mètres. |
| Max Density | 6 | Nombre d’instances par texel de détail à pleine densité (255). Plage 1–32. |
| Color Noise Scale | 12 | Échelle du bruit qui mélange la couleur saine et la couleur sèche. |
| Wind Strength | 0.5 | 0–1. La direction et la vitesse du vent se règlent sur le RTSVegetationRenderer. |
| Render Distance | 70 | Les 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 Shadows | désactivé | Les ombres des détails sont coûteuses ; laissez cette option désactivée pour l’herbe. |
| Align To Ground | activé | Incline les instances pour qu’elles suivent la normale du sol. |
| Max Slope | 40 | Aucune instance n’apparaît sur les pentes plus raides que cette valeur (en degrés). |
| Avoid Water | activé | Aucune instance n’apparaît sous l’eau. |
| Icon | aucune | Icô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ètre | Par défaut | Description |
|---|---|---|
| Id | généré | Identifiant stable stocké dans les fichiers de carte. |
| Name | « Tree » | Affiché dans la palette. |
| Prefab | aucun | Prefab avec des MeshRenderers et un LODGroup facultatif (LOD0 et LOD1 sont utilisés). |
| Spawn Mode | Instanced | Instanced : 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 Scale | 0.85 / 1.2 | Plage d’échelle uniforme aléatoire. |
| Random Rotation | activé | Lacet aléatoire lors du placement. |
| Tint A / Tint B | blanc / vert pâle | Plage de teinte aléatoire par instance. |
| Footprint Radius | 0.8 | Rayon, en mètres, bloqué dans la carte de cheminement (mis à l’échelle avec l’arbre). |
| Blocks Vision | activé | Les arbres bloquent la ligne de vue pour le brouillard de guerre, comme dans les RTS classiques. |
| Min Spacing | 1.6 | Distance minimale par rapport aux autres arbres lors de la dispersion. |
| Colliders | activé | 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 / Height | 0.4 / 4 | Taille des proxys de collider capsule (mode Instanced). |
| Render Distance | 250 | Les arbres situés au-delà de cette distance de la caméra ne sont pas affichés. |
| Cast Shadows | activé | Projection d’ombres. |
| Icon | aucune | Icô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 avecprototype.GetPrefab(d.variant): 0 correspond au prefab principal, et les variantes invalides ou vides se rabattent sur celui-ci.VariantCountinclut 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 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ètre | Par défaut | Description |
|---|---|---|
| Id | gé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. |
| Prefab | aucun | L’objet à placer. |
| Variants | vide | Prefabs alternatifs facultatifs ; une variante est choisie au hasard lors du placement. L’instance enregistre l’index de la variante (0 = prefab principal). |
| Spawn Mode | GameObject | GameObject : un GameObject par instance (scripts, colliders, animations). Instanced : instanciation GPU, aucun GameObject, accessoires statiques uniquement, le mode le plus rapide. |
| Min / Max Scale | 0.9 / 1.1 | Plage d’échelle uniforme aléatoire. |
| Random Yaw | activé | Rotation aléatoire autour de l’axe vertical. |
| Yaw Step | 0 | Contraint le lacet à des multiples de cet angle (0 = libre), par exemple 90 pour les murs et les clôtures. |
| Max Random Tilt | 0 | Inclinaison aléatoire en degrés (0–45). |
| Align To Normal | 0 | Aligne l’axe vertical sur la normale du sol (0 = vertical, 1 = entièrement aligné). |
| Snap To Grid | désactivé | Aligne la position sur les centres des cellules. |
| Y Offset | 0 | Décalage vertical en mètres, ajouté au moment du rendu (une valeur négative enfonce l’objet dans le sol). |
| Tint A / Tint B | blanc / blanc | Plage de teintes aléatoires par instance. |
| Footprint Shape | Circle | None, 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 Effect | Unwalkable, Unbuildable | Indicateurs PathingOverride écrits à l’intérieur de l’emprise. |
| Blocks Vision | désactivé | Bloque la ligne de vue pour le brouillard de guerre. |
| Min Spacing | 1 | Distance minimale par rapport aux autres objets de décor lors de la dispersion. |
| Cast Shadows | activé | Projection d’ombres. |
| Icon | aucune | Icô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 vautNoneou que l’instance porte l’indicateurDecorFlags.IgnorePathing. - Utilisez
Unbuildableseul pour les décorations plates sur lesquelles les unités peuvent marcher (fleurs, gravats), etUnwalkablepour les objets solides.
Modes d’apparition
| GameObject | Instanced | |
|---|---|---|
| Objets de scène | Un par instance, sous un enfant nommé « RTS Decor » (non enregistré avec la scène) | Aucun |
| Scripts, colliders, animation | Oui (chaque racine reçoit un composant RTSDecorInstance) | Non |
| Rendu | Renderers normaux du prefab | Graphics.RenderMeshInstanced avec le LOD0, culling par patch |
| Idéal pour | Accessoires interactifs, mines d’or, objets destructibles | Des 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.
| Partie | Type | Contenu |
|---|---|---|
| Nombre magique | 4 octets | ASCII RTSM |
| Version du format | int32 | RTSMapSerializer.CurrentVersion (actuellement 1) |
| Longueur de l’en-tête | int32 | Nombre d’octets d’en-tête qui suivent |
| En-tête | octets | string name, string author, string description, int32 width, int32 height, float cellSize, int32 maxPlayers, string tilesetId, int64 modifiedUtcTicks |
| Corps | flux deflate brut (RFC 1951, sans enveloppe zlib ni gzip) jusqu’à la fin du fichier | Une 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.
| Étiquette | Valeur | Charge utile |
|---|---|---|
DIMS | 0x534D4944 | int32 width, int32 height, float cellSize, float cliffLevelHeight, int32 splatResolution, int32 detailResolution, int32 pathingResolution, uint32 nextInstanceId. Doit être la première section. |
INFO | 0x4F464E49 | string name, author, description ; int32 maxPlayers ; string tilesetId ; int64 createdUtcTicks, modifiedUtcTicks |
HGHT | 0x54484748 | Hauteurs fines : un float par vertex |
LEVL | 0x4C56454C | Niveaux de falaise : un octet par vertex |
VFLG | 0x474C4656 | Indicateurs de vertex : un octet par vertex |
CTYP | 0x50595443 | Types de falaise : un octet par vertex |
WATR | 0x52544157 | Hauteurs de la surface de l’eau : un float par vertex |
SPLT | 0x544C5053 | Nombre de splat maps en int32 (4), puis, pour chaque splat map, un tableau d’octets RGBA par texel |
DETL | 0x4C544544 | Nombre de couches en int32, puis, pour chaque couche : string prototypeId et un tableau d’octets de densité par texel de détail |
TREE | 0x45455254 | Liste 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) |
DECO | 0x4F434544 | Liste 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) |
PATH | 0x48544150 | Surcharges de cheminement manuelles : un octet par cellule de cheminement |
REGN | 0x4E474552 | Nombre en int32, puis, pour chaque région : string name, float x, z, width, depth, float4 colour, properties |
STRT | 0x54525453 | Nombre en int32, puis, pour chaque position de départ : int32 player, float3 position, float yaw |
MARK | 0x4B52414D | Nombre en int32, puis, pour chaque marqueur : string name, string tag, float3 position, float4 rotation, properties |
ENVR | 0x52564E45 | float4 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 :
| Hook | Type | Moment de l’appel |
|---|---|---|
CustomSectionWriter | Action<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. |
CustomSectionReader | Action<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 exempleXGLD). 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.
MapDatane prévoit pas d’emplacement pour vos données. Conservez-les à côté de la carte (l’exemple utilise uneConditionalWeakTable). Les données conservées de cette façon ne sont pas copiées parMapData.Clone()ni parResizeMap, 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 :
- Créez un terrain avec . Si le projet n’a pas encore de tileset, on vous propose de créer d’abord le contenu de démo : acceptez.
- Ouvrez .
- Dans l’onglet Height, cliquez sur Raise / Lower. L’édition s’active automatiquement.
- 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.
- 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 :
- 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 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.
| Commande | Rôle |
|---|---|
| Sélecteur de terrain | Choisit 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 Select | Sélectionne le GameObject du terrain dans la fenêtre Hierarchy et le met en évidence. |
| Nom de la carte et point | Le 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. |
| Reload | Recharge la carte depuis son asset et abandonne les modifications non enregistrées. Nécessite un asset de carte. |
| Undo / Redo | Annule 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 Off | Active 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 .
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.
| Panneau | Contenu |
|---|---|
| Category Tools | La 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’outil | Le 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 Started | Affiché 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. |
| Brush | Forme, 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. |
| Symmetry | Mode et centre de symétrie (non affiché pour les outils à glissement). Voir Symétrie. |
| Tool Settings | Les 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égorie | Panneaux 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.

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ètre | Commande |
|---|---|
| Nombre avec une plage | Curseur avec un champ de valeur |
| Valeur booléenne (activé/désactivé) | Case à cocher |
| Choix (énumération) | Liste déroulante |
| Couleur / texte | Champ de couleur / champ de texte |
| Calque de sol | Palette 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 falaise | Palette des calques de falaise du tileset. |
| Niveau de falaise | Boutons 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. |
| Joueur | Les 16 couleurs de joueur (Red, Blue, Teal, Purple, Yellow, Orange, Green, Pink, …). |
| Prototypes de détails, d’arbres ou de décors | Grille 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’asset | Champ 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ètre | Description |
|---|---|
| Name | Nom 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. |
| Author | Auteur de la carte. |
| Description | Courte description présentée aux joueurs. |
| Max Players | Nombre de joueurs recommandé (1–16). |
| Map Asset | L’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ètre | Par défaut | Description |
|---|---|---|
| Size presets | – | Boutons pour des cartes carrées de 64, 96, 128, 192, 256, 384 et 512 cellules. |
| Width / Height | d’après la section Default Map du terrain (128) | Taille en cellules. Multiple de 16, de 16 à 1024. |
| Cell Size | 2 m | Taille d’une cellule en mètres. Les cartes des RTS classiques utilisent environ 2 m. |
| Cliff Level Height | 2 m | Hauteur réelle d’un niveau de falaise. |
| Base Cliff Level | 2 | Niveau de falaise initial de toute la carte. La valeur 2 laisse de la place pour creuser des lacs et des vallées. |
| Base Ground Layer | 0 | Calque de sol qui recouvre initialement toute la carte. |
| Splat | 4 | Texels 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. |
| Details | 2 | Texels de densité d’herbe par cellule (1, 2 ou 4). |
| Pathing | 2 | Cellules 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. |
| Name | New Map | Nom 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.
- Saisissez New Width et New Height en cellules (multiples de 16).
- 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é.
- Choisissez le Fill Level (niveau de falaise) et le Fill Layer (calque de sol) des nouvelles zones.
- 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.
| Commande | Description |
|---|---|
| Seed, Style, Symmetry | La 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 Locations | Sections repliables contenant les paramètres détaillés du générateur pour chaque étape. |
| Randomize Seed | Choisit une nouvelle graine aléatoire. |
| Apply Style Preset | Charge les valeurs de bruit, de falaises, de rampes et d’eau du style sélectionné. |
| Reset | Réinitialise tous les paramètres du générateur aux valeurs par défaut du style sélectionné. |
| Generate | Remplace 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ètre | Description |
|---|---|
| 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 Scale | Nombre de mètres représentés par la plage 16-bit complète. 0 = automatique. |
| Height Offset | Import : nombre de mètres ajoutés à chaque hauteur. Export : hauteur enregistrée avec la valeur 0. |
| Flip Vertically | Retourne l’image selon l’axe Z. Utilisez ce paramètre si la carte apparaît en miroir. |
| RAW Width / RAW Height | Taille des fichiers RAW. 0 = déduite de la taille du fichier (fichiers carrés uniquement). |
| RAW Little Endian | Ordre 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ètre | Description |
|---|---|
| Sun Colour | Couleur de la lumière du soleil. |
| Sun Intensity | Intensité de la lumière du soleil (0–8). |
| Sun Rotation | En degrés : x = inclinaison (hauteur au-dessus de l’horizon), y = lacet. |
| Ambient Colour | Couleur de la lumière ambiante (ciel). |
| Fog | Active le brouillard atmosphérique en fonction de la distance. |
| Fog Colour / Fog Density | Couleur 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
| Panneau | Contenu |
|---|---|
| View | Show 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 Component | L’Inspector complet du composant RTS Terrain édité (voir Le composant RTS Terrain) et un bouton Select Terrain. |
| Undo History | Max 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. |
| Shortcuts | Les 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 & Maintenance | Open Documentation, Validate Project (exécute ) 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. |
| About | Version 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
| Saisie | Action |
|---|---|
| Bouton gauche de la souris | Peint 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+clic | Pré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+glisser | Fait orbiter la caméra comme d’habitude. Ne peint jamais. |
| Bouton droit / du milieu | Conservent 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. |
| Esc | Exé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 terrain | Fait 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 :
- 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 ;
- 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 Unity | Poigné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 :
| Quand | Ce qui se passe |
|---|---|
| Enregistrement d’une scène | Les 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 Mode | La 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 Mode | La 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 Unity | Demande 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éfaut | Entrée du Shortcut Manager | Action |
|---|---|---|
| [ | RTS Terrain Studio/Brush Smaller | Rayon du pinceau × 0.87. |
| ] | RTS Terrain Studio/Brush Larger | Rayon du pinceau × 1.15. |
| - | RTS Terrain Studio/Strength Down | Intensité du pinceau − 5 %. |
| = | RTS Terrain Studio/Strength Up | Intensité du pinceau + 5 %. |
| R | RTS Terrain Studio/Toggle Random Rotation | Active ou désactive la rotation aléatoire du pinceau. Lorsque Select Decor est actif, sélectionne à la place l’outil Scale de Unity. |
| G | RTS Terrain Studio/Toggle Grid | Affiche ou masque la grille des cellules. |
| P | RTS Terrain Studio/Cycle Pathing Overlay | Fait défiler Off → Walkability → Buildability → Combined → Off. |
| 1 | RTS Terrain Studio/Height Tools | Sé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. |
| 2 | RTS Terrain Studio/Cliff Tools | |
| 3 | RTS Terrain Studio/Paint Tools | |
| 4 | RTS Terrain Studio/Vegetation Tools | |
| 5 | RTS Terrain Studio/Decor Tools | |
| 6 | RTS Terrain Studio/Water Tools | |
| 7 | RTS Terrain Studio/Pathing Tools | |
| 8 | RTS 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 :
| Touche | Emplacement | Action |
|---|---|---|
| Shift (maintenue) | Scene View | Inverser l’outil (abaisser, effacer, retirer). |
| Ctrl+clic (Cmd+clic sur macOS) | Scene View | Prélever une valeur (hauteur, calque, niveau, type de falaise, hauteur d’eau). |
| Esc | Scene View ayant le focus clavier | Annuler 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 Studio | Changer d’onglet de catégorie. |
| Esc | Fenêtre RTS Terrain Studio | Annuler le trait et arrêter l’édition. |
| Tab, Enter, Space | Fenêtre RTS Terrain Studio | Déplacer le focus entre les outils et les onglets ; activer l’élément qui a le focus. |
| Ctrl+clic, Shift+clic | Grilles de prototypes | Ajouter 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 , sous les catégories de Unity (Main Menu/Edit, Tools) :
| Touche par défaut | Emplacement | Action |
|---|---|---|
| Ctrl+Z / Ctrl+Y | Partout dans Unity | Annuler / rétablir les modifications du terrain via le menu Edit de Unity. |
| W E Y | Scene View, outil Select Decor | Outils Move, Rotate et Transform de Unity : ils choisissent la poignée de la sélection de décors. |
| Delete, Ctrl+D, Ctrl+A, F | Scene View, outil Select Decor | Delete, 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
- Ouvrez (sur macOS, ) ou cliquez sur Edit Shortcuts… dans l’onglet Settings.
- Sélectionnez la catégorie RTS Terrain Studio.
- Affectez de nouvelles touches aux entrées listées ci-dessus.
- 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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Shape | Circle, Square, Diamond, Custom | Circle | Contour du pinceau. Les formes Square et Diamond acceptent une rotation. Custom utilise un asset Brush Shape. |
| Custom Shape | – | aucun | L’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. |
| Radius | 0.25–128 m | 6 m | Rayon du pinceau en mètres. Le curseur est logarithmique pour permettre un réglage fin des petits pinceaux. Raccourcis [ et ]. |
| Strength | 0.01–1 | 0.5 | Effet de chaque empreinte. Raccourcis - et =. |
| Hardness | 0–1 | 0.35 | 0 = bord doux sur tout le rayon, 1 = bord net. Désactivé tant que Falloff Curve est activé. |
| Falloff Curve | activé/désactivé | désactivé | Utilise une courbe personnalisée au lieu de Hardness. |
| Curve | – | ease in-out de 1 à 0 | Poids depuis le centre du pinceau (x = 0) jusqu’à son bord (x = 1). |
| Rotation | 0–360° | 0 | Rotation 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 Rotation | activé/désactivé | désactivé | Fait pivoter chaque empreinte de façon aléatoire. Idéal avec des tampons personnalisés. Raccourci R. |
| Spacing | 0.05–2 | 0.2 | Distance entre les empreintes, proportionnelle au rayon. Des valeurs plus petites donnent des traits plus lisses. |
| Jitter | 0–1 | 0 | Dé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 × spacingmè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.
- 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.
- Créez l’asset avec et assignez-lui la texture.
- 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.
- 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ètre | Par défaut | Description |
|---|---|---|
| Texture | aucune | Texture en niveaux de gris ou alpha. Blanc = effet complet. |
| Use Red Channel | activé | Lit le canal rouge. Désactivez-le pour lire le canal alpha à la place. |
| Invert | désactivé | Inverse le masque. |
| Resolution | 64 | Ré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être | Nom de l’overlay / dans le code | Copies | Rôle | À utiliser pour |
|---|---|---|---|---|
| Off | None | 1 | Seul le pinceau lui-même peint. | Cartes libres, cartes de campagne, détails de finition qui ne doivent pas se répéter. |
| Mirror X | Mirror X (MirrorX) | 2 | Reflète gauche ↔ droite par rapport à l’axe vertical passant par le centre. | Deux joueurs ou équipes face à face, ouest contre est. |
| Mirror Z | Mirror Z (MirrorZ) | 2 | Reflète haut ↔ bas par rapport à l’axe horizontal. | Deux joueurs ou équipes face à face, nord contre sud. |
| Mirror XZ | Mirror XZ (MirrorXZ) | 4 | Reflè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) | 2 | Symé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) | 4 | Symétrie de rotation par quarts de tour. Nécessite une carte carrée. | Le classique chacun pour soi à quatre joueurs. |
| Diagonal | Mirror Diagonal (MirrorDiagonal) | 2 | Reflè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 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 clic | Une é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écor | Une é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 Scene | Une étape chacun (Generate Map, Import Heightmap, Auto Paint Map …). |
| Champs des informations de la carte et de l’environnement | Une étape lorsque vous quittez le champ (Edit Map Info, Edit Environment). |
| Trait annulé avec Esc | Aucune étape. Les modifications du trait sont défaites. |
| New Map, Resize, Open, Reload, passage à un autre terrain | Impossible à 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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Max Steps | 10–1000 | 100 | Nombre d’étapes d’annulation conservées. |
| Memory Limit (MB) | 32–4096 | 512 | Mé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.
| Outil | Id | Rôle | Saisie et touches de modification |
|---|---|---|---|
| Raise / Lower | height.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. |
| Smooth | height.smooth | Adoucit les bosses et les arêtes vives du sol sans estomper les parois de falaise. | Pinceau, répété 20 fois/s. |
| Flatten | height.flatten | Aplanit 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 Height | height.set | Rè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. |
| Noise | height.noise | Ajoute 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. |
| Terrace | height.terrace | Transforme 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. |
| Erode | height.erode | Simule 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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Speed | 0.01–2 | 0.15 | Variation de hauteur par empreinte, en mètres, à pleine intensité du pinceau. |
Paramètres de l’outil Smooth
| Paramètre | Plage | Par défaut | Description |
|---|---|---|---|
| Filter Radius | 1–4 | 1 | Voisinage, en vertices, sur lequel la moyenne est calculée. Des valeurs plus élevées éliminent des reliefs plus grands. |
| Iterations | 1–8 | 2 | Passes de lissage par empreinte. |
Paramètres de l’outil Flatten
| Paramètre | Plage | Par défaut | Description |
|---|---|---|---|
| Target | Stroke Start, Fixed Height | Stroke Start | Stroke Start utilise la hauteur sous le curseur au début du trait. Fixed Height utilise Target Height. |
| Target Height | −32–32 m | 0 | Hauteur 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. |
| Mode | Flatten, Raise Only, Lower Only | Flatten | Aplanir 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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Height | −32–64 m | 0 | Hauteur à 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 Space | Fine Height, Ground Height | Fine Height | Hauteur fine relative au niveau de falaise, ou hauteur absolue du sol. |
Paramètres de l’outil Noise
| Paramètre | Plage | Par défaut | Description |
|---|---|---|---|
| Noise Type | Fbm, Ridged, Billow | Fbm | Fbm : collines ondulées. Ridged : crêtes vives. Billow : bosses arrondies. |
| Scale | 2–256 m | 24 | Taille des reliefs les plus grands. |
| Amplitude | 0.01–4 m | 0.25 | Hauteur ajoutée par empreinte à pleine intensité. |
| Octaves | 1–8 | 4 | Nombre de couches de détail. Plus il y a d’octaves, plus les détails ajoutés sont fins. |
| Roughness | 0.2–0.8 | 0.5 | Rapport d’amplitude entre les octaves. Des valeurs plus élevées donnent un sol plus accidenté. |
| Seed | 0–9999 | 1 | Modifie le motif. La même graine produit toujours le même motif. |
Paramètres de l’outil Terrace
| Paramètre | Plage | Par défaut | Description |
|---|---|---|---|
| Step Height | 0.1–8 m | 1 | Hauteur d’une marche de terrasse. |
| Sharpness | 0–1 | 0.7 | 0 = marches douces et arrondies. 1 = contremarches nettes et raides. |
| Offset | −4–4 m | 0 | Décale toutes les marches vers le haut ou vers le bas. |
Paramètres de l’outil Erode
| Paramètre | Plage | Par défaut | Description |
|---|---|---|---|
| Talus Angle | 5–70° | 30 | Les pentes plus escarpées que cet angle s’érodent. |
| Erosion Strength | 0.05–1 | 0.5 | Part de la matière excédentaire déplacée à chaque itération. |
| Iterations | 1–50 | 8 | Passes 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.
| Outil | Id | Rôle | Saisie et touches de modification |
|---|---|---|---|
| Raise / Lower Level | cliff.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 Level | cliff.set | Peint un niveau de falaise exact, pratique pour les grands plateaux, les cuvettes et les ébauches rapides. | Pinceau. Ctrl+clic : prélever le niveau. |
| Ramp | cliff.ramp | Transforme 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 Type | cliff.type | Change 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 Cliffs | cliff.smoothEdges | Supprime 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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Break Ramps | activé/désactivé | activé | Retire l’indicateur de rampe des vertices dont le niveau change. |
| Paint Cliff Edges | activé/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 Width | 0.25–4 cellules | 1 | Largeur du bord peint, mesurée à partir de la paroi de falaise. |
| Edge Strength | 0.1–1 | 0.9 | Degré de recouvrement du sol par le calque de bord juste à côté de la paroi. |
| Edge Sides | Both / Top / Bottom | Both | Peindre le rebord du plateau, le pied de la falaise, ou les deux. |
| Clean Up Old Edges | activé/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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Level | 0–15 (palette) | 2 | Niveau de falaise à peindre. |
| Break Ramps | activé/désactivé | activé | Retire l’indicateur de rampe des vertices dont le niveau change. |
| Paramètres de bord | comme ci-dessus | Paint 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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Cliff Type | 0–3 (palette) | 0 | Calque de falaise du tileset à peindre. |
Paramètres de l’outil Clean Cliffs
| Paramètre | Plage | Par défaut | Description |
|---|---|---|---|
| Strictness | 5–8 | 8 | Nombre 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 Ramps | activé/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.
- 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).
- Choisissez Raise / Lower Level, Set Level, Ramp ou Clean Cliffs, et laissez Paint Cliff Edges activé.
- 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.
| Outil | Id | Rôle | Saisie et touches de modification |
|---|---|---|---|
| Paint Layer | paint.layer | Peint 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 Paint | paint.tile | Peint 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 / Replace | paint.fill | Remplace 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 Paint | paint.smooth | Floute les transitions entre calques de sol sous le pinceau pour obtenir des fondus plus doux. | Pinceau, répété 15 fois/s. |
| Auto Paint | paint.auto | Peint 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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Layer | palette | 0 | Calque de sol du tileset à peindre. |
| Opacity | 0.05–1 | 1 | Couverture 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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Layer | palette | 0 | Calque de sol du tileset à peindre. |
| Soft Border | activé/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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Layer | palette | 0 | Calque de sol utilisé pour remplir la zone. |
| Mode | Replace Dominant Layer, Fill Connected, Fill All | Fill Connected | Replace 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 Blends | activé/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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Blur Radius | 1–3 | 1 | Taille du noyau de flou, en texels de splat. Des valeurs plus élevées lissent plus rapidement. |
Paramètres de l’outil Auto Paint
| Paramètre | Par défaut | Description |
|---|---|---|
| Profile | aucun | L’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é.
| Outil | Id | Rôle | Saisie et touches de modification |
|---|---|---|---|
| Paint Details | veg.details | Peint 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 Details | veg.detailsErase | Supprime l’herbe et les autres détails de végétation sous le pinceau. | Pinceau, répété 10 fois/s. |
| Place Trees | veg.trees | Disperse 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 Trees | veg.treesErase | Supprime 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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Details | grille de prototypes | aucun | Prototypes de détails à peindre. |
| Target Density | 0–1 | 0.6 | Densité vers laquelle peint le pinceau (1 = densité maximale du prototype). |
| Mode | Raise, Set | Raise | Raise ne fait qu’augmenter la densité. Set éclaircit aussi les zones plus denses jusqu’à la cible. |
Paramètres de l’outil Erase Details
| Paramètre | Plage | Par défaut | Description |
|---|---|---|---|
| Only Selected | activé/désactivé | désactivé | N’effacer que les prototypes de détails sélectionnés au lieu de tous les détails. |
| Details | grille de prototypes | aucun | Prototypes de détails à effacer lorsque Only Selected est activé. |
Paramètres de l’outil Place Trees
| Paramètre | Plage | Par défaut | Description |
|---|---|---|---|
| Trees | grille de prototypes | aucun | Prototypes d’arbres placés au hasard. |
| Mode | Scatter, Single | Scatter | Scatter peint des arbres avec le pinceau. Single place un arbre par clic et affiche un aperçu fantôme. |
| Density | 0.05–5 | 0.6 | Nombre d’arbres par 100 m² que fait apparaître chaque empreinte à pleine intensité. L’espacement minimal des prototypes s’applique toujours. |
| Max Slope | 0–90° | 35 | Les arbres dispersés ne sont pas placés sur des pentes plus escarpées. |
| Avoid Water | activé/désactivé | activé | Ne pas disperser d’arbres sous l’eau. |
Paramètres de l’outil Erase Trees
| Paramètre | Plage | Par défaut | Description |
|---|---|---|---|
| Only Selected | activé/désactivé | désactivé | Ne supprimer que les arbres des prototypes sélectionnés. |
| Trees | grille de prototypes | aucun | Prototypes 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.
| Outil | Id | Rôle | Saisie et touches de modification |
|---|---|---|---|
| Place Decor | decor.place | Place 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 Decor | decor.erase | Supprime 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 Decor | decor.select | Sé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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Mode | Single, Scatter | Single | Single place un objet par clic, avec un aperçu fantôme. Scatter peint des objets au pinceau. |
| Decor | grille de prototypes | aucun | Prototypes de décor placés au hasard. Si aucun n’est sélectionné, le premier de la bibliothèque est utilisé. |
| Density | 0.05–5 | 0.4 | Scatter : nombre d’objets par 100 m² que fait apparaître chaque empreinte à pleine intensité. |
| Use Prototype Defaults | activé/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 Yaw | activé/désactivé | activé | Rotation aléatoire autour de l’axe vertical (si les valeurs par défaut du prototype ne sont pas utilisées). |
| Yaw | 0–360° | 0 | Rotation autour de l’axe vertical lorsque Random Yaw est désactivé. |
| Scale | 0.1–5 | 1 | Multiplicateur appliqué à l’échelle aléatoire du prototype. |
| Align To Ground | 0–1 | 0 | 0 = vertical, 1 = suit la pente du sol (si les valeurs par défaut du prototype ne sont pas utilisées). |
| Snap To Grid | activé/désactivé | désactivé | Place les objets au centre des cellules. |
| Random Variant | activé/désactivé | activé | Utilise une variante de prefab aléatoire du prototype. |
| Max Slope | 0–90° | 90 | Scatter : ignore les pentes plus escarpées que cette valeur. 90 = aucune limite. |
| Avoid Water | activé/désactivé | désactivé | Scatter : ne place aucun objet sous l’eau. |
Paramètres de l’outil Erase Decor
| Paramètre | Plage | Par défaut | Description |
|---|---|---|---|
| Only Selected | activé/désactivé | désactivé | Ne supprime que les objets des prototypes sélectionnés. |
| Decor | grille de prototypes | aucun | Prototypes de décor à supprimer lorsque Only Selected est activé. |
Paramètres de l’outil Select Decor
| Paramètre | Plage | Par défaut | Description |
|---|---|---|---|
| Pick Radius | 0.25–10 m | 1 | Distance 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 Locked | activé/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.
| Bouton | Action |
|---|---|
| Select All | Sélectionne tous les objets de décor de la carte (les objets verrouillés sont ignorés). |
| Clear | Vide la sélection. |
| Delete | Supprime les objets sélectionnés. |
| Duplicate | Duplique 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 Ground | Repose 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 / Unlock | Les 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.
| Outil | Id | Rôle | Saisie et touches de modification |
|---|---|---|---|
| Paint Water | water.paint | Peint 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 Water | water.erase | Retire l’eau des vertices situés sous le pinceau. | Pinceau. |
| Flood Fill | water.flood | Remplit 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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Water Height | Cliff Level Plus Offset, Absolute Height, Picked Height | Cliff Level Plus Offset | Méthode de détermination de la hauteur de la surface de l’eau. |
| Level | 0–15 (palette) | 1 | Niveau de falaise sur lequel se base la surface de l’eau (mode Cliff Level Plus Offset). |
| Offset | −8–16 m | 0.6 niveau | Hauteur 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 m | 3.2 | Surface de l’eau en mètres, dans l’espace local de la carte (mode Absolute Height). |
| Picked Height | −16–64 m | 3.2 | Hauteur 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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Force | activé/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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Max Vertices | 100–1,000,000 | 20,000 | Limite 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.
| Outil | Id | Rôle | Saisie et touches de modification |
|---|---|---|---|
| Paint Pathing | pathing.paint | Peint 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 Pathing | pathing.clear | Supprime toutes les surcharges de cheminement peintes, pour que le cheminement automatique s’applique de nouveau. | Pinceau. |
Paramètres de l’outil Paint Pathing
| Paramètre | Plage | Par défaut | Description |
|---|---|---|---|
| Override | voir ci-dessous | Blocker | Surcharge de cheminement à peindre. |
| Surcharge | Effet |
|---|---|
| Blocker | Non praticable et non constructible : un mur invisible, typique des bordures de la carte et des zones décoratives. |
| Unwalkable | Les unités terrestres ne peuvent pas s’y déplacer. |
| Unbuildable | Aucun bâtiment ne peut y être placé, par exemple pour garder libres les passages et les expansions. |
| Unflyable | Les unités aériennes ne peuvent pas survoler cette zone. |
| Force Walkable | Les unités terrestres peuvent s’y déplacer, même si la pente, l’eau ou des emprises bloqueraient le passage. |
| Force Buildable | Des bâtiments peuvent y être placés, même si les règles déduites l’interdiraient. |
Couleurs de la superposition de cheminement
| Superposition | Couleurs |
|---|---|
| Walkability | Vert = praticable, rouge = bloqué, rouge foncé = falaise, orange = trop escarpé, bleu = eau profonde, cyan = eau peu profonde. |
| Buildability | Vert = constructible, jaune = praticable mais non constructible, rouge / rouge foncé = non praticable. |
| Flyability | Bleu clair = survolable, magenta = non survolable. |
| Water | Cyan = eau peu profonde, bleu = eau profonde. |
| Combined | Tout à 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.
| Outil | Id | Rôle | Saisie et touches de modification |
|---|---|---|---|
| Start Locations | markers.start | Place 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. |
| Regions | markers.region | Faites 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. |
| Markers | markers.marker | Place 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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Player | Player 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. |
| Yaw | 0–360° | 0 | Orientation de la position de départ. |
| Symmetry Assigns Next Players | activé/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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Color | couleur | bleu translucide | Couleur des nouvelles régions. |
| Snap To Cells | activé/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ètre | Plage | Par défaut | Description |
|---|---|---|---|
| Name | texte | Marker | Nom des nouveaux marqueurs. Un numéro est ajouté si le nom est déjà utilisé. |
| Tag | texte | vide | Texte libre que le code de votre jeu utilise pour retrouver les marqueurs, par exemple camera ou waypoint. |
| Yaw | 0–360° | 0 | Orientation 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
- 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 .
- 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.
- 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.
- Cliquez sur Use In Auto Paint Tool pour que l’outil pinceau peigne avec ce profil.
| Paramètre du profil | Par défaut | Description |
|---|---|---|
| Base Layer | 0 | Calque qui recouvre chaque texel avant l’application des règles. |
| Start From Existing | dé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ètre | Par défaut | Description |
|---|---|---|
| Name | Rule | Nom affiché de la règle. |
| Layer | 0 | Calque de sol (index dans le tileset) peint par cette règle. |
| Enabled | activé | Les règles désactivées sont ignorées. |
| Use Height, Min Height, Max Height | désactivé, 0, 20 | Peint uniquement là où la hauteur du sol dans l’espace local de la carte (en mètres) se situe dans la plage. |
| Height Falloff | 0.5 | Transition douce au-delà de la plage de hauteur, en mètres (0 = bord net). |
| Use Slope, Min Slope, Max Slope | désactivé, 0, 90 | Peint uniquement là où la pente (en degrés) se situe dans la plage. |
| Slope Falloff | 5 | Transition douce au-delà de la plage de pente, en degrés. |
| Use Cliff Level, Min Cliff Level, Max Cliff Level | désactivé, 0, 15 | Peint uniquement sur ces niveaux de falaise (bord net). |
| Near Cliff Distance | 0 | Peint uniquement jusqu’à cette distance d’une paroi de falaise, en cellules (0 = désactivé). S’estompe sur la moitié extérieure. |
| Near Water Distance | 0 | Peint uniquement jusqu’à cette distance de l’eau, en cellules (0 = désactivé). S’estompe sur la moitié extérieure. |
| Noise Scale | 16 | Taille des motifs du bruit, en mètres. |
| Noise Amount | 0 | Force avec laquelle le bruit fragmente la règle (0 = aucun bruit, 1 = plaques). |
| Noise Seed | 0 | Des règles avec des graines différentes produisent des plaques différentes. |
| Strength | 1 | Intensité globale de la règle (0–1). |
| Blend Mode | Replace | Manière dont la règle se combine avec les règles situées au-dessus d’elle (voir ci-dessous). |
| Mode de fondu | Effet |
|---|---|
| Add | Ajoute le calque de la règle par-dessus. Les calques existants sont réduits proportionnellement lors de la normalisation du résultat. |
| Replace | Fait tendre chaque calque vers le calque de la règle, selon le poids de la règle. C’est le choix habituel. |
| Multiply | Multiplie 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ègle | Peint | Conditions |
|---|---|---|
| Dirt Patches | terre | Plaques de bruit (échelle 14 m), intensité 0.55. |
| Sand Shore | sable | Jusqu’à 3 cellules de l’eau, légèrement fragmenté par du bruit. |
| Rock Slopes | roche | Pentes de 28° ou plus (atténuation de 8°). |
| Rock Near Cliffs | roche | Jusqu’à 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 , ou ajoutez-le à n’importe quel GameObject avec .
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
| Zone | Contenu |
|---|---|
| Header | Nom 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. |
| Actions | Open RTS Terrain Studio, Edit Terrain (active ou désactive l’édition dans la Scene View pour ce terrain), Save, Save As… et Reload. |
| Warnings | Problè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). |
| Assets | Champs Map, Tileset, Vegetation et Decor, chacun avec un bouton New qui crée et assigne un nouvel asset. |
| Chunks & Geometry, Cliff Shape, Physics, Rendering | Les paramètres du terrain (tableau ci-dessous). |
| Pathing Rules | Mode de déduction de la carte de cheminement (tableau ci-dessous). Elle est reconstruite automatiquement après chaque modification. |
| Default Map | Taille et valeurs par défaut de la carte créée lorsqu’aucun asset de carte n’est assigné. |
| Rebuild Terrain | 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 é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ètre | Par défaut | Description |
|---|---|---|
| Chunks & Geometry | ||
| Chunk Size | 32 | Nombre 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 Subdivisions | 2 | Nombre de quads par côté de cellule sur un sol lisse (1–4). 1 = aspect RTS classique, 2–4 = collines plus douces. |
| Cliff Subdivisions | 4 | Ré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 Noise | 0.18 | Dé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 Scale | 1.6 | Échelle du bruit de falaise, en unités monde (minimum 0.1). |
| Cliff Slant | 0.12 | Recul du bord supérieur d’une falaise, qui incline légèrement les parois, en fraction de cellule (0–0.4). |
| Cliff Wall Segments | 3 | Nombre de segments verticaux par niveau de falaise pour la géométrie des parois (1–8). |
| Physics | ||
| Collider Mode | Mesh Collider | None : aucun collider ; utilisez le raycast du terrain pour les requêtes. Mesh Collider : un MeshCollider par chunk, reconstruit après chaque modification. |
| Chunk Layer | Default (0) | Layer des GameObjects des chunks, utilisé par les colliders et les caméras. |
| Rendering | ||
| Cast Shadows | On | Mode de projection des ombres des chunks. |
| Receive Shadows | activé | Indique si les chunks reçoivent des ombres. |
| Material Override | aucun | Matériau facultatif. S’il est vide, un matériau utilisant le shader RTS Terrain Studio/Terrain est créé. |
| Show Grid | dé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 Opacity | 0.35 | Opacité 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ètre | Par défaut | Description |
|---|---|---|
| Max Walkable Slope | 42° | Un sol plus escarpé que cet angle n’est pas praticable. |
| Max Buildable Slope | 18° | Un sol plus escarpé que cet angle n’est pas constructible. |
| Cliff Margin | 0.25 | Distance 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 Buildable | désactivé | Autorise les bâtiments en eau peu profonde. |
| Tree Footprint Scale | 1 | Multiplicateur du rayon d’emprise de cheminement de chaque arbre. |
| Use Ground Layer Rules | activé | 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ètre | Par défaut | Description |
|---|---|---|
| Width / Height | 128 / 128 | Taille en cellules, multiple de 16 (16–1024). |
| Cell Size | 2 | Taille d’une cellule, en unités monde. |
| Cliff Level Height | 2 | Hauteur d’un niveau de falaise, en unités monde. |
| Base Cliff Level | 2 | Niveau de falaise initial de chaque vertex (0–15). |
| Base Ground Layer | 0 | Calque de sol qui recouvre initialement la carte. |
| Splat Resolution | 4 | Nombre de texels de splat par cellule (1, 2, 4 ou 8). |
| Detail Resolution | 2 | Nombre de texels de densité de détails par cellule (1, 2 ou 4). |
| Pathing Resolution | 2 | Nombre 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.
| Composant | Ajouté par le menu de création | Utilité |
|---|---|---|
| Vegetation Renderer | oui | Affiche 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 Renderer | oui | Construit 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 Manager | oui | Affiche les objets de décor de la carte et les maintient au sol lorsque les hauteurs changent. |
| Environment | par le New Map Wizard (facultatif), ou via | Applique à 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 Manager | Calcule le brouillard de guerre pour l’équipe locale. Un seul par scène. | |
| 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.

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.
- Choisissez . 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.
- 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. - 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.
- 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.
- 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.
- Appuyez sur Esc ou F5 pour revenir à l’éditeur. La carte retrouve exactement son état d’avant le test en jeu.
- 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 ().
- 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/UIdu package. Il contient le thème et la feuille de style de l’interface.
Étapes
- Ouvrez votre scène et choisissez .
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. - 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.
- 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).
- 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 :
| Objet | Utilité |
|---|---|
RTSEditSession | La 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 UI | Contient un UIDocument avec l’interface complète de l’éditeur. Il est détruit dès que le composant est désactivé. |
RTSRuntimeEditorCamera | Ajouté à 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. |
RuntimeToolGizmos | Dessine 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. |
PanelSettings | Créé 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.mainet 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ètre | Par défaut | Description |
|---|---|---|
| Scene | ||
| Terrain | vide | Le terrain à éditer. Si le champ est vide, le premier RTS Terrain de la scène est utilisé (RTSTerrain.Main). |
| Target Camera | vide | La 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 Camera | activé | 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 Visible | activé | 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 Key | F2 | Affiche 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 Tool | height.raise | L’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 Hint | activé | 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 Command | activé | 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 Changes | activé | 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 MB | 512 | La 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 Url | vide | La 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 Folder | vide | Le 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 Images | activé | É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 Settings | vide | Panel 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 Scale | activé | 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 Scale | 1 | Facteur 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 Order | 1000 | L’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.
| Zone | Position | Contenu |
|---|---|---|
| Barre supérieure | bord supérieur | Menus File et Map, annulation et rétablissement, symétrie, options d’affichage, Play Test, aide, masquage des panneaux, fermeture. |
| Barre d’outils | bord gauche | Huit boutons de catégorie (touches 1 à 8) et les outils de la catégorie sélectionnée. |
| Panneau d’outil | bord droit | Nom 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’état | bord inférieur | Informations sur le point situé sous le curseur, état de l’outil, pinceau, mémoire d’annulation et nom de la carte. |
| Éléments superposés | au-dessus de la carte | Notifications, info-bulles, boîtes de dialogue, astuce de bienvenue, barre de test en jeu et messages d’information. |
Barre supérieure
| Commande | Rôle |
|---|---|
| File | Ouvre le menu File (voir ci-dessous). |
| Map | Ouvre le menu Map (voir ci-dessous). |
| Undo / Redo | Annuler (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: Off | Ouvre 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°. |
| Grid | Affiche ou masque la grille des cellules (G). |
| Pathing | Ouvre 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. |
| Markers | Affiche 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 Test | Lance un test en jeu (F5). |
| Help (?) | Ouvre la fenêtre Shortcuts & Help (F1). |
| Eye | Masque 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ément | Raccourci | Rô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+O | Ouvre 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. |
| Save | Ctrl+S | Enregistre 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+S | Ouvre l’explorateur de cartes pour enregistrer la carte sous un nouveau nom. |
| Download Map | Builds 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 Folder | Ouvre 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. | |
| Quit | Ferme 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ément | Rô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 Map | Déplace la caméra de l’éditeur pour que toute la carte soit visible. Disponible uniquement avec la caméra intégrée. |
| Edited terrain | Affiché 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
| Mode | Copies | Usage typique |
|---|---|---|
| Off | 1 | Peindre sans symétrie. |
| Mirror Left / Right | 2 | Reflète par rapport à l’axe central vertical. |
| Mirror Top / Bottom | 2 | Reflète par rapport à l’axe central horizontal. |
| Mirror 4-Way | 4 | Reflète selon les deux axes. |
| Rotate 180° | 2 | Symétrie centrale autour du centre, typique des cartes 1v1. |
| Rotate 90° (4 players) | 4 | Symé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 Diagonal | 2 | Reflè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.
| Touche | Catégorie | Description | Outils |
|---|---|---|---|
| 1 | Height | Élever, abaisser, lisser et modeler le sol. | Raise / Lower, Smooth, Flatten, Set Height, Noise, Terrace, Erode |
| 2 | Cliffs | Niveaux de falaise, rampes et matériaux de falaise dans le style des RTS classiques. | Raise / Lower Level, Set Level, Ramp, Cliff Type, Clean Cliffs |
| 3 | Paint | Peindre les textures de sol. | Paint Layer, Tile Paint, Fill / Replace, Smooth Paint, Auto Paint |
| 4 | Vegetation | Herbe, fleurs et arbres. | Paint Details, Erase Details, Place Trees, Erase Trees |
| 5 | Decor | Placer, effacer et sélectionner des objets (doodads). | Place Decor, Erase Decor, Select Decor |
| 6 | Water | Lacs, rivières et mers. | Paint Water, Erase Water, Flood Fill |
| 7 | Pathing | Définir où les unités peuvent se déplacer, construire et voler. | Paint Pathing, Clear Pathing |
| 8 | Markers | Positions 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.
| Section | Affichée pour | Contenu |
|---|---|---|
| (à propos) | tous les outils | La description et l’indication d’utilisation de l’outil, par exemple Click: place / move · Shift+click: remove the nearest. |
| Brush | outils pinceaux | Shape (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. |
| Symmetry | tous les outils | Mode de symétrie, Centre X et Centre Z, et un avertissement lorsque le mode nécessite une carte carrée. |
| Settings | outils dotés d’options | Les 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. |
| Actions | certains outils | Commandes supplémentaires : Apply to Whole Map (Auto Paint), New Random Layout (Place Trees, Place Decor) et autres commandes similaires. |
| Selection | Select Decor | Delete, 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ément | Exemple | Signification |
|---|---|---|
| Cell | Cell 42, 17 | La cellule sous le curseur (x, z). |
| Height | Height 3.5 m | Hauteur du sol sous le curseur, en mètres. |
| Level | Level 2 | Le niveau de falaise sous le curseur (0 à 15). |
| Pathing | Walkable, Buildable | Ce que les unités peuvent faire à cet endroit, par exemple Shallow water, Cliff, Too steep, Blocked ou No flying. |
| Water | Water 1.2 m ou Dry | Profondeur d’eau sous le curseur. |
| État de l’outil | Informations fournies par l’outil actif, ou son indication d’utilisation. | |
| Brush | Brush 8.0 m 50 % | Rayon et intensité du pinceau. |
| Undo | Undo 12 4.2 MB | Le nombre d’étapes d’annulation et la mémoire qu’elles occupent. |
| Nom de la carte | ● Sandbox | Le 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 dialogue | Ouverte par | Contenu |
|---|---|---|
| New Map | File ▸ 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 Map | Map ▸ 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 Info | Map ▸ 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 Map | Map ▸ 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 As | File ▸ Open... / Save As... | L’explorateur de cartes. |
| Unsaved Changes | New, Open, Quit en présence de modifications non enregistrées | Save (enregistre d’abord, et demande un nom si la carte n’en a pas), Don't Save, Cancel. |
| Shortcuts & Help | F1 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.
| Partie | Description |
|---|---|
| Ligne du dossier | Le 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 cartes | Une 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étails | L’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 Name | Uniquement 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. |
| Delete | Supprime 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. |
| Download | Builds 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 / Save | Open 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
- Appuyez sur Ctrl+Shift+S. Le champ du nom contient déjà le nom de la carte actuelle.
- Saisissez un nouveau nom, par exemple
Glacier Pass (2v2), puis appuyez sur Enter. - 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.
- 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
| Saisie | Action |
|---|---|
| Bouton gauche de la souris | Peindre 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 souris | L’action inverse : abaisser au lieu d’élever, effacer au lieu de peindre, retirer au lieu de placer. |
| Ctrl + clic gauche | Pré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 milieu | Déplacer la caméra (« attraper le sol »). |
| Alt + glisser avec le bouton gauche ou droit | Faire pivoter la caméra. Tant que la touche Alt est enfoncée, le bouton gauche ne peint pas. |
| Molette de la souris | Zoomer et dézoomer en direction du point situé sous le curseur. |
Caméra (caméra intégrée de l’éditeur)
| Touche | Action |
|---|---|
| W A S D ou touches fléchées | Déplacer la caméra. Maintenez Shift enfoncée pour aller plus vite. |
| Q / E | Pivoter vers la gauche / la droite. |
| F | Centrer la caméra sur le point situé sous le curseur. |
Pinceau et outils
| Touche | Action |
|---|---|
| [ / ] | 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 à 8 | Sé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. |
| Esc | Annuler le trait en cours. Le terrain revient à l’état dans lequel il était quand vous avez appuyé sur le bouton. |
Fichier et historique
| Touche | Action |
|---|---|
| Ctrl+N ou Alt+N | Nouvelle carte. Dans les navigateurs web, seul Alt+N fonctionne, car le navigateur réserve Ctrl+N à l’ouverture d’une nouvelle fenêtre. |
| Ctrl+O | Ouvrir une carte (explorateur de cartes). |
| Ctrl+S | Enregistrer. Demande un nom la première fois. |
| Ctrl+Shift+S | Enregistrer sous. |
| Ctrl+Z | Annuler. |
| Ctrl+Y ou Ctrl+Shift+Z | Rétablir. |
Affichage et éditeur
| Touche | Action |
|---|---|
| G | Afficher ou masquer la grille des cellules. |
| P | Activer la superposition de cheminement (dernier mode utilisé, Combined au départ) ou la désactiver. |
| M | Afficher ou masquer les positions de départ, les régions et les marqueurs. |
| H | Masquer ou afficher les panneaux de l’éditeur. |
| F1 | Ouvrir Shortcuts & Help. |
| F5 | Lancer 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)
| Saisie | Action |
|---|---|
| Cliquer / tracer un rectangle de sélection | Sélectionner des objets. |
| Shift + clic / rectangle | Ajouter 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 multiple | Sélectionner uniquement cet objet. |
| Delete / Backspace | Supprimer les objets sélectionnés. |
| Ctrl+D | Dupliquer la sélection, décalée d’une cellule en diagonale (+X et +Z). |
| Ctrl+A | Sélectionner tous les objets non verrouillés. |
| Esc | Vider la sélection. |
Ce que fait la touche Esc
Esc exécute la première des actions suivantes qui s’applique :
- Ferme un menu déroulant ouvert.
- Retire le focus clavier d’un champ de texte ou d’un curseur.
- Ferme la boîte de dialogue au premier plan.
- Annule le glissement de décors (les objets reviennent à leur place).
- Annule le trait en cours (notification Stroke cancelled).
- Vide la sélection de décors (outil Select Decor).
- 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ètre | Par défaut | Description |
|---|---|---|
| Movement | ||
| Pan Speed | 18 | Vitesse de déplacement au clavier, en mètres par seconde, à la hauteur minimale. Elle augmente avec la hauteur. |
| Fast Multiplier | 2.5 | Multiplicateur de la vitesse de déplacement tant que Shift est maintenue enfoncée. |
| Edge Pan | désactivé | Déplace la caméra lorsque la souris touche le bord de l’écran. |
| Edge Pan Margin | 12 | Largeur de la bordure d’écran utilisée pour le défilement par les bords, en pixels. |
| Rotate Speed | 100 | Vitesse de rotation de Q / E, en degrés par seconde. |
| Mouse Rotate Speed | 0.25 | Rotation appliquée par Alt + glissement de la souris, en degrés par pixel. |
| Zoom | ||
| Min Height | 8 | Hauteur minimale de la caméra au-dessus du point focal, en mètres. |
| Max Height | 120 | Hauteur maximale de la caméra au-dessus du point focal, en mètres. |
| Zoom Step | 0.14 | Variation de hauteur par cran de molette, exprimée en fraction de la hauteur actuelle. |
| Zoom Towards Cursor | activé | Zoome vers le point situé sous le curseur plutôt que vers le centre de l’écran. |
| Min Pitch | 40 | Inclinaison en degrés sous l’horizon, à la hauteur minimale. |
| Max Pitch | 70 | Inclinaison à la hauteur maximale. |
| Pitch Curve | courbe ease-in-out | Interpolation entre Min Pitch (0) et Max Pitch (1) selon la hauteur normalisée. |
| Limits & Smoothing | ||
| Ground Clearance | 3 | Distance minimale autorisée entre la caméra et le sol situé en dessous, en mètres. |
| Bounds Padding | 8 | Espace supplémentaire autour du terrain dans lequel le point focal peut se déplacer, en mètres. |
| Smooth Time | 0.1 | Temps 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 :
| Membre | Description |
|---|---|
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 Height | L’orbite actuelle (lecture seule). |
bool IsDragging, bool WantsAltDrag | Vaut true tant que la caméra est déplacée par glissement, ou tant que la touche Alt est enfoncée. |
bool PointerBlocked, bool KeyboardBlocked | Dé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 Terrain | Le 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.

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
() é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
| Quand | L’éditeur… |
|---|---|
| Vous appuyez sur Play Test |
|
| Pendant le test en jeu | Ignore 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 |
|
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.
| Membre | Description |
|---|---|
static bool IsPlaytesting | Vaut true tant qu’un test en jeu est en cours. |
static event Action<bool> PlaytestChanged | Déclenché au début (true) ou à la fin (false) d’un test en jeu. |
static event Action<RTSTerrain> MapOpened | Dé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 EscapeConsumedThisFrame | Vaut 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 avecRTSCameraControlleretRTSFogOfWarManager. - 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 :
| Fichier | Exemple | Description |
|---|---|---|
| Carte | Glacier Pass (2v2).rtsmap | La 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çu | Glacier Pass (2v2).preview.png | Une 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 :
| Membre | Description |
|---|---|
| É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 HoverWorldPosition | Indique 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 ShowMarkers | Les options activées ou désactivées par G et M. |
PathingOverlayMode? PathingOverlay, float OverlayOpacity | La 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 ManualUrl | L’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 CanQuitApplication | Vé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 StoresMapsInBrowser | RunsInBrowser 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 HasReliableFunctionKeys | Vaut 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 Gizmos | La 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> MapSaved | Après l’enregistrement d’une carte (chemin complet du fichier). |
event Action<string> MapLoaded | Après l’ouverture d’une carte depuis un fichier (chemin complet) ou sa création (null). |
event Action<bool> VisibilityChanged | Quand 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 que | Utilité |
|---|---|---|
RTSRuntimeTheme.tss | RTSRuntimeEditor.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.uss | RTSRuntimeEditor.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 :
| Variable | Par défaut | Sert à |
|---|---|---|
--rts-panel | rgba(20, 24, 30, 0.92) | Fonds des panneaux (barre supérieure, barre d’outils, panneau d’outil, barre d’état). |
--rts-panel-solid | rgb(22, 26, 33) | Fonds opaques (boîtes de dialogue, fenêtres contextuelles). |
--rts-raised / --rts-hover / --rts-pressed | blanc à 6 % / 11 % / 3 % | États des boutons. |
--rts-border / --rts-border-strong | blanc à 8 % / 16 % | Bordures et séparateurs. |
--rts-input | rgba(0, 0, 0, 0.32) | Fonds des champs de texte et des curseurs. |
--rts-text / --rts-text-dim / --rts-text-faint | rgb(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-text | déclinaisons du bleu rgb(61, 169, 252) | Outils sélectionnés, boutons principaux, Play Test. |
--rts-danger / --rts-danger-dim | rgb(239, 83, 80) | Boutons de suppression et notifications d’erreur. |
--rts-warning / --rts-success | rgb(255, 183, 77) / rgb(102, 187, 106) | Notifications d’avertissement et de réussite. |
--rts-radius / --rts-radius-small | 6px / 4px | Rayon 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.
- 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-rootest plus spécifique que le sélecteur.rts-rootdu 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); } - 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.
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.
- Lancez et corrigez les problèmes signalés. La vérification Shader references est la plus importante pour les builds (voir l’étape suivante).
- 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’éditeurHidden/RTS Terrain Studio/GizmoLinesetHidden/RTS Terrain Studio/GizmoGhost) ; il conserve donc ces shaders dans l’assetResources/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. - Conservez le dossier
Resources/RTSTerrainStudioavecUI/RTSRuntimeTheme.tss,UI/RTSRuntimeEditor.ussetRTSShaderReferences.asset. L’éditeur les charge par leur chemin Resources. Si le thème est absent, la fenêtre Console affiche Controls will be unstyled. - 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).
- Entrées : l’éditeur fonctionne avec le package Input System comme avec l’ancien Input Manager. Voir Gestion des entrées.
- 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.
- Dossier des cartes : le dossier
Mapspar défaut, situé dansRTSMapSerializer.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). - 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.
- 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). - 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.
- 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ème | Cause 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 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 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. les ajoute tous pour vous.
| Composant | Ce qu’il dessine | Objets générés | Section |
|---|---|---|---|
RTSTerrain | Sol, falaises, rampes (meshes de chunks, un seul matériau partagé), grille des cellules, superpositions et curseur du pinceau | Racine « RTS Chunks » avec un enfant par chunk | Rendu du terrain, Shader de terrain |
RTSVegetationRenderer | Herbe et plantes peintes (détails), arbres | Objet masqué « RTS Vegetation Objects » (proxys de collider, arbres en GameObjects) | Végétation |
RTSWaterRenderer | Surface d’eau transparente avec couleur selon la profondeur, vagues, réfraction et écume | Racine masquée « RTS Water » avec un enfant par chunk contenant de l’eau | Eau |
RTSDecorManager | Accessoires et doodads, sous forme de GameObjects ou en instanciation GPU | Conteneur « RTS Decor » pour les objets qu’il fait apparaître | Dé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 carte | Aucun | Environnement |
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 :
- 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. - 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.
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.- Les données de collision sont précalculées en parallèle avec
Physics.BakeMeshet assignées aux composantsMeshColliderdes chunks. Buildtermine 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ètre | Par défaut | Plage | Description |
|---|---|---|---|
| Cliff Noise | 0.18 | 0–0.5 | Dé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 Scale | 1.6 | ≥ 0.1 | Taille 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 Slant | 0.12 | 0–0.4 | Recul 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 Segments | 3 | 1–8 | Segments 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ètre | Par défaut | Description |
|---|---|---|
| Chunk Size | 32 | Nombre 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 Subdivisions | 2 | Nombre 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 Subdivisions | 4 | Ré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 Segments | voir Mise en forme des parois de falaise | Aspect des parois de falaise. |
| Collider Mode | MeshCollider | None ou MeshCollider (un par chunk, reconstruit après les modifications). |
| Chunk Layer | 0 (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 Shadows | On | Mode de projection des ombres des renderers des chunks. |
| Receive Shadows | activé | Indique si les chunks reçoivent des ombres. |
| Material Override | vide | Matériau facultatif utilisé à la place du matériau par défaut (voir Matériaux). |
| Show Grid | désactivé | Affiche la grille des cellules en permanence (surtout utile pendant l’édition). |
| Grid Opacity | 0.35 | Opacité 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 :
- Material Override dans les paramètres du terrain (
RTSTerrainSettings.materialOverride). - Material Override du tileset (
RTSTileset.materialOverride), pour que tous les terrains qui utilisent ce tileset partagent le même aspect. - 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 . 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 :
| Membre | Description |
|---|---|
Material TerrainMaterial | L’instance de matériau partagée par tous les chunks (null tant que le terrain n’est pas activé). |
Transform ChunkRoot | L’objet « RTS Chunks » qui contient les GameObjects des chunks. |
IReadOnlyList<RTSTerrainChunk> Chunks, int2 ChunkCount, int ChunkSizeInCells | La grille des chunks. |
RTSTerrainChunk GetChunk(int2 chunkCoord), GetChunkAtCell(int2 cell) | Recherche un chunk. Renvoie null en dehors de la carte. |
bool IsRenderingReady | Vaut 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, OverlayOpacity | Superposition sur toute la carte. Passez null ou 0 pour la masquer. |
void SetGridVisible(bool visible, float opacity), IsGridVisible | Grille 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ôle | Piloté par |
|---|---|---|
| 16 calques de sol | Jusqu’à 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 hauteur | Dans 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-tiling | Dans 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-variation | Une 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 triplanaires | Jusqu’à 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 pentes | Au-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 |
| Occlusion | AO 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 cellules | Lignes 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 |
| Superposition | Superposition 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 pinceau | Le 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 tileset | Sans tileset, le terrain affiche un sol gris neutre et des falaises d’un gris plus foncé au lieu d’échouer. | Automatique |
| Options d’éclairage | Dé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 :
- Dans la fenêtre Project, choisissez et nommez-le, par exemple
Terrain Low End. - Dans l’Inspector du matériau, réglez le shader sur .
- 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.
- 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). - 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é | Type | Contenu |
|---|---|---|
_RTS_SplatMap0 … _RTS_SplatMap3 | Texture2D, RGBA linéaire | Poids 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_AlbedoArray | Texture2DArray, sRGB | RGB = 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_NormalArray | Texture2DArray, linéaire | RGB = normale en espace tangent × 0.5 + 0.5 (déjà décompressée depuis DXT5nm/BC5 lors de la construction du tableau). |
_RTS_LayerData | Texture2D 20 × 4, float, lue avec Load | Une colonne par tranche du tableau de textures, voir le tableau ci-dessous. |
_RTS_LayerCount | float | Nombre 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_MapSize | float4 | (taille réelle X, taille réelle Z, 1 / X, 1 / Z). |
_RTS_MapParams | float4 | (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_OverlayOpacity | Texture2D RGBA, float | Superposition sur toute la carte. Opacité 0 = désactivée. |
_RTS_GridParams | float4 | (activée 0/1, opacité, inutilisé, inutilisé). |
_SpecularHighlights, _EnvironmentReflections | bascules float | Mots-clés _SPECULARHIGHLIGHTS_OFF, _ENVIRONMENTREFLECTIONS_OFF. |
_RTS_LayerParams[20], _RTS_LayerTints[20], _RTS_LayerParams2[20] | tableaux float4 | Les 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) :
| Ligne | x | y | z | w |
|---|---|---|---|---|
| 0 | 1 / taille de tuile | intensité de la normale | lissage | fondu par hauteur |
| 1 | teinte RGB en couleur linéaire (Color.linear) | métallicité | ||
| 2 | anti-tiling | a une hauteur (0/1) | calque utilisé (0/1) | 0 |
| 3 | couleur 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 globale | Définie par | Contenu |
|---|---|---|
_RTS_FogOfWarTex, _RTS_FogOfWarParams, _RTS_FogOfWarUnexplored, _RTS_FogOfWarExplored, _RTS_FogOfWarEnabled | RTSFogOfWarManager | Texture 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_BrushMask | RTSBrushPreview | Curseur du pinceau. HLSL : RTS_BrushCursor(positionWS) renvoie la couleur (rgb) et la couverture (a). |
_RTS_Wind | RTSVegetationRenderer | xy = 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 :
- Copiez
Shaders/RTSTerrain.shaderet tout le dossierShaders/Includedans un dossier de votre propre projet (par exempleAssets/MyGame/Shaders), en conservant l’arborescence relative. Le shader inclut ses fichiers de passe sous la formeInclude/…, et les includes se référencent entre eux par chemin relatif. - Renommez le shader à la première ligne de votre copie, par exemple
Shader "MyGame/Terrain", pour éviter tout conflit avec l’original. - Faites vos modifications, en général dans
RTS_EvaluateTerrainSurfacede votre copie deRTSTerrainInput.hlsl. - 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.
- 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 / type | Utilité |
|---|---|
struct RTSTerrainSurface | Ré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) → RTSLayerData | Lit une colonne de _RTS_LayerData. |
RTS_DecodeArrayNormal(encoded, strength) | Décode un texel du tableau de normales. |
RTS_EvaluateNoise(positionXZ), RTS_ValueNoise, RTS_Hash21 | Bruit 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. |
| Constantes | RTS_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
- 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 ). - 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. » - Peignez des détails et placez des arbres avec les outils Vegetation (touche 4 dans la Scene View pendant l’édition).
- Pour les arbres dessinés en mode instancié, cochez Enable GPU Instancing sur leurs matériaux. 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ètre | Par défaut | Description |
|---|---|---|
| Quality | ||
| Detail Density Multiplier | 1 | Multiplie 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 Multiplier | 1 | Multiplie la distance de rendu de chaque prototype de détail (0.1–3). |
| Tree Distance Multiplier | 1 | Multiplie 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 Strength | 0.6 | Intensité globale du vent (0–3). Chaque prototype et chaque matériau l’ajustent ensuite. |
| Wind Speed | 1.6 | Vitesse de l’animation du vent (0–10). |
| Rendering | ||
| Draw Details | activé | Dessine les détails peints par densité. |
| Draw Trees | activé | Dessine les arbres instanciés sur le GPU. |
| Draw In Scene View | activé | Dessine aussi la végétation dans les caméras de la Scene View. |
| Crossed Quad Count | 3 | Nombre 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 Layer | 0 | Layer 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 rendu | Mesh | Matériau |
|---|---|---|
CrossedQuads | Mesh 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) |
Mesh | Le 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 | |
|---|---|---|
| Rendu | Graphics.RenderMeshInstanced, jusqu’à 1023 instances par draw call, culling par patch selon le frustum et Render Distance × Tree Distance Multiplier | Une instance de prefab par arbre, rendue par Unity comme n’importe quel GameObject |
| LOD | LOD0 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 instance | Oui, pour les matériaux qui utilisent RTS Terrain Studio/Vegetation (valeur aléatoire entre Tint A et Tint B) | Non |
| Colliders | Proxys capsules mis en pool (voir ci-dessous) | Les colliders du prefab |
| Scripts sur le prefab | Non exécutés (rien n’est instancié) | Exécutés normalement |
| Idéal pour | Forêts, paysages, grandes quantités d’arbres | Arbres 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 composantRTSTreeInstance(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éfaut | Description |
|---|---|---|
| Albedo, Color | blanc | Texture de base (son alpha sert au découpage) et couleur. |
| Alpha Clipping, Alpha Cutoff | activé, 0.5 | Test 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 Strength | désactivé, –, 1 | Normal map facultative (_NORMALMAP). |
| Smoothness, Specular Color | 0.2, gris foncé | Réponse spéculaire. |
| Wrap Lighting | 0.35 | Adoucit l’atténuation de la lumière sur les feuilles (0–1). |
| Translucency, Translucency Color | 0.6, vert clair | Lumière qui traverse les feuilles lorsqu’on regarde en direction du soleil. |
| Wind Mode | Object Height | Off, Vertex Color R ou Object Height. |
| Wind Strength, Wind Reference Height, Leaf Flutter | 1, 6, 0.5 | Échelle du vent côté matériau (multipliée par le vent global du renderer). |
| Cull | Off | Culling des faces. Avec Off, les deux faces des quads de feuillage sont rendues. |
| Receive Shadows | activé | 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
| Membre | Description |
|---|---|
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> TreeRemoved | Dé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, TreeColliderCount | Statistiques. 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
- Vérifiez que le GameObject du terrain possède un composant Water Renderer (, ou le bouton Add dans l’Inspector de
RTSTerrain). - Ouvrez l’asset URP actif, activez Depth Texture et Opaque Texture, puis réglez Opaque Downsampling sur None (voir ci-dessous). Le menu vérifie et corrige ces paramètres. Une caméra peut aussi activer les deux textures pour elle-même.
- Peignez l’eau avec les outils Water (touche 6 dans la Scene View pendant l’édition).
- 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 pour | Sans 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 nets | La 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ètre | Par défaut | Description |
|---|---|---|
| Material Template | vide | Maté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 Shadows | désactivé | En général, les surfaces d’eau ne font que recevoir des ombres. |
| Receive Shadows | activé | 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 Layer | 4 (Water) | Layer de GameObject des chunks d’eau (RTSWaterRenderer.DefaultLayer correspond au layer Water intégré à Unity). |
| Wave Amplitude Multiplier | 1 | Multiplie la valeur Wave Height du profil (0–4, 0 = eau immobile). |
| Cell Subdivisions | 2 | Quads 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 Usage | Off | Avec 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 Usage | Blend Probes | En 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.
| Champ | Par défaut | Description |
|---|---|---|
| Shallow Color | bleu canard, alpha 0.55 | Couleur de l’eau peu profonde (alpha = opacité). |
| Deep Color | bleu foncé, alpha 0.95 | Couleur atteinte à la profondeur Color Depth (alpha = opacité). |
| Color Depth | 3 m | Profondeur à laquelle la couleur de l’eau profonde est entièrement atteinte. |
| Shallow Depth Limit | 0.9 m | Au-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 Size | aucune, 0.6, 8 m | Ondulations 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 Height | 0.05 m | Amplitude des vagues de vertex (pondérée par le multiplicateur du renderer). |
| Smoothness | 0.92 | Lissé de la surface. |
| Refraction | 0.03 | Intensité du décalage de réfraction (0–0.2). |
| Foam Color, Foam Distance, Foam Texture | blanc 0.8, 0.6 m, aucune | Écume du rivage. Foam Distance atténue aussi les vagues en eau peu profonde. |
| Minimap Color | bleu | Couleur 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
| Membre | Description |
|---|---|
Material WaterMaterial | Maté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 Profile | Profil du tileset ou profil par défaut partagé. |
Transform ChunkRoot, ChunkCountX, ChunkCountZ, ActiveChunkCount, VertexCount, bool HasWater | Grille 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> MeshesRebuilt | Déclenché après une reconstruction complète ou partielle. |
RTSWaterChunk : Owner, Terrain, ChunkCoord, CellRect | Marqueur 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éthode | Valeur 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 ShaderTime | L’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ésentation | Une copie du prefab (ou de la variante) placée sous l’objet enfant « RTS Decor », avec un composant RTSDecorInstance | Dessiné avec Graphics.RenderMeshInstanced (premier niveau de LOD du prefab), jusqu’à 1023 instances par draw call |
| Culling | Celle d’Unity | Par patch (frustum + Max Draw Distance) |
| Scripts, colliders, animations | Oui | Non (aucun objet n’est créé) |
| Teinte | Via un MaterialPropertyBlock (_BaseColor et _Color) | Uniquement avec les shaders qui la prennent en charge (voir Teinte par instance) |
| Idéal pour | Les accessoires interactifs ou destructibles, de quelques centaines à quelques milliers d’objets | Les é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ètre | Par défaut | Description |
|---|---|---|
| Show In Scene View | activé | 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 Distance | 0 | Le décor instancié situé au-delà de cette distance de la caméra n’est pas dessiné (0 = aucune limite). |
| Shadow Culling Margin | 12 m | Marge 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 Tint | activé | Transmet les teintes par instance au décor instancié dont le shader les prend en charge. |
| Patch Size | 16 | Longueur 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 Prefab | 64 | Les 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 Prototypes | activé | 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 :
| Tag | Constante | Le shader doit |
|---|---|---|
"RTSInstanceTint" = "True" | RTSDecorManager.InstanceTintShaderTag | Multiplier 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.InstancedColorShaderTag | Lire _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.
| Membre | Description |
|---|---|
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, IsPlaceholder | Consultation 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, InstancesChanged | Après une reconstruction complète ; après une mise à jour incrémentale. |
InstanceSpawned, InstanceDespawning | Un 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
- Choisissez . 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. - Vous pouvez aussi ajouter au GameObject du terrain (l’Inspector de
RTSTerrainpropose un bouton Add). - Modifiez les valeurs dans l’onglet Map de la fenêtre de l’éditeur (), 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.
- 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ètre | Par défaut | Description |
|---|---|---|
| Terrain | vide | Terrain 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. |
| Sun | vide | Lumière directionnelle utilisée comme soleil. Vide = RenderSettings.sun, ou la lumière directionnelle active la plus intense. |
| Apply In Edit Mode | activé | 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 Sun | activé | Applique la couleur, l’intensité et la rotation du soleil (espace monde). |
| Apply Ambient | activé | Applique la lumière ambiante. |
| Ambient Mode | Trilight | Flat = une seule couleur ambiante. Trilight = dégradé ciel / équateur / sol dérivé de la couleur ambiante de la carte. |
| Sky Factor | 1.2 | Trilight : couleur du ciel = couleur ambiante × ce facteur (0–3). |
| Ground Factor | 0.55 | Trilight : couleur du sol = couleur ambiante × ce facteur (0–3). |
| Apply Fog | activé | Applique l’état activé/désactivé du brouillard atmosphérique, sa couleur et sa densité. |
| Fog Mode | Exponential Squared | Mode d’atténuation utilisé quand le brouillard atmosphérique est appliqué (la carte ne stocke que sa couleur et sa densité). |
| Restore On Disable | activé | 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
| Membre | Description |
|---|---|
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 CanApply | Terrain 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 ().
- 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
Instancedpour les arbres et accessoires purement décoratifs. Réservez le modeGameObjectaux 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 Size | Draw calls (carte de 256 × 256) | Coût de reconstruction par modification | À utiliser pour |
|---|---|---|---|
| 16 | 256 chunks | Le plus faible : retour visuel du pinceau le plus rapide | Petites cartes, édition intensive (éditeur en jeu sur des machines plus lentes) |
| 32 (par défaut) | 64 chunks | Équilibré | La plupart des cartes |
| 64 | 16 chunks | Le plus élevé : chaque modification reconstruit jusqu’à 64 × 64 cellules, plus les chunks voisins aux bordures | Grandes 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 Subdivisions | Vertices d’un chunk plat de 32 × 32 | Valeur effective de Cliff Subdivisions avec la valeur par défaut 4 (avec 8) |
|---|---|---|
| 1 | 1 089 | 4 (8) |
| 2 (par défaut) | 4 225 | 4 (8) |
| 3 | 9 409 | 6 (12) |
| 4 | 16 641 | 4 (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 2 | Résolution 4 (par défaut) | Résolution 8 |
|---|---|---|---|
| 128 × 128 | 1 Mio de données + 1.3 Mio sur le GPU | 4 Mio + 5.3 Mio | 16 Mio + 21 Mio |
| 256 × 256 | 4 Mio + 5.3 Mio | 16 Mio + 21 Mio | 64 Mio + 85 Mio |
| 512 × 512 | 16 Mio + 21 Mio | 64 Mio + 85 Mio | 256 Mio + 341 Mio |
| 1024 × 1024 | 64 Mio + 85 Mio | 256 Mio + 341 Mio | 1 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 Resolution | RGBA32 non compressé | BC7 / DXT5 (ordinateurs de bureau, consoles) | ASTC 6×6 (Android, iOS) |
|---|---|---|---|
| 256 | 13 Mio | 3.3 Mio | 1.5 Mio |
| 512 | 53 Mio | 13 Mio | 5.9 Mio |
| 1024 (par défaut) | 213 Mio | 53 Mio | 24 Mio |
| 2048 | 853 Mio | 213 Mio | 95 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 (). 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 et recherchez ces marqueurs sur le thread principal :
| Marqueur | Ce qui est mesuré |
|---|---|
RTSVegetation.Update | Application des modifications de la carte à la végétation (inclut les deux marqueurs de construction ci-dessous). |
RTSVegetation.BuildDetails | Régénération des patchs de détails modifiés. |
RTSVegetation.BuildTrees | Reconstruction des groupes d’arbres instanciés. |
RTSVegetation.Draw | Culling 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 () 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 carte | Textures de splat (GPU) | Tableaux de textures (1024, BC7) |
|---|---|---|---|
| 128 × 128 (256 m avec des cellules de 2 m) | ≈ 4.3 Mio | ≈ 5.3 Mio | 53 Mio par tileset |
| 256 × 256 | ≈ 17 Mio | ≈ 21 Mio | 53 Mio par tileset |
| 512 × 512 | ≈ 69 Mio | ≈ 85 Mio | 53 Mio par tileset |
| 1024 × 1024 | ≈ 275 Mio | ≈ 341 Mio | 53 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 typique | Remarques |
|---|---|---|
| 64–128 | Cartes 1v1 et petites cartes d’escarmouche, mobile | Tout se reconstruit instantanément. Une bonne taille pour l’éditeur en jeu sur n’importe quel appareil. |
| 128–256 | 2–4 joueurs | Le compromis idéal. Toutes les valeurs par défaut sont optimisées pour cette taille. |
| 256–512 | Grandes cartes, 4–8 joueurs | Ordinateur de bureau. Envisagez une résolution de splat de 2–4 et un Chunk Size de 32–64. |
| plus de 512 | Très grandes cartes | La 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.hlslindique 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
Noneet utilisezRTSTerrain.Raycast/RaycastAllpour 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 , 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
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
- Ouvrez une scène qui contient un RTS Terrain.
- Choisissez . Cette commande crée un GameObject
Fog of Wardoté d’un composantRTSFogOfWarManageret le sélectionne. - 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 , ou à la main, voir Rendu.)
- Ajoutez un composant
RTSFogOfWarRevealer() à chaque unité et à chaque bâtiment qui doit pouvoir voir. Réglez ses paramètres Team et Radius. - Ajoutez un composant
RTSFogOfWarHideable() à 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. - 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 :
- Détermine le niveau d’observation : le niveau de falaise à la position exacte du révélateur, plus son Height Bonus.
- Parcourt chaque cellule de brouillard comprise dans le rayon de vision (Radius).
- 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.
- 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 Sight | Comportement | À utiliser pour |
|---|---|---|
None | Les 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é. |
CliffLevels | Rè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 ou . Si plusieurs gestionnaires sont activés, seul le premier (RTSFogOfWarManager.Active) est utilisé, et l’Inspector vous en avertit.
| Paramètre | Par défaut | Description |
|---|---|---|
| Map | ||
| Terrain | vide | Terrain couvert par le brouillard de guerre. Si le champ est vide, RTSTerrain.Main est utilisé (le premier terrain activé). |
| Resolution Per Cell | 2 | Nombre 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 Interval | 0.1 | Secondes entre deux mises à jour de la visibilité. Avec 0, la mise à jour a lieu à chaque image. |
| Local Team | 0 | É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 Vision | tout à 0 | Pour 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 Sight | CliffLevelsAndBlockers | Manière dont les falaises et les objets bloquent la vue. Voir Comment la visibilité est calculée. |
| Compute All Teams | dé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 Explored | dé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 All | désactivé | Débogage : tout est visible et exploré pour toutes les équipes. |
| Look | ||
| Unexplored Color | noir, alpha 1 | Couleur des zones jamais explorées. L’alpha détermine l’intensité. |
| Explored Color | (0.3, 0.32, 0.38), alpha 0.6 | Teinte appliquée par multiplication aux zones explorées qui ne sont pas visibles en ce moment. L’alpha détermine l’intensité. |
| Fade Speed | 4 | Vitesse d’apparition et de disparition du brouillard de guerre (fondus complets par seconde). 0 = instantané. |
| Blur Iterations | 1 | Nombre de passes de flou GPU appliquées à la texture du brouillard de guerre (0 à 4, 0 = désactivé). |
| Blur Upscale | 2 | Multiplicateur 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 Mode | désactivé | Exécute le brouillard de guerre en Edit Mode, à titre d’aperçu. |
| Shaders | ||
| Blur Shader, Minimap Shader | assignés automatiquement | Ré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 :
| Bouton | Rôle |
|---|---|
| Explore All | Marque toute la carte comme explorée pour l’équipe locale. |
| Reset Exploration | Oublie tout ce que chaque équipe a exploré. |
| Update Now | Recalcule immédiatement la visibilité. |
| Rebuild Terrain Data | Relit 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ètre | Par défaut | Description |
|---|---|---|
| Team | 0 | Équipe qui reçoit la vision (0 à 31). |
| Radius | 12 | Rayon de vision en mètres. |
| Height Bonus | 0 | Niveaux de falaise supplémentaires par-dessus lesquels le révélateur peut voir (tours de guet, collines, éclaireurs volants). |
| Ignore Line Of Sight | désactivé | Voit par-dessus les falaises et les obstacles à la vision (unités aériennes). |
| Reveal When Disabled | dé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ètre | Par défaut | Description |
|---|---|---|
| Team | 0 | Équipe propriétaire de l’objet (0 à 31). |
| Mode | HideWhenNotVisible | HideWhenNotVisible : 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 Sighting | activé | 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 Canvases | activé | Désactive aussi les composants Canvas (barres de vie, étiquettes de nom). |
| Hide Colliders | dé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. |
| Pivot | vide | Transform 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éthode | Quand elle est utilisée | Ce 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 repli | Le 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 :
- Sélectionnez votre asset Universal Renderer Data (le renderer utilisé par les caméras de votre jeu).
- Dans son Inspector, cliquez sur Add Renderer Feature et choisissez RTS Fog Of War.
- 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 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 feature | Par défaut | Description |
|---|---|---|
| Show In Scene View | activé | 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 Event | AfterRenderingTransparents | Moment 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).
| Membre | Description |
|---|---|
| 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 Updated | Déclenché après chaque mise à jour de la visibilité, une fois les objets masquables actualisés. |
| État | |
IsSimulating, IsRunning, IsRenderingFog, HasGrid, HasVisibilityData | Indiquent 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, MemoryUsage | Informations sur la grille et la texture. |
int EffectiveResolutionPerCell | Nombre 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 BoundTerrain | Le 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, BlurUpscale | Proprié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> Hideables | Tous les révélateurs et objets masquables activés, tous gestionnaires confondus. |
static RegisterRevealer / UnregisterRevealer, RegisterHideable / UnregisterHideable | Appelé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éthode | Description |
|---|---|
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
SetAlliancesur 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 :
| Indicateur | Signification |
|---|---|
Walkable | Les unités terrestres peuvent y marcher. |
Buildable | On peut y placer des bâtiments. |
Flyable | Les 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. |
ShallowWater | Eau peu profonde : praticable, non constructible par défaut. |
DeepWater | Eau profonde : réservée aux unités navales. |
Cliff | La cellule touche une paroi de falaise. |
Blocked | La cellule est bloquée par l’emprise d’un arbre ou d’un objet de décor. |
Steep | La 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 :
- Terrain. Les parois de falaise (élargies selon Cliff Margin) deviennent
Cliff. Les pentes supérieures à Max Walkable Slope deviennentSteep. L’eau plus profonde que la limite de faible profondeur du tileset devientDeepWater, sinonShallowWater.Flyableest 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. - Emprises. Les arbres bloquent un cercle (Footprint Radius du prototype d’arbre × échelle de l’instance × Tree Footprint Scale) : ils définissent
Blockedet 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’indicateurIgnorePathingsont ignorées. - 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ètre | Par défaut | Description |
|---|---|---|
| Max Walkable Slope | 42 | Un sol plus pentu que cet angle (en degrés) n’est pas praticable. |
| Max Buildable Slope | 18 | Un sol plus pentu que cet angle (en degrés) n’est pas constructible. |
| Cliff Margin | 0.25 | Distance (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 Buildable | désactivé | Autorise la construction de bâtiments en eau peu profonde. |
| Tree Footprint Scale | 1 | Multiplicateur du rayon d’emprise de cheminement de chaque arbre. |
| Use Ground Layer Rules | activé | 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 / Surcharge | Effet |
|---|---|
| Paint Pathing : Blocker | Non praticable et non constructible : un mur invisible (bordures de carte, zones décoratives). |
| Paint Pathing : Unwalkable | Les unités terrestres ne peuvent pas marcher ici. |
| Paint Pathing : Unbuildable | Impossible de placer des bâtiments ici (pour garder libres les chemins et les expansions). |
| Paint Pathing : Unflyable | Les unités aériennes ne peuvent pas voler ici. |
| Paint Pathing : Force Walkable | Les unités terrestres peuvent marcher ici, même si la pente, l’eau ou des emprises les en empêcheraient. |
| Paint Pathing : Force Buildable | On peut placer des bâtiments ici, même si les règles dérivées l’interdisent. |
| Clear Pathing | Supprime 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 , sous macOS ) ; - la vue de cheminement de l’éditeur en jeu.
| Mode | Couleurs |
|---|---|
| Walkability | Vert = praticable, rouge = bloqué, rouge foncé = falaise, orange = trop escarpé, bleu = eau profonde, cyan = eau peu profonde. |
| Buildability | Vert = constructible, jaune = praticable mais non constructible, rouge / rouge foncé = non praticable. |
| Flyability | Bleu clair = survolable, magenta = non survolable. |
| Water | Cyan = eau peu profonde, bleu = eau profonde. |
| Combined | Tout à 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 Pathing | La grille de cheminement : Width, Height, CellSize, Flags (un octet par cellule, index = z × Width + x), Get(x, z), Version. |
event Action<RTSTerrain, RectInt> PathingChanged | Dé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éthode | Description |
|---|---|
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)) :
| Champ | Par défaut | Description |
|---|---|---|
unitRadius | 0 | Rayon 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. |
required | Walkable | Indicateurs que chaque cellule du chemin doit posséder (None est traité comme Walkable). |
allowShallowWater | true | Autorise la traversée de l’eau peu profonde (gués). |
maxSearchNodes | 500000 | Nombre maximal de nœuds développés avant que la recherche abandonne (0 = illimité). |
smoothPath | true | Supprime les points de passage inutiles grâce à la ligne de vue sur la grille (string pulling). |
snapToGround | true | Cale la coordonnée Y de chaque point de passage sur la hauteur du sol. |
allowPartial | true | Si la destination est inaccessible, renvoie un chemin vers la cellule accessible la plus proche. |
goalSearchRadius | 16 | Si la cellule de destination est bloquée, distance (en unités monde) jusqu’à laquelle chercher la cellule libre la plus proche. |
| PathStatus | Signification |
|---|---|
Success | Un chemin vers la destination (ou vers la cellule libre la plus proche d’une destination bloquée) a été trouvé. |
Partial | La destination est inaccessible ; le chemin mène à la cellule accessible la plus proche de celle-ci. |
NoPath | Aucun chemin n’existe (ou la limite de recherche a été atteinte) et les chemins partiels n’étaient pas autorisés. |
InvalidStart | Le 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 , 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ètre | Par défaut | Description |
|---|---|---|
| Max Requests Per Frame | 64 | Nombre de recherches de chemin lancées par image. Les requêtes en surplus attendent dans une file d’attente. |
| Max Parallel Jobs | 4 | Nombre 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 MB | 256 | Plafond 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 Frame | désactivé | Termine les jobs à la fin de l’image où ils ont été planifiés (latence plus faible, moins de parallélisme). |
| Membre | Description |
|---|---|
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, InFlightCount | Statistiques 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 viaterrain.GetPathingClearance()) proposeGetClearanceCells(x, z),GetClearanceMetres(x, z)etClearanceMap.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éthode | Description |
|---|---|
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 . 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
- 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).
- Choisissez . Cette commande crée un objet
RTS Demo Gamedoté du composantRTSDemoGame. - 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.
- Appuyez sur F1 pour afficher ou masquer la liste des commandes.
Commandes par défaut
| Saisie | Action |
|---|---|
| W A S D / touches fléchées | Faire 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 milieu | Faire défiler la caméra / saisir et faire glisser le sol. |
| Molette de la souris | Zoomer (un zoom rapproché rend la vue plus rasante). |
| Q / E, Alt + glisser avec le bouton droit | Faire pivoter la vue. |
| Clic gauche / glisser | Sélectionner une unité / tracer un rectangle de sélection. |
| Shift + clic | Ajouter ou retirer des unités. |
| Double-clic, Ctrl + clic | Sélectionner toutes les unités de ce type visibles à l’écran. |
| Esc | Annuler 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, 0 | Enregistrer un groupe de contrôle (Shift+chiffre y ajoute les unités sélectionnées). |
| 1…9, 0 | Rappeler un groupe (appuyez deux fois pour centrer la caméra dessus). |
| Clic droit | Se déplacer en formation (Shift met l’ordre en file d’attente et enchaîne la formation). |
| S / H / P | Arrêter / tenir la position / patrouiller (cliquez ensuite avec le bouton gauche sur le second point de patrouille). |
| Mini-carte | Clic gauche ou glisser : déplacer la caméra. Clic droit : déplacer les unités sélectionnées. |
| B | Placer un bâtiment (modification du cheminement à l’exécution). |
| Delete | Supprimer le bâtiment situé sous le curseur. |
| T | Abattre l’arbre situé sous le curseur. |
| Clic droit sur un arbre | Les ouvriers sélectionnés s’y rendent et l’abattent. |
| F1 | Afficher 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 :
- s’assure de la présence d’un
RTSFogOfWarManager(équipe locale = Local Team, exploration réinitialisée) et du service de recherche de chemin ; - 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 ;
- 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
RTSWanderAIaux unités ennemies, pour que vous puissiez les voir apparaître et disparaître dans le brouillard de guerre ; - 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ètre | Par défaut | Description |
|---|---|---|
| Start | ||
| Auto Start | activé | 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 Team | 0 | Équipe du joueur local (0 = joueur 1). La modifier par le code met aussi à jour le brouillard de guerre et la sélection. |
| Terrain | vide | Terrain sur lequel jouer. Vide = RTSTerrain.Main. |
| Units | ||
| Unit Prefabs | vide | Prefabs d’unités, utilisés à tour de rôle. Vide = unités de substitution procédurales. |
| Units Per Player | 8 | Nombre d’unités créées pour chaque joueur (de 1 à 60). |
| Max Players | 8 | Nombre maximal de joueurs qui reçoivent des unités. |
| Enemy Wander AI | activé | Les unités ennemies errent au hasard. |
| Wander Radius | 30 | Rayon d’errance de l’IA ennemie, en mètres. |
| Systems | ||
| Create Missing Systems | activé | 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 War | activé | Active le brouillard de guerre pendant la partie. |
| Minimap | activé | Affiche la mini-carte. |
| Hud | activé | Affiche le HUD (panneau d’informations, barre d’actions, aide F1). |
| Show Help On Start | activé | Affiche le panneau d’aide au démarrage de la partie. |
| Building Demo | activé | Active la démo de placement de bâtiments (B). |
| Tree Harvest Demo | activé | Active la démo de récolte d’arbres (T, ouvriers). |
| Restore Map On Stop | activé | 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 Manager | vide | Systè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ètre | Par défaut | Description |
|---|---|---|
| Target Camera | vide | Caméra déplacée. Vide = le composant Camera de ce GameObject, sinon Camera.main. |
| Terrain | vide | Terrain utilisé pour la hauteur du sol et les limites. Vide = RTSTerrain.Main. |
| Keyboard Pan, Pan Forward/Back/Left/Right Key, Arrow Keys | activé, W/S/A/D, activé | Défilement au clavier. |
| Yield Keys To Orders | activé | 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 Multiplier | 35 / 2 | Mè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 Multiplier | activé, 12 px, 1 | Dé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 Drag | activé | Maintenez le bouton du milieu enfoncé pour saisir et déplacer le sol. |
| Min / Max Distance | 12 / 75 | Distance par rapport au pivot en zoom avant / arrière maximal (en mètres). |
| Zoom Step, Start Zoom | 0.08, 0.6 | Variation 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 Speed | activé, Q/E, 100 | Rotation au clavier, en degrés par seconde. |
| Alt Right Drag Rotate, Drag Rotate Sensitivity | activé, 0.3 | Rotation avec Alt + glisser avec le bouton droit. |
| Snap Back Rotation, Snap Back Delay, Default Yaw | désactivé, 0.25, 0 | Revient à 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 Time | activé, 0.3 | Maintient le pivot à hauteur du sol, avec un lissage pour que les falaises ne fassent pas sauter la vue. |
| Clamp To Terrain, Bounds Margin | activé, 4 | Maintient le pivot à l’intérieur de la carte (une marge négative permet de regarder au-delà du bord). |
| Min Camera Clearance | 2 | Hauteur minimale de la caméra au-dessus du sol situé sous elle. |
| Pan / Zoom / Rotation Smooth Time | 0.08 / 0.12 / 0.08 | Lissage en secondes (0 = instantané). |
| Ignore Mouse Over UI | activé | Ignore la molette, le défilement par les bords et le glissement tant que le pointeur survole l’interface. |
| Use Unscaled Time | activé | 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ètre | Par défaut | Description |
|---|---|---|
| Team | 0 | Indice 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 Color | activé, rouge | Reprend 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, Acceleration | 5, 540, 25 | Mètres par seconde, degrés par seconde, mètres par seconde². |
| Radius, Height | 0.5, 1.8 | Rayon 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 Speed | désactivé, 8 | Incline l’unité selon le sol (véhicules, animaux). Désactivé, il maintient l’infanterie à la verticale. |
| Look Ahead, Arrival Distance, Slow Down Distance | 1.5, 0.15, 1.5 | Suivi de chemin (en mètres). |
| Stuck Check Interval | 0.6 | Secondes entre deux vérifications de progression. Une unité qui ne progresse pas recalcule son chemin. |
| Path Request Timeout | 3 | Dé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 Space | activé, 8, 0.1 | Séparation simple. Les unités inactives s’écartent pour laisser passer celles qui se déplacent. |
| Sight Radius | 14 | Rayon de vision pour le brouillard de guerre, en mètres. |
| Selectable | activé | Le joueur peut sélectionner cette unité. |
| Terrain | vide | Terrain sur lequel l’unité se déplace. Vide = le terrain situé sous l’unité (ou RTSTerrain.Main). |
| Path Provider | vide | Composant facultatif qui implémente IRTSUnitPathProvider. Vide = le fournisseur global par défaut (voir Fournisseurs de chemins). |
| Team Color Renderers, Team Color Mode | aucun, PropertyBlock | Renderers 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 Gizmos | activé | 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 :
| Classe | Utilité |
|---|---|
RTSUnitFactory | Unité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). |
RTSUnitSpawner | Fait 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). |
RTSWanderAI | Fait 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. |
RTSUnitRegistry | Toutes 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 viaRequestPath; 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 viaOnUnitMoveCommandetOnUnitStop; le fournisseur signale le résultat avecunit.NotifyArrived()ouunit.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ètre | Par défaut | Description |
|---|---|---|
| Target Camera | vide | Caméra utilisée pour la détection au clic. Vide = Camera.main. |
| Use Fog Of War Local Team | activé | Utilise l’équipe locale du gestionnaire de brouillard de guerre actif. |
| Local Team | 0 | Équipe dont les unités peuvent être sélectionnées (lorsqu’elle n’est pas reprise du brouillard de guerre). |
| Drag Threshold, Double Click Time | 6 px, 0.3 s | Distance à partir de laquelle un clic devient un rectangle de sélection ; délai du double-clic. |
| Max Selection | 0 | Nombre maximal d’unités sélectionnées (0 = illimité ; 12 est une limite courante dans les RTS classiques). |
| Pick Tolerance | 6 px | Rayon de détection supplémentaire, pour que l’on puisse cliquer facilement sur les petites unités. |
| Keep Selection On Empty Click | activé | 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 Key | Escape | Vide la sélection. |
| Control Groups, Group Double Tap Time | activé, 0.35 s | Ctrl+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ètre | Par défaut | Description |
|---|---|---|
| Selection, Target Camera | vide | Vide = RTSSelectionManager.Main / Camera.main. |
| Stop Key, Hold Key, Patrol Key, Cancel Key | S, H, P, Escape | Touches d’ordre. |
| Use Formation | activé | Déplace les groupes dans une formation en grille (désactivé = chaque unité se rend au point cliqué). |
| Spacing Multiplier, Extra Spacing, Width To Depth | 1.15, 0.3, 1.5 | Distance 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 Color | activé | 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ètre | Par défaut | Description |
|---|---|---|
| Terrain, Camera Controller, Command Controller | vide | Vide = RTSTerrain.Main, RTSCameraController.Main, RTSCommandController.Main. |
| Corner | BottomLeft | Coin de l’écran (les RTS classiques utilisent le coin inférieur gauche). |
| Size, Margin | 248, 16 | Taille du cadre et distance aux bords de l’écran, en pixels d’interface (résolution de référence 1920 × 1080). |
| Resolution | 256 | Résolution de l’image précalculée de la carte (côté le plus long). |
| Rebake Delay, Min Rebake Interval | 0.35 s, 1 s | Plusieurs 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 Interval | activé, 0.1 s | Assombrit 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 Rate | activé, 4, activé, blanc, 20 | Points, contour de la caméra et fréquence à laquelle ils sont redessinés. |
| Left Click Moves Camera, Right Click Moves Units | activé, 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ètre | Par défaut | Description |
|---|---|---|
| Size In Cells | 2 × 2 | Taille de l’emprise en cellules de la carte (X × Z). |
| Building Height | 3 | Hauteur du bâtiment procédural, en mètres. |
| Building Prefab | vide | Prefab 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 Radius | 10 | Rayon de vision des bâtiments (0 = aucune vision). Les bâtiments deviennent aussi des objets masquables, en mode fantôme. |
| Footprint Flags | Unwalkable, Unbuildable | Surcharges de cheminement écrites pour l’emprise. |
| Push Units Out | activé | Les unités qui se trouvent sur l’emprise s’écartent. |
| Require Explored | activé | 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 Key | B, Escape, Delete | Touches. |
| Valid Color, Invalid Color | vert, rouge | Couleurs des cellules de l’emprise. |
| Terrain, Target Camera | vide | Vide = 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ètre | Par défaut | Description |
|---|---|---|
| Harvest Key | T | Abat l’arbre sous le curseur. |
| Workers Harvest On Right Click | activé | 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 Radius | 1.5 | Distance maximale entre le rayon du curseur et un arbre pour pouvoir le sélectionner. |
| Chop Time, Work Distance | 1.5 s, 1.2 m | Durée pendant laquelle un ouvrier coupe l’arbre, et distance à laquelle il se tient du tronc. |
| Fall Duration, Fade Duration | 1.1 s, 0.5 s | Animation 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 Camera | vide | Camé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
| Classe | Utilité |
|---|---|
RTSMoveMarker | Anneau animé sur la cible d’un ordre : RTSMoveMarker.Spawn(position, color, radius, seconds). |
RTSGroundRing | Anneau qui épouse le terrain (cercles de sélection, portées) : RTSGroundRing.Create(name, color, radius, width, parent), puis Place(position). |
RTSSampleMaterials, RTSSampleMeshes | Matériaux URP mis en cache par couleur et meshes primitifs pour les substituts. |
RTSSampleUtility | Dé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.

Créer le contenu de démo
- 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).
- Choisissez . Une barre de progression affiche les étapes. L’opération prend quelques instants.
- 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 ).
- Le générateur sélectionne la scène
RTS Terrain Studio - Gameplay Demodans 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 (), 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) :
| Étape | Méthode | Ce qui est créé |
|---|---|---|
| Textures | CreateTextures() | 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ériaux | CreateMaterials() | 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 prefabs | CreateModels() | Arbres, buissons, rochers et accessoires low-poly, ainsi que leurs prefabs. |
| Tilesets, bibliothèques et pinceaux | CreateDataAssets() | 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’interface | UpdateResources() | 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émo | CreateMaps() | Trois fichiers .rtsmap (voir ci-dessous). |
| Scènes de démo | CreateScenes(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.
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) :
| Dossier | Contenu |
|---|---|
Content/Textures | Textures générées, réparties dans les sous-dossiers Ground, Cliffs, Water, Details, Props et Brushes. |
Content/Materials, Content/Meshes, Content/Prefabs | Matériaux, meshes et prefabs des arbres et des accessoires. |
Content/Tilesets | Summer.asset, Winter.asset et Summer Auto Paint.asset. |
Content/Libraries | Demo Vegetation.asset, Demo Decor.asset et leurs icônes. |
Content/Brushes | Formes de pinceau. |
Content/Maps | Two Rivers (1v1).rtsmap, Four Kingdoms (4p).rtsmap, Sandbox.rtsmap. |
Content/Settings | Paramètres de rendu (profil de post-traitement). |
Samples/Scenes | Les trois scènes de démo. |
Resources/RTSTerrainStudio | Références de shaders et UI/RTSRuntimePanelSettings.asset. |
Régénérer le contenu
Relancez 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) :
| Membre | Description |
|---|---|
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.IsCreated | Vaut 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ène | Carte | Contenu |
|---|---|---|
RTS Terrain Studio - Gameplay Demo | Two 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 Demo | Sandbox | L’é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 Playground | Four Kingdoms (4p) | Pas de gameplay. Une grande carte pour essayer les outils de l’éditeur Unity. |
Gameplay Demo : à essayer
- 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.
- 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.
- 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.
- É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.
- 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.
- 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.
- 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.
- 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
- Appuyez sur Play. L’éditeur en jeu s’ouvre sur la carte Sandbox ; toute la carte est visible.
- 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.
- Cliquez sur Play Test (F5).
RTSDemoGamefait 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. - 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
- Ouvrez la scène et la fenêtre RTS Terrain Studio ().
- Sélectionnez le RTS Terrain et essayez les outils sur la carte Four Kingdoms : falaises, rampes, peinture, végétation et décor.
- 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é.
- Envie d’y jouer ? Ajoutez 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 : , et . Elles nécessitent le contenu de démo et le package tiers correspondant.
La démo s’affiche mal ou sans textures ? Lancez 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 (, 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é.
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)
- Si votre projet n’a pas encore de tileset ni de bibliothèques, lancez une fois . 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.
- Sélectionnez votre RTS Terrain (ou créez-en un avec ) et ouvrez .
- Cliquez sur l’onglet Map et dépliez le panneau Generator.
- 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.
- Choisissez une symétrie dans Symmetry : Rotate2 pour une carte 1v1 équitable, Rotate4 pour 4 joueurs sur une carte carrée.
- Ouvrez Start Locations et réglez Count sur le nombre de joueurs.
- Cliquez sur Randomize Seed, puis sur Generate, et confirmez la boîte de dialogue.
- 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.
- 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 autres boutons du panneau :
| Bouton | Rôle |
|---|---|
| Randomize Seed | Choisit une nouvelle graine aléatoire. Tous les autres paramètres restent tels quels. |
| Apply Style Preset | Charge 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. |
| Reset | Réinitialise tous les paramètres du générateur aux valeurs par défaut du style sélectionné. |
| Generate | Demande 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)
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é :
| Option | Correspond à |
|---|---|
| Style | Applique le préréglage de style (réinitialise les options de forme situées en dessous). |
| Seed / Random | seed |
| Symmetry | symmetry |
| Terrain : Cliffs, Plateaus, Ramps, Ramp Count, Water, Lake Coverage, Island, Border | cliffs.enabled, cliffs.plateauCount, ramps.enabled, ramps.count, water.enabled, water.lakeCoverage, water.islandMode, border.mode |
| Content : Textures, Vegetation, Forests, Decor, Decor Count, Start Locations, Players | paint.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.
| Style | Aspect | Niveaux / plateaux | Rampes | Couverture en lacs |
|---|---|---|---|---|
| Plains | Terrain en grande partie plat avec quelques plateaux bas. Une carte classique de mêlée ouverte. | 2–3 / 2 | 3 | 0.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 / 2 | 4 | 0.06 |
| Highlands | De nombreux plateaux et falaises étagés, reliés par des rampes. | 2–6 / 5 | 8 | 0.04 |
| Islands | Masses de terre entourées d’eau (mode île, eau plus profonde, rivages plus larges). | 2–4 / 3 | 5 | 0.38 |
| Canyon | Bruit à crêtes transformé en canyons sinueux entre de hauts plateaux. | 2–5 / 3 | 6 | 0.03 |
| Arena | Une arène centrale basse entourée d’un anneau de hauteurs. | 2–4 / 3 | 6 | 0.03 |
Enregistrer vos propres préréglages
Vous avez trouvé des paramètres qui vous plaisent ? Enregistrez-les sous forme d’asset : 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étrie | Copies | Usage typique | Carte carrée requise |
|---|---|---|---|
None | 1 | Cartes de campagne ou de forme libre. | Non |
MirrorX | 2 | Miroir gauche ↔ droite (2 joueurs face à face horizontalement). | Non |
MirrorZ | 2 | Miroir haut ↔ bas. | Non |
MirrorXZ | 4 | Miroir sur les deux axes (4 coins). | Non |
Rotate2 (par défaut) | 2 | Symétrie centrale à 180°, l’agencement classique en 1v1. | Non |
Rotate4 | 4 | Symétrie de rotation à 90°, l’agencement classique à 4 joueurs. | Oui (sinon repli sur Rotate2) |
MirrorDiagonal | 2 | Miroir selon la diagonale (x ↔ z). | Oui (sinon repli sur MirrorX) |
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ètre | Par défaut | Description |
|---|---|---|
Seed (seed) | 12345 | Graine aléatoire. Avec la même graine et les mêmes paramètres, vous obtenez toujours la même carte. |
Style (style) | Hills | Forme du terrain. Cliquez sur Apply Style Preset (ou appelez ApplyPreset) pour charger les valeurs par défaut correspondantes. |
Symmetry (symmetry) | Rotate2 | Génère un seul secteur et le copie pour que la carte soit équitable (voir Symétrie). |
Noise (noise, GeneratorNoiseSettings)
| Paramètre | Par défaut | Description |
|---|---|---|
| Scale | 85 m | Taille des grandes formes du terrain, en mètres. Des valeurs plus élevées donnent des plateaux plus grands. |
| Octaves | 4 | Nombre de couches de bruit (1–8). Davantage d’octaves ajoutent des détails plus fins aux contours. |
| Persistence | 0.5 | Multiplicateur d’amplitude par octave (0.5 = chaque octave est deux fois moins forte que la précédente). |
| Lacunarity | 2 | Multiplicateur de fréquence par octave. |
| Ridged Amount | 0 | Mélange progressif vers un bruit à crêtes (crêtes vives et canyons). Le style Canyon utilise 1. |
| Warp | 0.4 | Intensité de la déformation de domaine (domain warp). Donne aux contours des formes plus naturelles et plus fluides. |
| Contrast | 1 | Des valeurs plus élevées repoussent une plus grande partie de la surface vers les plateaux les plus bas et les plus hauts. |
| Smoothing | 2 | Passes de flou appliquées avant la conversion du champ en niveaux de falaise (supprime les minuscules formes parasites dues au bruit). |
| Fine Height Amplitude | 1.6 m | Amplitude du bruit de hauteur fine (collines au sommet des plateaux). |
| Fine Height Scale | 22 m | Taille des formes du bruit de hauteur fine. |
| Fine Height Octaves | 3 | Nombre d’octaves du bruit de hauteur fine. |
| Cliff Edge Fade | 4 cellules | Distance 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ètre | Par défaut | Description |
|---|---|---|
| Enabled | Activé | 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 Level | 2 | Niveau de falaise du plateau le plus bas (0–15). Le niveau 2 laisse de la place pour creuser des lacs en dessous. |
| Max Level | 3 | Niveau de falaise du plateau le plus haut. |
| Plateau Count | 2 | Nombre de niveaux de plateau distincts entre Min Level et Max Level. |
| Hysteresis | 0.04 | Bande 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 Width | 8 cellules | Largeur 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 Passes | 2 | Passes qui suppriment les vertices isolés et les pics. |
| Cliff Type | 0 | Type de falaise (calque de falaise 0–3 du tileset) attribué à tous les vertices. |
Ramps (ramps, GeneratorRampSettings)
| Paramètre | Par défaut | Description |
|---|---|---|
| Enabled | Activé | Place des rampes entre les plateaux adjacents. |
| Count | 4 | Nombre de rampes dans le secteur généré (les copies symétriques en ajoutent d’autres). |
| Width | 3 cellules | Largeur d’une rampe le long de la falaise. |
| Length | 2 cellules | Longueur d’une rampe par niveau de falaise, perpendiculairement à la falaise. Une valeur de 2 donne une pente douce. |
| Ensure Connectivity | Activé | Ajoute des rampes supplémentaires si nécessaire, pour que chaque plateau soit accessible depuis tous les autres. |
| Min Spacing | 12 cellules | Distance minimale entre deux rampes. Une rampe qui en chevaucherait une autre n’est pas placée. |
| Min Plateau Size | 40 | La passe de connectivité ignore les plateaux qui comptent moins de vertices. |
Water (water, GeneratorWaterSettings)
| Paramètre | Par défaut | Description |
|---|---|---|
| Enabled | Activé | Génère des lacs ou une mer, ainsi que leurs surfaces d’eau. |
| Sea Level Offset | −0.25 | Surface 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 Coverage | 0.06 | Fraction de la carte (les zones les plus basses) transformée en lacs ou en mer (0–0.7). |
| Max Depth | 2.5 m | Point le plus profond des lacs sous la surface de l’eau. |
| Shore Width | 4 cellules | Largeur du rivage en pente, de la ligne de rivage jusqu’à la profondeur maximale. |
| Island Mode | Dé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 Falloff | 0.25 | Mode île : largeur de l’atténuation vers le bord, en fraction de la taille de la carte. |
Border (border, GeneratorBorderSettings)
| Paramètre | Par défaut | Description |
|---|---|---|
| Mode | None | None : 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). |
| Width | 2 cellules | Largeur de la bordure. |
| Cliff Level | 0 | Niveau de falaise de la bordure HighCliffs. 0 = automatique (deux niveaux au-dessus du plateau le plus haut). |
Paint (paint, GeneratorPaintSettings)
| Paramètre | Par défaut | Description |
|---|---|---|
| Mode | AutoPaint | KeepExisting : 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. |
| Profile | aucun | Un RTSAutoPaintProfile (). Vide = règles par défaut intégrées, associées d’après les noms des calques du tileset. |
| Base Layer | 0 | Calque de sol utilisé par FillBaseLayer. |
Vegetation (vegetation, GeneratorVegetationSettings)
| Paramètre | Par défaut | Description |
|---|---|---|
| Enabled | Activé | 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 Empty | Activé | Si les listes ci-dessous sont vides, tous les prototypes de la bibliothèque de végétation sont utilisés. |
| Clear Existing | Activé | Supprime les couches de détails et les arbres existants avant la génération. |
| Details | vide | Couches de détails (herbe) à générer, voir le tableau suivant. |
| Tree Prototype Ids | vide | Ids des prototypes d’arbres utilisés pour les forêts. |
| Forest Coverage | 0.22 | Fraction du sol propice couverte de forêts. |
| Forest Noise Scale | 55 m | Taille des formes du bruit de forêt. |
| Tree Spacing | 2.6 m | Distance entre les arbres. |
| Tree Density | 0.85 | Probabilité qu’un emplacement libre dans une forêt reçoive un arbre (des valeurs plus basses donnent des forêts clairsemées). |
| Max Tree Slope | 26° | Aucun arbre sur les pentes plus raides. |
| Start Location Clearance | 14 m | Distance 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ètre | Par défaut | Description |
|---|---|---|
| Prototype Id | "" | Id du prototype de détail dans la bibliothèque de végétation. |
| Density | 0.6 | Densité dans les zones couvertes (1 = densité maximale du prototype). |
| Coverage | 0.55 | Fraction du sol propice qui est couverte. |
| Noise Scale | 28 m | Taille des formes du bruit de couverture. |
| Max Slope | 32° | Aucun détail sur les pentes plus raides. |
Decor (decor, GeneratorDecorSettings)
| Paramètre | Par défaut | Description |
|---|---|---|
| Enabled | Activé | Disperse des décors (nécessite une bibliothèque de décors sur le terrain). |
| Use Whole Library When Empty | Activé | Si la liste ci-dessous est vide, tous les prototypes de la bibliothèque de décors sont utilisés. |
| Clear Existing | Activé | Supprime les décors existants avant la génération. |
| Prototype Ids | vide | Ids des prototypes de décor à disperser. |
| Count | 60 | Nombre d’objets de décor dans le secteur généré (les copies symétriques en ajoutent d’autres). |
| Min Spacing | 3 m | Distance minimale entre les objets de décor (l’espacement propre au prototype s’applique s’il est plus grand). |
| Max Slope | 30° | Aucun décor sur les pentes plus raides. |
| Start Location Clearance | 12 m | Distance 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ètre | Par défaut | Description |
|---|---|---|
| Enabled | Activé | Place les positions de départ. Si ce paramètre est désactivé, les positions de départ existantes sont conservées. |
| Count | 2 | Nombre de positions de départ (1–16). |
| Flat Radius | 5 cellules | Rayon qui doit rester plat autour d’une position de départ (un seul niveau, sans falaises, rampes ni eau). |
| Edge Margin | 8 cellules | Distance minimale au bord de la carte. |
| Update Max Players | Activé | Écrit la valeur de Count dans le champ Max Players de la carte (MapInfo.maxPlayers). |
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
- Ouvrez l’onglet Map et dépliez le panneau Heightmap.
- 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.
- Laissez Height Scale sur 0 (automatique), sauf si vous savez combien de mètres votre image représente.
- 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). - Vérifiez le résultat. Appuyez sur Ctrl+Z pour annuler et essayer un autre mode ou une autre échelle.
| Mode d’import | Données écrites | Description |
|---|---|---|
| Fine Heights Only | Hauteurs | Uniquement 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 Heights | Hauteurs, niveaux de falaise | L’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 Levels | Hauteurs | L’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’import | Par défaut | Description |
|---|---|---|
| Mode | voir ci-dessus | Manière dont l’image est convertie en niveaux et en hauteurs. |
| Height Scale | 0 (automatique) | Nombre de mètres représentés par toute la plage 16-bit. 0 = 16 × hauteur de niveau. |
| Height Offset | 0 | Mètres ajoutés à chaque hauteur importée. |
| Flip Vertically | Désactivé | Retourne l’image selon l’axe Z (à utiliser quand la carte apparaît en miroir). |
| RAW Width / RAW Height | 0 | Nombre 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 Endian | Activé | Ordre des octets des fichiers RAW. Windows et la plupart des outils écrivent en little endian. |
Exporter
| Paramètre d’export / bouton | Par défaut | Description |
|---|---|---|
| Source | Ground Height | Ground Height : niveaux de falaise plus hauteur fine (valeur absolue). Fine Heights : uniquement la hauteur fine au-dessus des niveaux. |
| Height Scale | 0 (automatique) | Nombre de mètres représentés par 65535. |
| Height Offset | 0 | Hauteur enregistrée avec la valeur 0. |
| RAW Little Endian | Activé | 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);
}
}
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
.rtsmapdans 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
- Ouvrez l’onglet Map et dépliez le panneau Minimap.
- 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).
- Ajustez les Bake Options si vous le souhaitez (voir le tableau ci-dessous).
- 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ètre | Par défaut | Description |
|---|---|---|
| Ground Mode | BlendedLayers | BlendedLayers 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 Brightness | 0.05 | Variation de luminosité par niveau de falaise, par rapport au niveau 2 (les plateaux plus hauts paraissent plus clairs). |
| Hill Shading / Strength | Activé / 1 | Assombrit 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 Direction | Désactivé | Utilise la direction du soleil définie dans l’environnement de la carte au lieu de Light Direction. |
| Draw Cliffs / Cliff Color / Cliff Opacity | Activé / noir / 0.8 | Colore les cellules de falaise. Noir = utiliser la couleur de falaise du tileset. |
| Draw Water | Activé | Eau colorée selon la profondeur (profil d’eau du tileset). |
| Draw Trees / Tree Color / Tree Dot Size | Activé / vert foncé / 0.75 px | Arbres représentés par des points (les valeurs inférieures à 1 dessinent des pixels isolés). |
| Draw Decor / Decor Color / Decor Dot Size | Désactivé / marron / 0.75 px | Objets de décor représentés par des points. |
| Draw Start Locations / Start Location Size | Activé / 4 px | Marqueurs aux couleurs des joueurs. |
| Scale Markers | Activé | Adapte la taille des marqueurs à la taille de la texture (taille de référence 256). |
| Player Colors | 16 couleurs de joueur classiques des RTS | Couleur par index de joueur. Les entrées manquantes utilisent MinimapBakeOptions.DefaultPlayerColors. |
| Draw Regions | Dé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.
- Ouvrez l’onglet Map et dépliez le panneau Validation.
- Cliquez sur Validate Map. Le résumé indique le nombre d’erreurs, d’avertissements et d’informations, ou No problems found.
- 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).
- Corrigez les problèmes et relancez la validation.
Ce qui est vérifié
| Zone | Vérification | Gravité |
|---|---|---|
| Tileset | Aucun tileset assigné (le terrain s’affiche avec des couleurs neutres de repli) | Warning |
| Le tileset n’a aucun calque de sol | Warning | |
| 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étrie | Vertices dont la hauteur est invalide (NaN ou infini) | Error |
| Des cellules de falaise utilisent un type de falaise que le tileset ne définit pas | Warning | |
| La carte contient des falaises, mais le tileset n’a aucun calque de falaise | Warning | |
| Peinture du sol | Texels 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 pas | Warning | |
| Un calque de sol peint n’a pas de texture d’albédo | Info | |
| Positions de départ | La carte n’a aucune position de départ | Error |
| Moins de positions de départ que la valeur de Max Players | Warning | |
| Un joueur a plus d’une position de départ | Warning | |
| Une position de départ se trouve hors de la carte | Error | |
| Une position de départ se trouve sur un bord de falaise | Warning | |
| Une position de départ est recouverte d’eau profonde / se trouve dans de l’eau peu profonde | Error / 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 praticable | Error | |
| 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étails | Il 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ée | Warning |
| Des objets référencent un index de prototype absent de la palette de la carte | Error | |
| Des objets ou des couches de détails utilisent un prototype absent de la bibliothèque | Warning | |
| 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 existants | Warning | |
| Régions | Une 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 |
| Performances | Trop d’arbres, d’objets de décor ou de couches de détails | Warning |
| Trop d’arbres ou d’objets de décor en mode d’apparition GameObject | Warning | |
| Grande carte (consommation de mémoire et temps de construction) | Info |
Seuils (MapValidationSettings)
| Paramètre | Par défaut | Description |
|---|---|---|
maxTrees | 20000 | Nombre d’arbres au-delà duquel un avertissement de performances s’affiche. |
maxGameObjectTrees | 1500 | Nombre d’arbres en mode d’apparition GameObject au-delà duquel un avertissement s’affiche. |
maxDecor | 6000 | Nombre d’objets de décor au-delà duquel un avertissement s’affiche. |
maxGameObjectDecor | 2000 | Nombre d’objets de décor en mode d’apparition GameObject au-delà duquel un avertissement s’affiche. |
maxDetailLayers | 8 | Nombre de couches de détails au-delà duquel un avertissement s’affiche. |
largeMapSize | 512 | Les cartes plus grandes que cette valeur (en cellules par côté) reçoivent une information sur la mémoire et les temps de construction. |
minStartDistanceCells | 12 | Des positions de départ plus proches que cette distance déclenchent un avertissement. |
walkableEdgeFraction | 0.1 | Proportion de cellules praticables sur l’anneau extérieur au-delà de laquelle l’information sur le bord praticable s’affiche. |
checkReachability | true | Vé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égration | Prérequis | Ce que vous obtenez | Menu de la scène de démo |
|---|---|---|---|
| Mirror | Mirror 96 ou plus récent | Jeu 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. | |
| A* Pathfinding Project | A* Pathfinding Project Pro 5.4.4 ou plus récent, antérieur à 6.0 | Graphes 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. | |
| Unity NavMesh | AI Navigation (com.unity.ai.navigation) 2.0 ou plus récent | Un 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. |
La fenêtre 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.
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 (
versionDefinesdans 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
MIRRORque Mirror ajoute lui-même aux Player Settings.
| Assembly | Version define | Define constraints |
|---|---|---|
RTSTerrainStudio.Integrations.Mirror et .Mirror.Editor | aucun | MIRROR |
RTSTerrainStudio.Integrations.Mirror.DefineCleanup.Editor | aucun | aucune (toujours compilée ; supprime les symboles Mirror obsolètes, voir Supprimer des intégrations) |
RTSTerrainStudio.Integrations.AStar et .AStar.Editor | com.arongranberg.astar dans [5.4.4,6.0.0) → RTS_ASTAR | RTS_ASTAR, !RTS_ASTAR_DISABLED |
RTSTerrainStudio.Integrations.NavMesh et .NavMesh.Editor | com.unity.ai.navigation 2.0.0 ou plus récent → RTS_AI_NAVIGATION | RTS_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.
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.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
- Importez Mirror (Asset Store ou GitHub). Mirror ajoute le symbole de définition
MIRROR, et l’intégration se compile. - Exécutez (une fois par projet).
- Exécutez . La commande crée, dans
Integrations/Mirror/Demo: la scèneRTS Mirror Demo.unity, les prefabsPrefabs/RTS Network Unit.prefab(une capsule de substitution avecRTSUnit,RTSNetworkUnit,NetworkIdentityetNetworkTransformReliable) etPrefabs/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. - 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.
- 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.
- 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éthode | Procédure |
|---|---|
| Build de joueur (le plus fiable) | Ouvrez . 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 , 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 . 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éseau | Saisissez 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 ou pour tester un nouveau téléchargement. L’éditeur et un build de joueur Windows du même projet partagent ce dossier.
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 sur | Utilité |
|---|---|---|
RTSNetworkManager | Objet gestionnaire réseau | Attribue 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. |
RTSNetworkMapSync | Mê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. |
RTSFogOfWarInterestManagement | Même objet | Gestion d’intérêt de Mirror : chaque client ne reçoit que les unités que son équipe peut voir. |
RTSNetworkFogOfWar | Même objet | Configure le RTSFogOfWarManager : le serveur calcule toutes les équipes, un client uniquement la sienne. |
RTSNetworkStatusUI | Même objet (facultatif) | Barre de progression du téléchargement et « You are Player N » (IMGUI). |
RTSNetworkPlayer | Prefab du joueur | SyncVar d’équipe. Configure le joueur local (équipe du brouillard de guerre, sélection, caméra) et envoie les ordres sous forme de commandes. |
RTSNetworkUnit | Prefabs d’unités | SyncVar d’équipe. Le déplacement s’exécute uniquement sur le serveur ; les clients se contentent d’afficher l’unité. |
RTSNetworkCommandRelay | Ajouté automatiquement sur les clients | Envoie au serveur les ordres du RTSCommandController d’exemple. |
- Construisez une scène RTS Terrain Studio normale : un
RTSTerrainavec une carte qui contient des positions de départ, unRTSFogOfWarManager, unRTSCameraController, unRTSSelectionManageret unRTSCommandController. N’ajoutez pasRTSDemoGame: c’est le gestionnaire réseau qui fait apparaître les unités. - Créez un objet vide et ajoutez-y
KcpTransport,RTSNetworkManager(qui ajouteRTSNetworkMapSync),RTSFogOfWarInterestManagement,RTSNetworkFogOfWaret, si vous le souhaitez,NetworkManagerHUD. Assignez le transport au champ Transport du gestionnaire. - Créez un prefab de joueur avec
NetworkIdentityetRTSNetworkPlayer, puis assignez-le au champ Player Prefab. - Créez un prefab d’unité avec
NetworkIdentity,RTSUnit,RTSNetworkUnitetNetworkTransformReliable(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. - 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).
- Placez les composants d’IA ou de logique des prefabs d’unités (par exemple
RTSWanderAIou vos propres scripts d’IA) dans la liste Server Only Behaviours deRTSNetworkUnit, afin que les clients ne les exécutent pas.
| Paramètre | Par défaut | Description |
|---|---|---|
| RTSNetworkManager | ||
| Terrain | vide | Terrain sur lequel se joue la partie. Vide = RTSTerrain.Main. |
| Unit Prefab | vide | Unité de départ de chaque joueur (nécessite NetworkIdentity, RTSUnit et RTSNetworkUnit). |
| Units Per Player | 5 | Nombre d’unités de départ (0–64). |
| Max Players Override | 0 | Permet d’avoir moins de joueurs que d’emplacements sur la carte (0 = toutes les positions de départ). |
| Unit Spacing | 2 m | Distance entre les unités de départ. |
| Spawn Offset | 4 m | Distance 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 Disconnect | Activé | Détruit les unités d’un joueur qui quitte la partie. |
| Reserve Team Of Kept Units | Activé | Si les unités restent : garde l’emplacement d’équipe réservé tant que l’une d’elles est en vie. |
| Reject Disconnect Delay | 0.5 s | Secondes entre le message de refus et la déconnexion, pour que le message ait le temps d’arriver. |
| RTSNetworkUnit | ||
| Server Only Behaviours | vide | Behaviours que les clients désactivent, car c’est le serveur qui exécute la logique de l’unité. |
| RTSNetworkPlayer | ||
| Jump Camera To Start | Activé | Déplace la caméra RTS vers la position de départ au début de la partie. |
| Create Command Relay | Activé | 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 Second | 256, 20 | Validation 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 (
ServerChangeSceneou 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 RTSNetworkMapSync | Par défaut | Description |
|---|---|---|
| Terrain | vide | Terrain dont la carte est envoyée (serveur) et remplacée (client). Vide = RTSTerrain.Main. |
| Chunk Size | 16 Ko | Taille en octets de chaque message de chunk, réduite automatiquement pour respecter la taille maximale des messages du transport. |
| Chunks In Flight | 8 | Chunks 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 Timeout | 30 s | Secondes sans progression au bout desquelles un transfert échoue. |
| Load Timeout | 120 s | Serveur : 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 Failure | Activé | Serveur : déconnecte les clients dont le transfert a échoué (ils ne peuvent pas jouer sans la carte). |
| Max Map Size MB | 64 | Client : taille maximale de carte acceptée par le client (protège contre les serveurs défaillants ou malveillants). |
| Reuse Loaded Map | Activé | Ignore le téléchargement si le client affiche déjà exactement la carte du serveur. |
| Use Cache / Max Cached Maps | Activé / 20 | Conserve 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 Transfers | Activé | 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.
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ètre | Par défaut | Description |
|---|---|---|
| Fog Of War | vide | Brouillard de guerre côté serveur. Vide = RTSFogOfWarManager.Active. |
| Rebuild Interval | 0.2 s | Secondes 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 Time | 0.5 s | Secondes pendant lesquelles une unité reste observée après être sortie du champ de vision d’une équipe. |
| Share With Allies | Activé | Les équipes qui partagent leur vision voient toujours les unités les unes des autres. |
| Show All Without Fog | Activé | 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 All | Dé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();
}
}
| Membre | Description |
|---|---|
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, All | Dé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, Local | L’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. RTSBuildingPlacementDemoetRTSTreeHarvestDemos’exécutent localement et ne sont pas synchronisés en réseau.RTSDemoGameest 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.Statereste à Idle. UtilisezRTSUnit.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
SetAlliancesur 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ème | Solution |
|---|---|
| « 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 Mirror | Le symbole de définition MIRROR est toujours défini. Voir Supprimer des intégrations. |
| Les unités ne bougent pas sur le client | Le prefab d’unité a besoin de NetworkTransformReliable, et la scène d’un RTSCommandController. |
| Les unités ennemies sont toujours visibles | RTSFogOfWarInterestManagement 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 fois | Le 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.
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 (ou supprimez le dossier de l’intégration).Démarrage rapide : la scène de démo
- Installez A* Pathfinding Project Pro 5.4 ou plus récent.
- Exécutez une fois .
- Exécutez . 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é. - 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.
- 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 . La commande ajoute un GameObject A* Pathfinding comportant :
| Composant | Utilité |
|---|---|
AstarPath | Le 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 () 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.
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
RTSAstarUnitSetupavec Required Traversal = Deep Water. Par le code, les méthodes de fabriqueRTSAstarGraphProfile.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) etAmphibious()(« 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 RTSAstarGraphBuilder | Description |
|---|---|
| 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, Tags | Les 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 All | Le 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 Only | HandlesMovement = 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 fournisseur | Par défaut | Description |
|---|---|---|
| Mode | Agent Movement | Voir ci-dessus. |
| Graph Builder | vide | Graph Builder dont les graphes sont utilisés. Vide = le Graph Builder du terrain de l’unité. |
| Auto Configure Units | Activé | 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 Builtin | Activé | 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 Paths | Activé | 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 Time | 1.5 s | Agent 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é.
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
- Supprimez
Integrations/AStarPathfinding/Demo(ouIntegrations/UnityNavMesh/Demo) s’il existe. - 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).
- 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.
- Si vous aviez ajouté
RTS_ASTAR_DISABLEDpour 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.
- Supprimez d’abord
Integrations/Mirror/Demo. - Supprimez le dossier
Mirrordans l’éditeur Unity (fenêtre Project). La petite assembly d’éditeurRTSTerrainStudio.Integrations.Mirror.DefineCleanup.Editordé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 fait la même chose manuellement. - Vérifiez les de chaque plateforme pour laquelle vous générez un build : aucune entrée
MIRRORouMIRROR_..._OR_NEWERne 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 aussiEDGEGAP_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.
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
| Assembly | Espace de noms | Contenu |
|---|---|---|
RTSTerrainStudio.Runtime | RTSTerrainStudio | Terrain, 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.Samples | RTSTerrainStudio.Samples | Caméra RTS, unités, sélection, commandes, interface de la mini-carte, jeu de démo. |
RTSTerrainStudio.Editor | RTSTerrainStudio.Editor | Fenêtre de l’éditeur, outils de la Scene View, inspecteurs, importeurs, fenêtres de configuration, RTSEditorContext. |
RTSTerrainStudio.Integrations.* | RTSTerrainStudio.Integrations.Mirror / .AStar / .NavMesh | Inté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 × Heightcellules deCellSizemètres (2 m par défaut). Les rectangles passés àNotifyChangedsont exprimés en cellules. - Vertices : les coins des cellules, au nombre de
(Width + 1) × (Height + 1); indicez * 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.
| Membre | Valeur renvoyée |
|---|---|
RTSTerrain.Main, RTSTerrain.All | Le 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), WorldBounds | Indique 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;
}
}
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 :
- Modifiez les données dans
terrain.Map(sur le thread principal). - Appelez
terrain.NotifyChanged(layers, cellRect)avec lesMapLayersmodifiés et le rectangle modifié en cellules, ouNotifyChangedAll(layers)après une modification de toute la carte. - 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. Appelezterrain.ProcessPendingChanges()si vous avez besoin des résultats dans la même frame (l’appeler souvent coûte peu).
Données (MapData) | Grille / type | Indicateur MapLayers |
|---|---|---|
Heights | vertices, float, hauteur fine en mètres, qui s’ajoute au niveau | Heights |
CliffLevels | vertices, byte 0–15 | CliffLevels |
VertexFlags | vertices, VertexFlags (Ramp, Water, User0, User1) | VertexFlags |
CliffTypes | vertices, byte 0–3 | CliffTypes |
WaterHeights | vertices, 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 255 | Splat |
DetailLayers | texels de détail, un octet de densité par couche (DetailLayer.prototypeId, density) | Details |
Trees, Decor | listes de TreeInstanceData / DecorInstanceData avec des indices de palette pointant vers TreePrototypeIds / DecorPrototypeIds | Trees, Decor |
PathingOverrides | texels de cheminement, surcharges peintes | PathingOverrides |
Regions, StartLocations, Markers | listes | Regions, StartLocations, Markers |
Info, Environment | informations de la carte et éclairage | Info, Environment |
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));
}
}
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();
}
}
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.
- 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). - Faites dériver votre classe de
RTSToolet redéfinissezId(unique, par exemple"height.crater"),DisplayNameetCategory. - Ajoutez des champs publics avec
[ToolSetting("Label", ...)]pour les options que l’utilisateur peut modifier. - Redéfinissez
ApplyDab: calculez les poids du pinceau avecBrushUtility.ComputeWeights, appelezctx.Record(layers, cells)avant de modifier les données, modifiez les données, puis appelezctx.MarkChanged(layers, cells)après. - Revenez dans Unity. Une fois le script compilé, l’outil apparaît dans son onglet.
- 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
| Membre | Par défaut | Description |
|---|---|---|
Id, DisplayName, Category | obligatoire | Id 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. |
IconName | Id | Nom 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. |
Order | 0 | Position dans la catégorie. |
InputMode | Brush | Brush : empreintes le long du trajet du pointeur (selon l’espacement du pinceau). Click : une empreinte par appui. Drag : OnDragBegin / OnDragUpdate / OnDragEnd (rectangles, lignes). |
UsesBrush | true pour Brush | Affiche le panneau du pinceau (taille, forme, intensité…). |
RepeatRate | 0 | Empreintes par seconde tant que le bouton reste enfoncé sans que le pointeur bouge (pour élever ou abaisser en continu). |
ModifiedLayers | None | À titre informatif : utilisé par les superpositions et la barre d’état. |
PreviewColor | bleu clair | Couleur du curseur de pinceau projeté. |
Snap | None | Aligne le centre du pinceau sur les vertices (outils de falaise) ou sur les centres des cellules. |
SupportsPick + OnPick | false | Ctrl+clic prélève une valeur (une hauteur, un calque) au lieu de peindre. |
OnActivated, OnDeactivated, OnSettingChanged | Callbacks du cycle de vie. | |
OnStrokeBegin, OnStrokeEnd, OnStrokeCancelled | Appelé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) | null | Texte 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.
ApplyDabest appelée une fois pour chaque copie symétrique ;dab.symmetryvous indique de quelle copie il s’agit (avec son décalage de lacet et l’indication d’une éventuelle mise en miroir).dab.rotationest déjà transformée. - L’empreinte (
BrushDab) contientlocalPosition,worldPosition,radius,strength,rotation,invert(Shift enfoncée),isFirstDabetdabIndex. - Poids du pinceau :
BrushGrid.Verticesavec une résolution de 1 pour les couches par vertex,BrushGrid.Texelsavecmap.SplatResolution,DetailResolutionouPathingResolutionpour les couches raster. Convertissez les rectangles avecBrushUtility.VertexRectToCellRect,TexelRectToCellRectouGetCellRect(map, dab). Libérez toujours les poids. - Les valeurs aléatoires doivent être identiques pour toutes les copies symétriques d’une empreinte.
ctx.Randomreç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 quanddab.symmetry.index == 0, mettez-les en cache pour cedab.dabIndexet réutilisez-les pour les autres copies en les reflétant ou en les faisant pivoter avecSymmetricScatter.TransformOffsetetSymmetryPoint.TransformYaw. La classe publiqueSymmetricScatter(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,WaterTargetToolouPathingTool(ces classes fournissent la catégorie, la couleur du curseur et le texte d’état ;WaterTargetToolajoute aussi les paramètres Water Height et le prélèvement par Ctrl+clic), ou appelezTerrainToolUtility.BeginHardVertexSelection(ctx, dab, layers, out weights, out forcedIndex, out cells). Les vertices dont le poids vaut au moinsTerrainToolUtility.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érezweightsmême lorsque la méthode renvoie false. - Performances : les outils intégrés exécutent leurs boucles dans des jobs Burst (voir
RaiseLowerTooletPaintLayerTooldansRuntime/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 desession.Tools, si bien queSetActiveTool,RTSEditorContext.ActivateTooletFindToolne 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 aussiRTSEditorContext.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 dansAssembly-CSharp, qui la référence automatiquement). Le registre ignore les assemblies dont le nom commence parSystem,Unity.,UnityEngine,UnityEditor,Mono.,mscorlib,netstandardoununit. 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.xmldu package conserve les outils intégrés ; marquez les vôtres avec[UnityEngine.Scripting.Preserve]ou listez-les dans un fichierlink.xmlde 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, avecRTSEditorContext.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.
| Membre | Description |
|---|---|
BrushSettings Brush | Le 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 Symmetry | mode (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), ActiveTool | Recherche 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énement | Signature | Déclenchement |
|---|---|---|
MapLoaded | Action<RTSTerrain> | Après l’assignation d’une nouvelle carte (chargement, nouvelle carte, redimensionnement, reconstruction). Reconstruisez tout ce que vous calculez à partir de la carte. |
MapUnloading | Action<RTSTerrain> | Avant que la carte actuelle soit remplacée ou libérée. Supprimez ici vos références à cette carte. |
MapChanged | Action<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. |
ChangesProcessed | Action<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. |
PathingChanged | Action<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). |
TilesetChanged | Action<RTSTerrain> | La référence au tileset ou son contenu a changé. |
LibrariesChanged | Action<RTSTerrain> | La référence à une bibliothèque de végétation ou de décors, ou son contenu, a changé. |
RTSTerrain.TerrainEnabled / TerrainDisabled | static Action<RTSTerrain> | Un terrain a été activé ou désactivé (modifications du registre). |
RTSRuntimeEditorEvents.PlaytestChanged | static 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.MapOpened | static 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.
| Membre | Description |
|---|---|
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, FileExtension | Le dossier Maps situé dans StorageRoot (utilisé par l’éditeur en jeu, sauf si son paramètre Maps Folder est défini) et ".rtsmap". |
RTSMapSerializer.StorageRoot | Le 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(...), IsSupported | Builds 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();
}
}
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.
- Ouvrez . 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.
- 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
Shadersdu package (clic droit ▸ Reimport). - 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
RTSTerrainest 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 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(). - Lancez 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
RTSFogOfWarRevealerdont 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 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 dansRTSMapSerializer.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 : ▸ 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é (). 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.Mainsi 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 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 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 , 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.
- 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. - Validez le projet. 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.
- 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.
- 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.
- 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 restaure les assets de démo.
- Vérifiez les intégrations. Des erreurs de compilation dans
Integrationsaprès la suppression de Mirror signifient que le symboleMIRRORest 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. - 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.
- Toujours bloqué ? Reproduisez le problème dans une nouvelle scène, avec un terrain créé via 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ôme | Cause probable | Voir |
|---|---|---|
| Matériaux roses | URP inactif, erreurs de shader, matériaux Built-in sur vos prefabs | FAQ |
| Terrain invisible | Aucune carte chargée, composant désactivé, layer des chunks exclu par le culling | FAQ |
| Le pinceau agit à côté du curseur | Terrain mis à l’échelle ou rotation X/Z | FAQ |
| Pas de brouillard de guerre | Renderer feature manquante, aucun révélateur de l’équipe locale, Reveal All activé | FAQ |
| Eau noire | Depth / Opaque Texture désactivées | FAQ |
| Végétation absente des builds | Références de shaders, instanciation GPU | FAQ |
| Les unités ne bougent pas | Carte de cheminement pas encore construite, départ ou destination non praticable, fournisseur sans graphe ni NavMesh | Validation des cartes, Intégrations |
| Le générateur place moins de positions de départ | Pas assez d’espace plat pour Flat Radius / Edge Margin | Paramè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 incorrects | Import et export de heightmaps |
| Erreurs de compilation liées à Mirror après sa suppression | Symbole MIRROR obsolète encore défini | Supprimer des intégrations |
| Boîte de dialogue RTS Terrain Studio requires URP | URP 17.3 n’est pas installé, ou l’éditeur est antérieur à Unity 6.3 | Unity et pipeline de rendu |
| Build Web : interface minuscule, cartes perdues, touches qui ouvrent des fonctions du navigateur | Modèle de taille fixe, stockage du navigateur, raccourcis du navigateur | Builds 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
.rtsmapcommun à 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
AIPathet 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.