ThreeKingdomsSlingshot/Assets/Scripts/Runtime/Skills/SkillVfxFade.cs

86 lines
3.8 KiB
C#
Raw Permalink Normal View History

스킬 이펙트 1차 + IB(쿠로네코) 연출 시험 — 돌진·조준 UI·타격감 (PD 2026-11-10) - 기본 공격(돌진) = IB 이펙트 그대로 시험: 앞 빛 물결 · 속도 꼬리(진영색 4색 · 멈춘 자리에서 0.12초 흐려짐) · WL 흙먼지 · 기준점 dash(아래로 갈수록 발 쪽) · 히트 이펙트 제거(PD 지정 대기) - 슬링샷 방향 결정 UI = IB GameTouchArrow 이식(IbAimArrow · IB 유닛 반지름 0.496 기준 비율) + 진행 중 캐릭터 연출(IbUnitMarks: 발밑 원 · 몸 빛 · 조준 중 속성 방울) · 값 표 Resources/Skills/ib_ui.csv - 기병: 복귀 영역(채운 원 · PreviewCavalryReturn) · 복귀 때 돌아서기(UnitView.TurnAround) - 타격감: HitFeel + CameraController.Shake · 표 hit_feel.csv(IB 흔들림 값은 디컴파일에 없어 추정값) - 액티브 스킬 1차 연출(Fable 제안 56 스킬 · 사본 Resources/Fx/TKS_Fx_Sk_*) · SkillVfx 확장(s_camp · f_fwd · f_drift · f_fade · s_over · b_flat · 트레일 페이드) · 셀화 셰이더 포트 - 2D 돌진 시험본(Dash2D · Aura2D test_aura) · 이전 시험 행은 skill_vfx.csv 에 # 주석 - 여포 크기: dz_boss_lvbu 몸 높이 819 → 718(깃털 제외 · 말 탄 유닛 머리 끝 상한 때문에 작아졌음) - 원본 = Assets/VFX/IB(쿠로네코 · GUID 유지 · Tools/wl_vfx_import.py --skip-scripts) · 사본 도구 Tools/make_ib_fx_copies.cs · make_ib_camp_textures.py · build_dash2d.cs - 테스트 PlayMode 118/118 통과 · 자동 재직렬화(png meta · UITheme · ProjectSettings) 제외 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 04:19:44 +00:00
using UnityEngine;
namespace TKS
{
/// <summary>
/// 이펙트 자연 소멸(2026-11-10 PD 「슬링샷 이동이 종료될 때 자연스럽게 소멸」): 방출을 멈추고 살아 있는 입자의 불투명도를 dur 초 동안 0 으로 낮춘 뒤 지운다.
/// 수명이 무한인 층(투사체 머리·꼬리)도 사라지게 입자 색 알파를 직접 줄인다(모든 이식 셰이더가 입자 색 알파를 곱함). 값 = 표 skill_vfx.csv f_fade.
/// </summary>
public class SkillVfxFade : MonoBehaviour
{
float dur;
float t;
ParticleSystem[] systems;
ParticleSystem.Particle[] buf = new ParticleSystem.Particle[64];
/// <summary>2D 평면 이펙트(b_flat)의 스프라이트 층 — 처음 불투명도에서 0 으로(트레일은 방출만 멈추면 제 길이만큼 줄어듦).</summary>
SpriteRenderer[] sprites;
float[] spriteAlpha;
/// <summary>꼬리(트레일) — 남은 꼬리 전체의 불투명도를 함께 낮춤(IB 속도 꼬리 0.6초가 멈춘 뒤 늦게 사라지던 문제 · PD 2026-11-10).</summary>
TrailRenderer[] trails;
Gradient[] trailGrad;
public static void Begin(GameObject go, float seconds)
{
if (go == null) return;
var f = go.GetComponent<SkillVfxFade>();
if (f != null) return;
f = go.AddComponent<SkillVfxFade>();
f.dur = Mathf.Max(0.05f, seconds);
f.systems = go.GetComponentsInChildren<ParticleSystem>(true);
foreach (var ps in f.systems) ps.Stop(false, ParticleSystemStopBehavior.StopEmitting);
f.trails = go.GetComponentsInChildren<TrailRenderer>(true);
f.trailGrad = new Gradient[f.trails.Length];
for (int i = 0; i < f.trails.Length; i++)
{
f.trails[i].emitting = false;
f.trailGrad[i] = f.trails[i].colorGradient;
}
f.sprites = go.GetComponentsInChildren<SpriteRenderer>(true);
f.spriteAlpha = new float[f.sprites.Length];
for (int i = 0; i < f.sprites.Length; i++) f.spriteAlpha[i] = f.sprites[i].color.a;
}
void LateUpdate()
{
float prev = Mathf.Clamp01(1f - t / dur);
t += Time.deltaTime;
float now = Mathf.Clamp01(1f - t / dur);
float k = prev > 1e-4f ? now / prev : 0f; // 이번 프레임 알파 배율(누적하면 1 - t/dur)
foreach (var ps in systems)
{
if (ps == null) continue;
int n = ps.particleCount;
if (n == 0) continue;
if (buf.Length < n) buf = new ParticleSystem.Particle[Mathf.NextPowerOfTwo(n)];
n = ps.GetParticles(buf, n);
for (int i = 0; i < n; i++)
{
var c = buf[i].startColor;
c.a = (byte)Mathf.Clamp(Mathf.RoundToInt(c.a * k), 0, 255);
buf[i].startColor = c;
}
ps.SetParticles(buf, n);
}
for (int i = 0; i < trails.Length; i++)
{
if (trails[i] == null) continue;
var g = trailGrad[i];
var ak = g.alphaKeys;
for (int j = 0; j < ak.Length; j++) ak[j].alpha *= now;
var ng = new Gradient();
ng.SetKeys(g.colorKeys, ak);
ng.mode = g.mode;
trails[i].colorGradient = ng;
}
for (int i = 0; i < sprites.Length; i++)
{
if (sprites[i] == null) continue;
var c = sprites[i].color;
c.a = spriteAlpha[i] * now;
sprites[i].color = c;
}
if (t >= dur) Destroy(gameObject);
}
}
}