From d90543dd8630f7efbcce83ac17b0975698cf6fca Mon Sep 17 00:00:00 2001 From: JiWoong Sul Date: Mon, 19 Jan 2026 19:39:32 +0900 Subject: [PATCH] =?UTF-8?q?fix(speed):=20=EB=B0=B0=EC=86=8D=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 광고 후 배속 적용 안됨: isShowingAd 플래그로 lifecycle reload 방지 - 배속 종료 후 복귀 안됨: setSpeed(_savedSpeedMultiplier) 추가 - 복귀 상자 장비 장착 안됨: _loop?.replaceState() 추가 - 세이브 로드 시 1배속 고정: 명예의 전당 해금 시 최소 2배속 보장 --- lib/src/features/game/game_play_screen.dart | 6 ++++- .../game/game_session_controller.dart | 24 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/src/features/game/game_play_screen.dart b/lib/src/features/game/game_play_screen.dart index aa7a0f7..890112e 100644 --- a/lib/src/features/game/game_play_screen.dart +++ b/lib/src/features/game/game_play_screen.dart @@ -289,9 +289,12 @@ class _GamePlayScreenState extends State } // 모바일: 앱이 포그라운드로 돌아올 때 전체 재로드 + // (광고 표시 중에는 reload 건너뛰기 - 배속 부스트 등 상태 유지) if (appState == AppLifecycleState.resumed && isMobile) { _audioController.resumeAll(); - _reloadGameScreen(); + if (!widget.controller.isShowingAd) { + _reloadGameScreen(); + } } } @@ -659,6 +662,7 @@ class _GamePlayScreenState extends State speedBoostEndMs: widget.controller.monetization.speedBoostEndMs, isPaidUser: widget.controller.monetization.isPaidUser, onSpeedBoostActivate: _handleSpeedBoost, + isSpeedBoostActive: widget.controller.isSpeedBoostActive, adSpeedMultiplier: widget.controller.adSpeedMultiplier, has2xUnlocked: widget.controller.has2xUnlocked, ), diff --git a/lib/src/features/game/game_session_controller.dart b/lib/src/features/game/game_session_controller.dart index f7a2fcf..d0e8d51 100644 --- a/lib/src/features/game/game_session_controller.dart +++ b/lib/src/features/game/game_session_controller.dart @@ -66,6 +66,9 @@ class GameSessionController extends ChangeNotifier { int _speedBoostRemainingSeconds = 0; static const int _speedBoostDuration = 300; // 5분 + // 광고 표시 중 플래그 (lifecycle reload 방지용) + bool _isShowingAd = false; + /// 광고 배속 배율 (릴리즈: 5x, 디버그빌드+디버그모드: 20x) int get _speedBoostMultiplier => (kDebugMode && _cheatsEnabled) ? 20 : 5; @@ -153,8 +156,16 @@ class GameSessionController extends ChangeNotifier { // 명예의 전당 체크 → 가용 배속 결정 final availableSpeeds = await _getAvailableSpeeds(); - // 새 게임이면 1배속, 재개/부활이면 기존 배속 유지 - final initialSpeed = isNewGame ? 1 : previousSpeed; + // 명예의 전당 해금 시 기본 2배속, 아니면 1배속 + final hasHallOfFame = availableSpeeds.contains(2); + // 새 게임이면 기본 배속, 세이브 로드 시 명예의 전당 해금 시 최소 2배속 보장 + final int initialSpeed; + if (isNewGame) { + initialSpeed = hasHallOfFame ? 2 : 1; + } else { + // 세이브 로드: 명예의 전당 해금 시 최소 2배속 + initialSpeed = (hasHallOfFame && previousSpeed < 2) ? 2 : previousSpeed; + } _loop = ProgressLoop( initialState: state, @@ -593,6 +604,9 @@ class GameSessionController extends ChangeNotifier { /// 속도 부스트 활성화 여부 bool get isSpeedBoostActive => _isSpeedBoostActive; + /// 광고 표시 중 여부 (lifecycle reload 방지용) + bool get isShowingAd => _isShowingAd; + /// 속도 부스트 남은 시간 (초) int get speedBoostRemainingSeconds => _speedBoostRemainingSeconds; @@ -626,6 +640,8 @@ class GameSessionController extends ChangeNotifier { // 무료 유저는 인터스티셜 광고 필요 bool activated = false; + _isShowingAd = true; // 광고 표시 시작 (lifecycle reload 방지) + final adResult = await AdService.instance.showInterstitialAd( adType: AdType.interstitialSpeed, onComplete: () { @@ -634,6 +650,8 @@ class GameSessionController extends ChangeNotifier { }, ); + _isShowingAd = false; // 광고 표시 종료 + if (adResult == AdResult.completed || adResult == AdResult.debugSkipped) { debugPrint('[GameSession] Speed boost activated (free user with ad)'); return activated; @@ -690,6 +708,7 @@ class GameSessionController extends ChangeNotifier { if (_loop != null) { _getAvailableSpeeds().then((speeds) { _loop!.updateAvailableSpeeds(speeds); + _loop!.setSpeed(_savedSpeedMultiplier); }); } @@ -825,6 +844,7 @@ class GameSessionController extends ChangeNotifier { } _state = updatedState; + _loop?.replaceState(updatedState); // ProgressLoop 상태도 업데이트 // 저장 unawaited(saveManager.saveState(