Cette page n’est pas encore traduite : la version anglaise est affichée.
Map
Le monde statique : limites, terrain, obstacles, et « où peut-on aller ? ». Le modèle physique est volontairement bien plus simple que le modèle visuel : des primitives dotées d’une emprise au sol et d’une hauteur, des couches assorties de règles, et une seule requête de position valide que tous les autres modules réutilisent.
Quand l’utiliser
- Il vous faut un monde statique (limites, terrain, obstacles) que le serveur peut interroger, et pas seulement afficher.
- Les apparitions (spawn), les butins et les décors doivent tomber à des endroits autorisés : une seule requête
RandomPositionfondée sur des règles, sans contournement possible. - Les arènes doivent se régénérer à chaque match : une
Seeddéclarée reproduit la même carte (map) dans un rapport de bug. - Les caisses et les murs se brisent puis reviennent : des objets destructibles, avec des points de vie et des délais de réapparition.
- Les bots et les projectiles ont besoin de raycasts et de tests de ligne de vue sur l’ensemble des obstacles.
- Inutile quand le monde est purement visuel et qu’aucun code serveur ne demande où l’on peut aller.
Qui fait quoi
| Acteur | Ce qu’il fait sur cette page |
|---|---|
schema-author | déclare les cartes, les primitives d’obstacle, les objets destructibles, les couches et leurs règles |
room-owner | associe une carte à une salle (room) ; demande des positions d’apparition ; lance des raycasts |
operator | place ou retire des obstacles et des couches depuis le panneau |
En bref
arena déclarée : graine et limites, terrain, rochers, caisses qui réapparaissent, une couche de règles[Map("arena", Seed = 42, Bounds = "160x160")]
public static class Arena
{
[Terrain(HeightNoise = 0.3f)] public static Terrain Height; // 3D height field
[Scatter("rock", Count = 40, MinSpacing = 6)] public static ObstacleSet Rocks;
[Destructible("crate", Count = 12, Hp = 100, RespawnAfter = "30s")] public static ObstacleSet Crates;
[Layer("ground", NotInside = "water")] public static Layer Ground;
}
// or: Maps.Named("arena-caves-v3") — authored in the panel or loaded from an asset@Map('arena', { seed: 42, bounds: '160x160' })
export class Arena {
@Terrain({ heightNoise: 0.3 }) height: Terrain; // 3D height field
@Scatter('rock', { count: 40, minSpacing: 6 }) rocks: ObstacleSet;
@Destructible('crate', { count: 12, hp: 100, respawnAfter: '30s' }) crates: ObstacleSet;
@Layer('ground', { notInside: 'water' }) ground: Layer;
}
// or: Maps.named('arena-caves-v3') — authored in the panel or loaded from an asset@Map("arena", seed=42, bounds="160x160")
class Arena:
height = terrain(height_noise=0.3) # 3D height field
rocks = scatter("rock", count=40, min_spacing=6)
crates = destructible("crate", count=12, hp=100, respawn_after="30s")
ground = layer("ground", not_inside="water")
# or: maps.named("arena-caves-v3") — authored in the panel or loaded from an assetLa déclaration par attributs en Go n’est pas encore tranchée (O-1). Les exemples arriveront quand la forme d’écriture sera choisie.
USTRUCT(PSMap = (Name = "arena", Seed = 42, Bounds = "160x160"))
struct FArena
{
GENERATED_BODY()
UPROPERTY(PSTerrain = (HeightNoise = "0.3")) FPSTerrain Height; // 3D height field
UPROPERTY(PSScatter = (Obstacle = "rock", Count = 40, MinSpacing = 6)) FPSObstacleSet Rocks;
UPROPERTY(PSDestructible = (Obstacle = "crate", Count = 12, Hp = 100,
RespawnAfter = "30s")) FPSObstacleSet Crates;
UPROPERTY(PSStratum = (Name = "ground", NotInside = "water")) FPSStratum Ground;
};
// or: PS::Maps::Named(TEXT("arena-caves-v3")) — authored in the panel or loaded from an asset
// declarations compile into the same pushed model — playserv push from the UE project or CI[Map("arena", Seed = 42, Bounds = "160x160")]
public static class Arena
{
[Terrain(HeightNoise = 0.3f)] public static Terrain Height; // 3D height field
[Scatter("rock", Count = 40, MinSpacing = 6)] public static ObstacleSet Rocks;
[Destructible("crate", Count = 12, Hp = 100, RespawnAfter = "30s")] public static ObstacleSet Crates;
[Layer("ground", NotInside = "water")] public static Layer Ground;
}
// or: Maps.Named("arena-caves-v3") — authored in the panel or loaded from an assetScatter et Destructible sont des générateurs de placement, pas des tirages au runtime. Un générateur est résolu au moment où la version de la carte est publiée : les quarante rochers deviennent quarante primitives déclarées, et la version publiée contient les primitives, pas la règle. La même Seed donne donc les mêmes quarante rochers dans le match, dans le replay et dans le rapport de bug — et les limites de géométrie sont vérifiées une seule fois, sur cet ensemble résolu, avant que la version n’atteigne un environnement.
La requête que tout le reste utilise :
RandomPosition : une apparition équitable, au sol, loin des joueurs, sans répétitionvar spawn = map.RandomPosition(r =>
{
r.Layer("ground");
r.AwayFrom(players, minDistance: 12);
r.NoRepeat(lastN: 3);
});const spawn = map.randomPosition((r) => {
r.layer('ground');
r.awayFrom(players, { minDistance: 12 });
r.noRepeat({ lastN: 3 });
});spawn = map.random_position(rules=lambda r: (
r.layer("ground"),
r.away_from(players, min_distance=12),
r.no_repeat(last_n=3),
))La déclaration par attributs en Go n’est pas encore tranchée (O-1). Les exemples arriveront quand la forme d’écriture sera choisie.
// Dedicated-server host: place a spawn through the same rule-based query
Map->Positions->GetRandom({ .Stratum = PSKeys::Strata::Ground,
.AwayFrom = Players,
.MinDistance = 12.f,
.NoRepeatLastN = 3 },
TPSOnResult<FVector>::CreateLambda([](const TPSResult<FVector>& Result)
{
if (!Result.HasValue()) { return; }
PlaceSpawn(Result.Value());
}));
// co_await support ships later: a built-in SDK coroutine wrapper that respects Unreal's GC and threading.var spawn = map.RandomPosition(r =>
{
r.Layer("ground");
r.AwayFrom(players, minDistance: 12);
r.NoRepeat(lastN: 3);
});Le modèle
Deux couches, déclarées par des personnes différentes.
| Couche | Ce qu’elle contient, et qui la déclare |
|---|---|
statique | terrain avec relief, primitives d’obstacle, limites et lieux — du contenu créé par des auteurs |
dynamique | des obstacles apportés par des entités au runtime : portes, objets destructibles, plateformes. Un objet destructible est donc une entité avec un cycle de vie, des états et un propriétaire, et il ne relève de la carte que pour l’obstacle qu’il apporte : un rocher statique est déclaré dans la carte, une porte est une entité qui apporte un obstacle. Ces obstacles n’ont pas de cycle de vie propre ici : il appartient à l’entité |
Ce que déclare une carte.
| Déclare | Ce que c’est |
|---|---|
key et version | une carte est du contenu d’auteur : déclarée dans le code, désignée par sa key et versionnée — la version fait partie de ce qu’une salle référence. Modifier la géométrie d’une version publiée est interdit ; toute modification donne une nouvelle version |
terrain | un champ de hauteurs — une grille régulière au pas déclaré, et ce pas est une limite de précision déclarée : une requête de hauteur répond à ce pas près, pas exactement. Le terrain peut être absent : une arène dans le vide est parfaitement valide |
obstacles | un ensemble fermé de primitives — boîte, sphère, capsule, enveloppe convexe avec une limite de sommets déclarée. Un maillage de triangles arbitraire n’est pas accepté : c’est à cette condition qu’une vérification côté serveur est seulement possible |
type de franchissabilité par obstacle | infranchissable · franchissable pour une classe déclarée · bloque seulement la ligne de vue. Une même primitive sert de mur comme de buisson, et la différence est déclarée au lieu d’être modélisée deux fois |
limites | le volume hors duquel une position n’est pas admise |
strates du monde | des strates spatiales déclarées à l’intérieur d’une carte — sol, souterrain, air. Ce sont des déclarations de géométrie et d’adressage |
lieux | des emplacements ou des zones nommés — un point d’apparition, une zone de capture, un couloir. Un lieu répond à la question où, jamais à ce qui s’y passe : il ne porte aucune logique de jeu |
générateur de placement | facultatif : une règle qui produit des primitives — un nombre, un espacement minimal, une zone, une graine. Il est résolu à la publication d’une version, de façon déterministe d’après la graine, et la carte contient ensuite des primitives, pas une règle |
Une strate du monde et une instance de carte ne sont jamais synonymes.
| Ce que c’est | |
|---|---|
strate du monde | une déclaration à l’intérieur de la carte — sol, souterrain, air |
instance de carte | une copie au runtime, indépendante, de la carte publiée. Les instances partagent la géométrie publiée, immuable, mais chacune a ses propres obstacles dynamiques et sa propre liste d’entités. Une salle occupe une instance et peut y sélectionner des strates |
Ce qui vaut pour toute requête.
| Toujours | Ce que c’est |
|---|---|
un seul référentiel géométrique | toute la géométrie s’exprime dans le référentiel de coordonnées déclaré par la plateforme, et la précision de chaque champ géométrique est déclarée sur le champ lui-même |
le modèle du monde | est une simplification : la géométrie du serveur n’est pas le modèle graphique, et n’a pas à l’être |
une réponse nomme son instance et son instant | la réponse à une requête s’appuie sur la couche statique de la carte et sur les obstacles dynamiques de l’instance visée, et elle déclare l’instant auquel elle est vraie : les obstacles dynamiques changent, la réponse est donc un snapshot |
les valeurs | sont managed, pas seed : la géométrie ne se règle pas au jour le jour, si bien qu’une modification depuis la console d’administration est refusée au lieu d’être conservée en silence |
le mouvement et le contact | ne sont pas résolus ici : la carte dit ce qu’est l’espace ; savoir si une position est admissible et quelle réaction s’ensuit relève des collisions, et l’appliquer relève du déplacement |
Erreurs
- Une carte, une version ou une instance introuvable répond not found, tout comme une version retirée : inutile de réessayer.
- Publier une géométrie modifiée sous une version existante est un conflit : créez une nouvelle version.
- Les échecs de publication surviennent à la déclaration ou au déploiement, jamais au runtime — une carte qui dépasse la limite de primitives, une enveloppe convexe qui dépasse sa limite de sommets ou un maillage arbitraire utilisé comme obstacle donnent tous lieu à un refus de validation, avant toute mise en production.
- Une requête de hauteur hors des limites n’est pas une erreur : c’est la réponse déclarée « hors des limites », et elle se distingue de « à l’intérieur d’un obstacle », car dans un cas le client fait demi-tour et dans l’autre il contourne l’obstacle.
- Un rythme de requêtes dépassé répond dans la catégorie limite de débit, avec une échéance.
Limites
Les chiffres viendront avec le chapitre sur les limites de la plateforme ; ce qui se passe à chaque plafond, lui, est déjà fixé.
- Primitives d’obstacle par carte, sommets d’enveloppe convexe, résolution du champ de hauteurs, taille des limites, lieux par carte : chaque dépassement est refusé à la publication, pas au moment de la requête.
- Instances par carte : la création d’une instance de plus est refusée comme conflit ; les instances existantes ne sont jamais libérées pour faire de la place.
- Versions conservées : la plus ancienne version en cours de dépréciation est retirée ; une version qui sert une salle active ne l’est jamais.
- Le rythme des requêtes spatiales : une limite de débit, avec une échéance.