Цю сторінку ще не перекладено — показано англійську версію.
Map
Статичний світ: межі, рельєф, перешкоди і питання «куди що можна поставити?». Фізична модель навмисно набагато простіша за візуальну: примітиви з площею основи й висотою, шари з правилами і один запит допустимої позиції, яким користуються всі інші модулі.
Коли це потрібно
- Вам потрібен статичний світ — межі, рельєф, перешкоди, — до якого сервер може надсилати запити, а не лише малювати його.
- Точки появи, предмети, що випадають, і декорації мають потрапляти в допустимі місця: для цього є один запит
RandomPositionна правилах, і обійти його не можна. - Арени мають генеруватися заново на кожен матч: оголошений
Seedвідтворює ту саму мапу (map) у баг-репорті. - Ящики й стіни ламаються і з’являються знову: руйновані об’єкти з HP і таймерами респавну.
- Ботам (bot) і снарядам потрібні raycast і перевірка прямої видимості щодо набору перешкод.
- Не потрібно, якщо світ суто візуальний і серверний код не питає, куди що можна поставити.
Хто що робить
| Актор | Що робить на цій сторінці |
|---|---|
schema-author | оголошує мапи, примітиви перешкод, руйновані об’єкти, шари та їхні правила |
room-owner | прив’язує мапу до кімнати (room); запитує позиції появи; робить raycast |
operator | розставляє і прибирає перешкоди й шари з панелі |
Коротко
arena: сід і межі, рельєф, камені, ящики з респавном, шар із правилами[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 assetЯк оголошувати через атрибути в Go, поки не вирішено (O-1). Приклади з’являться, коли оберуть спосіб запису.
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 і Destructible — генератори розстановки, а не кидки кубика під час гри. Генератор спрацьовує, коли публікують версію мапи: сорок каменів перетворюються на сорок оголошених примітивів, і опублікована версія містить примітиви, а не прав ило. Тому той самий Seed дає ті самі сорок каменів і в матчі, і в повторі, і в баг-репорті. А геометричні обмеження платформа перевіряє один раз, на цьому готовому наборі, ще до того, як версія потрапить у середовище (environment).
Запит, яким користуються всі інші:
RandomPosition: чесна точка появи на землі, подалі від гравців, без повторівvar 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),
))Як оголошувати через атрибути в Go, поки не вирішено (O-1). Приклади з’являться, коли оберуть спосіб запису.
// 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);
});Модель
Два шари, і оголошують їх різні люди.
| Шар | Що в ньому і хто його оголошує |
|---|---|
статичний | рельєф із висотами, примітиви перешкод, межі й локації — авторський контент |
динамічний | перешкоди, які під час гри приносять сутності: двері, руйновані об’єкти, платформи. Тому руйнований об’єкт — це сутність з життєвим циклом, станами й власником, і частиною мапи вона стає лише там, де приносить перешкоду. Статичний камінь оголошують у мапі, а двері — це сутність (entity), яка приносить перешкоду. Власного життєвого циклу тут вони не мають: він належить сутності |
Що оголошує мапа.
| Що оголошує | Що це |
|---|---|
key і version | мапа — це авторський контент: її оголошують у коді, адресують за key і версіонують, а версія входить до того, на що посилається кімната. Змінювати геометрію випущеної версії заборонено: будь-яка правка — це нова версія |
рельєф | поле висот — регулярна сітка з оголошеним кроком. Крок — це оголошена межа точності, тож запит висоти відповідає з цією точністю, а не точно. Рельєфу може не бути: арена в порожнечі цілком допустима |
перешкоди | закритий набір примітивів: паралелепіпед, сфера, капсула й опукла оболонка з оголошеним лімітом вершин. Довільний трикутний меш платформа не приймає — лише за цієї умови перевірка на сервері взагалі можлива |
тип прохідності для кожної перешкоди | непрохідна · прохідна для оголошеного класу · лише перекриває пряму видим ість. Той самий примітив слугує і стіною, і кущем, а різницю оголошують, а не моделюють двічі |
межі | об’єм, поза яким позиція неприпустима |
яруси світу | оголошені просторові яруси всередині мапи — земля, підземелля, повітря. Це оголошення геометрії й адресації |
локації | іменовані місця чи області — точка появи, зона захоплення, коридор. Локація відповідає на питання де, але ніколи — що відбувається: ігрової логіки в ній немає |
генератор розстановки | за бажанням — правило, що породжує примітиви: кількість, мінімальна відстань, область, сід. Він спрацьовує під час публікації версії, детерміновано за сідом, і після цього мапа зберігає примітиви, а не правило |
Ярус світу й екземпляр мапи — ніколи не синоніми.
| Що це | |
|---|---|
ярус світу | оголошення всередині мапи — земля, підземелля, повітря |
екземпляр мапи | незалежна копія опублікованої мапи під час гри. Екземпляри спільно використовують незмінну опубліковану геометрію, але динамічні перешкоди й склад сутностей у кожного свої. Кімната займає екземпляр і може вибрати яруси всередині нього |
Що справджується для будь-якого запиту.
| Завжди | Що це |
|---|---|
єдиний геометричний канон | уся геометрія задана в оголошеному платформою каноні координат, а точність кожного геометричного поля (field) оголошують на самому полі |
модель світу | це спрощення: геометрія на сервері — не арт-модель і не зобов’язана нею бути |
відповідь називає свій екземпляр і момент | на запит відповідають за статичним шаром мапи й динамічними перешкодами того екземпляра, про який спитали, і відповідь указує момент, для якого вона правильна. Динамічні перешкоди змінюються, тож відповідь — це снапшот |
значення | належать до managed, а не до seed: геометрію не підкручують щодня, тож правку з адмін-консолі платформа відхиляє, а не зберігає мовчки |
рух і контакт | тут не обробляються: мапа відповідає, яким є простір. Чи допустима позиція і якою буде реакція, вирішують зіткнення, а застосовує це до руху переміщення |
Помилки
- Мапу, версію чи екземпляр не знайдено — відповідь not found; так само відповідає й відкликана версія. Повторювати запит марно.
- Публікація зміненої геометрії під наявною версією — конфлікт: створіть нову версію.
- Помилки публікації виникають під час оголошення й деплою, але ніколи під час гри: мапа понад ліміт примітивів, опукла оболонка понад ліміт вершин, довільний меш як переш кода — усе це відмови під час валідації ще до випуску.
- Запит висоти за межами — не помилка, а оголошена відповідь «за межами». Її можна відрізнити від відповіді «всередині перешкоди», бо в одному випадку клієнт розвертається, а в іншому — об’їжджає.
- Перевищено частоту запитів — відповідь із категорії обмеження частоти із зазначенням, коли можна повторити.
Обмеження
Конкретні числа з’являться в розділі про обмеження платформи, а що відбувається на кожній стелі, визначено вже зараз.
- Примітивів перешкод на мапу, вершин опуклої оболонки, роздільна здатність поля висот, розмір меж, локацій на мапу: усе це платформа відхиляє під час публікації, а не під час запиту.
- Екземплярів на мапу: створення ще одного відхиляється як конфлікт; наявні екземпляри платформа ніколи не прибирає, щоб звільнити місце.
- Збережені версії: платформа відкликає найстарішу версію в статусі deprecating, але версію, на якій працює жива кімната, — ніколи.
- Частота запитів до простору: обмеження частоти із зазначенням, коли можна повторити.