feat(phase7): 고정 4색 팔레트 시스템 적용
- ascii_colors.dart 생성 - 흰색(object): 캐릭터, 몬스터, 아이템 - 시안(positive): 힐, 버프, 레벨업, 획득 - 마젠타(negative): 데미지, 디버프, 사망, 손실 - 검정(background): 배경 - 테마 선택 기능 제거 - AsciiAnimationCard: colorTheme 파라미터 제거, 고정 색상 사용 - TaskProgressPanel: 테마 버튼 제거 - GamePlayScreen: 테마 관련 상태/메서드 제거 - 이펙트 색상 시스템 업데이트 - '*' (히트) → 마젠타 - '!' '+' (강조/버프) → 시안 - '~' (디버프) → 마젠타
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:askiineverdie/l10n/app_localizations.dart';
|
||||
import 'package:askiineverdie/src/core/animation/ascii_animation_data.dart';
|
||||
import 'package:askiineverdie/src/core/animation/ascii_animation_type.dart';
|
||||
import 'package:askiineverdie/src/core/l10n/game_data_l10n.dart';
|
||||
import 'package:askiineverdie/src/core/model/game_state.dart';
|
||||
import 'package:askiineverdie/src/core/storage/theme_preferences.dart';
|
||||
import 'package:askiineverdie/src/core/util/pq_logic.dart' as pq_logic;
|
||||
import 'package:askiineverdie/src/features/game/game_session_controller.dart';
|
||||
import 'package:askiineverdie/src/features/game/widgets/task_progress_panel.dart';
|
||||
|
||||
/// 게임 진행 화면 (Main.dfm 기반 3패널 레이아웃)
|
||||
///
|
||||
/// Phase 7: colorTheme 제거됨, 고정 4색 팔레트 사용
|
||||
class GamePlayScreen extends StatefulWidget {
|
||||
const GamePlayScreen({super.key, required this.controller});
|
||||
|
||||
@@ -22,7 +22,6 @@ class GamePlayScreen extends StatefulWidget {
|
||||
|
||||
class _GamePlayScreenState extends State<GamePlayScreen>
|
||||
with WidgetsBindingObserver {
|
||||
AsciiColorTheme _colorTheme = AsciiColorTheme.green;
|
||||
AsciiAnimationType? _specialAnimation;
|
||||
|
||||
// 이전 상태 추적 (레벨업/퀘스트/Act 완료 감지용)
|
||||
@@ -30,28 +29,6 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
||||
int _lastQuestCount = 0;
|
||||
int _lastPlotStageCount = 0;
|
||||
|
||||
void _cycleColorTheme() {
|
||||
setState(() {
|
||||
_colorTheme = switch (_colorTheme) {
|
||||
AsciiColorTheme.green => AsciiColorTheme.amber,
|
||||
AsciiColorTheme.amber => AsciiColorTheme.white,
|
||||
AsciiColorTheme.white => AsciiColorTheme.system,
|
||||
AsciiColorTheme.system => AsciiColorTheme.green,
|
||||
};
|
||||
});
|
||||
// 테마 변경 시 저장
|
||||
ThemePreferences.saveColorTheme(_colorTheme);
|
||||
}
|
||||
|
||||
Future<void> _loadColorTheme() async {
|
||||
final theme = await ThemePreferences.loadColorTheme();
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_colorTheme = theme;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _checkSpecialEvents(GameState state) {
|
||||
// 레벨업 감지
|
||||
if (state.traits.level > _lastLevel && _lastLevel > 0) {
|
||||
@@ -92,7 +69,6 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
||||
super.initState();
|
||||
widget.controller.addListener(_onControllerChanged);
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
_loadColorTheme();
|
||||
|
||||
// 초기 상태 설정
|
||||
final state = widget.controller.state;
|
||||
@@ -216,7 +192,7 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
// 상단: ASCII 애니메이션 + Task Progress
|
||||
// 상단: ASCII 애니메이션 + Task Progress (Phase 7: 고정 4색 팔레트)
|
||||
TaskProgressPanel(
|
||||
progress: state.progress,
|
||||
speedMultiplier: widget.controller.loop?.speedMultiplier ?? 1,
|
||||
@@ -224,8 +200,6 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
||||
widget.controller.loop?.cycleSpeed();
|
||||
setState(() {});
|
||||
},
|
||||
colorTheme: _colorTheme,
|
||||
onThemeCycle: _cycleColorTheme,
|
||||
isPaused: !widget.controller.isRunning,
|
||||
onPauseToggle: () async {
|
||||
await widget.controller.togglePause();
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:askiineverdie/src/core/animation/battle_composer.dart';
|
||||
import 'package:askiineverdie/src/core/animation/character_frames.dart';
|
||||
import 'package:askiineverdie/src/core/animation/monster_size.dart';
|
||||
import 'package:askiineverdie/src/core/animation/weapon_category.dart';
|
||||
import 'package:askiineverdie/src/core/constants/ascii_colors.dart';
|
||||
import 'package:askiineverdie/src/core/model/game_state.dart';
|
||||
|
||||
/// ASCII 애니메이션 카드 위젯
|
||||
@@ -336,31 +337,26 @@ class _AsciiAnimationCardState extends State<AsciiAnimationCard> {
|
||||
return TextSpan(children: spans);
|
||||
}
|
||||
|
||||
/// 이펙트 문자별 색상 반환
|
||||
/// 이펙트 문자별 색상 반환 (Phase 7: 4색 팔레트)
|
||||
Color _getEffectColor(String char) {
|
||||
return switch (char) {
|
||||
'*' => Colors.orange, // 히트/폭발
|
||||
'!' => Colors.yellow, // 강조
|
||||
'=' || '>' || '<' => Colors.cyan, // 슬래시/찌르기
|
||||
'~' => Colors.purple, // 물결/마법
|
||||
_ => Colors.white,
|
||||
'*' => AsciiColors.negative, // 히트/폭발 (마젠타)
|
||||
'!' => AsciiColors.positive, // 강조 (시안)
|
||||
'=' || '>' || '<' => AsciiColors.positive, // 슬래시/찌르기 (시안)
|
||||
'~' => AsciiColors.negative, // 물결/디버프 (마젠타)
|
||||
'+' => AsciiColors.positive, // 회복/버프 (시안)
|
||||
_ => AsciiColors.object, // 오브젝트 (흰색)
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final brightness = Theme.of(context).brightness;
|
||||
final colors = getThemeColors(widget.colorTheme, brightness);
|
||||
|
||||
// 특수 애니메이션 중이면 특별한 배경색 적용
|
||||
final isSpecial = _currentSpecialAnimation != null;
|
||||
final bgColor = isSpecial
|
||||
? colors.backgroundColor.withValues(alpha: 0.95)
|
||||
: colors.backgroundColor;
|
||||
// Phase 7: 고정 4색 팔레트 사용 (colorTheme 무시)
|
||||
const bgColor = AsciiColors.background;
|
||||
const textColor = AsciiColors.object;
|
||||
|
||||
// 프레임 텍스트 결정
|
||||
String frameText;
|
||||
Color textColor = colors.textColor;
|
||||
|
||||
if (_isBattleMode && _battleComposer != null) {
|
||||
// 새 배틀 시스템 사용 (배경 포함)
|
||||
@@ -380,13 +376,16 @@ class _AsciiAnimationCardState extends State<AsciiAnimationCard> {
|
||||
frameText = _animationData.frames[frameIndex];
|
||||
}
|
||||
|
||||
// 특수 애니메이션 중이면 테두리 표시
|
||||
final isSpecial = _currentSpecialAnimation != null;
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(
|
||||
color: bgColor,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
border: isSpecial
|
||||
? Border.all(color: colors.textColor.withValues(alpha: 0.5))
|
||||
? Border.all(color: AsciiColors.positive.withValues(alpha: 0.5))
|
||||
: null,
|
||||
),
|
||||
child: _isBattleMode
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:askiineverdie/l10n/app_localizations.dart';
|
||||
import 'package:askiineverdie/src/core/animation/ascii_animation_data.dart';
|
||||
import 'package:askiineverdie/src/core/animation/ascii_animation_type.dart';
|
||||
import 'package:askiineverdie/src/core/model/game_state.dart';
|
||||
import 'package:askiineverdie/src/features/game/widgets/ascii_animation_card.dart';
|
||||
|
||||
/// 상단 패널: ASCII 애니메이션 + Task Progress 바
|
||||
///
|
||||
/// Phase 7: colorTheme 제거됨, 고정 4색 팔레트 사용
|
||||
class TaskProgressPanel extends StatelessWidget {
|
||||
const TaskProgressPanel({
|
||||
super.key,
|
||||
required this.progress,
|
||||
required this.speedMultiplier,
|
||||
required this.onSpeedCycle,
|
||||
required this.colorTheme,
|
||||
required this.onThemeCycle,
|
||||
required this.isPaused,
|
||||
required this.onPauseToggle,
|
||||
this.specialAnimation,
|
||||
@@ -27,8 +26,6 @@ class TaskProgressPanel extends StatelessWidget {
|
||||
final ProgressState progress;
|
||||
final int speedMultiplier;
|
||||
final VoidCallback onSpeedCycle;
|
||||
final AsciiColorTheme colorTheme;
|
||||
final VoidCallback onThemeCycle;
|
||||
|
||||
/// 일시 정지 상태
|
||||
final bool isPaused;
|
||||
@@ -56,13 +53,12 @@ class TaskProgressPanel extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// ASCII 애니메이션 카드
|
||||
// ASCII 애니메이션 카드 (Phase 7: 고정 4색 팔레트)
|
||||
SizedBox(
|
||||
height: 120,
|
||||
child: AsciiAnimationCard(
|
||||
taskType: progress.currentTask.type,
|
||||
monsterBaseName: progress.currentTask.monsterBaseName,
|
||||
colorTheme: colorTheme,
|
||||
specialAnimation: specialAnimation,
|
||||
weaponName: weaponName,
|
||||
shieldName: shieldName,
|
||||
@@ -73,11 +69,9 @@ class TaskProgressPanel extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// 상태 메시지 + 버튼들
|
||||
// 상태 메시지 + 버튼들 (Phase 7: 테마 버튼 제거됨)
|
||||
Row(
|
||||
children: [
|
||||
_buildThemeButton(context),
|
||||
const SizedBox(width: 4),
|
||||
_buildPauseButton(context),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
@@ -102,41 +96,6 @@ class TaskProgressPanel extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildThemeButton(BuildContext context) {
|
||||
final themeLabel = switch (colorTheme) {
|
||||
AsciiColorTheme.green => 'G',
|
||||
AsciiColorTheme.amber => 'A',
|
||||
AsciiColorTheme.white => 'W',
|
||||
AsciiColorTheme.system => 'S',
|
||||
};
|
||||
|
||||
final themeColor = switch (colorTheme) {
|
||||
AsciiColorTheme.green => const Color(0xFF00FF00),
|
||||
AsciiColorTheme.amber => const Color(0xFFFFB000),
|
||||
AsciiColorTheme.white => Colors.white,
|
||||
AsciiColorTheme.system => Theme.of(context).colorScheme.primary,
|
||||
};
|
||||
|
||||
return SizedBox(
|
||||
height: 28,
|
||||
child: OutlinedButton(
|
||||
onPressed: onThemeCycle,
|
||||
style: OutlinedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
visualDensity: VisualDensity.compact,
|
||||
side: BorderSide(color: themeColor.withValues(alpha: 0.5)),
|
||||
),
|
||||
child: Text(
|
||||
themeLabel,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: themeColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPauseButton(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: 28,
|
||||
|
||||
Reference in New Issue
Block a user