Эта страница ещё не переведена — показана английская версия.
Аптечки в Tanks
Это второй урок на Tanks. В нём три шага и ни одного нового модуля: объявление (declaration) аптечки, объявление мест, где аптечки появляются, и один хук, который решает, что происходит при подборе. Проходите его после страницы Первые шаги, а с уроком про таблицу лидеров — в любом порядке.
Объявите аптечку
Аптечка — это сущность (entity) с пресетом объектов мира и телом, которое сообщает о касании, но никого не останавливает. Подбираемым предметом, а не препятствием, её делает Response.Pass на слое pickups: о касании сообщается, а движ ение проходит насквозь.
pickups — касание регистрируется, движение не меняется[Entity("health-crate", Persistence = Persistence.Runtime, Presets = new[] { Preset.WorldObjects })]
public class HealthCrate
{
[Sync] public Vector3 Position;
[Body(Shape.Sphere, Radius = 0.5f, Layer = "pickups")]
[CollidesWith("vehicles", Response.Pass)] // reported, motion passes through
public Body Body;
}@Entity('health-crate', { persistence: Persistence.Runtime, presets: [Preset.WorldObjects] })
export class HealthCrate {
@Sync position: Vector3;
@Body({ shape: 'sphere', radius: 0.5, layer: 'pickups' })
@CollidesWith('vehicles', Response.Pass) // reported, motion passes through
body: Body;
}@entity("health-crate", persistence=Persistence.RUNTIME, presets=[Preset.WORLD_OBJECTS])
class HealthCrate:
position: Vector3 = sync()
body: Body = body(shape="sphere", radius=0.5, layer="pickups",
collides_with=[("vehicles", Response.PASS)])Как объявлять через атрибуты в Go, пока не решено (O-1). Примеры появятся, когда выберут спосо б записи.
UCLASS(PSEntity = (Name = "health-crate", Persistence = "Runtime", Presets = "world-objects"))
class UHealthCrate : public UObject
{
GENERATED_BODY()
UPROPERTY(PSSync) FVector3f Position;
UPROPERTY(PSBody = (Shape = "Sphere", Radius = "0.5", Layer = "pickups"),
PSCollidesWith = "vehicles:Pass") // reported, motion passes through
FPSBody Body;
};
// declarations compile into the same pushed model — playserv push from the UE project or CIОбъявления пишутся в серверном проекте и загружаются командой playserv push, а биндинг Unity работает на клиенте со сгенерированным типизированным API (HealthCrate).
Две вещи писать не пришлось. Где рисовать аптечку — клиент и так отрисовывает объя вленные объекты мира. И как её позиция доходит до клиентов — [Sync] сам и есть сетевой вызов.
Подробнее — на страницах Entity Presets и Collision.
Объявите, где появляются аптечки
Размещение — тоже объявление, и именно от этого шага зависит, покажется ли фича честной. Минимальное расстояние не даёт аптечкам скапливаться в одном месте, отступ от игроков (player) — появляться посреди дуэли, а правило без повторов — раз за разом выпадать в одной и той же точке.
[DropTable("health-crates", Layer = "ground", MinSpacing = 8, AwayFromPlayers = 10, NoRepeat = 3)]
public static partial class HealthCrates
{
public static readonly Drop Crate = Drop.Of<HealthCrate>(weight: 1);
}@DropTable('health-crates', { layer: 'ground', minSpacing: 8, awayFromPlayers: 10, noRepeat: 3 })
export class HealthCrates {
static crate = Drop.of(HealthCrate, { weight: 1 });
}@drop_table("health-crates", layer="ground", min_spacing=8, away_from_players=10, no_repeat=3)
class HealthCrates:
crate = drop_of(HealthCrate, weight=1)Как объявлять через атрибуты в Go, пока не решено (O-1). Примеры появятся, когда выберут способ записи.
USTRUCT(PSDropTable = (Name = "health-crates", Layer = "ground", MinSpacing = 8,
AwayFromPlayers = 10, NoRepeat = 3))
struct FHealthCrates
{
GENERATED_BODY()
UPROPERTY(PSEntry = (Entity = "health-crate", Weight = 1)) FPSDrop Crate;
};
// declarations compile into the same pushed model — playserv push from the UE project or CIОбъявления пишутся в серверном проекте и загружаются командой playserv push, а клиент Unity видит результат как появившиеся в мире предметы и события подбора.
Допустимые позиции выдаёт модуль Map. Таблица выпадения (drop table) запрашивает точку на слое ground, а карта отвечает точко й, до которой действительно можно доехать, так что аптечка никогда не окажется внутри стены.
Подробнее — на страницах Entity Presets и Map.
Лечение при подборе
Один хук — и это весь код в уроке. Он выполняется на платформе как облачная функция, поэтому во вкладках движков его нет.
[Before(Drops.Pickup)]
public static Verdict HealOnPickup(PickupIntent p)
{
if (p.WorldItem.Kind != "health-crate") return Hook.Continue(p);
if (p.Player.Tank.Hp.IsFull) return Hook.Reject("already at full health");
p.Player.Tank.Hp.Adjust(+40, by: p.Player);
return Hook.Continue(p);
}export const healOnPickup = before(Drops.pickup, (p: PickupIntent) => {
if (p.worldItem.kind !== 'health-crate') return Hook.continue(p);
if (p.player.tank.hp.isFull) return Hook.reject('already at full health');
p.player.tank.hp.adjust(+40, { by: p.player });
return Hook.continue(p);
});@before(drops.pickup)
def heal_on_pickup(p: PickupIntent) -> Verdict:
if p.world_item.kind != "health-crate":
return Hook.continue_(p)
if p.player.tank.hp.is_full:
return Hook.reject("already at full health")
p.player.tank.hp.adjust(+40, by=p.player)
return Hook.continue_(p)Как объявлять через атрибуты в Go, пока не решено (O-1). Примеры появятся, когда выберут способ записи.
Хук — это облачная функция: он выполняется на платформе, а не в движке. Напишите его на C#, TypeScript или Python, а Unreal подпишется на события изменения характеристики и подбора, которые он порождает. В планах — функции, написанные прямо в движке: графы Blueprint и C++, который будет транслироваться в скрипт, проверяемый платформой. Их будут анализировать и загружать так же, как любые объявления, а выполняться они по-прежнему будут на платформе.
Хук — это облачная функция: он выполняется на платформе, а не в движке. Напишите его на C#, TypeScript или Python, а Unity подпишется на события изменения характери стики и подбора, которые он порождает.
Чего хуку делать не приходится:
- Отказ типизирован. Танк с полным здоровьем получает
already at full healthс причиной, которую клиент может показать игроку, а аптечка остаётся на месте для того, кому она нужнее. - Характеристики меняет только сервер. Клиент не может попросить изменить характеристику (stat), поэтому писать для подбора исключение в античите не нужно.
- HUD обновляется сам.
Adjustпорождаетchanged, а клиент уже подписан на объявленные характеристики танка. Сетевого сообщения вы не писали.
Подробнее — на страницах Extensibility и Entity Presets.
Что дальше
- Entity Presets — генератор выпадения, объекты мира и модель характеристик, на которые опирался урок. Все три — пресеты
entity, а не модули. - Collision — слои, реакции и разница между касанием, о котором только сообщается, и касанием, которое остан авливает движение.
- Map — как выбирается допустимая позиция и что значит «достижимая».
- Extensibility — все точки вызова хуков по порядку и правила вето.
- Таблица лидеров в Tanks — второй пример на Tanks.