UX·FX v1.5 — 햅틱 단계 · 라이브 띠 · HERO 전광판 · Push 우선순위 · Shield · 이클립스 성공·실패 연출

This commit is contained in:
Sn-Kinos
2026-10-06 20:12:44 +09:00
parent a04626b003
commit 62b9637db9
30 changed files with 851 additions and 118 deletions
+45 -32
View File
@@ -1,11 +1,11 @@
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../theme/tokens.dart';
import 'planet_fx_scope.dart';
import '../i18n/app_locale.dart';
import 'fx_intensity.dart';
/// v1.5 §2.1/6. 진화·HERO 발동은 하나의 타임라인을 쓰며 첫 조회는 기준점이다.
class PlanetEvolution extends StatefulWidget {
@@ -206,9 +206,9 @@ class _PlanetEvolutionState extends State<PlanetEvolution>
_fx.forward(from: 0);
if (ending) return;
if (evolution || hero) {
HapticFeedback.heavyImpact();
fxHaptic(FxIntensity.legendary); // Evolution · HERO GIFT
} else {
HapticFeedback.mediumImpact();
fxHaptic(FxIntensity.medium); // Level Up
}
}
@@ -469,35 +469,7 @@ class _HeroPainter extends CustomPainter {
).createShader(Rect.fromCircle(center: point, radius: radius * 2)),
);
} else {
final burst = (p - 0.5) * 2;
final paint = Paint()
..style = PaintingStyle.stroke
..strokeWidth = 2 * (1 - burst) + 0.5
..color = color.withValues(alpha: (1 - burst) * 0.65);
canvas.save();
canvas.translate(c.dx, c.dy);
canvas.rotate(-0.32);
for (var i = 0; i < 2; i++) {
canvas.drawOval(
Rect.fromCenter(
center: Offset.zero,
width: r * (0.8 + burst * 2.2 - i * 0.15),
height: r * (0.3 + burst - i * 0.05),
),
paint,
);
}
canvas.restore();
final count = lowEffects ? 8 : 24;
for (var i = 0; i < count; i++) {
final a = i * 2.399;
final reach = r * (0.3 + burst * (0.8 + (i % 3) * 0.12));
canvas.drawCircle(
c + Offset(math.cos(a), math.sin(a) * 0.7) * reach,
1 + i % 3 * 0.4,
Paint()..color = color.withValues(alpha: (1 - burst) * 0.8),
);
}
paintOrbitBurst(canvas, size, (p - 0.5) * 2, color, lowEffects);
}
}
@@ -507,3 +479,44 @@ class _HeroPainter extends CustomPainter {
old.lowEffects != lowEffects ||
old.ending != ending;
}
/// Orbit Burst — 기울어진 궤도 고리가 바깥으로 퍼지고 입자가 흩어진다. [burst] 0 → 1.
/// HERO 발동의 Ring Wave 와 이클립스 성공(v1.5 §5 「짧은 Orbit Burst」)이 같이 쓴다.
void paintOrbitBurst(
Canvas canvas,
Size size,
double burst,
Color color,
bool lowEffects,
) {
final c = size.center(Offset.zero);
final r = size.shortestSide * 0.46;
final paint = Paint()
..style = PaintingStyle.stroke
..strokeWidth = 2 * (1 - burst) + 0.5
..color = color.withValues(alpha: (1 - burst) * 0.65);
canvas.save();
canvas.translate(c.dx, c.dy);
canvas.rotate(-0.32);
for (var i = 0; i < 2; i++) {
canvas.drawOval(
Rect.fromCenter(
center: Offset.zero,
width: r * (0.8 + burst * 2.2 - i * 0.15),
height: r * (0.3 + burst - i * 0.05),
),
paint,
);
}
canvas.restore();
final count = lowEffects ? 8 : 24;
for (var i = 0; i < count; i++) {
final a = i * 2.399;
final reach = r * (0.3 + burst * (0.8 + (i % 3) * 0.12));
canvas.drawCircle(
c + Offset(math.cos(a), math.sin(a) * 0.7) * reach,
1 + i % 3 * 0.4,
Paint()..color = color.withValues(alpha: (1 - burst) * 0.8),
);
}
}