From 6a1f97fbc2c237ddcc19e5810d5b6e89ae7499a9 Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Wed, 21 Oct 2026 12:04:00 +0900 Subject: [PATCH] =?UTF-8?q?Stage=206=20=ED=96=89=EC=84=B1=EC=97=90=20?= =?UTF-8?q?=EC=9E=90=EA=B8=B0=EC=9E=A5=20=EB=9D=BC=EC=9D=B8=EC=9D=B4=20?= =?UTF-8?q?=ED=96=89=EC=84=B1=EC=9D=84=20=EA=B0=90=EC=8B=B8=EB=A9=B0=20?= =?UTF-8?q?=EB=B0=94=EA=B9=A5=EC=9C=BC=EB=A1=9C=20=EB=B2=88=EC=A7=80?= =?UTF-8?q?=EB=8A=94=20=EC=97=B0=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/core/ui/planet_25d.dart | 62 +++++++++++++++++++++++++ app/test/planet_give_reaction_test.dart | 18 +++++++ 2 files changed, 80 insertions(+) diff --git a/app/lib/core/ui/planet_25d.dart b/app/lib/core/ui/planet_25d.dart index ae31594..c74e4fd 100644 --- a/app/lib/core/ui/planet_25d.dart +++ b/app/lib/core/ui/planet_25d.dart @@ -472,6 +472,21 @@ class _Planet25DState extends State ), ), ), + // Stage 6 — Figma `2024:20821` 「자기장(Field) 라인이 행성을 감싸며 외곽으로 방사됨」. + // 본체 뒤에 깔아 구면 바깥으로 뻗는 부분만 보이게 한다. + if (stage == 6) + Positioned.fill( + child: IgnorePointer( + child: CustomPaint( + key: const ValueKey('planet-field-lines'), + painter: _FieldLinePainter( + t: t, + color: glow, + lowEffects: _lowEffects, + ), + ), + ), + ), // 6. 링 — 뒤쪽 절반. 본체 뒤에 깔린다. if (ring) Positioned.fill( @@ -902,6 +917,53 @@ class _OrbitPainter extends CustomPainter { old.lowEffects != lowEffects; } +/// Stage 6 자기장 — 양극을 잇는 고리를 좌우로 겹겹이 그리고, 밝은 띠가 안쪽에서 바깥 고리로 +/// 번져 나간다(외곽 방사). 저사양은 고리 수만 줄인다. +class _FieldLinePainter extends CustomPainter { + const _FieldLinePainter({ + required this.t, + required this.color, + required this.lowEffects, + }); + final double t; + final Color color; + final bool lowEffects; + + @override + void paint(Canvas canvas, Size size) { + final c = size.center(Offset.zero); + final r = size.shortestSide * 0.42; + final loops = lowEffects ? 2 : 4; + // 방사 위치 0~1 — 한 주기에 네 번 안쪽에서 바깥으로. + final wave = (t * 4) % 1; + for (var i = 0; i < loops; i++) { + final k = (i + 1) / loops; + final w = r * (0.55 + 0.75 * k); + final h = r * (1.05 + 0.25 * k); + final glow = 1 - ((k - wave).abs() * 2.5).clamp(0.0, 1.0); + final paint = Paint() + ..style = PaintingStyle.stroke + ..strokeWidth = 1.0 + glow * 1.2 + ..color = Color.lerp(color, Colors.white, 0.35)! + .withValues(alpha: (0.14 + 0.36 * glow) * (1 - k * 0.4)); + for (final side in const [-1.0, 1.0]) { + canvas.drawOval( + Rect.fromCenter( + center: c + Offset(side * w / 2, 0), + width: w, + height: h * 2, + ), + paint, + ); + } + } + } + + @override + bool shouldRepaint(_FieldLinePainter old) => + old.t != t || old.color != color || old.lowEffects != lowEffects; +} + /// Stage 6: 폭죽 대신 구면 주위에 머무는 넓고 일정한 대기광. class _SustainedAura extends CustomPainter { const _SustainedAura({required this.color, required this.lowEffects}); diff --git a/app/test/planet_give_reaction_test.dart b/app/test/planet_give_reaction_test.dart index 2d6158a..0b5197f 100644 --- a/app/test/planet_give_reaction_test.dart +++ b/app/test/planet_give_reaction_test.dart @@ -182,4 +182,22 @@ void main() { await tester.pump(const Duration(seconds: 3)); }); }); + + testWidgets('Stage 6 은 자기장 라인이 행성을 감싼다(Figma 2024:20821) · Stage 5 는 없다', (tester) async { + Future pumpStage(int stage) => tester.pumpWidget( + MaterialApp( + home: Center( + child: Planet25D( + image: 'assets/figma/planet-home.png', + size: 200, + stage: stage, + ), + ), + ), + ); + await pumpStage(6); + expect(find.byKey(const ValueKey('planet-field-lines')), findsOneWidget); + await pumpStage(5); + expect(find.byKey(const ValueKey('planet-field-lines')), findsNothing); + }); }