Skip to main content

xgaida-x-nixi-gamefeel-vfx

Джус и визуальный фидбэк Guildmaster: политика значимости (что достойно slowmo и тряски), per-hit фидбэк (hitstop, вспышка, сплющивание, боевые цифры), VFX, death-shatter, screen shake за IScreenShake, feel-конфиги и шов префаб-VFX (SO→префаб→пул→сокет). Зови на любую задачу про сочность, VFX, тряску, замедление, партиклы и всё под Presentation-визуалом. НЕ применять к: боевому времени и его контракту (combat-sim — здесь только потребитель), звуку (audio), определениям VfxData как контента (data-authoring).

الانتقال إلى التثبيت

معلومات المصدر

المستودع
Kaliguri/Guildmaster-Autobattler
آخر نشاط في المصدر
٧ أغسطس ٢٠٢٦ في ٠٢:٣٨
لغة SKILL.md المكتشفة
الروسية
النجوم
٠
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
4 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
xgaida-x-nixi-gamefeel-vfx
description
Джус и визуальный фидбэк Guildmaster: политика значимости (что достойно slowmo и тряски), per-hit фидбэк (hitstop, вспышка, сплющивание, боевые цифры), VFX, death-shatter, screen shake за IScreenShake, feel-конфиги и шов префаб-VFX (SO→префаб→пул→сокет). Зови на любую задачу про сочность, VFX, тряску, замедление, партиклы и всё под Presentation-визуалом. НЕ применять к: боевому времени и его контракту (combat-sim — здесь только потребитель), звуку (audio), определениям VfxData как контента (data-authoring).
# Gamefeel & VFX — рабочий контур Guildmaster Этот скилл — процедура, а не справка. Он превращает разрозненные правила «сочности» в чеклист, который прогоняется на КАЖДОЙ фидбэк-задаче. Цель — чтобы джус и VFX оставались развязанными от боевого ядра (смотрят на sim, не мутируют его), data-driven (значения и формы — в SO, эффекты — в префабах), а новый фидбэк ложился в готовые швы, а не рядом с ними. **Роль на этом слое:** я держу КОНТРАКТ фидбэка (кто на что подписан, где живёт global-feel, как эффект попадает на экран, какие швы). Визуальную приёмку и полиш — как именно выглядит бёрст, кривая шейка, тайминг «на глаз», сам арт — делает Макс. Я кручу визуал-параметры только по его ТЗ и показываю результат. ## Дизайн-документация джуса — тоже мой контур (решено 2026-07-31) **Кластер `docs/wiki/gdd/70-gamefeel/` принадлежит этому скиллу, а не `gdd-scribe`.** Писарь ГДД владеет чистым геймдизайном — механиками, балансом, контентом; в джусе дизайн и реализация неотделимы (тайминг эффекта — одновременно дизайн-решение и число в конфиге), и разводить их по двум скиллам значило бы развести один факт по двум головам. Прецедент — `narrative` с `60-narrative`. | Файл кластера | Что держит | |---|---| | `vfx-language.md` | **как выглядит событие**: роли-слои, тайминги, масштаб в долях роста юнита, словарь боевых событий | | `vfx-color.md` | чем красим: главный цвет и палитра разброса, роли оттенков ростера | | `asset-palette.md` | чем рисуем: связка «роль → текстура». **Не инвентарь ассетов** — тот живёт в `tech/10-reference/asset-inventory` | | `backlog-gamefeel.md`, `backlog-vfx-particles-shaders.md` | банки идей: тактильный слой и визуальный | Правила ведения те же, что у остальной ГДД: принятое решение — записью в `gdd/00-meta/journal-adr.md` с датой и причиной (append-only, старое помечается `superseded`); своё предложение — только как `proposed`; после правки прогнать оба гейта — `check-wiki-frontmatter.ps1` и `check-wiki-links.ps1`. **Эффект, показанный в бою, обязан иметь строку в словаре событий** (`vfx-language.md`). Не имеет — значит его форму никто не выбирал, и следующий заход соберёт её заново по-своему. ## Модель боевого удара — принята 31.07.2026, читать ПЕРЕД любым разговором о формах Канон целиком — `docs/wiki/gdd/70-gamefeel/vfx-language.md`; здесь только то, без чего разговор начнётся с нуля. **Терминология обязательна к использованию** (заведена по жалобе Макса «терминов нет норм, путаюсь»). **Термины:** **форма** (серп / веретено / звезда) · **ядро** (радиальная вспышка, параметр — радиус) · **искры** (частицы прочь) · **порез** (красная метка на теле, накапливается) · **остаток** (пыль, след) · **дуга за клинком** (VFX-сектор от плеча на взмахе) · **A** (начало взмаха, маркер `StrikeStart` как геометрия) · **B** (точка попадания, маркер `Hit`). Слово «разрез» изъято. **Две стадии, и они в разное время — поэтому не конфликтуют:** | Стадия | Что | Когда | |---|---|---| | 1 · взмах | **дуга за клинком** — сектор от плеча, заметающий пройденный угол | strike-фаза, до хита | | 2 · хит | **серп** A→B, **ядро**, **искры**, **порез** | от кадра `Hit` | **Семь правил, которые ломаются легче всего:** 1. **Форма строится по ДВУМ ТОЧКАМ (A→B), а не по траектории клипа.** Точка хита — **середина** формы у серпа и веретена (клинок проходит навылет), **конец** у звезды-дробящего. 2. **Нет контакта — нет серпа.** На промахе: дуга есть, серпа/ядра/искр/пореза нет, только «evade». Дуга рисуется на каждом взмахе — она говорит «клинок прошёл здесь», и это правда даже при промахе. 3. **Три архетипа — это ПРАВИЛА ГЕНЕРАЦИИ, а не три готовых знака.** Процедурно гуляют прогиб, толщина в коридоре, неровность, лучи звезды. **Размер не гуляет** — он несёт урон. 4. **Форма говорит КАК доставили, цвет говорит ЧЕМ ударили.** Отдельных форм под элементы нет и не будет: элемент несёт палитра юнита. Дальний бой — линия-всполох, тот же колющий с нулевым прогибом, после хита, по вектору снаряда. 5. **Всё рисуем сами шейдером на одном quad (SDF).** Спрайтовые листы эффектов — не наш путь: форма параметрическая, потому что настраивается данными, а не перерисовывается. Пиксель-арт отменён (`2026-08-01/14`), юнит теперь плоский сторибук — эффект и юнит в одной гладкости, а различает их яркость. 6. **Порез — это СОСТОЯНИЕ тела** (`BodyVisualState` через `IUnitBodyVisual`), не событие. Лимит 12, позиции из `IRngService`, хил гасит **самые старые** пропорционально их запасу HP. 7. **Количество и размер — пропорция урону с ПОТОЛКОМ.** Категорий «лёгкий/тяжёлый» нет. Искры: `6 + доля_HP × 120`, не больше 48. Форма замирает вместе с hitstop. **Живой стенд — `docs/gamefeel-demos/index.html`**, растущий одностраничник: показывает всё это в движении на настоящем тайминге 30 Гц. Новая тема — новый раздел; после вердикта в разделе обязан появиться стенд «принято». Правила ведения — `docs/gamefeel-demos/README.md`. ## Прежде всего: карта фидбэк-слоя Слой уже построен и живёт в презентации. Ничего не изобретай — читай, продолжай, встраивайся в существующие швы. | Что | Где | |---|---| | Режиссёр значимости (global-feel: kill-slowmo, heavy-shake, финишер) | `Assets/_Project/Scripts/Game/Services/CombatFeelDirector.cs` | | Мост sim→presentation + per-hit фидбэк (hitstop, цифры, спавн VFX) | `Assets/_Project/Scripts/Presentation/CombatPresenter.cs` | | Тряска камеры за интерфейсом | `Assets/_Project/Scripts/Presentation/Camera/IScreenShake.cs`, `ScreenShake.cs` (Cinemachine-extension). Регистрация — `WorldLifetimeScope`; заглушки нет и не заводим | | Пул + спавн VFX-префабов (ключ пула — `EntityId`) | `Assets/_Project/Scripts/Presentation/CombatVfx.cs`, `PooledVfx.cs` | | Определение VFX (префаб, sorting, дефолт-направление) | `Assets/_Project/Scripts/Data/Definitions/VfxData.cs` — владеет `data-authoring` | | Разлёт спрайта на осколки при смерти | `Assets/_Project/Scripts/Presentation/DeathShatter.cs`, `ShatterMesh.cs` | | Всплывающие боевые цифры (урон/хил/evade) | `Assets/_Project/Scripts/Presentation/FloatingText.cs` | | Вспышка арены/фон | `Assets/_Project/Scripts/Presentation/CombatAreaFlash.cs` | | Вид юнита: вспышка/сплющивание/hitstop/death-хуки, точки-сокеты | `Assets/_Project/Scripts/Presentation/UnitView.cs`, `UnitAnimation.cs` | | Единый feel-конфиг (impact-параметры, тумблеры `Enable*`) | `Assets/_Project/Scripts/Presentation/Design/CombatFeelConfig.cs` | | Палитра боевого UI | `Assets/_Project/Scripts/Presentation/Design/CombatColorPalette.cs` | | Боевое время (ПОТРЕБЛЯЕМ, не владеем) — slowmo/пауза/скорость | `Assets/_Project/Scripts/Game/Services/TimeScaleService.cs` → скилл `combat-sim` | **Слой (asmdef):** всё это — `Guildmaster.Presentation` (визуал-компоненты) и `Guildmaster.Game` (сервисы-режиссёры, сшивка через VContainer + MessagePipe). `Presentation` ссылается на `Combat` и СМОТРИТ на него; `Combat` на презентацию не смотрит НИКОГДА. `CombatFeelDirector` живёт в `Game`, потому что ему нужны и `CombatSimulation` (события), и `TimeScaleService`/`IScreenShake` — их `Presentation` не тянет (иначе цикл asmdef). ## Четыре правила, нарушение которых = переделка (HARD) Каждое закрывает конкретный способ, которым фидбэк незаметно загнивает. Пойми «почему» — тогда не придётся заучивать «нельзя». 1. **Все VFX — префабы. И точка.** Конечная форма любого боевого VFX (партиклы / VFX Graph / ShaderGraph-материал) — самодостаточный префаб, лежащий ссылкой в SO, который презентер спавнит в мировой точке-сокете через `ObjectPool` по боевому событию. Эталон уже в проекте: `UnitData.ViewPrefab` — «визуал/анимация/размер настроены ПРЯМО в нём, префаб самодостаточен» (`CombatPresenter.HandleUnitSpawned`). Так же спавнятся `_bulletPrefab`, `_floatingTextPrefab`. *Почему:* префаб — единственная форма, где художник собирает эффект без кода, а код про эффект знает ровно одно: «заспавнить в точке». Кодовый меш плодит визуал в C#, который нельзя приёмить глазами и нельзя отдать художнику. *Где код остаётся законно:* `DeathShatter`/`ShatterMesh` (меш режется из спрайта конкретного юнита — префабом не подменить) и dev-слой `CombatStatusOverlay`. `PixelBurst*` удалён. Новый эффект кодовым мешем не делаем даже «на время». *Шов* (`VfxData` SO → префаб → `CombatVfx`-пул → сокет) **построен** — им и пользуемся, см. раздел ниже и `references/vfx-and-pooling.md`. 2. **Global-feel только в `CombatFeelDirector`; per-hit — в презентере.** Глобальные эффекты значимости (kill-slowmo, heavy-shake, финишер-таймлайн, тряска) решает ОДНО место — `CombatFeelDirector`, по политике «что достойно момента». Точечный фидбэк пары «источник+цель» (hitstop, вспышка, сплющивание, искры, цифры) — в `CombatPresenter`. Не размазывай глобальный feel по `UnitView` и не дёргай глобальную тряску/время из точечного фидбэка. *Почему:* значимость — это политика («килл щёлкает, царапина нет»). Размажешь по вьюхам — потеряешь единую точку, где её крутят, и получишь slowmo на каждый тик DoT. 3. **Значения и формы — из feel-SO, не хардкод.** Тайминги, факторы, кривые — в `CombatFeelConfig` (+ `VfxData` для префабных эффектов). Потребители тянут значения ОТТУДА (`UnitView`, `CombatPresenter`, `ScreenShake`, `CombatFeelDirector`), а не из чисел в коде. Крутить фидбэк = править SO. *Почему:* джус настраивается итерациями «на глаз» — это работа Макса в инспекторе. Число в коде = правка кода на каждый чих баланса фидбэка и недоступно дизайнеру. **ЦВЕТ — исключение: он живёт НЕ в feel-SO** (с 30.07.2026). Ни `CombatFeelConfig`, ни `CombatColorPalette` не хранят `Color` — они называют роли `--gm-color-combat-*`, значения лежат в `UI/Theme/tokens.*.uss` → снимок `GuildmasterPalette` (пересобрать: Alebardium → Дизайн-система). HDR туда не едет: в палитре LDR-база, силу свечения задают числа-множители в конфиге (осколки ×2.75, вспышка смерти ×1.8 — один оттенок пересвета, два события). Новый цвет фидбэка = ступень в примитивах + роль в семантике + пересборка снимка + имя роли в `PaletteSnapshotTests`. Заводить `Color`-поле в конфиге — прямой откат: семь таких полей уже дублировали токены и совпадали только потому, что их никто не правил. 4. **Presentation читает sim только через события/MessagePipe и не влияет на детерминизм.** Фидбэк СМОТРИТ на бой: подписка на C#-события `CombatSimulation` (презентер) или на MessagePipe (`CombatFeelDirector`, как `AudioPresenter`). Никогда не пишет в `RuntimeUnit`/sim и ничего не решает за бой. Всё визуальное живёт на `Time.deltaTime`/твинах/unscaled, не на sim-тике. *Почему:* как только фидбэк мутирует мир или влияет на порядок тика — рушится и детерминизм (кооп-checksum), и headless-тестируемость боя. Это инвариант `combat-sim`, здесь он в силе как граница. **Плюс два инварианта реестра (30.07, заказ Макса «чтобы ни о ком не забыть»):** 5. **У КАЖДОГО эффекта есть выключатель, и он один по форме.** Тумблер `Enable*` в `CombatFeelConfig`; длительность настраивает, а не выключает. До правки джус выключался четырьмя разными способами, а пять эффектов (вспышка удара, сплющивание, вспышка телеграфа, поза гвардии, разлёт на осколки) не выключались вовсе — «список тумблеров» отвечал на вопрос «всё ли включено» неправдой. 6. **Перепись живёт в тесте, а не в SO.** `FeelToggleCoverageTests` держит таблицу «вход → чем выключается» и роняет сборку, если появился новый `Play*`/`Show*`/`Raise*` без записи. Отдельный SO-список стал бы вторым владельцем факта и разошёлся бы с кодом на первом же эффекте; перепись в тесте расходиться не умеет — она падает. *Самая ценная проверка там — текстовая:* тумблер обязан ЧИТАТЬСЯ в коде презентации. Рефлексия этого не видит (свойство существует и возвращает значение, даже если его никто не спрашивает), а именно так выглядит «завели ручку и забыли подключить». *Законное исключение:* тумблер, применяемый ВНУТРИ конфига (цвет вспышки по школе) — он наружу не торчит и помечен в переписи отдельным видом. ## Проверка «дружит ли с новой презентацией юнита» (30.07) Скелетный юнит — не один спрайт, поэтому вопрос «работает ли фидбэк» разбивается на четыре, и все проверяются без play-mode: - **Материальное — только через шов** `IUnitBodyVisual` (тинт, вспышка, голограмма, контур, сортировка, силуэт, осколки). Признак нарушения — обращение к `SpriteRenderer` в презентации вне `Body/`. - **Материал вспышки обязан стоять на КАЖДОЙ части** (`_FlashAmount`): часть без него физически не умеет вспыхивать. Считать: 16 из 16 у костяного. - **Позиционное — по сокетам** (`FeetPoint`/`HeadPoint`/`ShotPoint`/`HitPoint`). Не разведён сокет — фолбэк на центр юнита, и искры бьют в живот вместо груди. Проверять на префабе, а не на глаз. - **Разлёт — по частям, сиблингом самой части**: осколки руки стартуют в пространстве руки, со счётчиком на один финальный колбэк, а не шестнадцать. ## Свечение оружия и цвета юнита — карта швов перед заходом (30.07) Следующий крупный заказ. Перед первой правкой знать вот это, чтобы не строить второй канал рядом с готовым: - **Материальное состояние тела подаётся ОДНИМ куском** (`BodyVisualState` → `IUnitBodyVisual.Apply`) раз в кадр, имена шейдерных параметров держит `BodyShaderIds`. Новый визуальный признак — поле туда, а не отдельный писатель в `UnitView`. - **Оружие и щит — отдельные части скелета** со своими рендерерами и материалом вспышки. Светить клинок физически можно уже сейчас. - **НО шов адресует ТЕЛО ЦЕЛИКОМ:** `Apply` кладёт одно состояние на все части. Это первое, что придётся расширять, и делать это надстройкой поверх общего состояния (роль части: `Weapon`/`Shield`/`Body`), а не вторым независимым каналом: меч обязан вспыхивать вместе со всеми при ударе И светиться сам. Выносить оружие из тела в отдельный держатель — хуже: потеряются внутренняя сортировка группы и общий шаттер. - **Линия дуги для трейла уже считается офлайн:** `RigSweep` отдаёт путь предмета с разбивкой на windup / strike / recovery и площадь по спрайту. Слеш-трейл живёт на strike-фазе, её границы известны. - **Цвет берётся с юнита, не из префаба:** `UnitData.VfxColor` (там, где цвет ровно один) и `VfxPalette` (диапазон разброса частиц), плюс `ResolveVfxPalette()`. Хвост трейла — тот же свет, теряющий прозрачность, а НЕ переход во второй цвет. - **Bloom только на VFX, порог ≥ 1.0.** Свечение арта — отдельный заход; цвет ровно в 1.0 порог не пробивает. ## Дуга за клинком — где искать, если она «идёт не так» (07.08.2026) Самый дорогой эффект по числу заходов: чинился четырежды, и три раза корень лежал НЕ в нём. Порядок проверки — от эффекта вниз, потому что дуга — последний потребитель длинной цепочки. | Симптом | Где смотреть на самом деле | |---|---| | след лежит мимо клинка | геометрия предмета: `UnitHeldItem` — длина объявлена, направление берётся с меша рабочей части. Мерить угол «хват → остриё» против угла нарисованного клинка | | след не следует за мечом по ходу взмаха | клип крутит узел `Weapon_*` отдельно от кисти — запрещено, держит `WeaponFollowsTheHandTests` | | след исчезает мгновенно | `SwingArcTrailSeconds` (длина хвоста ВО ВРЕМЕНИ) и `SwingArcFadeOut`. В стенде — ещё и фиктивное время: делегат фазы зовётся на каждой перерисовке, нулевой шаг не должен двигать часы | | след «висит» дальше меча к концу удара | радиус сектора обязан СЛЕДОВАТЬ за рукой, а не помнить максимальный размах | Владельцы: `SwingArcGeometry` (плечо и остриё), `SwingArcLaunch` (все числа запуска), `SwingArcVfx.Tick` (шаг жизни). Все трое зовутся и боем, и стендом — считать что-либо из этого своими руками запрещено, держит `SwingArcSingleOwnerTests`. **Урок, который стоит помнить дольше самой дуги.** Симптом читался как дефект эффекта и трижды в нём же чинился. Все правки были нужны, но корень лежал двумя слоями ниже — в риге, — и нашёлся не рассуждением, а ЗАМЕРОМ: угол вектора «хват → остриё» против угла нарисованного клинка, два числа. Когда эффект «почти правильный», спрашивать надо не его, а то, из чего он считается. ## Граница со смежными скиллами (режем чётко) Фидбэк стоит на стыке трёх скиллов. На каждом стыке — взаимная ссылка «см. другой скилл», а не спор за файл. - **combat-sim** владеет **боевым временем**: `TimeScaleService` (единственный писатель `Time.timeScale`, композит `GameSpeed × Cinematic`, пауза, шов под геймплейный хрономант) и шов sim→MessagePipe. `CombatFeelDirector` (мой) — **потребитель**: дёргает `TimeScaleService.CinematicPulse`/`PlayCinematicSequence` и `IScreenShake.Shake`. Тип `CinematicSegment` живёт на шве в `TimeScaleService` (им владеет combat-sim), FeelDirector его конструирует. Инвариант «`timeScale` пишет только `TimeScaleService`» — за combat-sim. - **audio** владеет звуком: `IAudioService`, FMOD, стингеры, микс. Пересечение — `TimeScaleService` толкает slowmo-питч через `IAudioService.SetGlobalParameter` (`AudioParameters.TimeScale`): вызов геймплейный (combat-sim), параметр — audio. Джус и звук на одно событие подписываются НЕЗАВИСИМО (оба слушают MessagePipe/sim), не через друг друга. - **data-authoring** владеет **ОПРЕДЕЛЕНИЕМ** контента-SO. Целевой `VfxData` (id, ссылка на VFX-префаб, параметры, loc — если нужен) — как `EffectData`: определение за data-authoring. **Спавн-механика** (пул, точки-сокеты, презентер, привязка к событию) — моя. Ровно как эффект: определение — data-authoring, поведение/спавн — здесь. ## Шов префаб-VFX ПОСТРОЕН Зеркало `UnitData.ViewPrefab`, и он уже работает: 1. **`VfxData`** SO (`Data/Definitions/`, владеет `data-authoring`): `id` (`domain.name`), ссылка на префаб, sorting layer/order, `DefaultDirDeg`. 2. **`CombatVfx`** + `PooledVfx` (здесь): пул на префаб, `Get` → позиционировать в мировую точку-сокет → `Play`, авто-`Release` по завершению. **Ключ пула — `EntityId`, не `int`.** Относительный order детей приходит из самого префаба, а не из кода. 3. Презентер по боевому событию резолвит `VfxData` и просит проиграть в точке (`ShotPoint`/`HitPoint`/`FeetPoint` на `UnitView`); `dirDeg = null` → `VfxData.DefaultDirDeg`. `PixelBurst*` мигрирован и удалён. Кодом законно остаются `DeathShatter`/`ShatterMesh` (меш режется из спрайта конкретного юнита) и dev-слой `CombatStatusOverlay`. Детали и антипаттерны — `references/vfx-and-pooling.md`. ## Как я авторю фидбэк-код — ГИБРИД (файл + проверка через MCP) 1. **Пишу C#-файлы напрямую** (`Write`/`Edit`) — контролирую код и его слой (Presentation
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub